Files
bigcapital/packages/server/src/modules/SaleReceipts/commands/EditSaleReceipt.service.ts
2025-04-07 11:51:24 +02:00

111 lines
3.8 KiB
TypeScript

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<typeof SaleReceipt>,
@Inject(Customer.name)
private readonly customerModel: TenantModelProxy<typeof Customer>,
) {}
/**
* 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;
});
}
}