import { Knex } from 'knex'; import { Inject, Service } from 'typedi'; import { ICreditNote, ICreditNoteRefundDTO, IRefundCreditNote, IRefundCreditNoteCreatedPayload, IRefundCreditNoteCreatingPayload, } from '@/interfaces'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import UnitOfWork from '@/services/UnitOfWork'; import events from '@/subscribers/events'; import RefundCreditNote from './RefundCreditNote'; @Service() export default class CreateRefundCreditNote extends RefundCreditNote { @Inject() tenancy: HasTenancyService; @Inject() private uow: UnitOfWork; @Inject() private eventPublisher: EventPublisher; /** * Retrieve the credit note graph. * @param {number} tenantId * @param {number} creditNoteId * @returns {Promise} */ public createCreditNoteRefund = async ( tenantId: number, creditNoteId: number, newCreditNoteDTO: ICreditNoteRefundDTO ): Promise => { const { RefundCreditNote, Account } = this.tenancy.models(tenantId); // Retrieve the credit note or throw not found service error. const creditNote = await this.getCreditNoteOrThrowError( tenantId, creditNoteId ); // Retrieve the withdrawal account or throw not found service error. const fromAccount = await Account.query() .findById(newCreditNoteDTO.fromAccountId) .throwIfNotFound(); // Validate the credit note remaining amount. this.validateCreditRemainingAmount(creditNote, newCreditNoteDTO.amount); // Validate the refund withdrawal account type. this.validateRefundWithdrawwalAccountType(fromAccount); // Creates a refund credit note transaction. return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => { // Triggers `onCreditNoteRefundCreating` event. await this.eventPublisher.emitAsync(events.creditNote.onRefundCreating, { trx, creditNote, tenantId, newCreditNoteDTO, } as IRefundCreditNoteCreatingPayload); // Stores the refund credit note graph to the storage layer. const refundCreditNote = await RefundCreditNote.query(trx).insertAndFetch( { ...this.transformDTOToModel(creditNote, newCreditNoteDTO), } ); // Triggers `onCreditNoteRefundCreated` event. await this.eventPublisher.emitAsync(events.creditNote.onRefundCreated, { trx, refundCreditNote, creditNote, tenantId, } as IRefundCreditNoteCreatedPayload); return refundCreditNote; }); }; /** * Transformes the refund credit note DTO to model. * @param {number} creditNoteId * @param {ICreditNoteRefundDTO} creditNoteDTO * @returns {ICreditNote} */ private transformDTOToModel = ( creditNote: ICreditNote, creditNoteDTO: ICreditNoteRefundDTO ): IRefundCreditNote => { return { creditNoteId: creditNote.id, currencyCode: creditNote.currencyCode, ...creditNoteDTO, exchangeRate: creditNoteDTO.exchangeRate || 1, }; }; }