import { Inject, Injectable } from '@nestjs/common'; import { Knex } from 'knex'; import { ISaleReceiptEditedPayload, ISaleReceiptEditingPayload, } from '../types/SaleReceipts.types'; import { SaleReceiptValidators } from './SaleReceiptValidators.service'; import { SaleReceiptDTOTransformer } from './SaleReceiptDTOTransformer.service'; import { SaleReceipt } from '../models/SaleReceipt'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { Contact } from '@/modules/Contacts/models/Contact'; import { events } from '@/common/events/events'; import { Customer } from '@/modules/Customers/models/Customer'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { EditSaleReceiptDto } from '../dtos/SaleReceipt.dto'; @Injectable() export class EditSaleReceipt { constructor( private readonly itemsEntriesService: ItemsEntriesService, private readonly eventPublisher: EventEmitter2, private readonly uow: UnitOfWork, private readonly validators: SaleReceiptValidators, private readonly dtoTransformer: SaleReceiptDTOTransformer, @Inject(SaleReceipt.name) private readonly saleReceiptModel: TenantModelProxy, @Inject(Customer.name) private readonly customerModel: TenantModelProxy, ) {} /** * Edit details sale receipt with associated entries. * @param {Integer} saleReceiptId * @param {ISaleReceipt} saleReceipt * @return {void} */ public async editSaleReceipt( saleReceiptId: number, saleReceiptDTO: EditSaleReceiptDto, ) { // Retrieve sale receipt or throw not found service error. const oldSaleReceipt = await this.saleReceiptModel() .query() .findById(saleReceiptId) .withGraphFetched('entries') .throwIfNotFound(); // Retrieves the payment customer model. const paymentCustomer = await this.customerModel() .query() .findById(saleReceiptDTO.customerId) .throwIfNotFound(); // Transform sale receipt DTO to model. const saleReceiptObj = await this.dtoTransformer.transformDTOToModel( saleReceiptDTO, paymentCustomer, oldSaleReceipt, ); // Validate receipt deposit account existance and type. await this.validators.validateReceiptDepositAccountExistence( saleReceiptDTO.depositAccountId, ); // Validate items IDs existance on the storage. await this.itemsEntriesService.validateItemsIdsExistance( saleReceiptDTO.entries, ); // Validate the sellable items. await this.itemsEntriesService.validateNonSellableEntriesItems( saleReceiptDTO.entries, ); // Validate sale receipt number uniuqiness. if (saleReceiptDTO.receiptNumber) { await this.validators.validateReceiptNumberUnique( saleReceiptDTO.receiptNumber, saleReceiptId, ); } // Edits the sale receipt tranasctions with associated transactions under UOW env. return this.uow.withTransaction(async (trx: Knex.Transaction) => { // Triggers `onSaleReceiptsEditing` event. await this.eventPublisher.emitAsync(events.saleReceipt.onEditing, { oldSaleReceipt, saleReceiptDTO, trx, } as ISaleReceiptEditingPayload); // Upsert the receipt graph to the storage. const saleReceipt = await this.saleReceiptModel() .query(trx) .upsertGraphAndFetch({ id: saleReceiptId, ...saleReceiptObj, }); // Triggers `onSaleReceiptEdited` event. await this.eventPublisher.emitAsync(events.saleReceipt.onEdited, { oldSaleReceipt, saleReceipt, saleReceiptDTO, trx, } as ISaleReceiptEditedPayload); return saleReceipt; }); } }