fix: booking invoice issue

This commit is contained in:
ghost2023
2026-07-01 16:11:47 +03:00
parent 43d1634823
commit 2f79178496
3 changed files with 56 additions and 54 deletions

View File

@@ -65,7 +65,7 @@ export class BookingInvoiceService {
async ensureInvoiceForBooking( async ensureInvoiceForBooking(
booking: Booking, booking: Booking,
invoiceOptions: InvoiceOptions = {}, invoiceOptions: InvoiceOptions = {},
): Promise<Invoice | null> { ): Promise<Invoice> {
const existing = await this.billing.findPayable( const existing = await this.billing.findPayable(
Freight.InvoiceSource.Booking, Freight.InvoiceSource.Booking,
booking.id, booking.id,
@@ -77,16 +77,9 @@ export class BookingInvoiceService {
this.logger.warn( this.logger.warn(
`Skipping invoice for booking ${booking.reference} (${booking.id}): no company to bill.`, `Skipping invoice for booking ${booking.reference} (${booking.id}): no company to bill.`,
); );
return null;
} }
const input = this.buildInput(booking, invoiceOptions); const input = this.buildInput(booking, invoiceOptions);
if (!input) {
this.logger.warn(
`Skipping invoice for booking ${booking.reference} (${booking.id}): no priced amount.`,
);
return null;
}
return this.billing.generateInvoice(input); return this.billing.generateInvoice(input);
} }
@@ -154,7 +147,7 @@ export class BookingInvoiceService {
private buildInput( private buildInput(
booking: Booking, booking: Booking,
invoiceOptions: InvoiceOptions = {}, invoiceOptions: InvoiceOptions = {},
): GenerateInvoiceInput | null { ): GenerateInvoiceInput {
const breakdown = (booking.pricingBreakdown ?? const breakdown = (booking.pricingBreakdown ??
{}) as StoredPricingBreakdown; {}) as StoredPricingBreakdown;
const currency = breakdown.currency ?? booking.paymentCurrency ?? "ETB"; const currency = breakdown.currency ?? booking.paymentCurrency ?? "ETB";
@@ -172,7 +165,7 @@ export class BookingInvoiceService {
// Fall back to a single freight line when no breakdown was snapshotted. // Fall back to a single freight line when no breakdown was snapshotted.
if (lines.length === 0) { if (lines.length === 0) {
const amount = Number(booking.totalAmount); const amount = Number(booking.totalAmount);
if (!Number.isFinite(amount) || amount <= 0) return null; if (!Number.isFinite(amount) || amount <= 0) throw new Error("No price");
lines.push({ lines.push({
chargeType: "FREIGHT", chargeType: "FREIGHT",
description: "Rail freight", description: "Rail freight",

View File

@@ -3,6 +3,7 @@ import {
forwardRef, forwardRef,
Inject, Inject,
Injectable, Injectable,
Logger,
} from "@nestjs/common"; } from "@nestjs/common";
import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type"; import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type";
@@ -31,6 +32,7 @@ import { Freight } from "@edr/types";
@Injectable() @Injectable()
export class BookingTransitionService { export class BookingTransitionService {
private readonly logger = new Logger(BookingTransitionService.name);
constructor( constructor(
private readonly bookingsRepository: BookingsRepository, private readonly bookingsRepository: BookingsRepository,
private readonly ruleEngineService: RuleEngineService, private readonly ruleEngineService: RuleEngineService,
@@ -918,8 +920,10 @@ export class BookingTransitionService {
private async acceptOperationRequest(booking: Booking): Promise<Booking> { private async acceptOperationRequest(booking: Booking): Promise<Booking> {
const now = new Date(); const now = new Date();
const invoice = const invoice = await this.invoiceService.ensureInvoiceForBooking(booking);
(await this.invoiceService.ensureInvoiceForBooking(booking))!; this.logger.log(
`Generated invoice ${invoice.invoiceNumber} (${invoice.id}) for ${booking.reference}:${booking.id}`,
);
await this.invoiceService.updateStatus( await this.invoiceService.updateStatus(
invoice.id, invoice.id,
Freight.InvoiceStatus.Pending, Freight.InvoiceStatus.Pending,

View File

@@ -1,44 +1,44 @@
import { Module, forwardRef } from '@nestjs/common'; import { Module, forwardRef } from "@nestjs/common";
import { ConfigService } from '@nestjs/config'; import { ConfigService } from "@nestjs/config";
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from "@nestjs/typeorm";
import { ExchangeModule, ExchangeOptions } from '@edr/api-common'; import { ExchangeModule, ExchangeOptions } from "@edr/api-common";
// import { CustomersModule } from '../customers/customers.module'; // import { CustomersModule } from '../customers/customers.module';
import { CompaniesModule } from '../companies/companies.module'; import { CompaniesModule } from "../companies/companies.module";
import { FilesModule } from '../files/files.module'; import { FilesModule } from "../files/files.module";
import { MinioModule } from '../minio/minio.module'; import { MinioModule } from "../minio/minio.module";
import { RuleEngineModule } from '../rule-engine/rule-engine.module'; import { RuleEngineModule } from "../rule-engine/rule-engine.module";
import { FileUploadSettingsModule } from '../file-upload-settings/file-upload-settings.module'; import { FileUploadSettingsModule } from "../file-upload-settings/file-upload-settings.module";
import { SignaturesModule } from '../signatures/signatures.module'; import { SignaturesModule } from "../signatures/signatures.module";
import { BillingModule } from '../billing/billing.module'; import { BillingModule } from "../billing/billing.module";
import { FirstMileModule } from '../first-mile/first-mile.module'; import { FirstMileModule } from "../first-mile/first-mile.module";
import { BookingContractService } from './booking-contract.service'; import { BookingContractService } from "./booking-contract.service";
import { BookingInvoiceService } from './booking-invoice.service'; import { BookingInvoiceService } from "./booking-invoice.service";
import { BookingPaymentController } from './booking-payment.controller'; import { BookingPaymentController } from "./booking-payment.controller";
import { BookingPaymentService } from './booking-payment.service'; import { BookingPaymentService } from "./booking-payment.service";
import { BookingPricingService } from './booking-pricing.service'; import { BookingPricingService } from "./booking-pricing.service";
import { BookingReferenceDataService } from './booking-reference-data.service'; import { BookingReferenceDataService } from "./booking-reference-data.service";
import { BookingTransitionService } from './booking-transition.service'; import { BookingTransitionService } from "./booking-transition.service";
import { BookingsController } from './bookings.controller'; import { BookingsController } from "./bookings.controller";
import { PayController } from './pay.controller'; import { PayController } from "./pay.controller";
import { BookingsRepository } from './bookings.repository'; import { BookingsRepository } from "./bookings.repository";
import { ConsolidationService } from './consolidation.service'; import { ConsolidationService } from "./consolidation.service";
import { BookingsService } from './bookings.service'; import { BookingsService } from "./bookings.service";
import { BookingApprovalStep } from './entities/booking-approval-step.entity'; import { BookingApprovalStep } from "./entities/booking-approval-step.entity";
import { BookingCargoModifier } from './entities/booking-cargo-modifier.entity'; import { BookingCargoModifier } from "./entities/booking-cargo-modifier.entity";
import { BookingDocumentReview } from './entities/booking-document-review.entity'; import { BookingDocumentReview } from "./entities/booking-document-review.entity";
import { BookingContainer } from './entities/booking-container.entity'; import { BookingContainer } from "./entities/booking-container.entity";
import { BookingRateSnapshot } from './entities/booking-rate-snapshot.entity'; import { BookingRateSnapshot } from "./entities/booking-rate-snapshot.entity";
import { BookingContractSignature } from './entities/booking-contract-signature.entity'; import { BookingContractSignature } from "./entities/booking-contract-signature.entity";
import { BookingReviewNote } from './entities/booking-review-note.entity'; import { BookingReviewNote } from "./entities/booking-review-note.entity";
import { Booking } from './entities/booking.entity'; import { Booking } from "./entities/booking.entity";
import { BookingContainerAllocation } from './entities/booking-container-allocation.entity'; import { BookingContainerAllocation } from "./entities/booking-container-allocation.entity";
import { ContractPdfService } from '../../contracts/contract-pdf.service'; import { ContractPdfService } from "../../contracts/contract-pdf.service";
import { ContractPricingScheduleBuilder } from '../../contracts/contract-pricing-schedule.builder'; import { ContractPricingScheduleBuilder } from "../../contracts/contract-pricing-schedule.builder";
import { ContractRendererService } from '../../contracts/contract-renderer.service'; import { ContractRendererService } from "../../contracts/contract-renderer.service";
import { ContractTemplateResolver } from '../../contracts/contract-template.resolver'; import { ContractTemplateResolver } from "../../contracts/contract-template.resolver";
import { ContractViewModelBuilder } from '../../contracts/contract-view-model.builder'; import { ContractViewModelBuilder } from "../../contracts/contract-view-model.builder";
import { TrainSchedulingModule } from '../train-scheduling/train-scheduling.module'; import { TrainSchedulingModule } from "../train-scheduling/train-scheduling.module";
@Module({ @Module({
imports: [ imports: [
@@ -66,7 +66,7 @@ import { TrainSchedulingModule } from '../train-scheduling/train-scheduling.modu
ExchangeModule.forRootAsync({ ExchangeModule.forRootAsync({
inject: [ConfigService], inject: [ConfigService],
useFactory: (config: ConfigService): ExchangeOptions => useFactory: (config: ConfigService): ExchangeOptions =>
config.get<ExchangeOptions>('app.cbeExchange') ?? {}, config.get<ExchangeOptions>("app.cbeExchange") ?? {},
}), }),
], ],
controllers: [BookingsController, PayController, BookingPaymentController], controllers: [BookingsController, PayController, BookingPaymentController],
@@ -86,6 +86,11 @@ import { TrainSchedulingModule } from '../train-scheduling/train-scheduling.modu
ContractRendererService, ContractRendererService,
ContractPdfService, ContractPdfService,
], ],
exports: [BookingsService, BookingsRepository, BookingPricingService, BookingInvoiceService], exports: [
BookingsService,
BookingsRepository,
BookingPricingService,
BookingInvoiceService,
],
}) })
export class BookingsModule {} export class BookingsModule { }