import { Knex } from 'knex'; import { Service, Inject } from 'typedi'; import { ICreditNoteCreatedPayload, ICreditNoteCreatingPayload, ICreditNoteNewDTO, } from '@/interfaces'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import ItemsEntriesService from '@/services/Items/ItemsEntriesService'; import UnitOfWork from '@/services/UnitOfWork'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; import BaseCreditNotes from './CreditNotes'; @Service() export default class CreateCreditNote extends BaseCreditNotes { @Inject() private uow: UnitOfWork; @Inject() private itemsEntriesService: ItemsEntriesService; @Inject() private tenancy: HasTenancyService; @Inject() private eventPublisher: EventPublisher; /** * Creates a new credit note. * @param creditNoteDTO */ public newCreditNote = async ( tenantId: number, creditNoteDTO: ICreditNoteNewDTO, trx?: Knex.Transaction ) => { const { CreditNote, Contact } = this.tenancy.models(tenantId); // Triggers `onCreditNoteCreate` event. await this.eventPublisher.emitAsync(events.creditNote.onCreate, { tenantId, creditNoteDTO, }); // Validate customer existance. const customer = await Contact.query() .modify('customer') .findById(creditNoteDTO.customerId) .throwIfNotFound(); // Validate items ids existance. await this.itemsEntriesService.validateItemsIdsExistance( tenantId, creditNoteDTO.entries ); // Validate items should be sellable items. await this.itemsEntriesService.validateNonSellableEntriesItems( tenantId, creditNoteDTO.entries ); // Transformes the given DTO to storage layer data. const creditNoteModel = await this.transformCreateEditDTOToModel( tenantId, creditNoteDTO, customer.currencyCode ); // Creates a new credit card transactions under unit-of-work envirement. return this.uow.withTransaction( tenantId, async (trx: Knex.Transaction) => { // Triggers `onCreditNoteCreating` event. await this.eventPublisher.emitAsync(events.creditNote.onCreating, { tenantId, creditNoteDTO, trx, } as ICreditNoteCreatingPayload); // Upsert the credit note graph. const creditNote = await CreditNote.query(trx).upsertGraph({ ...creditNoteModel, }); // Triggers `onCreditNoteCreated` event. await this.eventPublisher.emitAsync(events.creditNote.onCreated, { tenantId, creditNoteDTO, creditNote, creditNoteId: creditNote.id, trx, } as ICreditNoteCreatedPayload); return creditNote; }, trx ); }; }