Files
bigcapital/packages/server-nest/src/modules/PaymentReceived/commands/EditPaymentReceived.service.ts
2024-12-25 00:43:55 +02:00

161 lines
5.5 KiB
TypeScript

import { Inject, Injectable } from '@nestjs/common';
import { Knex } from 'knex';
import { EventEmitter2 } from '@nestjs/event-emitter';
import {
IPaymentReceivedEditDTO,
IPaymentReceivedEditedPayload,
IPaymentReceivedEditingPayload,
} from '../types/PaymentReceived.types';
import { PaymentReceiveDTOTransformer } from './PaymentReceivedDTOTransformer';
import { PaymentReceivedValidators } from './PaymentReceivedValidators.service';
import { PaymentReceived } from '../models/PaymentReceived';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { events } from '@/common/events/events';
import { Customer } from '@/modules/Customers/models/Customer';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
@Injectable()
export class EditPaymentReceived {
constructor(
private readonly transformer: PaymentReceiveDTOTransformer,
private readonly validators: PaymentReceivedValidators,
private readonly eventPublisher: EventEmitter2,
private readonly uow: UnitOfWork,
private readonly tenancyContext: TenancyContext,
@Inject(PaymentReceived)
private readonly paymentReceiveModel: typeof PaymentReceived,
@Inject(Customer.name)
private readonly customerModel: typeof Customer,
) {}
/**
* Edit details the given payment receive with associated entries.
* ------
* - Update the payment receive transactions.
* - Insert the new payment receive entries.
* - Update the given payment receive entries.
* - Delete the not presented payment receive entries.
* - Re-insert the journal transactions and update the different accounts balance.
* - Update the different customer balances.
* - Update the different invoice payment amount.
* @async
* @param {number} paymentReceiveId -
* @param {IPaymentReceivedEditDTO} paymentReceiveDTO -
*/
public async editPaymentReceive(
paymentReceiveId: number,
paymentReceiveDTO: IPaymentReceivedEditDTO,
) {
const tenant = await this.tenancyContext.getTenant(true);
// Validate the payment receive existance.
const oldPaymentReceive = await this.paymentReceiveModel
.query()
.withGraphFetched('entries')
.findById(paymentReceiveId)
.throwIfNotFound();
// Validates the payment existance.
this.validators.validatePaymentExistance(oldPaymentReceive);
// Validate customer existance.
const customer = await this.customerModel
.query()
.findById(paymentReceiveDTO.customerId)
.throwIfNotFound();
// Transformes the payment receive DTO to model.
const paymentReceiveObj = await this.transformEditDTOToModel(
customer,
paymentReceiveDTO,
oldPaymentReceive,
);
// Validate customer whether modified.
this.validators.validateCustomerNotModified(
paymentReceiveDTO,
oldPaymentReceive,
);
// Validate payment receive number uniquiness.
if (paymentReceiveDTO.paymentReceiveNo) {
await this.validators.validatePaymentReceiveNoExistance(
paymentReceiveDTO.paymentReceiveNo,
paymentReceiveId,
);
}
// Validate the deposit account existance and type.
const depositAccount = await this.validators.getDepositAccountOrThrowError(
paymentReceiveDTO.depositAccountId,
);
// Validate the entries ids existance on payment receive type.
await this.validators.validateEntriesIdsExistance(
paymentReceiveId,
paymentReceiveDTO.entries,
);
// Validate payment receive invoices IDs existance and associated
// to the given customer id.
await this.validators.validateInvoicesIDsExistance(
oldPaymentReceive.customerId,
paymentReceiveDTO.entries,
);
// Validate invoice payment amount.
await this.validators.validateInvoicesPaymentsAmount(
paymentReceiveDTO.entries,
oldPaymentReceive.entries,
);
// Validates the payment account currency code.
this.validators.validatePaymentAccountCurrency(
depositAccount.currencyCode,
customer.currencyCode,
tenant?.metadata.baseCurrency,
);
// Creates payment receive transaction under UOW envirement.
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Triggers `onPaymentReceiveEditing` event.
await this.eventPublisher.emitAsync(events.paymentReceive.onEditing, {
trx,
oldPaymentReceive,
paymentReceiveDTO,
} as IPaymentReceivedEditingPayload);
// Update the payment receive transaction.
const paymentReceive = await this.paymentReceiveModel
.query(trx)
.upsertGraphAndFetch({
id: paymentReceiveId,
...paymentReceiveObj,
});
// Triggers `onPaymentReceiveEdited` event.
await this.eventPublisher.emitAsync(events.paymentReceive.onEdited, {
paymentReceiveId,
paymentReceive,
oldPaymentReceive,
paymentReceiveDTO,
trx,
} as IPaymentReceivedEditedPayload);
return paymentReceive;
});
}
/**
* Transform the edit payment receive DTO.
* @param {ICustomer} customer
* @param {IPaymentReceivedEditDTO} paymentReceiveDTO
* @param {IPaymentReceived} oldPaymentReceive
* @returns
*/
private transformEditDTOToModel = async (
customer: Customer,
paymentReceiveDTO: IPaymentReceivedEditDTO,
oldPaymentReceive: PaymentReceived,
) => {
return this.transformer.transformPaymentReceiveDTOToModel(
customer,
paymentReceiveDTO,
oldPaymentReceive,
);
};
}