mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 15:18:11 +00:00
feat: ( payments ) convert ETB to method currency before charging
This commit is contained in:
@@ -1,13 +1,69 @@
|
||||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import {
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { PrismaService } from '../../common/prisma.service';
|
||||
import { Currency } from '@prisma/client';
|
||||
|
||||
/**
|
||||
* Minor-unit decimal places per currency, used to round the CHARGE amount sent to the payment
|
||||
* microservice. DJF has no minor unit (whole francs only); ETB and USD use 2 decimals.
|
||||
*/
|
||||
const CHARGE_CURRENCY_DECIMALS: Record<string, number> = {
|
||||
ETB: 2,
|
||||
USD: 2,
|
||||
DJF: 0,
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class CurrencyService {
|
||||
private readonly logger = new Logger(CurrencyService.name);
|
||||
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async convertEtbMinorToChargeMajor(
|
||||
amountMinorEtb: number,
|
||||
targetCurrency: string,
|
||||
): Promise<number> {
|
||||
const target = targetCurrency.toUpperCase();
|
||||
const decimals = CHARGE_CURRENCY_DECIMALS[target];
|
||||
if (decimals === undefined) {
|
||||
throw new BadRequestException(`Unsupported charge currency: ${targetCurrency}`);
|
||||
}
|
||||
|
||||
const sourceMajor = amountMinorEtb / 100;
|
||||
if (target === Currency.ETB) {
|
||||
return this.roundTo(sourceMajor, decimals);
|
||||
}
|
||||
|
||||
const rate = await this.getRateOrThrow(Currency.ETB, target as Currency);
|
||||
return this.roundTo(sourceMajor * rate, decimals);
|
||||
}
|
||||
|
||||
async getRateOrThrow(
|
||||
fromCurrency: Currency,
|
||||
toCurrency: Currency,
|
||||
): Promise<number> {
|
||||
if (fromCurrency === toCurrency) return 1;
|
||||
const exchangeRate = await this.prisma.currencyExchangeRate.findFirst({
|
||||
where: { fromCurrency, toCurrency },
|
||||
orderBy: { effectiveDate: 'desc' },
|
||||
});
|
||||
if (!exchangeRate) {
|
||||
throw new BadRequestException(
|
||||
`No exchange rate configured for ${fromCurrency}->${toCurrency}`,
|
||||
);
|
||||
}
|
||||
return Number(exchangeRate.rate);
|
||||
}
|
||||
|
||||
private roundTo(value: number, decimals: number): number {
|
||||
const factor = 10 ** decimals;
|
||||
return Math.round(value * factor) / factor;
|
||||
}
|
||||
|
||||
async convertAmount(
|
||||
amountMinor: number,
|
||||
fromCurrency: Currency,
|
||||
|
||||
Reference in New Issue
Block a user