import { Service, Inject } from 'typedi'; import { Knex } from 'knex'; import { IAllocatedLandedCostCreatedPayload, IBillLandedCost, ILandedCostDTO, } from '@/interfaces'; import BaseLandedCostService from './BaseLandedCost'; import events from '@/subscribers/events'; import UnitOfWork from '@/services/UnitOfWork'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; @Service() export default class AllocateLandedCost extends BaseLandedCostService { @Inject() uow: UnitOfWork; @Inject() eventPublisher: EventPublisher; /** * ================================= * - Allocate landed cost. * ================================= * - Validates the allocate cost not the same purchase invoice id. * - Get the given bill (purchase invoice) or throw not found error. * - Get the given landed cost transaction or throw not found error. * - Validate landed cost transaction has enough unallocated cost amount. * - Validate landed cost transaction entry has enough unallocated cost amount. * - Validate allocate entries existance and associated with cost bill transaction. * - Writes inventory landed cost transaction. * - Increment the allocated landed cost transaction. * - Increment the allocated landed cost transaction entry. * -------------------------------- * @param {ILandedCostDTO} landedCostDTO - Landed cost DTO. * @param {number} tenantId - Tenant id. * @param {number} billId - Purchase invoice id. */ public allocateLandedCost = async ( tenantId: number, allocateCostDTO: ILandedCostDTO, billId: number ): Promise => { const { BillLandedCost, Bill } = this.tenancy.models(tenantId); // Retrieve total cost of allocated items. const amount = this.getAllocateItemsCostTotal(allocateCostDTO); // Retrieve the purchase invoice or throw not found error. const bill = await Bill.query() .findById(billId) .withGraphFetched('entries') .throwIfNotFound(); // Retrieve landed cost transaction or throw not found service error. const costTransaction = await this.getLandedCostOrThrowError( tenantId, allocateCostDTO.transactionType, allocateCostDTO.transactionId ); // Retrieve landed cost transaction entries. const costTransactionEntry = await this.getLandedCostEntry( tenantId, allocateCostDTO.transactionType, allocateCostDTO.transactionId, allocateCostDTO.transactionEntryId ); // Validates allocate cost items association with the purchase invoice entries. this.validateAllocateCostItems(bill.entries, allocateCostDTO.items); // Validate the amount of cost with unallocated landed cost. this.validateLandedCostEntryAmount( costTransactionEntry.unallocatedCostAmount, amount ); // Transformes DTO to bill landed cost model object. const billLandedCostObj = this.transformToBillLandedCost( allocateCostDTO, bill, costTransaction, costTransactionEntry ); // Saves landed cost transactions with associated tranasctions under // unit-of-work eniverment. return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => { // Save the bill landed cost model. const billLandedCost = await BillLandedCost.query(trx).insertGraph( billLandedCostObj ); // Triggers `onBillLandedCostCreated` event. await this.eventPublisher.emitAsync(events.billLandedCost.onCreated, { tenantId, bill, billLandedCostId: billLandedCost.id, billLandedCost, costTransaction, costTransactionEntry, trx, } as IAllocatedLandedCostCreatedPayload); return billLandedCost; }); }; }