diff --git a/apps/edr-freight-api/src/modules/billing/billing.controller.ts b/apps/edr-freight-api/src/modules/billing/billing.controller.ts index 9a441ab65..7da5e2d66 100644 --- a/apps/edr-freight-api/src/modules/billing/billing.controller.ts +++ b/apps/edr-freight-api/src/modules/billing/billing.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Param, ParseUUIDPipe, Res } from "@nestjs/common"; -import { ApiOperation, ApiTags } from "@nestjs/swagger"; +import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; import type { Response } from "express"; import { FreightAdmin } from "../../common/booking-guards"; @@ -8,6 +8,7 @@ import { BillingService } from "./billing.service"; @ApiTags("billing") @Controller("billing") @FreightAdmin() +@ApiBearerAuth() export class BillingController { constructor(private readonly billingService: BillingService) { } diff --git a/apps/edr-freight-api/src/modules/billing/billing.service.ts b/apps/edr-freight-api/src/modules/billing/billing.service.ts index 443f511ee..3566bf4e5 100644 --- a/apps/edr-freight-api/src/modules/billing/billing.service.ts +++ b/apps/edr-freight-api/src/modules/billing/billing.service.ts @@ -344,6 +344,7 @@ export class BillingService { input: GenerateInvoiceInput, manager?: EntityManager, ): Promise { + console.log("oooooooooo", input); const run = (mg: EntityManager) => this.createInvoice(input, mg); return manager ? run(manager) : this.dataSource.transaction(run); } diff --git a/apps/edr-freight-api/src/modules/first-mile/first-mile.controller.ts b/apps/edr-freight-api/src/modules/first-mile/first-mile.controller.ts index 6bb307a4b..680bb5d09 100644 --- a/apps/edr-freight-api/src/modules/first-mile/first-mile.controller.ts +++ b/apps/edr-freight-api/src/modules/first-mile/first-mile.controller.ts @@ -21,6 +21,9 @@ import { AllocateFirstMileContainersDto } from './dto/allocate-containers.dto'; import { FirstMileStatus } from './entities/first-mile.entity'; import { FirstMileService } from './first-mile.service'; import { FirstMileInvoiceService } from './first-mile-invoice.service'; +import { BillingService } from '../billing/billing.service'; +import { BookingsService } from '../bookings/bookings.service'; +import { Freight } from '@edr/types'; @ApiTags('first-mile') @ApiBearerAuth() @@ -30,7 +33,9 @@ export class FirstMileController { constructor( private readonly firstMileService: FirstMileService, private readonly firstMileInvoiceService: FirstMileInvoiceService, - ) {} + private readonly billingService: BillingService, + private readonly bookingsService: BookingsService + ) { } @Get() @ApiOperation({ summary: 'List first-mile legs' }) @@ -80,7 +85,34 @@ export class FirstMileController { async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateFirstMileDto) { const record = await this.firstMileService.update(id, dto); // Auto-generate invoice if distance or payment was updated - if (dto.exactKm !== undefined || dto.remainingPayment !== undefined) { + const booking = await this.bookingsService.findById(record.bookingId); + if (dto.exactKm !== undefined || dto.exactKm != record.exactKm || dto.remainingPayment !== undefined || dto.remainingPayment !== record.remainingPayment) { + await this.billingService.generateInvoice({ + source: Freight.InvoiceSource.FirstMile, + sourceId: record.id, + type: "FIRST_MILE", + companyId: booking.companyId, + companyProfileId: booking.companyProfileId, + currency: "ETB", + + lines: [ + { + chargeType: "FIRST_MILE", + description: "First Mile Transportation Service", + quantity: 1, + unitRate: record.remainingPayment, + amount: record.remainingPayment, + currency: "ETB", + }, + ], + + subtotalAmount: record.remainingPayment, + taxAmount: 0, // Replace if VAT/tax applies + totalAmount: record.remainingPayment, + + dueInDays: 7, + status: Freight.InvoiceStatus.Pending, + }); await this.firstMileInvoiceService.ensureInvoiceFor(record); } return record; diff --git a/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts b/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts index 929d97a3e..7e3ddcb08 100644 --- a/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts +++ b/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts @@ -21,6 +21,9 @@ import { AllocateLastMileContainersDto } from './dto/allocate-containers.dto'; import { LastMileStatus } from './entities/last-mile.entity'; import { LastMileService } from './last-mile.service'; import { LastMileInvoiceService } from './last-mile-invoice.service'; +import { Freight } from '@edr/types'; +import { BillingService } from '../billing/billing.service'; +import { BookingsService } from '../bookings/bookings.service'; @ApiTags('last-mile') @ApiBearerAuth() @@ -30,6 +33,8 @@ export class LastMileController { constructor( private readonly lastMileService: LastMileService, private readonly lastMileInvoiceService: LastMileInvoiceService, + private readonly billingService: BillingService, + private readonly bookingsService: BookingsService ) {} @Get() @@ -80,9 +85,36 @@ export class LastMileController { async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateLastMileDto) { const record = await this.lastMileService.update(id, dto); // Auto-generate invoice if distance or payment was updated - if (dto.exactKm !== undefined || dto.remainingPayment !== undefined) { - await this.lastMileInvoiceService.ensureInvoiceFor(record); - } + const booking = await this.bookingsService.findById(record.bookingId); + if (dto.exactKm !== undefined || dto.exactKm != record.exactKm || dto.remainingPayment !== undefined || dto.remainingPayment !== record.remainingPayment) { + await this.billingService.generateInvoice({ + source: Freight.InvoiceSource.FirstMile, + sourceId: record.id, + type: "FIRST_MILE", + companyId: booking.companyId, + companyProfileId: booking.companyProfileId, + currency: "ETB", + + lines: [ + { + chargeType: "FIRST_MILE", + description: "First Mile Transportation Service", + quantity: 1, + unitRate: record.remainingPayment, + amount: record.remainingPayment, + currency: "ETB", + }, + ], + + subtotalAmount: record.remainingPayment, + taxAmount: 0, // Replace if VAT/tax applies + totalAmount: record.remainingPayment, + + dueInDays: 7, + status: Freight.InvoiceStatus.Pending, + }); + await this.lastMileInvoiceService.ensureInvoiceFor(record); + } return record; } diff --git a/packages/types/src/freight/index.ts b/packages/types/src/freight/index.ts index 3d92a5652..24128d23d 100644 --- a/packages/types/src/freight/index.ts +++ b/packages/types/src/freight/index.ts @@ -149,6 +149,7 @@ export enum InvoiceSource { Booking = "booking", Warehouse = "warehouse", Demurrage = "demurrage", + FirstMile = "firstmile" } export enum SchedulingStatus {