import { Body, Controller, Get, Patch } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; import { CurrentUser } from "@edr/api-common"; import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type"; import { BookingStaff, MixedAudience } from "../../common/booking-guards"; import { FREIGHT_PERMS } from "../../seed/freight-permissions.registry"; import { UpdateExchangeSettingDto } from "./dto/update-exchange-setting.dto"; import { ExchangeSettingsService } from "./exchange-settings.service"; @ApiTags("exchange-settings") @ApiBearerAuth() @Controller("exchange-settings") export class ExchangeSettingsController { constructor(private readonly service: ExchangeSettingsService) {} @Get() @BookingStaff([FREIGHT_PERMS.settings.exchangeRate.view, FREIGHT_PERMS.admin]) @ApiOperation({ summary: "Current USD→ETB fallback rate and CBE feed health", }) async get() { const setting = await this.service.get(); const status = this.service.getFeedStatus(); return { fallbackRate: setting.fallbackRate, fallbackSource: setting.fallbackSource, lastSyncedAt: setting.lastSyncedAt, updatedById: setting.updatedById, djfEnabled: setting.djfEnabled, feed: status, }; } @Get("currencies") @MixedAudience([FREIGHT_PERMS.settings.exchangeRate.view, FREIGHT_PERMS.admin]) @ApiOperation({ summary: "Currencies a booking or contract may be billed in right now", }) async currencies() { // Customers reach this too — the portal's currency picker must offer exactly what the // API will accept, or the choice fires and comes back a 400. return { currencies: await this.service.enabledCurrencies() }; } @Patch() @BookingStaff([FREIGHT_PERMS.settings.exchangeRate.manage, FREIGHT_PERMS.admin]) @ApiOperation({ summary: "Set the USD→ETB fallback by hand (used only while CBE is unreachable) " + "and/or turn DJF billing on and off", }) async update( @Body() dto: UpdateExchangeSettingDto, @CurrentUser() user: TCurrentUser, ) { // An omitted field leaves that setting alone — setting the rate stamps it MANUAL, and // toggling DJF must not do that as a side effect. let updated = await this.service.get(); if (dto.fallbackRate !== undefined) { updated = await this.service.setManualRate( dto.fallbackRate, user?.id ?? null, ); } if (dto.djfEnabled !== undefined) { updated = await this.service.setDjfEnabled( dto.djfEnabled, user?.id ?? null, ); } return { fallbackRate: updated.fallbackRate, fallbackSource: updated.fallbackSource, lastSyncedAt: updated.lastSyncedAt, updatedById: updated.updatedById, djfEnabled: updated.djfEnabled, }; } }