mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
Backoffice contact details, currency mgmt. updates
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { Controller, Get, Post, Patch, Delete, Param, Body, SetMetadata } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNumber, IsOptional, IsString, Min } from 'class-validator';
|
||||
import { Currency } from '@prisma/client';
|
||||
import { CurrencyService } from './currency.service';
|
||||
import { PassengerAdmin } from '../../common/passenger-guards';
|
||||
|
||||
class CreateRateDto {
|
||||
@IsEnum(Currency) fromCurrency: Currency;
|
||||
@IsEnum(Currency) toCurrency: Currency;
|
||||
@IsNumber() @Min(0.000001) rate: number;
|
||||
@IsOptional() @IsString() source?: string;
|
||||
}
|
||||
|
||||
class UpdateRateDto {
|
||||
@IsNumber() @Min(0.000001) rate: number;
|
||||
@IsOptional() @IsString() source?: string;
|
||||
}
|
||||
|
||||
@ApiTags('Currency')
|
||||
@Controller('currencies')
|
||||
export class CurrencyController {
|
||||
constructor(private readonly currencyService: CurrencyService) {}
|
||||
|
||||
@Get()
|
||||
@SetMetadata('isPublic', true)
|
||||
@ApiOperation({ summary: 'List all exchange rates' })
|
||||
listRates() {
|
||||
return this.currencyService.listRates();
|
||||
}
|
||||
|
||||
@Post()
|
||||
@PassengerAdmin()
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Create exchange rate' })
|
||||
create(@Body() dto: CreateRateDto) {
|
||||
return this.currencyService.upsertRate(dto.fromCurrency, dto.toCurrency, dto.rate, undefined, dto.source ?? 'MANUAL');
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@PassengerAdmin()
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Update exchange rate by ID' })
|
||||
update(@Param('id') id: string, @Body() dto: UpdateRateDto) {
|
||||
return this.currencyService.updateRateById(id, dto.rate, dto.source ?? 'MANUAL');
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@PassengerAdmin()
|
||||
@ApiBearerAuth('IAM-auth')
|
||||
@ApiOperation({ summary: 'Delete exchange rate by ID' })
|
||||
delete(@Param('id') id: string) {
|
||||
return this.currencyService.deleteRate(id);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
import { CurrencyService } from './currency.service';
|
||||
import { CurrencyController } from './currency.controller';
|
||||
import { PrismaModule } from '../../common/prisma.module';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, HttpModule],
|
||||
imports: [PrismaModule],
|
||||
controllers: [CurrencyController],
|
||||
providers: [CurrencyService],
|
||||
exports: [CurrencyService],
|
||||
})
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { Injectable, Logger, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { PrismaService } from '../../common/prisma.service';
|
||||
import { Currency } from '@prisma/client';
|
||||
|
||||
@@ -24,11 +16,7 @@ const CHARGE_CURRENCY_DECIMALS: Record<string, number> = {
|
||||
export class CurrencyService {
|
||||
private readonly logger = new Logger(CurrencyService.name);
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly httpService: HttpService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
/**
|
||||
* Converts a stored display-currency minor amount to the charge major amount
|
||||
@@ -148,53 +136,6 @@ export class CurrencyService {
|
||||
return Number(exchangeRate.rate);
|
||||
}
|
||||
|
||||
async syncExchangeRates(): Promise<void> {
|
||||
this.logger.log('Syncing exchange rates from central bank API');
|
||||
|
||||
const today = this.todayUtc();
|
||||
// Fallback rates used when the API is unreachable
|
||||
const fallbackRates = [
|
||||
{ from: Currency.ETB, to: Currency.ETB, rate: 1.0 },
|
||||
{ from: Currency.ETB, to: Currency.DJF, rate: 3.25 },
|
||||
{ from: Currency.ETB, to: Currency.USD, rate: 0.018 },
|
||||
{ from: Currency.DJF, to: Currency.ETB, rate: 0.3077 },
|
||||
{ from: Currency.USD, to: Currency.ETB, rate: 55.56 },
|
||||
];
|
||||
|
||||
const apiUrl = this.configService.get<string>('EXCHANGE_RATE_API_URL');
|
||||
if (apiUrl) {
|
||||
try {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.get<Record<string, number>>(apiUrl, { timeout: 5000 }),
|
||||
);
|
||||
// Expected response shape: { "ETB_DJF": 3.25, "ETB_USD": 0.018, ... }
|
||||
const data = response.data;
|
||||
const apiRates = [
|
||||
{ from: Currency.ETB, to: Currency.ETB, rate: 1.0 },
|
||||
{ from: Currency.ETB, to: Currency.DJF, rate: data['ETB_DJF'] ?? fallbackRates[1].rate },
|
||||
{ from: Currency.ETB, to: Currency.USD, rate: data['ETB_USD'] ?? fallbackRates[2].rate },
|
||||
{ from: Currency.DJF, to: Currency.ETB, rate: data['DJF_ETB'] ?? fallbackRates[3].rate },
|
||||
{ from: Currency.USD, to: Currency.ETB, rate: data['USD_ETB'] ?? fallbackRates[4].rate },
|
||||
];
|
||||
for (const { from, to, rate } of apiRates) {
|
||||
await this.upsertRate(from, to, rate, today, 'CENTRAL_BANK_API');
|
||||
}
|
||||
this.logger.log('Exchange rates synced from central bank API');
|
||||
return;
|
||||
} catch (err) {
|
||||
this.logger.warn(
|
||||
`Central bank API unreachable (${(err as Error).message}), falling back to configured rates`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: persist the static rates so the DB always has a current row
|
||||
for (const { from, to, rate } of fallbackRates) {
|
||||
await this.upsertRate(from, to, rate, today, 'FALLBACK');
|
||||
}
|
||||
this.logger.log('Exchange rates synced using fallback values');
|
||||
}
|
||||
|
||||
async listRates() {
|
||||
return this.prisma.currencyExchangeRate.findMany({
|
||||
orderBy: [{ fromCurrency: 'asc' }, { toCurrency: 'asc' }, { effectiveDate: 'desc' }],
|
||||
|
||||
Reference in New Issue
Block a user