refactor: credit notes and vendor credits to Nestjs

This commit is contained in:
Ahmed Bouhuolia
2024-12-29 22:55:42 +02:00
parent caf235e2b5
commit 77bbf6828d
93 changed files with 2249 additions and 1634 deletions

View File

@@ -38,6 +38,7 @@
"@types/passport-local": "^1.0.38", "@types/passport-local": "^1.0.38",
"@types/ramda": "^0.30.2", "@types/ramda": "^0.30.2",
"accounting": "^0.4.1", "accounting": "^0.4.1",
"bluebird": "^3.7.2",
"async": "^3.2.0", "async": "^3.2.0",
"axios": "^1.6.0", "axios": "^1.6.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",

View File

@@ -0,0 +1,4 @@
export enum DiscountType {
Percentage = 'percentage',
Amount = 'amount',
}

View File

@@ -46,10 +46,12 @@ import { BillsModule } from '../Bills/Bills.module';
import { SaleInvoicesModule } from '../SaleInvoices/SaleInvoices.module'; import { SaleInvoicesModule } from '../SaleInvoices/SaleInvoices.module';
import { SaleReceiptsModule } from '../SaleReceipts/SaleReceipts.module'; import { SaleReceiptsModule } from '../SaleReceipts/SaleReceipts.module';
import { ManualJournalsModule } from '../ManualJournals/ManualJournals.module'; import { ManualJournalsModule } from '../ManualJournals/ManualJournals.module';
import { VendorCreditsModule } from '../VendorCredit/VendorCredits.module';
import { CreditNotesModule } from '../CreditNotes/CreditNotes.module'; import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
import { VendorCreditsModule } from '../VendorCredit/VendorCredits.module';
import { VendorCreditApplyBillsModule } from '../VendorCreditsApplyBills/VendorCreditApplyBills.module'; import { VendorCreditApplyBillsModule } from '../VendorCreditsApplyBills/VendorCreditApplyBills.module';
// import { BillPaymentsModule } from '../BillPayments/BillPayments.module'; import { VendorCreditsRefundModule } from '../VendorCreditsRefund/VendorCreditsRefund.module';
import { CreditNoteRefundsModule } from '../CreditNoteRefunds/CreditNoteRefunds.module';
import { BillPaymentsModule } from '../BillPayments/BillPayments.module';
@Module({ @Module({
imports: [ imports: [
@@ -120,10 +122,12 @@ import { VendorCreditApplyBillsModule } from '../VendorCreditsApplyBills/VendorC
SaleReceiptsModule, SaleReceiptsModule,
BillsModule, BillsModule,
ManualJournalsModule, ManualJournalsModule,
CreditNotesModule,
VendorCreditsModule, VendorCreditsModule,
VendorCreditApplyBillsModule, VendorCreditApplyBillsModule,
CreditNotesModule, VendorCreditsRefundModule,
// BillPaymentsModule, CreditNoteRefundsModule,
BillPaymentsModule,
], ],
controllers: [AppController], controllers: [AppController],
providers: [ providers: [

View File

@@ -25,8 +25,9 @@ import { BranchesSettingsService } from '../Branches/BranchesSettings';
CommandBillPaymentDTOTransformer, CommandBillPaymentDTOTransformer,
BranchTransactionDTOTransformer, BranchTransactionDTOTransformer,
BranchesSettingsService, BranchesSettingsService,
TenancyContext TenancyContext,
], ],
exports: [BillPaymentValidators],
controllers: [], controllers: [],
}) })
export class BillPaymentsModule {} export class BillPaymentsModule {}

View File

@@ -0,0 +1,42 @@
import { Body, Controller, Delete, Param, Post } from '@nestjs/common';
import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types';
import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service';
import { RefundCreditNote } from './models/RefundCreditNote';
@Controller('credit-notes')
export class CreditNoteRefundsController {
constructor(
private readonly creditNotesRefundsApplication: CreditNotesRefundsApplication,
) {}
/**
* Create a refund credit note.
* @param {number} creditNoteId - The credit note ID.
* @param {ICreditNoteRefundDTO} creditNoteDTO - The credit note DTO.
* @returns {Promise<RefundCreditNote>}
*/
@Post(':creditNoteId/refunds')
createRefundCreditNote(
@Param('creditNoteId') creditNoteId: number,
@Body() creditNoteDTO: ICreditNoteRefundDTO,
): Promise<RefundCreditNote> {
return this.creditNotesRefundsApplication.createRefundCreditNote(
creditNoteId,
creditNoteDTO,
);
}
/**
* Delete a refund credit note.
* @param {number} refundCreditId - The refund credit ID.
* @returns {Promise<void>}
*/
@Delete('refunds/:refundCreditId')
deleteRefundCreditNote(
@Param('refundCreditId') refundCreditId: number,
): Promise<void> {
return this.creditNotesRefundsApplication.deleteRefundCreditNote(
refundCreditId,
);
}
}

View File

@@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { CreateRefundCreditNoteService } from './commands/CreateRefundCreditNote.service';
import { DeleteRefundCreditNoteService } from './commands/DeleteRefundCreditNote.service';
import { RefundCreditNoteService } from './commands/RefundCreditNote.service';
import { RefundSyncCreditNoteBalanceService } from './commands/RefundSyncCreditNoteBalance';
import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service';
import { CreditNoteRefundsController } from './CreditNoteRefunds.controller';
import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
@Module({
imports: [CreditNotesModule],
providers: [
CreateRefundCreditNoteService,
DeleteRefundCreditNoteService,
RefundCreditNoteService,
RefundSyncCreditNoteBalanceService,
CreditNotesRefundsApplication,
],
controllers: [CreditNoteRefundsController],
})
export class CreditNoteRefundsModule {}

View File

@@ -0,0 +1,43 @@
import { Injectable } from '@nestjs/common';
import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types';
import { CreateRefundCreditNoteService } from './commands/CreateRefundCreditNote.service';
import { DeleteRefundCreditNoteService } from './commands/DeleteRefundCreditNote.service';
import { RefundCreditNoteService } from './commands/RefundCreditNote.service';
import { RefundSyncCreditNoteBalanceService } from './commands/RefundSyncCreditNoteBalance';
@Injectable()
export class CreditNotesRefundsApplication {
constructor(
private readonly createRefundCreditNoteService: CreateRefundCreditNoteService,
private readonly deleteRefundCreditNoteService: DeleteRefundCreditNoteService,
private readonly refundCreditNoteService: RefundCreditNoteService,
private readonly refundSyncCreditNoteBalanceService: RefundSyncCreditNoteBalanceService,
) {}
/**
* Create a refund credit note.
* @param {number} creditNoteId - The credit note ID.
* @param {ICreditNoteRefundDTO} creditNoteDTO - The credit note DTO.
* @returns {Promise<RefundCreditNote>}
*/
public createRefundCreditNote(
creditNoteId: number,
creditNoteDTO: ICreditNoteRefundDTO,
) {
return this.createRefundCreditNoteService.createCreditNoteRefund(
creditNoteId,
creditNoteDTO,
);
}
/**
* Delete a refund credit note.
* @param {number} refundCreditId - The refund credit ID.
* @returns {Promise<void>}
*/
public deleteRefundCreditNote(refundCreditId: number) {
return this.deleteRefundCreditNoteService.deleteCreditNoteRefund(
refundCreditId,
);
}
}

View File

@@ -4,14 +4,14 @@ import {
ICreditNoteRefundDTO, ICreditNoteRefundDTO,
IRefundCreditNoteCreatedPayload, IRefundCreditNoteCreatedPayload,
IRefundCreditNoteCreatingPayload, IRefundCreditNoteCreatingPayload,
} from '../types/CreditNotes.types'; } from '../types/CreditNoteRefunds.types';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { Account } from '@/modules/Accounts/models/Account.model'; import { Account } from '@/modules/Accounts/models/Account.model';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '@/modules/CreditNoteRefunds/models/RefundCreditNote';
import { CommandCreditNoteDTOTransform } from '@/modules/CreditNotes/commands/CommandCreditNoteDTOTransform.service';
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { CommandCreditNoteDTOTransform } from './CommandCreditNoteDTOTransform.service';
import { CreditNote } from '../models/CreditNote';
@Injectable() @Injectable()
export class CreateRefundCreditNoteService { export class CreateRefundCreditNoteService {
@@ -63,9 +63,9 @@ export class CreateRefundCreditNoteService {
newCreditNoteDTO.amount, newCreditNoteDTO.amount,
); );
// Validate the refund withdrawal account type. // Validate the refund withdrawal account type.
this.commandCreditNoteDTOTransform.validateRefundWithdrawwalAccountType( // this.commandCreditNoteDTOTransform.validateRefundWithdrawwalAccountType(
fromAccount, // fromAccount,
); // );
// Creates a refund credit note transaction. // Creates a refund credit note transaction.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Triggers `onCreditNoteRefundCreating` event. // Triggers `onCreditNoteRefundCreating` event.
@@ -102,7 +102,7 @@ export class CreateRefundCreditNoteService {
private transformDTOToModel = ( private transformDTOToModel = (
creditNote: CreditNote, creditNote: CreditNote,
creditNoteDTO: ICreditNoteRefundDTO, creditNoteDTO: ICreditNoteRefundDTO,
): RefundCreditNote => { ): Partial<RefundCreditNote> => {
return { return {
creditNoteId: creditNote.id, creditNoteId: creditNote.id,
currencyCode: creditNote.currencyCode, currencyCode: creditNote.currencyCode,

View File

@@ -4,18 +4,17 @@ import { Knex } from 'knex';
import { import {
IRefundCreditNoteDeletedPayload, IRefundCreditNoteDeletedPayload,
IRefundCreditNoteDeletingPayload, IRefundCreditNoteDeletingPayload,
IRefundVendorCreditDeletedPayload, } from '../types/CreditNoteRefunds.types';
} from '../types/CreditNotes.types';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '../models/RefundCreditNote';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
@Injectable() @Injectable()
export default class DeleteRefundCreditNote { export class DeleteRefundCreditNoteService {
/** /**
* @param {UnitOfWork} uow * @param {UnitOfWork} uow - Unit of work.
* @param {EventEmitter2} eventPublisher * @param {EventEmitter2} eventPublisher - Event emitter.
* @param {typeof RefundCreditNoteModel} refundCreditNoteModel * @param {typeof RefundCreditNote} refundCreditNoteModel - Refund credit note model.
*/ */
constructor( constructor(
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
@@ -27,8 +26,8 @@ export default class DeleteRefundCreditNote {
/** /**
* Retrieve the credit note graph. * Retrieve the credit note graph.
* @param {number} refundCreditId * @param {number} refundCreditId - Refund credit note ID.
* @returns * @returns {Promise<void>}
*/ */
public deleteCreditNoteRefund = async (refundCreditId: number) => { public deleteCreditNoteRefund = async (refundCreditId: number) => {
// Retrieve the old credit note or throw not found service error. // Retrieve the old credit note or throw not found service error.
@@ -56,7 +55,6 @@ export default class DeleteRefundCreditNote {
events.creditNote.onRefundDeleting, events.creditNote.onRefundDeleting,
eventPayload, eventPayload,
); );
// Deletes the refund credit note graph from the storage. // Deletes the refund credit note graph from the storage.
await this.refundCreditNoteModel await this.refundCreditNoteModel
.query(trx) .query(trx)
@@ -66,7 +64,7 @@ export default class DeleteRefundCreditNote {
// Triggers `onCreditNoteRefundDeleted` event. // Triggers `onCreditNoteRefundDeleted` event.
await this.eventPublisher.emitAsync( await this.eventPublisher.emitAsync(
events.creditNote.onRefundDeleted, events.creditNote.onRefundDeleted,
eventPayload as IRefundVendorCreditDeletedPayload, eventPayload as IRefundCreditNoteDeletedPayload,
); );
}); });
}; };

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { ERRORS } from '../constants'; import { ERRORS } from '../../CreditNotes/constants';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '../models/RefundCreditNote';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { Account } from '@/modules/Accounts/models/Account.model'; import { Account } from '@/modules/Accounts/models/Account.model';

View File

@@ -1,9 +1,9 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
@Injectable() @Injectable()
export class RefundSyncCreditNoteBalance { export class RefundSyncCreditNoteBalanceService {
/** /**
* @param {typeof CreditNote} creditNoteModel - The credit note model. * @param {typeof CreditNote} creditNoteModel - The credit note model.
*/ */

View File

@@ -1,8 +1,8 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import RefundCreditNoteTransformer from './RefundCreditNoteTransformer';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '../models/RefundCreditNote';
import { IRefundCreditNotePOJO } from '../types/CreditNotes.types'; import { RefundCreditNoteTransformer } from '@/modules/CreditNotes/queries/RefundCreditNoteTransformer';
import { IRefundCreditNotePOJO } from '../types/CreditNoteRefunds.types';
@Injectable() @Injectable()
export class ListCreditNoteRefunds { export class ListCreditNoteRefunds {

View File

@@ -1,7 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { IRefundCreditNote } from '../types/CreditNotes.types';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '../models/RefundCreditNote';
import { RefundCreditNoteTransformer } from './RefundCreditNoteTransformer'; import { RefundCreditNoteTransformer } from '../../CreditNotes/queries/RefundCreditNoteTransformer';
@Injectable() @Injectable()
export class GetRefundCreditNoteTransaction { export class GetRefundCreditNoteTransaction {
@@ -24,7 +23,7 @@ export class GetRefundCreditNoteTransaction {
*/ */
public async getRefundCreditTransaction( public async getRefundCreditTransaction(
refundCreditId: number refundCreditId: number
): Promise<IRefundCreditNote> { ): Promise<RefundCreditNote> {
const refundCreditNote = await this.refundCreditNoteModel const refundCreditNote = await this.refundCreditNoteModel
.query() .query()
.findById(refundCreditId) .findById(refundCreditId)

View File

@@ -0,0 +1,47 @@
import { Knex } from 'knex';
import { RefundCreditNote } from '../models/RefundCreditNote';
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
export interface ICreditNoteRefundDTO {
fromAccountId: number;
amount: number;
exchangeRate?: number;
referenceNo: string;
description: string;
date: Date;
branchId?: number;
}
export interface IRefundCreditNotePOJO {
formattedAmount: string;
}
export interface IRefundCreditNoteDeletedPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: RefundCreditNote;
}
export interface IRefundCreditNoteDeletingPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: RefundCreditNote;
}
export interface IRefundCreditNoteCreatingPayload {
trx: Knex.Transaction;
creditNote: CreditNote;
newCreditNoteDTO: ICreditNoteRefundDTO;
}
export interface IRefundCreditNoteCreatedPayload {
trx: Knex.Transaction;
refundCreditNote: RefundCreditNote;
creditNote: CreditNote;
}
export interface IRefundCreditNoteOpenedPayload {
creditNoteId: number;
oldCreditNote: CreditNote;
trx: Knex.Transaction;
}

View File

@@ -1,6 +1,5 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { CreateCreditNoteService } from './commands/CreateCreditNote.service'; import { CreateCreditNoteService } from './commands/CreateCreditNote.service';
import { CreateRefundCreditNoteService } from './commands/CreateRefundCreditNote.service';
import { DeleteCreditNoteService } from './commands/DeleteCreditNote.service'; import { DeleteCreditNoteService } from './commands/DeleteCreditNote.service';
import { EditCreditNoteService } from './commands/EditCreditNote.service'; import { EditCreditNoteService } from './commands/EditCreditNote.service';
import { OpenCreditNoteService } from './commands/OpenCreditNote.service'; import { OpenCreditNoteService } from './commands/OpenCreditNote.service';
@@ -8,24 +7,33 @@ import { GetCreditNotePdf } from './queries/GetCreditNotePdf.serivce';
import { import {
ICreditNoteEditDTO, ICreditNoteEditDTO,
ICreditNoteNewDTO, ICreditNoteNewDTO,
ICreditNoteRefundDTO,
} from './types/CreditNotes.types'; } from './types/CreditNotes.types';
@Injectable() @Injectable()
export class CreditNoteApplication { export class CreditNoteApplication {
constructor( constructor(
private createCreditNoteService: CreateCreditNoteService, private createCreditNoteService: CreateCreditNoteService,
private createRefundCreditNoteService: CreateRefundCreditNoteService,
private editCreditNoteService: EditCreditNoteService, private editCreditNoteService: EditCreditNoteService,
private openCreditNoteService: OpenCreditNoteService, private openCreditNoteService: OpenCreditNoteService,
private deleteCreditNoteService: DeleteCreditNoteService, private deleteCreditNoteService: DeleteCreditNoteService,
private getCreditNotePdfService: GetCreditNotePdf, private getCreditNotePdfService: GetCreditNotePdf,
) {} ) {}
/**
* Creates a new credit note.
* @param {ICreditNoteNewDTO} creditNoteDTO
* @returns {Promise<CreditNote>}
*/
createCreditNote(creditNoteDTO: ICreditNoteNewDTO) { createCreditNote(creditNoteDTO: ICreditNoteNewDTO) {
return this.createCreditNoteService.creditCreditNote(creditNoteDTO); return this.createCreditNoteService.creditCreditNote(creditNoteDTO);
} }
/**
* Edits a credit note.
* @param {number} creditNoteId
* @param {ICreditNoteEditDTO} creditNoteDTO
* @returns {Promise<CreditNote>}
*/
editCreditNote(creditNoteId: number, creditNoteDTO: ICreditNoteEditDTO) { editCreditNote(creditNoteId: number, creditNoteDTO: ICreditNoteEditDTO) {
return this.editCreditNoteService.editCreditNote( return this.editCreditNoteService.editCreditNote(
creditNoteId, creditNoteId,
@@ -33,24 +41,29 @@ export class CreditNoteApplication {
); );
} }
/**
* Opens a credit note.
* @param {number} creditNoteId
* @returns {Promise<CreditNote>}
*/
openCreditNote(creditNoteId: number) { openCreditNote(creditNoteId: number) {
return this.openCreditNoteService.openCreditNote(creditNoteId); return this.openCreditNoteService.openCreditNote(creditNoteId);
} }
/**
* Deletes a credit note.
* @param {number} creditNoteId
* @returns {Promise<CreditNote>}
*/
deleteCreditNote(creditNoteId: number) { deleteCreditNote(creditNoteId: number) {
return this.deleteCreditNoteService.deleteCreditNote(creditNoteId); return this.deleteCreditNoteService.deleteCreditNote(creditNoteId);
} }
createRefundCreditNote( /**
creditNoteId: number, * Retrieves the PDF for a credit note.
creditNoteDTO: ICreditNoteRefundDTO, * @param {number} creditNoteId
) { * @returns {Promise<string>}
return this.createRefundCreditNoteService.createCreditNoteRefund( */
creditNoteId,
creditNoteDTO,
);
}
getCreditNotePdf(creditNoteId: number) { getCreditNotePdf(creditNoteId: number) {
return this.getCreditNotePdfService.getCreditNotePdf(creditNoteId); return this.getCreditNotePdfService.getCreditNotePdf(creditNoteId);
} }

View File

@@ -3,7 +3,6 @@ import { CreditNoteApplication } from './CreditNoteApplication.service';
import { import {
ICreditNoteEditDTO, ICreditNoteEditDTO,
ICreditNoteNewDTO, ICreditNoteNewDTO,
ICreditNoteRefundDTO,
} from './types/CreditNotes.types'; } from './types/CreditNotes.types';
@Controller('credit-notes') @Controller('credit-notes')
@@ -38,15 +37,4 @@ export class CreditNotesController {
deleteCreditNote(@Param('id') creditNoteId: number) { deleteCreditNote(@Param('id') creditNoteId: number) {
return this.creditNoteApplication.deleteCreditNote(creditNoteId); return this.creditNoteApplication.deleteCreditNote(creditNoteId);
} }
@Post(':id/refund')
createRefundCreditNote(
@Param('id') creditNoteId: number,
@Body() creditNoteDTO: ICreditNoteRefundDTO,
) {
return this.creditNoteApplication.createRefundCreditNote(
creditNoteId,
creditNoteDTO,
);
}
} }

View File

@@ -1,28 +1,59 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { CreateCreditNoteService } from './commands/CreateCreditNote.service'; import { CreateCreditNoteService } from './commands/CreateCreditNote.service';
import { CommandCreditNoteDTOTransform } from './commands/CommandCreditNoteDTOTransform.service'; import { CommandCreditNoteDTOTransform } from './commands/CommandCreditNoteDTOTransform.service';
import { CreateRefundCreditNoteService } from './commands/CreateRefundCreditNote.service';
import { EditCreditNoteService } from './commands/EditCreditNote.service'; import { EditCreditNoteService } from './commands/EditCreditNote.service';
import { OpenCreditNoteService } from './commands/OpenCreditNote.service'; import { OpenCreditNoteService } from './commands/OpenCreditNote.service';
import { DeleteCreditNoteService } from './commands/DeleteCreditNote.service'; import { DeleteCreditNoteService } from './commands/DeleteCreditNote.service';
import { CreditNoteApplySyncCredit } from './commands/CreditNoteApplySyncCredit.service';
import { DeleteCustomerLinkedCreditNoteService } from './commands/DeleteCustomerLinkedCreditNote.service';
import { CreditNoteAutoIncrementService } from './commands/CreditNoteAutoIncrement.service'; import { CreditNoteAutoIncrementService } from './commands/CreditNoteAutoIncrement.service';
import { CreditNoteApplication } from './CreditNoteApplication.service'; import { CreditNoteApplication } from './CreditNoteApplication.service';
import { CreditNotesController } from './CreditNotes.controller'; import { CreditNotesController } from './CreditNotes.controller';
import { GetCreditNoteState } from './queries/GetCreditNoteState.service';
import { GetCreditNotePdf } from './queries/GetCreditNotePdf.serivce';
import { ItemsModule } from '../Items/items.module';
import { BranchesModule } from '../Branches/Branches.module';
import { WarehousesModule } from '../Warehouses/Warehouses.module';
import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module';
import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module';
import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module';
import { GetCreditNote } from './queries/GetCreditNote.service';
import { CreditNoteBrandingTemplate } from './queries/CreditNoteBrandingTemplate.service';
import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module';
@Module({ @Module({
imports: [
ItemsModule,
BranchesModule,
WarehousesModule,
PdfTemplatesModule,
ChromiumlyTenancyModule,
TemplateInjectableModule,
AutoIncrementOrdersModule
],
providers: [ providers: [
CreateCreditNoteService, CreateCreditNoteService,
GetCreditNote,
CommandCreditNoteDTOTransform, CommandCreditNoteDTOTransform,
CreateRefundCreditNoteService,
EditCreditNoteService, EditCreditNoteService,
OpenCreditNoteService, OpenCreditNoteService,
DeleteCreditNoteService, DeleteCreditNoteService,
CreditNoteApplySyncCredit, GetCreditNotePdf,
DeleteCustomerLinkedCreditNoteService,
CreditNoteAutoIncrementService, CreditNoteAutoIncrementService,
CreditNoteApplication GetCreditNoteState,
CreditNoteApplication,
CreditNoteBrandingTemplate
],
exports: [
CreateCreditNoteService,
GetCreditNote,
CommandCreditNoteDTOTransform,
EditCreditNoteService,
OpenCreditNoteService,
DeleteCreditNoteService,
GetCreditNotePdf,
CreditNoteAutoIncrementService,
GetCreditNoteState,
CreditNoteApplication,
CreditNoteBrandingTemplate
], ],
controllers: [CreditNotesController], controllers: [CreditNotesController],
}) })

View File

@@ -1,42 +0,0 @@
import { Service, Inject } from 'typedi';
import BaseCreditNotes from '../CreditNotes';
import { ISaleInvoice } from '@/interfaces';
import { CreditNoteWithInvoicesToApplyTransformer } from './commands/CreditNoteWithInvoicesToApplyTransformer';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
@Service()
export default class GetCreditNoteAssociatedInvoicesToApply extends BaseCreditNotes {
@Inject()
private transformer: TransformerInjectable;
/**
* Retrieve credit note associated invoices to apply.
* @param {number} tenantId
* @param {number} creditNoteId
* @returns {Promise<ISaleInvoice[]>}
*/
public getCreditAssociatedInvoicesToApply = async (
tenantId: number,
creditNoteId: number
): Promise<ISaleInvoice[]> => {
const { SaleInvoice } = this.tenancy.models(tenantId);
// Retireve credit note or throw not found service error.
const creditNote = await this.getCreditNoteOrThrowError(
tenantId,
creditNoteId
);
// Retrieves the published due invoices that associated to the given customer.
const saleInvoices = await SaleInvoice.query()
.where('customerId', creditNote.customerId)
.modify('dueInvoices')
.modify('published');
// Transformes the sale invoices models to POJO.
return this.transformer.transform(
tenantId,
saleInvoices,
new CreditNoteWithInvoicesToApplyTransformer()
);
};
}

View File

@@ -5,7 +5,6 @@ import * as R from 'ramda';
import composeAsync from 'async/compose'; import composeAsync from 'async/compose';
import { ERRORS } from '../constants'; import { ERRORS } from '../constants';
import { import {
ICreditNote,
ICreditNoteEditDTO, ICreditNoteEditDTO,
ICreditNoteEntryNewDTO, ICreditNoteEntryNewDTO,
ICreditNoteNewDTO, ICreditNoteNewDTO,
@@ -92,9 +91,9 @@ export class CommandCreditNoteDTOTransform {
)(initialDTO); )(initialDTO);
return R.compose( return R.compose(
this.branchDTOTransform.transformDTO<ICreditNote>, this.branchDTOTransform.transformDTO<CreditNote>,
this.warehouseDTOTransform.transformDTO<ICreditNote>, this.warehouseDTOTransform.transformDTO<CreditNote>,
)(initialAsyncDTO); )(initialAsyncDTO) as CreditNote;
}; };
/** /**

View File

@@ -1,5 +1,5 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { import {
ICreditNoteCreatedPayload, ICreditNoteCreatedPayload,
ICreditNoteCreatingPayload, ICreditNoteCreatingPayload,
@@ -15,13 +15,25 @@ import { events } from '@/common/events/events';
@Injectable() @Injectable()
export class CreateCreditNoteService { export class CreateCreditNoteService {
/**
* @param {UnitOfWork} uow - Unit of work.
* @param {ItemsEntriesService} itemsEntriesService - Items entries service.
* @param {EventEmitter2} eventPublisher - Event emitter.
* @param {typeof CreditNote} creditNoteModel - Credit note model.
* @param {typeof Contact} contactModel - Contact model.
* @param {CommandCreditNoteDTOTransform} commandCreditNoteDTOTransform - Command credit note DTO transform service.
*/
constructor( constructor(
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly itemsEntriesService: ItemsEntriesService, private readonly itemsEntriesService: ItemsEntriesService,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
private readonly creditNoteModel: typeof CreditNote,
private readonly contactModel: typeof Contact,
private readonly commandCreditNoteDTOTransform: CommandCreditNoteDTOTransform, private readonly commandCreditNoteDTOTransform: CommandCreditNoteDTOTransform,
@Inject(CreditNote.name)
private readonly creditNoteModel: typeof CreditNote,
@Inject(Contact.name)
private readonly contactModel: typeof Contact,
) {} ) {}
/** /**

View File

@@ -6,10 +6,10 @@ import {
} from '../types/CreditNotes.types'; } from '../types/CreditNotes.types';
import { ERRORS } from '../constants'; import { ERRORS } from '../constants';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../models/CreditNote';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice'; import { CreditNoteAppliedInvoice } from '../../CreditNotesApplyInvoice/models/CreditNoteAppliedInvoice';
import { import {
RefundCreditNote as RefundCreditNoteModel, RefundCreditNote as RefundCreditNoteModel,
} from '../models/RefundCreditNote'; } from '../../CreditNoteRefunds/models/RefundCreditNote';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { ItemEntry } from '@/modules/Items/models/ItemEntry'; import { ItemEntry } from '@/modules/Items/models/ItemEntry';

View File

@@ -49,7 +49,6 @@ export class OpenCreditNoteService {
// Sales the credit note transactions with associated entries. // Sales the credit note transactions with associated entries.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
const eventPayload = { const eventPayload = {
creditNoteId,
oldCreditNote, oldCreditNote,
trx, trx,
} as ICreditNoteOpeningPayload; } as ICreditNoteOpeningPayload;
@@ -62,8 +61,7 @@ export class OpenCreditNoteService {
// Saves the credit note graph to the storage. // Saves the credit note graph to the storage.
const creditNote = await this.creditNoteModel const creditNote = await this.creditNoteModel
.query(trx) .query(trx)
.findById(creditNoteId) .updateAndFetchById(creditNoteId, {
.update({
openedAt: new Date(), openedAt: new Date(),
}); });
// Triggers `onCreditNoteOpened` event. // Triggers `onCreditNoteOpened` event.
@@ -77,10 +75,10 @@ export class OpenCreditNoteService {
}; };
/** /**
* * Throws an error if the given credit note is already open.
* @param creditNote * @param {CreditNote} creditNote -
*/ */
public throwErrorIfAlreadyOpen = (creditNote) => { public throwErrorIfAlreadyOpen = (creditNote: CreditNote) => {
if (creditNote.openedAt) { if (creditNote.openedAt) {
throw new ServiceError(ERRORS.CREDIT_NOTE_ALREADY_OPENED); throw new ServiceError(ERRORS.CREDIT_NOTE_ALREADY_OPENED);
} }

View File

@@ -1,3 +1,9 @@
import { DiscountType } from '@/common/types/Discount';
import { BaseModel } from '@/models/Model';
import { Branch } from '@/modules/Branches/models/Branch.model';
import { Customer } from '@/modules/Customers/models/Customer';
import { ItemEntry } from '@/modules/Items/models/ItemEntry';
import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model';
import { mixin, Model, raw } from 'objection'; import { mixin, Model, raw } from 'objection';
// import TenantModel from 'models/TenantModel'; // import TenantModel from 'models/TenantModel';
// import ModelSetting from './ModelSetting'; // import ModelSetting from './ModelSetting';
@@ -5,22 +11,32 @@ import { mixin, Model, raw } from 'objection';
// import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants'; // import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants';
// import ModelSearchable from './ModelSearchable'; // import ModelSearchable from './ModelSearchable';
// import CreditNoteMeta from './CreditNote.Meta'; // import CreditNoteMeta from './CreditNote.Meta';
import { BaseModel } from '@/models/Model'; // import { DiscountType } from '@/interfaces';
export class CreditNote extends BaseModel { export class CreditNote extends BaseModel {
customerId: number; public amount: number;
creditNoteDate: Date; public exchangeRate: number;
creditNoteNumber: string; public openedAt: Date;
referenceNo: string; public discount: number;
amount: number; public discountType: DiscountType;
exchangeRate: number; public adjustment: number;
refundedAmount: number; public refundedAmount: number;
invoicesAmount: number; public invoicesAmount: number;
currencyCode: string; public creditNoteDate: Date;
note: string; public creditNoteNumber: string;
termsConditions: string; public currencyCode: string;
openedAt: Date; public customerId: number;
userId: number;
public branchId: number;
public warehouseId: number;
public customer!: Customer;
public entries!: ItemEntry[];
public branch!: Branch;
public warehouse!: Warehouse;
/** /**
* Table name * Table name
@@ -46,8 +62,21 @@ export class CreditNote extends BaseModel {
'isPublished', 'isPublished',
'isOpen', 'isOpen',
'isClosed', 'isClosed',
'creditsRemaining', 'creditsRemaining',
'creditsUsed', 'creditsUsed',
'subtotal',
'subtotalLocal',
'discountAmount',
'discountAmountLocal',
'discountPercentage',
'total',
'totalLocal',
'adjustmentLocal',
]; ];
} }
@@ -59,6 +88,72 @@ export class CreditNote extends BaseModel {
return this.amount * this.exchangeRate; return this.amount * this.exchangeRate;
} }
/**
* Credit note subtotal.
* @returns {number}
*/
get subtotal() {
return this.amount;
}
/**
* Credit note subtotal in local currency.
* @returns {number}
*/
get subtotalLocal() {
return this.subtotal * this.exchangeRate;
}
/**
* Discount amount.
* @returns {number}
*/
get discountAmount() {
return this.discountType === DiscountType.Amount
? this.discount
: this.subtotal * (this.discount / 100);
}
/**
* Discount amount in local currency.
* @returns {number}
*/
get discountAmountLocal() {
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
}
/**
* Discount percentage.
* @returns {number | null}
*/
get discountPercentage(): number | null {
return this.discountType === DiscountType.Percentage ? this.discount : null;
}
/**
* Adjustment amount in local currency.
* @returns {number}
*/
get adjustmentLocal() {
return this.adjustment ? this.adjustment * this.exchangeRate : null;
}
/**
* Credit note total.
* @returns {number}
*/
get total() {
return this.subtotal - this.discountAmount + this.adjustment;
}
/**
* Credit note total in local currency.
* @returns {number}
*/
get totalLocal() {
return this.total * this.exchangeRate;
}
/** /**
* Detarmines whether the credit note is draft. * Detarmines whether the credit note is draft.
* @returns {boolean} * @returns {boolean}
@@ -98,6 +193,9 @@ export class CreditNote extends BaseModel {
return Math.max(this.amount - this.refundedAmount - this.invoicesAmount, 0); return Math.max(this.amount - this.refundedAmount - this.invoicesAmount, 0);
} }
/**
* Retrieve the credits used.
*/
get creditsUsed() { get creditsUsed() {
return this.refundedAmount + this.invoicesAmount; return this.refundedAmount + this.invoicesAmount;
} }
@@ -128,7 +226,7 @@ export class CreditNote extends BaseModel {
query query
.where( .where(
raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) < raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) <
COALESCE(AMOUNT)`) COALESCE(AMOUNT)`),
) )
.modify('published'); .modify('published');
}, },
@@ -140,7 +238,7 @@ export class CreditNote extends BaseModel {
query query
.where( .where(
raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) = raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) =
COALESCE(AMOUNT)`) COALESCE(AMOUNT)`),
) )
.modify('published'); .modify('published');
}, },
@@ -171,7 +269,7 @@ export class CreditNote extends BaseModel {
*/ */
sortByStatus(query, order) { sortByStatus(query, order) {
query.orderByRaw( query.orderByRaw(
`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) = COALESCE(AMOUNT) ${order}` `COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICES_AMOUNT) = COALESCE(AMOUNT) ${order}`,
); );
}, },
}; };
@@ -181,12 +279,15 @@ export class CreditNote extends BaseModel {
* Relationship mapping. * Relationship mapping.
*/ */
static get relationMappings() { static get relationMappings() {
const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model'); const {
const { ItemEntry } = require('../../TransactionItemEntry/models/ItemEntry'); AccountTransaction,
} = require('../../Accounts/models/AccountTransaction.model');
const { ItemEntry } = require('../../Items/models/ItemEntry');
const { Customer } = require('../../Customers/models/Customer'); const { Customer } = require('../../Customers/models/Customer');
const { Branch } = require('../../Branches/models/Branch.model'); const { Branch } = require('../../Branches/models/Branch.model');
const { Document } = require('../../ChromiumlyTenancy/models/Document'); const { Document } = require('../../ChromiumlyTenancy/models/Document');
const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); const { Warehouse } = require('../../Warehouses/models/Warehouse.model');
const { PdfTemplate } = require('../../PdfTemplate/models/PdfTemplate');
return { return {
/** /**
@@ -277,12 +378,24 @@ export class CreditNote extends BaseModel {
query.where('model_ref', 'CreditNote'); query.where('model_ref', 'CreditNote');
}, },
}, },
/**
* Credit note may belongs to pdf branding template.
*/
pdfTemplate: {
relation: Model.BelongsToOneRelation,
modelClass: PdfTemplate,
join: {
from: 'credit_notes.pdfTemplateId',
to: 'pdf_templates.id',
},
},
}; };
} }
/** // /**
* Sale invoice meta. // * Sale invoice meta.
*/ // */
// static get meta() { // static get meta() {
// return CreditNoteMeta; // return CreditNoteMeta;
// } // }

View File

@@ -12,6 +12,15 @@ import { events } from '@/common/events/events';
@Injectable() @Injectable()
export class GetCreditNotePdf { export class GetCreditNotePdf {
/**
* @param {ChromiumlyTenancy} chromiumlyTenancy - Chromiumly tenancy service.
* @param {TemplateInjectable} templateInjectable - Template injectable service.
* @param {GetCreditNote} getCreditNoteService - Get credit note service.
* @param {CreditNoteBrandingTemplate} creditNoteBrandingTemplate - Credit note branding template service.
* @param {EventEmitter2} eventPublisher - Event publisher service.
* @param {typeof CreditNote} creditNoteModel - Credit note model.
* @param {typeof PdfTemplateModel} pdfTemplateModel - Pdf template model.
*/
constructor( constructor(
private readonly chromiumlyTenancy: ChromiumlyTenancy, private readonly chromiumlyTenancy: ChromiumlyTenancy,
private readonly templateInjectable: TemplateInjectable, private readonly templateInjectable: TemplateInjectable,

View File

@@ -1,67 +0,0 @@
import { Service, Inject } from 'typedi';
import { sumBy } from 'lodash';
import events from '@/subscribers/events';
import {
IApplyCreditToInvoicesCreatedPayload,
IApplyCreditToInvoicesDeletedPayload,
} from '@/interfaces';
import CreditNoteApplySyncCredit from '../commands/CreditNoteApplySyncCredit.service';
@Service()
export default class CreditNoteApplySyncCreditSubscriber {
@Inject()
syncInvoicedAmountWithCredit: CreditNoteApplySyncCredit;
/**
*
* @param bus
*/
attach(bus) {
bus.subscribe(
events.creditNote.onApplyToInvoicesCreated,
this.incrementCreditedAmountOnceApplyToInvoicesCreated
);
bus.subscribe(
events.creditNote.onApplyToInvoicesDeleted,
this.decrementCreditedAmountOnceApplyToInvoicesDeleted
);
}
/**
* Increment credited amount of credit note transaction once the transaction created.
* @param {IApplyCreditToInvoicesCreatedPayload} payload -
*/
private incrementCreditedAmountOnceApplyToInvoicesCreated = async ({
trx,
creditNote,
tenantId,
creditNoteAppliedInvoices,
}: IApplyCreditToInvoicesCreatedPayload) => {
const totalCredited = sumBy(creditNoteAppliedInvoices, 'amount');
await this.syncInvoicedAmountWithCredit.incrementCreditNoteInvoicedAmount(
tenantId,
creditNote.id,
totalCredited,
trx
);
};
/**
* Decrement credited amount of credit note transaction once the transaction deleted.
* @param {IApplyCreditToInvoicesDeletedPayload} payload -
*/
private decrementCreditedAmountOnceApplyToInvoicesDeleted = async ({
tenantId,
creditNote,
creditNoteAppliedToInvoice,
trx,
}: IApplyCreditToInvoicesDeletedPayload) => {
await this.syncInvoicedAmountWithCredit.decrementCreditNoteInvoicedAmount(
tenantId,
creditNote.id,
creditNoteAppliedToInvoice.amount,
trx
);
};
}

View File

@@ -1,61 +0,0 @@
import { Service, Inject } from 'typedi';
import events from '@/subscribers/events';
import {
IApplyCreditToInvoicesCreatedPayload,
IApplyCreditToInvoicesDeletedPayload,
} from '@/interfaces';
import CreditNoteApplySyncInvoicesCreditedAmount from '../commands/CreditNoteApplySyncInvoices.service';
@Service()
export default class CreditNoteApplySyncInvoicesCreditedAmountSubscriber {
@Inject()
private syncInvoicesWithCreditNote: CreditNoteApplySyncInvoicesCreditedAmount;
/**
* Attaches events with handlers.
*/
public attach(bus) {
bus.subscribe(
events.creditNote.onApplyToInvoicesCreated,
this.incrementAppliedInvoicesOnceCreditCreated
);
bus.subscribe(
events.creditNote.onApplyToInvoicesDeleted,
this.decrementAppliedInvoicesOnceCreditDeleted
);
}
/**
* Increment invoices credited amount once the credit note apply to invoices transaction
* @param {IApplyCreditToInvoicesCreatedPayload} payload -
*/
private incrementAppliedInvoicesOnceCreditCreated = async ({
trx,
tenantId,
creditNoteAppliedInvoices,
}: IApplyCreditToInvoicesCreatedPayload) => {
await this.syncInvoicesWithCreditNote.incrementInvoicesCreditedAmount(
tenantId,
creditNoteAppliedInvoices,
trx
);
};
/**
*
* @param {IApplyCreditToInvoicesDeletedPayload} payload -
*/
private decrementAppliedInvoicesOnceCreditDeleted = async ({
trx,
creditNoteAppliedToInvoice,
tenantId,
}: IApplyCreditToInvoicesDeletedPayload) => {
// Decrement invoice credited amount.
await this.syncInvoicesWithCreditNote.decrementInvoiceCreditedAmount(
tenantId,
creditNoteAppliedToInvoice.invoiceId,
creditNoteAppliedToInvoice.amount,
trx
);
};
}

View File

@@ -1,30 +1,30 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import BaseCreditNotes from '../commands/CommandCreditNoteDTOTransform.service'; // import BaseCreditNotes from '../commands/CommandCreditNoteDTOTransform.service';
import { ICreditNoteCreatedPayload } from '@/interfaces'; // import { ICreditNoteCreatedPayload } from '@/interfaces';
@Service() // @Service()
export default class CreditNoteAutoSerialSubscriber { // export default class CreditNoteAutoSerialSubscriber {
@Inject() // @Inject()
creditNotesService: BaseCreditNotes; // creditNotesService: BaseCreditNotes;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
public attach(bus) { // public attach(bus) {
bus.subscribe( // bus.subscribe(
events.creditNote.onCreated, // events.creditNote.onCreated,
this.autoSerialIncrementOnceCreated // this.autoSerialIncrementOnceCreated
); // );
} // }
/** // /**
* Auto serial increment once credit note created. // * Auto serial increment once credit note created.
* @param {ICreditNoteCreatedPayload} payload - // * @param {ICreditNoteCreatedPayload} payload -
*/ // */
private autoSerialIncrementOnceCreated = async ({ // private autoSerialIncrementOnceCreated = async ({
tenantId, // tenantId,
}: ICreditNoteCreatedPayload) => { // }: ICreditNoteCreatedPayload) => {
await this.creditNotesService.incrementSerialNumber(tenantId); // await this.creditNotesService.incrementSerialNumber(tenantId);
}; // };
} // }

View File

@@ -1,113 +1,113 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { // import {
ICreditNoteCreatedPayload, // ICreditNoteCreatedPayload,
ICreditNoteDeletedPayload, // ICreditNoteDeletedPayload,
ICreditNoteEditedPayload, // ICreditNoteEditedPayload,
ICreditNoteOpenedPayload, // ICreditNoteOpenedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import CreditNoteGLEntries from '../commands/CreditNoteGLEntries'; // import CreditNoteGLEntries from '../commands/CreditNoteGLEntries';
@Service() // @Service()
export default class CreditNoteGLEntriesSubscriber { // export default class CreditNoteGLEntriesSubscriber {
@Inject() // @Inject()
private creditNoteGLEntries: CreditNoteGLEntries; // private creditNoteGLEntries: CreditNoteGLEntries;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
* @param bus // * @param bus
*/ // */
public attach(bus) { // public attach(bus) {
bus.subscribe( // bus.subscribe(
events.creditNote.onCreated, // events.creditNote.onCreated,
this.writeGlEntriesOnceCreditNoteCreated // this.writeGlEntriesOnceCreditNoteCreated
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onOpened, // events.creditNote.onOpened,
this.writeGLEntriesOnceCreditNoteOpened // this.writeGLEntriesOnceCreditNoteOpened
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onEdited, // events.creditNote.onEdited,
this.editVendorCreditGLEntriesOnceEdited // this.editVendorCreditGLEntriesOnceEdited
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onDeleted, // events.creditNote.onDeleted,
this.revertGLEntriesOnceCreditNoteDeleted // this.revertGLEntriesOnceCreditNoteDeleted
); // );
} // }
/** // /**
* Writes the GL entries once the credit note transaction created or open. // * Writes the GL entries once the credit note transaction created or open.
* @private // * @private
* @param {ICreditNoteCreatedPayload|ICreditNoteOpenedPayload} payload - // * @param {ICreditNoteCreatedPayload|ICreditNoteOpenedPayload} payload -
*/ // */
private writeGlEntriesOnceCreditNoteCreated = async ({ // private writeGlEntriesOnceCreditNoteCreated = async ({
tenantId, // tenantId,
creditNote, // creditNote,
creditNoteId, // creditNoteId,
trx, // trx,
}: ICreditNoteCreatedPayload | ICreditNoteOpenedPayload) => { // }: ICreditNoteCreatedPayload | ICreditNoteOpenedPayload) => {
// Can't continue if the credit note is not published yet. // // Can't continue if the credit note is not published yet.
if (!creditNote.isPublished) return; // if (!creditNote.isPublished) return;
await this.creditNoteGLEntries.createVendorCreditGLEntries( // await this.creditNoteGLEntries.createVendorCreditGLEntries(
tenantId, // tenantId,
creditNoteId, // creditNoteId,
trx // trx
); // );
}; // };
/** // /**
* Writes the GL entries once the vendor credit transaction opened. // * Writes the GL entries once the vendor credit transaction opened.
* @param {ICreditNoteOpenedPayload} payload // * @param {ICreditNoteOpenedPayload} payload
*/ // */
private writeGLEntriesOnceCreditNoteOpened = async ({ // private writeGLEntriesOnceCreditNoteOpened = async ({
tenantId, // tenantId,
creditNoteId, // creditNoteId,
trx, // trx,
}: ICreditNoteOpenedPayload) => { // }: ICreditNoteOpenedPayload) => {
await this.creditNoteGLEntries.createVendorCreditGLEntries( // await this.creditNoteGLEntries.createVendorCreditGLEntries(
tenantId, // tenantId,
creditNoteId, // creditNoteId,
trx // trx
); // );
}; // };
/** // /**
* Reverts GL entries once credit note deleted. // * Reverts GL entries once credit note deleted.
*/ // */
private revertGLEntriesOnceCreditNoteDeleted = async ({ // private revertGLEntriesOnceCreditNoteDeleted = async ({
tenantId, // tenantId,
oldCreditNote, // oldCreditNote,
creditNoteId, // creditNoteId,
trx, // trx,
}: ICreditNoteDeletedPayload) => { // }: ICreditNoteDeletedPayload) => {
// Can't continue if the credit note is not published yet. // // Can't continue if the credit note is not published yet.
if (!oldCreditNote.isPublished) return; // if (!oldCreditNote.isPublished) return;
await this.creditNoteGLEntries.revertVendorCreditGLEntries( // await this.creditNoteGLEntries.revertVendorCreditGLEntries(
tenantId, // tenantId,
creditNoteId // creditNoteId
); // );
}; // };
/** // /**
* Edits vendor credit associated GL entries once the transaction edited. // * Edits vendor credit associated GL entries once the transaction edited.
* @param {ICreditNoteEditedPayload} payload - // * @param {ICreditNoteEditedPayload} payload -
*/ // */
private editVendorCreditGLEntriesOnceEdited = async ({ // private editVendorCreditGLEntriesOnceEdited = async ({
tenantId, // tenantId,
creditNote, // creditNote,
creditNoteId, // creditNoteId,
trx, // trx,
}: ICreditNoteEditedPayload) => { // }: ICreditNoteEditedPayload) => {
// Can't continue if the credit note is not published yet. // // Can't continue if the credit note is not published yet.
if (!creditNote.isPublished) return; // if (!creditNote.isPublished) return;
await this.creditNoteGLEntries.editVendorCreditGLEntries( // await this.creditNoteGLEntries.editVendorCreditGLEntries(
tenantId, // tenantId,
creditNoteId, // creditNoteId,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,98 +1,98 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import CreditNoteInventoryTransactions from '../commands/CreditNotesInventoryTransactions'; // import CreditNoteInventoryTransactions from '../commands/CreditNotesInventoryTransactions';
import { // import {
ICreditNoteCreatedPayload, // ICreditNoteCreatedPayload,
ICreditNoteDeletedPayload, // ICreditNoteDeletedPayload,
ICreditNoteEditedPayload, // ICreditNoteEditedPayload,
} from '@/interfaces'; // } from '@/interfaces';
@Service() // @Service()
export default class CreditNoteInventoryTransactionsSubscriber { // export default class CreditNoteInventoryTransactionsSubscriber {
@Inject() // @Inject()
inventoryTransactions: CreditNoteInventoryTransactions; // inventoryTransactions: CreditNoteInventoryTransactions;
/** // /**
* Attaches events with publisher. // * Attaches events with publisher.
*/ // */
public attach(bus) { // public attach(bus) {
bus.subscribe( // bus.subscribe(
events.creditNote.onCreated, // events.creditNote.onCreated,
this.writeInventoryTranscationsOnceCreated // this.writeInventoryTranscationsOnceCreated
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onEdited, // events.creditNote.onEdited,
this.rewriteInventoryTransactionsOnceEdited // this.rewriteInventoryTransactionsOnceEdited
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onDeleted, // events.creditNote.onDeleted,
this.revertInventoryTransactionsOnceDeleted // this.revertInventoryTransactionsOnceDeleted
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onOpened, // events.creditNote.onOpened,
this.writeInventoryTranscationsOnceCreated // this.writeInventoryTranscationsOnceCreated
); // );
} // }
/** // /**
* Writes inventory transactions once credit note created. // * Writes inventory transactions once credit note created.
* @param {ICreditNoteCreatedPayload} payload - // * @param {ICreditNoteCreatedPayload} payload -
* @returns {Promise<void>} // * @returns {Promise<void>}
*/ // */
public writeInventoryTranscationsOnceCreated = async ({ // public writeInventoryTranscationsOnceCreated = async ({
tenantId, // tenantId,
creditNote, // creditNote,
trx, // trx,
}: ICreditNoteCreatedPayload) => { // }: ICreditNoteCreatedPayload) => {
// Can't continue if the credit note is open yet. // // Can't continue if the credit note is open yet.
if (!creditNote.isOpen) return; // if (!creditNote.isOpen) return;
await this.inventoryTransactions.createInventoryTransactions( // await this.inventoryTransactions.createInventoryTransactions(
tenantId, // tenantId,
creditNote, // creditNote,
trx // trx
); // );
}; // };
/** // /**
* Rewrites inventory transactions once credit note edited. // * Rewrites inventory transactions once credit note edited.
* @param {ICreditNoteEditedPayload} payload - // * @param {ICreditNoteEditedPayload} payload -
* @returns {Promise<void>} // * @returns {Promise<void>}
*/ // */
public rewriteInventoryTransactionsOnceEdited = async ({ // public rewriteInventoryTransactionsOnceEdited = async ({
tenantId, // tenantId,
creditNoteId, // creditNoteId,
creditNote, // creditNote,
trx, // trx,
}: ICreditNoteEditedPayload) => { // }: ICreditNoteEditedPayload) => {
// Can't continue if the credit note is open yet. // // Can't continue if the credit note is open yet.
if (!creditNote.isOpen) return; // if (!creditNote.isOpen) return;
await this.inventoryTransactions.editInventoryTransactions( // await this.inventoryTransactions.editInventoryTransactions(
tenantId, // tenantId,
creditNoteId, // creditNoteId,
creditNote, // creditNote,
trx // trx
); // );
}; // };
/** // /**
* Reverts inventory transactions once credit note deleted. // * Reverts inventory transactions once credit note deleted.
* @param {ICreditNoteDeletedPayload} payload - // * @param {ICreditNoteDeletedPayload} payload -
*/ // */
public revertInventoryTransactionsOnceDeleted = async ({ // public revertInventoryTransactionsOnceDeleted = async ({
tenantId, // tenantId,
creditNoteId, // creditNoteId,
oldCreditNote, // oldCreditNote,
trx, // trx,
}: ICreditNoteDeletedPayload) => { // }: ICreditNoteDeletedPayload) => {
// Can't continue if the credit note is open yet. // // Can't continue if the credit note is open yet.
if (!oldCreditNote.isOpen) return; // if (!oldCreditNote.isOpen) return;
await this.inventoryTransactions.deleteInventoryTransactions( // await this.inventoryTransactions.deleteInventoryTransactions(
tenantId, // tenantId,
creditNoteId, // creditNoteId,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,48 +1,48 @@
import { Inject, Service } from 'typedi'; // import { Inject, Service } from 'typedi';
import { ServiceError } from '@/exceptions'; // import { ServiceError } from '@/exceptions';
import TenancyService from '@/services/Tenancy/TenancyService'; // import TenancyService from '@/services/Tenancy/TenancyService';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { ICustomerDeletingPayload } from '@/interfaces'; // import { ICustomerDeletingPayload } from '@/interfaces';
import DeleteCustomerLinkedCreidtNote from '../commands/DeleteCustomerLinkedCreditNote.service'; // import DeleteCustomerLinkedCreidtNote from '../commands/DeleteCustomerLinkedCreditNote.service';
const ERRORS = { // const ERRORS = {
CUSTOMER_HAS_TRANSACTIONS: 'CUSTOMER_HAS_TRANSACTIONS', // CUSTOMER_HAS_TRANSACTIONS: 'CUSTOMER_HAS_TRANSACTIONS',
}; // };
@Service() // @Service()
export default class DeleteCustomerLinkedCreditSubscriber { // export default class DeleteCustomerLinkedCreditSubscriber {
@Inject() // @Inject()
tenancy: TenancyService; // tenancy: TenancyService;
@Inject() // @Inject()
deleteCustomerLinkedCredit: DeleteCustomerLinkedCreidtNote; // deleteCustomerLinkedCredit: DeleteCustomerLinkedCreidtNote;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
* @param bus // * @param bus
*/ // */
public attach = (bus) => { // public attach = (bus) => {
bus.subscribe( // bus.subscribe(
events.customers.onDeleting, // events.customers.onDeleting,
this.validateCustomerHasNoLinkedCreditsOnDeleting // this.validateCustomerHasNoLinkedCreditsOnDeleting
); // );
}; // };
/** // /**
* Validate vendor has no associated credit transaction once the vendor deleting. // * Validate vendor has no associated credit transaction once the vendor deleting.
* @param {IVendorEventDeletingPayload} payload - // * @param {IVendorEventDeletingPayload} payload -
*/ // */
public validateCustomerHasNoLinkedCreditsOnDeleting = async ({ // public validateCustomerHasNoLinkedCreditsOnDeleting = async ({
tenantId, // tenantId,
customerId, // customerId,
}: ICustomerDeletingPayload) => { // }: ICustomerDeletingPayload) => {
try { // try {
await this.deleteCustomerLinkedCredit.validateCustomerHasNoCreditTransaction( // await this.deleteCustomerLinkedCredit.validateCustomerHasNoCreditTransaction(
tenantId, // tenantId,
customerId // customerId
); // );
} catch (error) { // } catch (error) {
throw new ServiceError(ERRORS.CUSTOMER_HAS_TRANSACTIONS); // throw new ServiceError(ERRORS.CUSTOMER_HAS_TRANSACTIONS);
} // }
}; // };
} // }

View File

@@ -1,61 +1,61 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import RefundCreditNoteGLEntries from '../commands/RefundCreditNoteGLEntries'; // import RefundCreditNoteGLEntries from '../commands/RefundCreditNoteGLEntries';
import { // import {
IRefundCreditNoteCreatedPayload, // IRefundCreditNoteCreatedPayload,
IRefundCreditNoteDeletedPayload, // IRefundCreditNoteDeletedPayload,
} from '@/interfaces'; // } from '@/interfaces';
@Service() // @Service()
export default class RefundCreditNoteGLEntriesSubscriber { // export default class RefundCreditNoteGLEntriesSubscriber {
@Inject() // @Inject()
refundCreditGLEntries: RefundCreditNoteGLEntries; // refundCreditGLEntries: RefundCreditNoteGLEntries;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
public attach = (bus) => { // public attach = (bus) => {
bus.subscribe( // bus.subscribe(
events.creditNote.onRefundCreated, // events.creditNote.onRefundCreated,
this.writeRefundCreditGLEntriesOnceCreated // this.writeRefundCreditGLEntriesOnceCreated
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onRefundDeleted, // events.creditNote.onRefundDeleted,
this.revertRefundCreditGLEntriesOnceDeleted // this.revertRefundCreditGLEntriesOnceDeleted
); // );
}; // };
/** // /**
* Writes refund credit note GL entries once the transaction created. // * Writes refund credit note GL entries once the transaction created.
* @param {IRefundCreditNoteCreatedPayload} payload - // * @param {IRefundCreditNoteCreatedPayload} payload -
*/ // */
private writeRefundCreditGLEntriesOnceCreated = async ({ // private writeRefundCreditGLEntriesOnceCreated = async ({
trx, // trx,
refundCreditNote, // refundCreditNote,
creditNote, // creditNote,
tenantId, // tenantId,
}: IRefundCreditNoteCreatedPayload) => { // }: IRefundCreditNoteCreatedPayload) => {
await this.refundCreditGLEntries.createRefundCreditGLEntries( // await this.refundCreditGLEntries.createRefundCreditGLEntries(
tenantId, // tenantId,
refundCreditNote.id, // refundCreditNote.id,
trx // trx
); // );
}; // };
/** // /**
* Reverts refund credit note GL entries once the transaction deleted. // * Reverts refund credit note GL entries once the transaction deleted.
* @param {IRefundCreditNoteDeletedPayload} payload - // * @param {IRefundCreditNoteDeletedPayload} payload -
*/ // */
private revertRefundCreditGLEntriesOnceDeleted = async ({ // private revertRefundCreditGLEntriesOnceDeleted = async ({
trx, // trx,
refundCreditId, // refundCreditId,
oldRefundCredit, // oldRefundCredit,
tenantId, // tenantId,
}: IRefundCreditNoteDeletedPayload) => { // }: IRefundCreditNoteDeletedPayload) => {
await this.refundCreditGLEntries.revertRefundCreditGLEntries( // await this.refundCreditGLEntries.revertRefundCreditGLEntries(
tenantId, // tenantId,
refundCreditId, // refundCreditId,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,62 +1,62 @@
import { Inject, Service } from 'typedi'; // import { Inject, Service } from 'typedi';
import { // import {
IRefundCreditNoteCreatedPayload, // IRefundCreditNoteCreatedPayload,
IRefundCreditNoteDeletedPayload, // IRefundCreditNoteDeletedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import RefundSyncCreditNoteBalance from '../commands/RefundSyncCreditNoteBalance'; // import RefundSyncCreditNoteBalance from '../commands/RefundSyncCreditNoteBalance';
@Service() // @Service()
export default class RefundSyncCreditNoteBalanceSubscriber { // export default class RefundSyncCreditNoteBalanceSubscriber {
@Inject() // @Inject()
refundSyncCreditBalance: RefundSyncCreditNoteBalance; // refundSyncCreditBalance: RefundSyncCreditNoteBalance;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
attach(bus) { // attach(bus) {
bus.subscribe( // bus.subscribe(
events.creditNote.onRefundCreated, // events.creditNote.onRefundCreated,
this.incrementRefundedAmountOnceRefundCreated // this.incrementRefundedAmountOnceRefundCreated
); // );
bus.subscribe( // bus.subscribe(
events.creditNote.onRefundDeleted, // events.creditNote.onRefundDeleted,
this.decrementRefundedAmountOnceRefundDeleted // this.decrementRefundedAmountOnceRefundDeleted
); // );
return bus; // return bus;
} // }
/** // /**
* Increment credit note refunded amount once associated refund transaction created. // * Increment credit note refunded amount once associated refund transaction created.
* @param {IRefundCreditNoteCreatedPayload} payload - // * @param {IRefundCreditNoteCreatedPayload} payload -
*/ // */
private incrementRefundedAmountOnceRefundCreated = async ({ // private incrementRefundedAmountOnceRefundCreated = async ({
trx, // trx,
refundCreditNote, // refundCreditNote,
tenantId, // tenantId,
}: IRefundCreditNoteCreatedPayload) => { // }: IRefundCreditNoteCreatedPayload) => {
await this.refundSyncCreditBalance.incrementCreditNoteRefundAmount( // await this.refundSyncCreditBalance.incrementCreditNoteRefundAmount(
tenantId, // tenantId,
refundCreditNote.creditNoteId, // refundCreditNote.creditNoteId,
refundCreditNote.amount, // refundCreditNote.amount,
trx // trx
); // );
}; // };
/** // /**
* Decrement credit note refunded amount once associated refuned transaction deleted. // * Decrement credit note refunded amount once associated refuned transaction deleted.
* @param {IRefundCreditNoteDeletedPayload} payload - // * @param {IRefundCreditNoteDeletedPayload} payload -
*/ // */
private decrementRefundedAmountOnceRefundDeleted = async ({ // private decrementRefundedAmountOnceRefundDeleted = async ({
trx, // trx,
oldRefundCredit, // oldRefundCredit,
tenantId, // tenantId,
}: IRefundCreditNoteDeletedPayload) => { // }: IRefundCreditNoteDeletedPayload) => {
await this.refundSyncCreditBalance.decrementCreditNoteRefundAmount( // await this.refundSyncCreditBalance.decrementCreditNoteRefundAmount(
tenantId, // tenantId,
oldRefundCredit.creditNoteId, // oldRefundCredit.creditNoteId,
oldRefundCredit.amount, // oldRefundCredit.amount,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,19 +1,11 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { DiscountType, IDynamicListFilter, IItemEntry } from '@/interfaces';
import { ILedgerEntry } from './Ledger';
import { AttachmentLinkDTO } from './Attachments';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../models/CreditNote';
import { RefundCreditNote } from '../models/RefundCreditNote'; import { RefundCreditNote } from '../../CreditNoteRefunds/models/RefundCreditNote';
import { AttachmentLinkDTO } from '@/modules/Attachments/Attachments.types';
import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types';
export interface ICreditNoteEntryNewDTO extends IItemEntryDTO {}
export interface ICreditNoteEntryNewDTO {
index?: number;
itemId: number;
rate: number;
quantity: number;
discount: number;
description: string;
warehouseId?: number;
}
export interface ICreditNoteNewDTO { export interface ICreditNoteNewDTO {
customerId: number; customerId: number;
exchangeRate?: number; exchangeRate?: number;
@@ -26,7 +18,7 @@ export interface ICreditNoteNewDTO {
warehouseId?: number; warehouseId?: number;
attachments?: AttachmentLinkDTO[]; attachments?: AttachmentLinkDTO[];
discount?: number; discount?: number;
discountType?: DiscountType; // discountType?: DiscountType;
adjustment?: number; adjustment?: number;
} }
@@ -43,34 +35,6 @@ export interface ICreditNoteEditDTO {
attachments?: AttachmentLinkDTO[]; attachments?: AttachmentLinkDTO[];
} }
export interface ICreditNoteEntry extends IItemEntry {}
export interface ICreditNote {
id?: number;
customerId: number;
amount: number;
refundedAmount: number;
currencyCode: string;
exchangeRate: number;
creditNoteDate: Date;
creditNoteNumber: string;
referenceNo?: string;
// note?: string;
openedAt: Date | null;
entries: ICreditNoteEntry[];
isOpen: boolean;
isClosed: boolean;
isDraft: boolean;
isPublished: boolean;
creditsRemaining: number;
localAmount?: number;
branchId?: number;
warehouseId: number;
createdAt?: Date;
termsConditions: string;
note: string;
}
export enum CreditNoteAction { export enum CreditNoteAction {
Create = 'Create', Create = 'Create',
Edit = 'Edit', Edit = 'Edit',
@@ -102,37 +66,28 @@ export interface ICreditNoteEditingPayload {
export interface ICreditNoteEditedPayload { export interface ICreditNoteEditedPayload {
trx: Knex.Transaction; trx: Knex.Transaction;
oldCreditNote: CreditNote; oldCreditNote: CreditNote;
// creditNoteId: number;
creditNote: CreditNote; creditNote: CreditNote;
creditNoteEditDTO: ICreditNoteEditDTO; creditNoteEditDTO: ICreditNoteEditDTO;
// tenantId: number;
} }
export interface ICreditNoteCreatedPayload { export interface ICreditNoteCreatedPayload {
// tenantId: number;
creditNoteDTO: ICreditNoteNewDTO; creditNoteDTO: ICreditNoteNewDTO;
creditNote: CreditNote; creditNote: CreditNote;
// creditNoteId: number;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface ICreditNoteCreatingPayload { export interface ICreditNoteCreatingPayload {
// tenantId: number;
creditNoteDTO: ICreditNoteNewDTO; creditNoteDTO: ICreditNoteNewDTO;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface ICreditNoteOpeningPayload { export interface ICreditNoteOpeningPayload {
tenantId: number;
creditNoteId: number;
oldCreditNote: CreditNote; oldCreditNote: CreditNote;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface ICreditNoteOpenedPayload { export interface ICreditNoteOpenedPayload {
// tenantId: number;
creditNote: CreditNote; creditNote: CreditNote;
// creditNoteId: number;
oldCreditNote: CreditNote; oldCreditNote: CreditNote;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
@@ -141,11 +96,11 @@ export interface ICreditNotesQueryDTO {
filterQuery?: (query: any) => void; filterQuery?: (query: any) => void;
} }
export interface ICreditNotesQueryDTO extends IDynamicListFilter { // export interface ICreditNotesQueryDTO extends IDynamicListFilter {
page: number; // page: number;
pageSize: number; // pageSize: number;
searchKeyword?: string; // searchKeyword?: string;
} // }
export interface ICreditNoteRefundDTO { export interface ICreditNoteRefundDTO {
fromAccountId: number; fromAccountId: number;
@@ -157,96 +112,22 @@ export interface ICreditNoteRefundDTO {
branchId?: number; branchId?: number;
} }
export interface ICreditNoteApplyInvoiceDTO { // export type ICreditNoteGLCommonEntry = Pick<
entries: { invoiceId: number; amount: number }[]; // ILedgerEntry,
} // | 'date'
export interface IRefundCreditNotePOJO { // | 'userId'
formattedAmount: string; // | 'currencyCode'
} // | 'exchangeRate'
// | 'transactionType'
export interface IRefundCreditNoteDeletedPayload { // | 'transactionId'
trx: Knex.Transaction; // | 'transactionNumber'
refundCreditId: number; // | 'referenceNumber'
oldRefundCredit: RefundCreditNote; // | 'createdAt'
tenantId: number; // | 'indexGroup'
} // | 'credit'
// | 'debit'
export interface IRefundCreditNoteDeletingPayload { // | 'branchId'
trx: Knex.Transaction; // >;
refundCreditId: number;
oldRefundCredit: RefundCreditNote;
// tenantId: number;
}
export interface IRefundCreditNoteCreatingPayload {
trx: Knex.Transaction;
creditNote: CreditNote;
newCreditNoteDTO: ICreditNoteRefundDTO;
// tenantId: number;
}
export interface IRefundCreditNoteCreatedPayload {
trx: Knex.Transaction;
refundCreditNote: RefundCreditNote;
creditNote: CreditNote;
// tenantId: number;
}
export interface IRefundCreditNoteOpenedPayload {
// tenantId: number;
creditNoteId: number;
oldCreditNote: CreditNote;
trx: Knex.Transaction;
}
export interface IApplyCreditToInvoiceEntryDTO {
amount: number;
invoiceId: number;
}
export interface IApplyCreditToInvoicesDTO {
entries: IApplyCreditToInvoiceEntryDTO[];
}
export interface IApplyCreditToInvoicesCreatedPayload {
trx: Knex.Transaction;
creditNote: ICreditNote;
creditNoteAppliedInvoices: ICreditNoteAppliedToInvoice[];
// tenantId: number;
}
export interface IApplyCreditToInvoicesDeletedPayload {
trx: Knex.Transaction;
creditNote: ICreditNote;
creditNoteAppliedToInvoice: ICreditNoteAppliedToInvoice;
// tenantId: number;
}
export interface ICreditNoteAppliedToInvoice {
invoiceId: number;
amount: number;
creditNoteId: number;
}
export interface ICreditNoteAppliedToInvoiceModel {
amount: number;
entries: ICreditNoteAppliedToInvoice[];
}
export type ICreditNoteGLCommonEntry = Pick<
ILedgerEntry,
| 'date'
| 'userId'
| 'currencyCode'
| 'exchangeRate'
| 'transactionType'
| 'transactionId'
| 'transactionNumber'
| 'referenceNumber'
| 'createdAt'
| 'indexGroup'
| 'credit'
| 'debit'
| 'branchId'
>;
export interface CreditNotePdfTemplateAttributes { export interface CreditNotePdfTemplateAttributes {
// # Primary color // # Primary color
@@ -304,4 +185,4 @@ export interface CreditNotePdfTemplateAttributes {
export interface ICreditNoteState { export interface ICreditNoteState {
defaultTemplateId: number; defaultTemplateId: number;
} }

View File

@@ -1,3 +1,4 @@
// @ts-nocheck
import { CreditNotePdfTemplateAttributes, ICreditNote } from '@/interfaces'; import { CreditNotePdfTemplateAttributes, ICreditNote } from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format'; import { contactAddressTextFormat } from '@/utils/address-text-format';

View File

@@ -1,6 +1,6 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../../CreditNotes/models/CreditNote';
@Injectable() @Injectable()
export class CreditNoteApplySyncCredit { export class CreditNoteApplySyncCredit {

View File

@@ -1,11 +1,15 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import Bluebird from 'bluebird'; import Bluebird from 'bluebird';
import { ICreditNoteAppliedToInvoice } from '../types/CreditNotes.types'; import { ICreditNoteAppliedToInvoice } from '../types/CreditNoteApplyInvoice.types';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';
@Injectable() @Injectable()
export class CreditNoteApplySyncInvoicesCreditedAmount { export class CreditNoteApplySyncInvoicesCreditedAmount {
/**
* @param {typeof SaleInvoice} saleInvoiceModel - Sale invoice model.
*/
constructor( constructor(
@Inject(SaleInvoice.name) @Inject(SaleInvoice.name)
private readonly saleInvoiceModel: typeof SaleInvoice, private readonly saleInvoiceModel: typeof SaleInvoice,
@@ -22,7 +26,7 @@ export class CreditNoteApplySyncInvoicesCreditedAmount {
) => { ) => {
await Bluebird.each( await Bluebird.each(
creditNoteAppliedInvoices, creditNoteAppliedInvoices,
(creditNoteAppliedInvoice: ICreditNoteAppliedToInvoice) => { (creditNoteAppliedInvoice: CreditNoteAppliedInvoice) => {
return this.saleInvoiceModel.query(trx) return this.saleInvoiceModel.query(trx)
.where('id', creditNoteAppliedInvoice.invoiceId) .where('id', creditNoteAppliedInvoice.invoiceId)
.increment('creditedAmount', creditNoteAppliedInvoice.amount); .increment('creditedAmount', creditNoteAppliedInvoice.amount);

View File

@@ -2,20 +2,20 @@ import { Inject, Injectable } from '@nestjs/common';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { sumBy } from 'lodash'; import { sumBy } from 'lodash';
import { import {
ICreditNoteAppliedToInvoice,
ICreditNoteAppliedToInvoiceModel, ICreditNoteAppliedToInvoiceModel,
IApplyCreditToInvoicesDTO, IApplyCreditToInvoicesDTO,
IApplyCreditToInvoicesCreatedPayload, IApplyCreditToInvoicesCreatedPayload,
ICreditNote, } from '../types/CreditNoteApplyInvoice.types';
} from '../types/CreditNotes.types'; import { ERRORS } from '../../CreditNotes/constants';
import { ERRORS } from '../constants';
import { PaymentReceivedValidators } from '@/modules/PaymentReceived/commands/PaymentReceivedValidators.service'; import { PaymentReceivedValidators } from '@/modules/PaymentReceived/commands/PaymentReceivedValidators.service';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';
import { CommandCreditNoteDTOTransform } from '@/modules/CreditNotes/commands/CommandCreditNoteDTOTransform.service';
@Injectable() @Injectable()
export class CreditNoteApplyToInvoices { export class CreditNoteApplyToInvoices {
@@ -29,9 +29,13 @@ export class CreditNoteApplyToInvoices {
private readonly paymentReceiveValidators: PaymentReceivedValidators, private readonly paymentReceiveValidators: PaymentReceivedValidators,
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
private readonly creditNoteDTOTransform: CommandCreditNoteDTOTransform,
@Inject(CreditNoteAppliedInvoice.name) @Inject(CreditNoteAppliedInvoice.name)
private readonly creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice, private readonly creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice,
@Inject(CreditNote.name)
private readonly creditNoteModel: typeof CreditNote,
) {} ) {}
/** /**
@@ -42,9 +46,12 @@ export class CreditNoteApplyToInvoices {
public async applyCreditNoteToInvoices( public async applyCreditNoteToInvoices(
creditNoteId: number, creditNoteId: number,
applyCreditToInvoicesDTO: IApplyCreditToInvoicesDTO, applyCreditToInvoicesDTO: IApplyCreditToInvoicesDTO,
): Promise<ICreditNoteAppliedToInvoice[]> { ): Promise<CreditNoteAppliedInvoice[]> {
// Saves the credit note or throw not found service error. // Saves the credit note or throw not found service error.
const creditNote = await this.getCreditNoteOrThrowError(creditNoteId); const creditNote = await this.creditNoteModel
.query()
.findById(creditNoteId)
.throwIfNotFound();
// Retrieve the applied invoices that associated to the credit note customer. // Retrieve the applied invoices that associated to the credit note customer.
const appliedInvoicesEntries = const appliedInvoicesEntries =
@@ -58,18 +65,16 @@ export class CreditNoteApplyToInvoices {
applyCreditToInvoicesDTO, applyCreditToInvoicesDTO,
creditNote, creditNote,
); );
// Validate invoices has remaining amount to apply. // Validate invoices has remaining amount to apply.
this.validateInvoicesRemainingAmount( this.validateInvoicesRemainingAmount(
appliedInvoicesEntries, appliedInvoicesEntries,
creditNoteAppliedModel.amount, creditNoteAppliedModel.amount,
); );
// Validate the credit note remaining amount. // Validate the credit note remaining amount.
this.validateCreditRemainingAmount( this.creditNoteDTOTransform.validateCreditRemainingAmount(
creditNote, creditNote,
creditNoteAppliedModel.amount, creditNoteAppliedModel.amount,
); );
// Creates credit note apply to invoice transaction. // Creates credit note apply to invoice transaction.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Saves the credit note apply to invoice graph to the storage layer. // Saves the credit note apply to invoice graph to the storage layer.
@@ -99,7 +104,7 @@ export class CreditNoteApplyToInvoices {
*/ */
private transformApplyDTOToModel = ( private transformApplyDTOToModel = (
applyDTO: IApplyCreditToInvoicesDTO, applyDTO: IApplyCreditToInvoicesDTO,
creditNote: ICreditNote, creditNote: CreditNote,
): ICreditNoteAppliedToInvoiceModel => { ): ICreditNoteAppliedToInvoiceModel => {
const entries = applyDTO.entries.map((entry) => ({ const entries = applyDTO.entries.map((entry) => ({
invoiceId: entry.invoiceId, invoiceId: entry.invoiceId,

View File

@@ -1,16 +1,22 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { IApplyCreditToInvoicesDeletedPayload } from '../types/CreditNotes.types'; import { IApplyCreditToInvoicesDeletedPayload } from '../types/CreditNoteApplyInvoice.types';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice'; import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../../CreditNotes/models/CreditNote';
import { ERRORS } from '../constants'; import { ERRORS } from '../../CreditNotes/constants';
@Injectable() @Injectable()
export default class DeleteCreditNoteApplyToInvoices { export default class DeleteCreditNoteApplyToInvoices {
/**
* @param {UnitOfWork} uow - Unit of work.
* @param {EventEmitter2} eventPublisher - Event emitter.
* @param {typeof CreditNoteAppliedInvoice} creditNoteAppliedInvoiceModel - Credit note applied invoice model.
* @param {typeof CreditNote} creditNoteModel - Credit note model.
*/
constructor( constructor(
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,

View File

@@ -1,10 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../../CreditNotes/models/CreditNote';
import { ERRORS } from '../constants'; import { ERRORS } from '../../CreditNotes/constants';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
@Injectable() @Injectable()
export class DeleteCustomerLinkedCreditNoteService { export class DeleteCustomerLinkedCreditNoteService {
/**
* @param {typeof CreditNote} creditNoteModel - Credit note model.
*/
constructor( constructor(
@Inject(CreditNote.name) @Inject(CreditNote.name)
private readonly creditNoteModel: typeof CreditNote, private readonly creditNoteModel: typeof CreditNote,

View File

@@ -5,7 +5,7 @@ import { mixin, Model } from 'objection';
// import ModelSearchable from './ModelSearchable'; // import ModelSearchable from './ModelSearchable';
import { BaseModel } from '@/models/Model'; import { BaseModel } from '@/models/Model';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { CreditNote } from './CreditNote'; import { CreditNote } from '../../CreditNotes/models/CreditNote';
export class CreditNoteAppliedInvoice extends BaseModel { export class CreditNoteAppliedInvoice extends BaseModel {
public amount: number; public amount: number;

View File

@@ -25,28 +25,58 @@ export class CreditNoteAppliedInvoiceTransformer extends Transformer {
return ['saleInvoice', 'creditNote']; return ['saleInvoice', 'creditNote'];
}; };
/**
* Formatted amount.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public formttedAmount = (item: CreditNoteAppliedInvoice) => { public formttedAmount = (item: CreditNoteAppliedInvoice) => {
return this.formatNumber(item.amount, { return this.formatNumber(item.amount, {
currencyCode: item.creditNote.currencyCode, currencyCode: item.creditNote.currencyCode,
}); });
}; };
/**
* Credit note number.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public creditNoteNumber = (item: CreditNoteAppliedInvoice) => { public creditNoteNumber = (item: CreditNoteAppliedInvoice) => {
return item.creditNote.creditNoteNumber; return item.creditNote.creditNoteNumber;
}; };
/**
* Credit note date.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public creditNoteDate = (item: CreditNoteAppliedInvoice) => { public creditNoteDate = (item: CreditNoteAppliedInvoice) => {
return item.creditNote.creditNoteDate; return item.creditNote.creditNoteDate;
}; };
/**
* Invoice number.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public invoiceNumber = (item: CreditNoteAppliedInvoice) => { public invoiceNumber = (item: CreditNoteAppliedInvoice) => {
return item.saleInvoice.invoiceNo; return item.saleInvoice.invoiceNo;
}; };
/**
* Invoice reference no.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public invoiceReferenceNo = (item: CreditNoteAppliedInvoice) => { public invoiceReferenceNo = (item: CreditNoteAppliedInvoice) => {
return item.saleInvoice.referenceNo; return item.saleInvoice.referenceNo;
}; };
/**
* Formatted credit note date.
* @param {CreditNoteAppliedInvoice} item -
* @returns {string}
*/
public formattedCreditNoteDate = (item: CreditNoteAppliedInvoice) => { public formattedCreditNoteDate = (item: CreditNoteAppliedInvoice) => {
return this.formatDate(item.creditNote.creditNoteDate); return this.formatDate(item.creditNote.creditNoteDate);
}; };

View File

@@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { CreditNoteAppliedInvoiceTransformer } from './CreditNoteAppliedInvoiceTransformer'; import { CreditNoteAppliedInvoiceTransformer } from './CreditNoteAppliedInvoiceTransformer';
import { CreditNote } from '../models/CreditNote'; import { CreditNote } from '../../CreditNotes/models/CreditNote';
import { TransformerInjectable } from '../../Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '../../Transformer/TransformerInjectable.service';
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice'; import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';

View File

@@ -1,11 +1,16 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { CreditNoteWithInvoicesToApplyTransformer } from '../commands/CreditNoteWithInvoicesToApplyTransformer';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { GetCreditNote } from './GetCreditNote.service'; import { GetCreditNote } from '../../CreditNotes/queries/GetCreditNote.service';
import { CreditNoteWithInvoicesToApplyTransformer } from './CreditNoteWithInvoicesToApplyTransformer';
@Injectable() @Injectable()
export class GetCreditNoteAssociatedInvoicesToApply { export class GetCreditNoteAssociatedInvoicesToApply {
/**
* @param {TransformerInjectable} transformer - Transformer service.
* @param {GetCreditNote} getCreditNote - Get credit note service.
* @param {typeof SaleInvoice} saleInvoiceModel - Sale invoice model.
*/
constructor( constructor(
private transformer: TransformerInjectable, private transformer: TransformerInjectable,
private getCreditNote: GetCreditNote, private getCreditNote: GetCreditNote,

View File

@@ -0,0 +1,67 @@
// import { Service, Inject } from 'typedi';
// import { sumBy } from 'lodash';
// import events from '@/subscribers/events';
// import {
// IApplyCreditToInvoicesCreatedPayload,
// IApplyCreditToInvoicesDeletedPayload,
// } from '@/interfaces';
// import CreditNoteApplySyncCredit from '../commands/CreditNoteApplySyncCredit.service';
// @Service()
// export default class CreditNoteApplySyncCreditSubscriber {
// @Inject()
// syncInvoicedAmountWithCredit: CreditNoteApplySyncCredit;
// /**
// *
// * @param bus
// */
// attach(bus) {
// bus.subscribe(
// events.creditNote.onApplyToInvoicesCreated,
// this.incrementCreditedAmountOnceApplyToInvoicesCreated
// );
// bus.subscribe(
// events.creditNote.onApplyToInvoicesDeleted,
// this.decrementCreditedAmountOnceApplyToInvoicesDeleted
// );
// }
// /**
// * Increment credited amount of credit note transaction once the transaction created.
// * @param {IApplyCreditToInvoicesCreatedPayload} payload -
// */
// private incrementCreditedAmountOnceApplyToInvoicesCreated = async ({
// trx,
// creditNote,
// tenantId,
// creditNoteAppliedInvoices,
// }: IApplyCreditToInvoicesCreatedPayload) => {
// const totalCredited = sumBy(creditNoteAppliedInvoices, 'amount');
// await this.syncInvoicedAmountWithCredit.incrementCreditNoteInvoicedAmount(
// tenantId,
// creditNote.id,
// totalCredited,
// trx
// );
// };
// /**
// * Decrement credited amount of credit note transaction once the transaction deleted.
// * @param {IApplyCreditToInvoicesDeletedPayload} payload -
// */
// private decrementCreditedAmountOnceApplyToInvoicesDeleted = async ({
// tenantId,
// creditNote,
// creditNoteAppliedToInvoice,
// trx,
// }: IApplyCreditToInvoicesDeletedPayload) => {
// await this.syncInvoicedAmountWithCredit.decrementCreditNoteInvoicedAmount(
// tenantId,
// creditNote.id,
// creditNoteAppliedToInvoice.amount,
// trx
// );
// };
// }

View File

@@ -0,0 +1,61 @@
// import { Service, Inject } from 'typedi';
// import events from '@/subscribers/events';
// import {
// IApplyCreditToInvoicesCreatedPayload,
// IApplyCreditToInvoicesDeletedPayload,
// } from '@/interfaces';
// import CreditNoteApplySyncInvoicesCreditedAmount from '../commands/CreditNoteApplySyncInvoices.service';
// @Service()
// export default class CreditNoteApplySyncInvoicesCreditedAmountSubscriber {
// @Inject()
// private syncInvoicesWithCreditNote: CreditNoteApplySyncInvoicesCreditedAmount;
// /**
// * Attaches events with handlers.
// */
// public attach(bus) {
// bus.subscribe(
// events.creditNote.onApplyToInvoicesCreated,
// this.incrementAppliedInvoicesOnceCreditCreated
// );
// bus.subscribe(
// events.creditNote.onApplyToInvoicesDeleted,
// this.decrementAppliedInvoicesOnceCreditDeleted
// );
// }
// /**
// * Increment invoices credited amount once the credit note apply to invoices transaction
// * @param {IApplyCreditToInvoicesCreatedPayload} payload -
// */
// private incrementAppliedInvoicesOnceCreditCreated = async ({
// trx,
// tenantId,
// creditNoteAppliedInvoices,
// }: IApplyCreditToInvoicesCreatedPayload) => {
// await this.syncInvoicesWithCreditNote.incrementInvoicesCreditedAmount(
// tenantId,
// creditNoteAppliedInvoices,
// trx
// );
// };
// /**
// *
// * @param {IApplyCreditToInvoicesDeletedPayload} payload -
// */
// private decrementAppliedInvoicesOnceCreditDeleted = async ({
// trx,
// creditNoteAppliedToInvoice,
// tenantId,
// }: IApplyCreditToInvoicesDeletedPayload) => {
// // Decrement invoice credited amount.
// await this.syncInvoicesWithCreditNote.decrementInvoiceCreditedAmount(
// tenantId,
// creditNoteAppliedToInvoice.invoiceId,
// creditNoteAppliedToInvoice.amount,
// trx
// );
// };
// }

View File

@@ -0,0 +1,35 @@
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
import { Knex } from 'knex';
export interface ICreditNoteApplyInvoiceDTO {
entries: { invoiceId: number; amount: number }[];
}
export interface IApplyCreditToInvoiceEntryDTO {
amount: number;
invoiceId: number;
}
export interface IApplyCreditToInvoicesDTO {
entries: IApplyCreditToInvoiceEntryDTO[];
}
export interface IApplyCreditToInvoicesCreatedPayload {
trx: Knex.Transaction;
creditNote: CreditNote;
creditNoteAppliedInvoices: ICreditNoteAppliedToInvoice[];
}
export interface IApplyCreditToInvoicesDeletedPayload {
trx: Knex.Transaction;
creditNote: CreditNote;
creditNoteAppliedToInvoice: ICreditNoteAppliedToInvoice;
}
export interface ICreditNoteAppliedToInvoice {
amount: number;
creditNoteId: number;
}
export interface ICreditNoteAppliedToInvoiceModel {
amount: number;
entries: ICreditNoteAppliedToInvoice[];
}

View File

@@ -1,14 +1,14 @@
import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { CustomerValidators } from './CustomerValidators.service'; import { CustomerValidators } from './CustomerValidators.service';
import { import {
ICustomerActivatedPayload, ICustomerActivatedPayload,
ICustomerActivatingPayload, ICustomerActivatingPayload,
} from '../types/Customers.types'; } from '../types/Customers.types';
import { Customer } from '@/modules/Customers/models/Customer'; import { Customer } from '@/modules/Customers/models/Customer';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { Knex } from 'knex';
@Injectable() @Injectable()
export class ActivateCustomer { export class ActivateCustomer {

View File

@@ -235,7 +235,7 @@ export class ItemsEntriesService {
* @param {ItemEntry[]} entries - Items entries. * @param {ItemEntry[]} entries - Items entries.
* @returns {number} * @returns {number}
*/ */
public getTotalItemsEntries(entries: ItemEntry[]): number { public getTotalItemsEntries(entries: IItemEntryDTO[]): number {
return sumBy(entries, (e) => ItemEntry.calcAmount(e)); return sumBy(entries, (e) => ItemEntry.calcAmount(e));
} }

View File

@@ -10,16 +10,6 @@ import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class SaleEstimate extends BaseModel { export class SaleEstimate extends BaseModel {
constructor(
private readonly itemEntryModel: typeof ItemEntry,
private readonly customerModel: typeof Customer,
private readonly branchModel: typeof Branch,
private readonly warehouseModel: typeof Warehouse,
private readonly documentModel: typeof Document,
) {
super();
}
exchangeRate!: number; exchangeRate!: number;
amount!: number; amount!: number;
@@ -216,64 +206,64 @@ export class SaleEstimate extends BaseModel {
/** /**
* Relationship mapping. * Relationship mapping.
*/ */
static get relationMappings() { // static get relationMappings() {
return { // return {
customer: { // customer: {
relation: Model.BelongsToOneRelation, // relation: Model.BelongsToOneRelation,
modelClass: this.customerModel, // modelClass: this.customerModel,
join: { // join: {
from: 'sales_estimates.customerId', // from: 'sales_estimates.customerId',
to: 'contacts.id', // to: 'contacts.id',
}, // },
filter(query) { // filter(query) {
query.where('contact_service', 'customer'); // query.where('contact_service', 'customer');
}, // },
}, // },
entries: { // entries: {
relation: Model.HasManyRelation, // relation: Model.HasManyRelation,
modelClass: this.itemEntryModel, // modelClass: this.itemEntryModel,
join: { // join: {
from: 'sales_estimates.id', // from: 'sales_estimates.id',
to: 'items_entries.referenceId', // to: 'items_entries.referenceId',
}, // },
filter(builder) { // filter(builder) {
builder.where('reference_type', 'SaleEstimate'); // builder.where('reference_type', 'SaleEstimate');
builder.orderBy('index', 'ASC'); // builder.orderBy('index', 'ASC');
}, // },
}, // },
branch: { // branch: {
relation: Model.BelongsToOneRelation, // relation: Model.BelongsToOneRelation,
modelClass: this.branchModel, // modelClass: this.branchModel,
join: { // join: {
from: 'sales_estimates.branchId', // from: 'sales_estimates.branchId',
to: 'branches.id', // to: 'branches.id',
}, // },
}, // },
warehouse: { // warehouse: {
relation: Model.BelongsToOneRelation, // relation: Model.BelongsToOneRelation,
modelClass: this.warehouseModel, // modelClass: this.warehouseModel,
join: { // join: {
from: 'sales_estimates.warehouseId', // from: 'sales_estimates.warehouseId',
to: 'warehouses.id', // to: 'warehouses.id',
}, // },
}, // },
attachments: { // attachments: {
relation: Model.ManyToManyRelation, // relation: Model.ManyToManyRelation,
modelClass: this.documentModel, // modelClass: this.documentModel,
join: { // join: {
from: 'sales_estimates.id', // from: 'sales_estimates.id',
through: { // through: {
from: 'document_links.modelId', // from: 'document_links.modelId',
to: 'document_links.documentId', // to: 'document_links.documentId',
}, // },
to: 'documents.id', // to: 'documents.id',
}, // },
filter(query) { // filter(query) {
query.where('model_ref', 'SaleEstimate'); // query.where('model_ref', 'SaleEstimate');
}, // },
}, // },
}; // };
} // }
/** /**
* Model settings. * Model settings.

View File

@@ -14,7 +14,7 @@ import { ServiceError } from '@/modules/Items/ServiceError';
import { ERRORS } from '../constants'; import { ERRORS } from '../constants';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry'; import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry';
import { CreditNoteAppliedInvoice } from '@/modules/CreditNotes/models/CreditNoteAppliedInvoice'; import { CreditNoteAppliedInvoice } from '@/modules/CreditNotesApplyInvoice/models/CreditNoteAppliedInvoice';
@Injectable() @Injectable()
export class DeleteSaleInvoice { export class DeleteSaleInvoice {

View File

@@ -28,12 +28,15 @@ import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost'
import { VendorCreditAppliedBill } from '@/modules/VendorCreditsApplyBills/models/VendorCreditAppliedBill'; import { VendorCreditAppliedBill } from '@/modules/VendorCreditsApplyBills/models/VendorCreditAppliedBill';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice'; import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry'; import { PaymentReceivedEntry } from '@/modules/PaymentReceived/models/PaymentReceivedEntry';
import { CreditNoteAppliedInvoice } from '@/modules/CreditNotes/models/CreditNoteAppliedInvoice'; import { CreditNoteAppliedInvoice } from '@/modules/CreditNotesApplyInvoice/models/CreditNoteAppliedInvoice';
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote'; import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
import { PaymentLink } from '@/modules/PaymentLinks/models/PaymentLink'; import { PaymentLink } from '@/modules/PaymentLinks/models/PaymentLink';
import { SaleReceipt } from '@/modules/SaleReceipts/models/SaleReceipt'; import { SaleReceipt } from '@/modules/SaleReceipts/models/SaleReceipt';
import { ManualJournal } from '@/modules/ManualJournals/models/ManualJournal'; import { ManualJournal } from '@/modules/ManualJournals/models/ManualJournal';
import { ManualJournalEntry } from '@/modules/ManualJournals/models/ManualJournalEntry'; import { ManualJournalEntry } from '@/modules/ManualJournals/models/ManualJournalEntry';
import { RefundCreditNote } from '@/modules/CreditNoteRefunds/models/RefundCreditNote';
import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
import { RefundVendorCredit } from '@/modules/VendorCreditsRefund/models/RefundVendorCredit';
const models = [ const models = [
Item, Item,
@@ -64,10 +67,15 @@ const models = [
PaymentReceivedEntry, PaymentReceivedEntry,
CreditNoteAppliedInvoice, CreditNoteAppliedInvoice,
CreditNote, CreditNote,
RefundCreditNote,
PaymentLink, PaymentLink,
SaleReceipt, SaleReceipt,
ManualJournal, ManualJournal,
ManualJournalEntry ManualJournalEntry,
VendorCredit,
VendorCreditAppliedBill,
RefundVendorCredit,
]; ];
const modelProviders = models.map((model) => { const modelProviders = models.map((model) => {

View File

@@ -5,9 +5,27 @@ import { EditVendorCreditService } from './commands/EditVendorCredit.service';
import { VendorCreditDTOTransformService } from './commands/VendorCreditDTOTransform.service'; import { VendorCreditDTOTransformService } from './commands/VendorCreditDTOTransform.service';
import { VendorCreditAutoIncrementService } from './commands/VendorCreditAutoIncrement.service'; import { VendorCreditAutoIncrementService } from './commands/VendorCreditAutoIncrement.service';
import { GetRefundVendorCreditService } from '../VendorCreditsRefund/queries/GetRefundVendorCredit.service'; import { GetRefundVendorCreditService } from '../VendorCreditsRefund/queries/GetRefundVendorCredit.service';
import GetVendorCreditService from './queries/GetVendorCredit.service'; import { GetVendorCreditService } from './queries/GetVendorCredit.service';
import { VendorCreditsController } from './VendorCredits.controller';
import { ItemsModule } from '../Items/items.module';
import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module';
import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module';
import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module';
import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module';
import { BranchesModule } from '../Branches/Branches.module';
import { WarehousesModule } from '../Warehouses/Warehouses.module';
import { VendorCreditsApplicationService } from './VendorCreditsApplication.service';
@Module({ @Module({
imports: [
ItemsModule,
PdfTemplatesModule,
ChromiumlyTenancyModule,
TemplateInjectableModule,
AutoIncrementOrdersModule,
BranchesModule,
WarehousesModule,
],
providers: [ providers: [
CreateVendorCreditService, CreateVendorCreditService,
DeleteVendorCreditService, DeleteVendorCreditService,
@@ -15,9 +33,19 @@ import GetVendorCreditService from './queries/GetVendorCredit.service';
VendorCreditDTOTransformService, VendorCreditDTOTransformService,
VendorCreditAutoIncrementService, VendorCreditAutoIncrementService,
GetRefundVendorCreditService, GetRefundVendorCreditService,
VendorCreditDTOTransformService, GetVendorCreditService,
GetVendorCreditService VendorCreditsApplicationService,
], ],
controllers: [], exports: [
CreateVendorCreditService,
DeleteVendorCreditService,
EditVendorCreditService,
VendorCreditDTOTransformService,
VendorCreditAutoIncrementService,
GetRefundVendorCreditService,
GetVendorCreditService,
VendorCreditsApplicationService,
],
controllers: [VendorCreditsController],
}) })
export class VendorCreditsModule {} export class VendorCreditsModule {}

View File

@@ -2,13 +2,19 @@ import { Knex } from 'knex';
import { CreateVendorCreditService } from './commands/CreateVendorCredit.service'; import { CreateVendorCreditService } from './commands/CreateVendorCredit.service';
import { DeleteVendorCreditService } from './commands/DeleteVendorCredit.service'; import { DeleteVendorCreditService } from './commands/DeleteVendorCredit.service';
import { EditVendorCreditService } from './commands/EditVendorCredit.service'; import { EditVendorCreditService } from './commands/EditVendorCredit.service';
import GetVendorCreditService from './queries/GetVendorCredit.service'; import { GetVendorCreditService } from './queries/GetVendorCredit.service';
import { IVendorCreditEditDTO } from './types/VendorCredit.types'; import { IVendorCreditEditDTO } from './types/VendorCredit.types';
import { IVendorCreditCreateDTO } from './types/VendorCredit.types'; import { IVendorCreditCreateDTO } from './types/VendorCredit.types';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class VendorCreditsApplicationService { export class VendorCreditsApplicationService {
/**
* @param {CreateVendorCreditService} createVendorCreditService - Create vendor credit service.
* @param {EditVendorCreditService} editVendorCreditService - Edit vendor credit service.
* @param {DeleteVendorCreditService} deleteVendorCreditService - Delete vendor credit service.
* @param {GetVendorCreditService} getVendorCreditService - Get vendor credit service.
*/
constructor( constructor(
private readonly createVendorCreditService: CreateVendorCreditService, private readonly createVendorCreditService: CreateVendorCreditService,
private readonly editVendorCreditService: EditVendorCreditService, private readonly editVendorCreditService: EditVendorCreditService,

View File

@@ -11,6 +11,7 @@ import { events } from '@/common/events/events';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { VendorCreditDTOTransformService } from './VendorCreditDTOTransform.service';
@Injectable() @Injectable()
export class CreateVendorCreditService { export class CreateVendorCreditService {
@@ -25,6 +26,7 @@ export class CreateVendorCreditService {
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly itemsEntriesService: ItemsEntriesService, private readonly itemsEntriesService: ItemsEntriesService,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
private readonly vendorCreditDTOTransformService: VendorCreditDTOTransformService,
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, private readonly vendorCreditModel: typeof VendorCredit,
@@ -45,7 +47,6 @@ export class CreateVendorCreditService {
await this.eventPublisher.emitAsync(events.vendorCredit.onCreate, { await this.eventPublisher.emitAsync(events.vendorCredit.onCreate, {
vendorCreditCreateDTO, vendorCreditCreateDTO,
}); });
// Retrieve the given vendor or throw not found service error. // Retrieve the given vendor or throw not found service error.
const vendor = await this.vendorModel const vendor = await this.vendorModel
.query() .query()
@@ -56,12 +57,12 @@ export class CreateVendorCreditService {
await this.itemsEntriesService.validateNonSellableEntriesItems( await this.itemsEntriesService.validateNonSellableEntriesItems(
vendorCreditCreateDTO.entries, vendorCreditCreateDTO.entries,
); );
// Transforms the credit DTO to storage layer. // Transforms the credit DTO to storage layer.
const vendorCreditModel = this.transformCreateEditDTOToModel( const vendorCreditModel =
vendorCreditCreateDTO, this.vendorCreditDTOTransformService.transformCreateEditDTOToModel(
vendor.currencyCode, vendorCreditCreateDTO,
); vendor.currencyCode,
);
// Saves the vendor credit transactions under UOW environment. // Saves the vendor credit transactions under UOW environment.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Triggers `onVendorCreditCreating` event. // Triggers `onVendorCreditCreating` event.

View File

@@ -11,7 +11,7 @@ import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
import { VendorCreditAppliedBill } from '../../VendorCreditsApplyBills/models/VendorCreditAppliedBill'; import { VendorCreditAppliedBill } from '../../VendorCreditsApplyBills/models/VendorCreditAppliedBill';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { RefundVendorCredit } from '../models/RefundVendorCredit'; import { RefundVendorCredit } from '../../VendorCreditsRefund/models/RefundVendorCredit';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
@Injectable() @Injectable()
@@ -25,11 +25,15 @@ export class DeleteVendorCreditService {
* @param {typeof VendorCreditAppliedBill} vendorCreditAppliedBillModel - The vendor credit applied bill model. * @param {typeof VendorCreditAppliedBill} vendorCreditAppliedBillModel - The vendor credit applied bill model.
*/ */
constructor( constructor(
private vendorCreditModel: typeof VendorCredit,
private itemEntryModel: typeof ItemEntry,
private eventPublisher: EventEmitter2, private eventPublisher: EventEmitter2,
private uow: UnitOfWork, private uow: UnitOfWork,
@Inject(ItemEntry.name)
private itemEntryModel: typeof ItemEntry,
@Inject(VendorCredit.name)
private vendorCreditModel: typeof VendorCredit,
@Inject(RefundVendorCredit.name) @Inject(RefundVendorCredit.name)
private refundVendorCreditModel: typeof RefundVendorCredit, private refundVendorCreditModel: typeof RefundVendorCredit,
@@ -46,7 +50,7 @@ export class DeleteVendorCreditService {
trx?: Knex.Transaction, trx?: Knex.Transaction,
) => { ) => {
// Retrieve the old vendor credit. // Retrieve the old vendor credit.
const oldVendorCredit = await this.refundVendorCreditModel const oldVendorCredit = await this.vendorCreditModel
.query() .query()
.findById(vendorCreditId) .findById(vendorCreditId)
.throwIfNotFound(); .throwIfNotFound();

View File

@@ -10,6 +10,8 @@ import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
import { VendorCredit } from '../models/VendorCredit'; import { VendorCredit } from '../models/VendorCredit';
import { Contact } from '@/modules/Contacts/models/Contact'; import { Contact } from '@/modules/Contacts/models/Contact';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { Knex } from 'knex';
import { VendorCreditDTOTransformService } from './VendorCreditDTOTransform.service';
@Injectable() @Injectable()
export class EditVendorCreditService { export class EditVendorCreditService {
@@ -24,6 +26,7 @@ export class EditVendorCreditService {
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly itemsEntriesService: ItemsEntriesService, private readonly itemsEntriesService: ItemsEntriesService,
private readonly vendorCreditDTOTransform: VendorCreditDTOTransformService,
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, private readonly vendorCreditModel: typeof VendorCredit,
@@ -69,11 +72,12 @@ export class EditVendorCreditService {
vendorCreditDTO.entries, vendorCreditDTO.entries,
); );
// Transformes edit DTO to model storage layer. // Transformes edit DTO to model storage layer.
const vendorCreditModel = this.transformCreateEditDTOToModel( const vendorCreditModel =
vendorCreditDTO, this.vendorCreditDTOTransform.transformCreateEditDTOToModel(
vendor.currencyCode, vendorCreditDTO,
oldVendorCredit, vendor.currencyCode,
); oldVendorCredit,
);
// Edits the vendor credit graph under unit-of-work envirement. // Edits the vendor credit graph under unit-of-work envirement.
return this.uow.withTransaction(async (trx) => { return this.uow.withTransaction(async (trx) => {
// Triggers `onVendorCreditEditing` event. // Triggers `onVendorCreditEditing` event.
@@ -94,7 +98,6 @@ export class EditVendorCreditService {
await this.eventPublisher.emitAsync(events.vendorCredit.onEdited, { await this.eventPublisher.emitAsync(events.vendorCredit.onEdited, {
oldVendorCredit, oldVendorCredit,
vendorCredit, vendorCredit,
vendorCreditId,
vendorCreditDTO, vendorCreditDTO,
trx, trx,
} as IVendorCreditEditedPayload); } as IVendorCreditEditedPayload);

View File

@@ -65,7 +65,7 @@ export class OpenVendorCreditService {
const vendorCredit = await this.vendorCreditModel const vendorCredit = await this.vendorCreditModel
.query(trx) .query(trx)
.findById(vendorCreditId) .findById(vendorCreditId)
.update({ .updateAndFetchById(vendorCreditId, {
openedAt: new Date(), openedAt: new Date(),
}); });
// Triggers `onVendorCreditOpened` event. // Triggers `onVendorCreditOpened` event.

View File

@@ -16,7 +16,6 @@ import { VendorCreditAutoIncrementService } from './VendorCreditAutoIncrement.se
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class VendorCreditDTOTransformService { export class VendorCreditDTOTransformService {
/** /**
@@ -29,7 +28,7 @@ export class VendorCreditDTOTransformService {
private itemsEntriesService: ItemsEntriesService, private itemsEntriesService: ItemsEntriesService,
private branchDTOTransform: BranchTransactionDTOTransformer, private branchDTOTransform: BranchTransactionDTOTransformer,
private warehouseDTOTransform: WarehouseTransactionDTOTransform, private warehouseDTOTransform: WarehouseTransactionDTOTransform,
private vendorCreditAutoIncrement: VendorCreditAutoIncrementService private vendorCreditAutoIncrement: VendorCreditAutoIncrementService,
) {} ) {}
/** /**
@@ -42,11 +41,11 @@ export class VendorCreditDTOTransformService {
public transformCreateEditDTOToModel = ( public transformCreateEditDTOToModel = (
vendorCreditDTO: IVendorCreditCreateDTO | IVendorCreditEditDTO, vendorCreditDTO: IVendorCreditCreateDTO | IVendorCreditEditDTO,
vendorCurrencyCode: string, vendorCurrencyCode: string,
oldVendorCredit?: VendorCredit oldVendorCredit?: VendorCredit,
): VendorCredit => { ): VendorCredit => {
// Calculates the total amount of items entries. // Calculates the total amount of items entries.
const amount = this.itemsEntriesService.getTotalItemsEntries( const amount = this.itemsEntriesService.getTotalItemsEntries(
vendorCreditDTO.entries vendorCreditDTO.entries,
); );
const entries = R.compose( const entries = R.compose(
// Associate the default index to each item entry. // Associate the default index to each item entry.
@@ -56,7 +55,7 @@ export class VendorCreditDTOTransformService {
R.map((entry: IVendorCreditEntryDTO) => ({ R.map((entry: IVendorCreditEntryDTO) => ({
referenceType: 'VendorCredit', referenceType: 'VendorCredit',
...entry, ...entry,
})) })),
)(vendorCreditDTO.entries); )(vendorCreditDTO.entries);
// Retreive the next vendor credit number. // Retreive the next vendor credit number.
@@ -81,8 +80,9 @@ export class VendorCreditDTOTransformService {
}), }),
}; };
return R.compose( return R.compose(
VendorCredit.fromJson<VendorCredit>,
this.branchDTOTransform.transformDTO<VendorCredit>, this.branchDTOTransform.transformDTO<VendorCredit>,
this.warehouseDTOTransform.transformDTO<VendorCredit>( this.warehouseDTOTransform.transformDTO<VendorCredit>,
)(initialDTO); )(initialDTO);
}; };
@@ -93,7 +93,7 @@ export class VendorCreditDTOTransformService {
*/ */
public validateCreditRemainingAmount = ( public validateCreditRemainingAmount = (
vendorCredit: VendorCredit, vendorCredit: VendorCredit,
amount: number amount: number,
) => { ) => {
if (vendorCredit.creditsRemaining < amount) { if (vendorCredit.creditsRemaining < amount) {
throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_NO_REMAINING_AMOUNT); throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_NO_REMAINING_AMOUNT);

View File

@@ -6,32 +6,52 @@ import { Model, raw, mixin } from 'objection';
// import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants'; // import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants';
// import ModelSearchable from './ModelSearchable'; // import ModelSearchable from './ModelSearchable';
// import VendorCreditMeta from './VendorCredit.Meta'; // import VendorCreditMeta from './VendorCredit.Meta';
// import { DiscountType } from '@/interfaces';
import { Vendor } from '@/modules/Vendors/models/Vendor';
import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model';
import { Branch } from '@/modules/Branches/models/Branch.model';
import { ItemEntry } from '@/modules/Items/models/ItemEntry';
import { BaseModel } from '@/models/Model'; import { BaseModel } from '@/models/Model';
import { DiscountType } from '@/common/types/Discount';
export class VendorCredit extends BaseModel { export class VendorCredit extends BaseModel {
vendorId: number; vendorId: number;
amount: number; amount: number;
currencyCode: string; currencyCode: string;
vendorCreditDate: Date; vendorCreditDate: Date;
vendorCreditNumber: string; vendorCreditNumber: string;
referenceNo: string; referenceNo: string;
refundedAmount: number; refundedAmount: number;
invoicedAmount: number; invoicedAmount: number;
adjustment: number;
exchangeRate: number; exchangeRate: number;
note: string; note: string;
openedAt: Date; openedAt: Date;
userId: number; userId: number;
discount: number;
discountType: DiscountType;
branchId: number; branchId: number;
warehouseId: number; warehouseId: number;
vendor?: Vendor;
warehouse?: Warehouse;
branch?: Branch;
entries?: ItemEntry[];
attachments?: Document[];
createdAt: Date;
updatedAt: Date;
/** /**
* Table name * Table name
*/ */
static get tableName() { static get tableName() {
return 'vendor_credits'; return 'vendor_credits';
} }
/** /**
* Vendor credit amount in local currency. * Vendor credit amount in local currency.
* @returns {number} * @returns {number}
@@ -40,6 +60,72 @@ export class VendorCredit extends BaseModel {
return this.amount * this.exchangeRate; return this.amount * this.exchangeRate;
} }
/**
* Vendor credit subtotal.
* @returns {number}
*/
get subtotal() {
return this.amount;
}
/**
* Vendor credit subtotal in local currency.
* @returns {number}
*/
get subtotalLocal() {
return this.subtotal * this.exchangeRate;
}
/**
* Discount amount.
* @returns {number}
*/
get discountAmount() {
return this.discountType === DiscountType.Amount
? this.discount
: this.subtotal * (this.discount / 100);
}
/**
* Discount amount in local currency.
* @returns {number | null}
*/
get discountAmountLocal() {
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
}
/**
* Discount percentage.
* @returns {number | null}
*/
get discountPercentage(): number | null {
return this.discountType === DiscountType.Percentage ? this.discount : null;
}
/**
* Adjustment amount in local currency.
* @returns {number | null}
*/
get adjustmentLocal() {
return this.adjustment ? this.adjustment * this.exchangeRate : null;
}
/**
* Vendor credit total.
* @returns {number}
*/
get total() {
return this.subtotal - this.discountAmount + this.adjustment;
}
/**
* Vendor credit total in local currency.
* @returns {number}
*/
get totalLocal() {
return this.total * this.exchangeRate;
}
/** /**
* Model modifiers. * Model modifiers.
*/ */
@@ -127,12 +213,22 @@ export class VendorCredit extends BaseModel {
*/ */
static get virtualAttributes() { static get virtualAttributes() {
return [ return [
'localAmount',
'isDraft', 'isDraft',
'isPublished', 'isPublished',
'isOpen', 'isOpen',
'isClosed', 'isClosed',
'creditsRemaining', 'creditsRemaining',
'localAmount',
'discountAmount',
'discountAmountLocal',
'discountPercentage',
'adjustmentLocal',
'total',
'totalLocal',
]; ];
} }

View File

@@ -1,13 +1,17 @@
import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { VendorCreditTransformer } from './VendorCreditTransformer'; import { VendorCreditTransformer } from './VendorCreditTransformer';
import { ERRORS } from '../constants'; import { ERRORS } from '../constants';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
import { VendorCredit } from '../models/VendorCredit'; import { VendorCredit } from '../models/VendorCredit';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { Knex } from 'knex';
@Injectable() @Injectable()
export default class GetVendorCreditService { export class GetVendorCreditService {
/**
* @param {typeof VendorCredit} vendorCreditModel - Vendor credit model.
* @param {TransformerInjectable} transformer - Transformer service.
*/
constructor( constructor(
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, private readonly vendorCreditModel: typeof VendorCredit,
@@ -15,20 +19,18 @@ export default class GetVendorCreditService {
) {} ) {}
/** /**
* Retrieve the given vendor credit. * Retrieves the given vendor credit.
* @param {number} vendorCreditId - Vendor credit id. * @param {number} vendorCreditId - Vendor credit id.
* @param {Knex.Transaction} trx - Knex transaction.
*/ */
public async getVendorCredit( public async getVendorCredit(vendorCreditId: number, trx?: Knex.Transaction) {
vendorCreditId: number,
trx?: Knex.Transaction,
) {
// Retrieve the vendor credit model graph. // Retrieve the vendor credit model graph.
const vendorCredit = await this.vendorCreditModel const vendorCredit = await this.vendorCreditModel
.query() .query(trx)
.findById(vendorCreditId) .findById(vendorCreditId)
.withGraphFetched('entries.item') .withGraphFetched('entries.item')
.withGraphFetched('vendor') .withGraphFetched('vendor')
.withGraphFetched('branch') .withGraphFetched('branch')
.withGraphFetched('attachments'); .withGraphFetched('attachments');
if (!vendorCredit) { if (!vendorCredit) {
@@ -36,7 +38,7 @@ export default class GetVendorCreditService {
} }
return this.transformer.transform( return this.transformer.transform(
vendorCredit, vendorCredit,
new VendorCreditTransformer() new VendorCreditTransformer(),
); );
} }
} }

View File

@@ -1,6 +1,7 @@
import { AttachmentTransformer } from "@/modules/Attachments/Attachment.transformer"; import { AttachmentTransformer } from "@/modules/Attachments/Attachment.transformer";
import { ItemEntryTransformer } from "@/modules/TransactionItemEntry/ItemEntry.transformer"; import { ItemEntryTransformer } from "@/modules/TransactionItemEntry/ItemEntry.transformer";
import { Transformer } from "@/modules/Transformer/Transformer"; import { Transformer } from "@/modules/Transformer/Transformer";
import { VendorCredit } from "../models/VendorCredit";
export class VendorCreditTransformer extends Transformer { export class VendorCreditTransformer extends Transformer {
/** /**
@@ -31,28 +32,28 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieve formatted vendor credit date. * Retrieve formatted vendor credit date.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {String} * @returns {String}
*/ */
protected formattedVendorCreditDate = (vendorCredit): string => { protected formattedVendorCreditDate = (vendorCredit: VendorCredit): string => {
return this.formatDate(vendorCredit.vendorCreditDate); return this.formatDate(vendorCredit.vendorCreditDate);
}; };
/** /**
* Retireve formatted created at date. * Retireve formatted created at date.
* @param vendorCredit * @param {VendorCredit} vendorCredit
* @returns {string} * @returns {string}
*/ */
protected formattedCreatedAt = (vendorCredit): string => { protected formattedCreatedAt = (vendorCredit: VendorCredit): string => {
return this.formatDate(vendorCredit.createdAt); return this.formatDate(vendorCredit.createdAt);
}; };
/** /**
* Retrieve formatted vendor credit amount. * Retrieve formatted vendor credit amount.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected formattedAmount = (vendorCredit): string => { protected formattedAmount = (vendorCredit: VendorCredit): string => {
return this.formatNumber(vendorCredit.amount, { return this.formatNumber(vendorCredit.amount, {
currencyCode: vendorCredit.currencyCode, currencyCode: vendorCredit.currencyCode,
}); });
@@ -60,19 +61,19 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the vendor credit formatted subtotal. * Retrieves the vendor credit formatted subtotal.
* @param {IVendorCredit} vendorCredit * @param {VendorCredit} vendorCredit
* @returns {string} * @returns {string}
*/ */
protected formattedSubtotal = (vendorCredit): string => { protected formattedSubtotal = (vendorCredit: VendorCredit): string => {
return this.formatNumber(vendorCredit.amount, { money: false }); return this.formatNumber(vendorCredit.amount, { money: false });
}; };
/** /**
* Retrieve formatted credits remaining. * Retrieve formatted credits remaining.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected formattedCreditsRemaining = (credit) => { protected formattedCreditsRemaining = (credit: VendorCredit): string => {
return this.formatNumber(credit.creditsRemaining, { return this.formatNumber(credit.creditsRemaining, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
}); });
@@ -92,7 +93,7 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the formatted discount amount in local currency. * Retrieves the formatted discount amount in local currency.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected discountAmountLocalFormatted = (credit): string => { protected discountAmountLocalFormatted = (credit): string => {
@@ -104,7 +105,7 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the formatted discount percentage. * Retrieves the formatted discount percentage.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected discountPercentageFormatted = (credit): string => { protected discountPercentageFormatted = (credit): string => {
@@ -113,7 +114,7 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the formatted adjustment amount. * Retrieves the formatted adjustment amount.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected adjustmentFormatted = (credit): string => { protected adjustmentFormatted = (credit): string => {
@@ -125,10 +126,10 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the formatted adjustment amount in local currency. * Retrieves the formatted adjustment amount in local currency.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected adjustmentLocalFormatted = (credit): string => { protected adjustmentLocalFormatted = (credit: VendorCredit): string => {
return this.formatNumber(credit.adjustmentLocal, { return this.formatNumber(credit.adjustmentLocal, {
currencyCode: this.context.organization.baseCurrency, currencyCode: this.context.organization.baseCurrency,
excerptZero: true, excerptZero: true,
@@ -140,7 +141,7 @@ export class VendorCreditTransformer extends Transformer {
* @param credit * @param credit
* @returns {string} * @returns {string}
*/ */
protected formattedInvoicedAmount = (credit) => { protected formattedInvoicedAmount = (credit: VendorCredit): string => {
return this.formatNumber(credit.invoicedAmount, { return this.formatNumber(credit.invoicedAmount, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
}); });
@@ -148,10 +149,10 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the formatted total. * Retrieves the formatted total.
* @param {IVendorCredit} credit * @param {VendorCredit} credit
* @returns {string} * @returns {string}
*/ */
protected totalFormatted = (credit) => { protected totalFormatted = (credit: VendorCredit): string => {
return this.formatNumber(credit.total, { return this.formatNumber(credit.total, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
}); });
@@ -159,10 +160,10 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the entries of the bill. * Retrieves the entries of the bill.
* @param {IVendorCredit} vendorCredit * @param {VendorCredit} vendorCredit
* @returns {} * @returns {}
*/ */
protected entries = (vendorCredit) => { protected entries = (vendorCredit: VendorCredit) => {
return this.item(vendorCredit.entries, new ItemEntryTransformer(), { return this.item(vendorCredit.entries, new ItemEntryTransformer(), {
currencyCode: vendorCredit.currencyCode, currencyCode: vendorCredit.currencyCode,
}); });
@@ -170,10 +171,10 @@ export class VendorCreditTransformer extends Transformer {
/** /**
* Retrieves the vendor credit attachments. * Retrieves the vendor credit attachments.
* @param {IVendorCredit} invoice * @param {VendorCredit} invoice
* @returns * @returns
*/ */
protected attachments = (vendorCredit) => { protected attachments = (vendorCredit: VendorCredit) => {
return this.item(vendorCredit.attachments, new AttachmentTransformer()); return this.item(vendorCredit.attachments, new AttachmentTransformer());
}; };
} }

View File

@@ -1,48 +1,48 @@
import { Inject, Injectable } from '@nestjs/common'; // import { Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter'; // import { OnEvent } from '@nestjs/event-emitter';
import { VendorCredit } from '../models/VendorCredit'; // import { VendorCredit } from '../models/VendorCredit';
import { IVendorEventDeletingPayload } from '@/modules/Vendors/types/Vendors.types'; // import { IVendorEventDeletingPayload } from '@/modules/Vendors/types/Vendors.types';
import { events } from '@/common/events/events'; // import { events } from '@/common/events/events';
import { ServiceError } from '@/modules/Items/ServiceError'; // import { ServiceError } from '@/modules/Items/ServiceError';
const ERRORS = { // const ERRORS = {
VENDOR_HAS_TRANSACTIONS: 'VENDOR_HAS_TRANSACTIONS', // VENDOR_HAS_TRANSACTIONS: 'VENDOR_HAS_TRANSACTIONS',
}; // };
@Injectable() // @Injectable()
export class DeleteVendorAssociatedVendorCredit { // export class DeleteVendorAssociatedVendorCredit {
/** // /**
* @param {typeof VendorCredit} vendorCreditModel - Vendor credit model. // * @param {typeof VendorCredit} vendorCreditModel - Vendor credit model.
*/ // */
constructor( // constructor(
@Inject(VendorCredit.name) // @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, // private readonly vendorCreditModel: typeof VendorCredit,
) {} // ) {}
/** // /**
* Validate vendor has no associated credit transaction once the vendor deleting. // * Validate vendor has no associated credit transaction once the vendor deleting.
* @param {IVendorEventDeletingPayload} payload - // * @param {IVendorEventDeletingPayload} payload -
*/ // */
@OnEvent(events.vendors.onDeleting) // @OnEvent(events.vendors.onDeleting)
public async validateVendorHasNoCreditsTransactionsOnceDeleting({ // public async validateVendorHasNoCreditsTransactionsOnceDeleting({
vendorId, // vendorId,
}: IVendorEventDeletingPayload) { // }: IVendorEventDeletingPayload) {
await this.validateVendorHasNoCreditsTransactions(vendorId); // await this.validateVendorHasNoCreditsTransactions(vendorId);
} // }
/** // /**
* Validate the given vendor has no associated vendor credit transactions. // * Validate the given vendor has no associated vendor credit transactions.
* @param {number} vendorId // * @param {number} vendorId
*/ // */
public async validateVendorHasNoCreditsTransactions( // public async validateVendorHasNoCreditsTransactions(
vendorId: number, // vendorId: number,
): Promise<void> { // ): Promise<void> {
const associatedVendors = await this.vendorCreditModel // const associatedVendors = await this.vendorCreditModel
.query() // .query()
.where('vendorId', vendorId); // .where('vendorId', vendorId);
if (associatedVendors.length > 0) { // if (associatedVendors.length > 0) {
throw new ServiceError(ERRORS.VENDOR_HAS_TRANSACTIONS); // throw new ServiceError(ERRORS.VENDOR_HAS_TRANSACTIONS);
} // }
} // }
} // }

View File

@@ -1,62 +1,62 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import { // import {
IRefundVendorCreditCreatedPayload, // IRefundVendorCreditCreatedPayload,
IRefundVendorCreditDeletedPayload, // IRefundVendorCreditDeletedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import RefundSyncCreditRefundedAmount from './RefundSyncCreditRefundedAmount'; // import RefundSyncCreditRefundedAmount from './RefundSyncCreditRefundedAmount';
@Service() // @Service()
export default class RefundSyncVendorCreditBalanceSubscriber { // export default class RefundSyncVendorCreditBalanceSubscriber {
@Inject() // @Inject()
refundSyncCreditRefunded: RefundSyncCreditRefundedAmount; // refundSyncCreditRefunded: RefundSyncCreditRefundedAmount;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
public attach = (bus) => { // public attach = (bus) => {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onRefundCreated, // events.vendorCredit.onRefundCreated,
this.incrementRefundedAmountOnceRefundCreated // this.incrementRefundedAmountOnceRefundCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onRefundDeleted, // events.vendorCredit.onRefundDeleted,
this.decrementRefundedAmountOnceRefundDeleted // this.decrementRefundedAmountOnceRefundDeleted
); // );
}; // };
/** // /**
* Increment refunded vendor credit amount once refund transaction created. // * Increment refunded vendor credit amount once refund transaction created.
* @param {IRefundVendorCreditCreatedPayload} payload - // * @param {IRefundVendorCreditCreatedPayload} payload -
*/ // */
private incrementRefundedAmountOnceRefundCreated = async ({ // private incrementRefundedAmountOnceRefundCreated = async ({
refundVendorCredit, // refundVendorCredit,
vendorCredit, // vendorCredit,
tenantId, // tenantId,
trx, // trx,
}: IRefundVendorCreditCreatedPayload) => { // }: IRefundVendorCreditCreatedPayload) => {
await this.refundSyncCreditRefunded.incrementCreditRefundedAmount( // await this.refundSyncCreditRefunded.incrementCreditRefundedAmount(
tenantId, // tenantId,
refundVendorCredit.vendorCreditId, // refundVendorCredit.vendorCreditId,
refundVendorCredit.amount, // refundVendorCredit.amount,
trx // trx
); // );
}; // };
/** // /**
* Decrement refunded vendor credit amount once refund transaction deleted. // * Decrement refunded vendor credit amount once refund transaction deleted.
* @param {IRefundVendorCreditDeletedPayload} payload - // * @param {IRefundVendorCreditDeletedPayload} payload -
*/ // */
private decrementRefundedAmountOnceRefundDeleted = async ({ // private decrementRefundedAmountOnceRefundDeleted = async ({
trx, // trx,
oldRefundCredit, // oldRefundCredit,
tenantId, // tenantId,
}: IRefundVendorCreditDeletedPayload) => { // }: IRefundVendorCreditDeletedPayload) => {
await this.refundSyncCreditRefunded.decrementCreditNoteRefundAmount( // await this.refundSyncCreditRefunded.decrementCreditNoteRefundAmount(
tenantId, // tenantId,
oldRefundCredit.vendorCreditId, // oldRefundCredit.vendorCreditId,
oldRefundCredit.amount, // oldRefundCredit.amount,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,59 +1,59 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import RefundVendorCreditGLEntries from '../RefundVendorCredits/commands/RefundVendorCreditGLEntries'; // import RefundVendorCreditGLEntries from '../RefundVendorCredits/commands/RefundVendorCreditGLEntries';
import { // import {
IRefundCreditNoteDeletedPayload, // IRefundCreditNoteDeletedPayload,
IRefundVendorCreditCreatedPayload, // IRefundVendorCreditCreatedPayload,
} from '@/interfaces'; // } from '@/interfaces';
@Service() // @Service()
export default class RefundVendorCreditGLEntriesSubscriber { // export default class RefundVendorCreditGLEntriesSubscriber {
@Inject() // @Inject()
refundVendorGLEntries: RefundVendorCreditGLEntries; // refundVendorGLEntries: RefundVendorCreditGLEntries;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
attach(bus) { // attach(bus) {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onRefundCreated, // events.vendorCredit.onRefundCreated,
this.writeRefundVendorCreditGLEntriesOnceCreated // this.writeRefundVendorCreditGLEntriesOnceCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onRefundDeleted, // events.vendorCredit.onRefundDeleted,
this.revertRefundVendorCreditOnceDeleted // this.revertRefundVendorCreditOnceDeleted
); // );
} // }
/** // /**
* Writes refund vendor credit GL entries once the transaction created. // * Writes refund vendor credit GL entries once the transaction created.
* @param {IRefundCreditNoteCreatedPayload} payload - // * @param {IRefundCreditNoteCreatedPayload} payload -
*/ // */
private writeRefundVendorCreditGLEntriesOnceCreated = async ({ // private writeRefundVendorCreditGLEntriesOnceCreated = async ({
tenantId, // tenantId,
trx, // trx,
refundVendorCredit, // refundVendorCredit,
}: IRefundVendorCreditCreatedPayload) => { // }: IRefundVendorCreditCreatedPayload) => {
await this.refundVendorGLEntries.saveRefundCreditGLEntries( // await this.refundVendorGLEntries.saveRefundCreditGLEntries(
tenantId, // tenantId,
refundVendorCredit.id, // refundVendorCredit.id,
trx // trx
); // );
}; // };
/** // /**
* Reverts refund vendor credit GL entries once the transaction deleted. // * Reverts refund vendor credit GL entries once the transaction deleted.
* @param {IRefundCreditNoteDeletedPayload} payload - // * @param {IRefundCreditNoteDeletedPayload} payload -
*/ // */
private revertRefundVendorCreditOnceDeleted = async ({ // private revertRefundVendorCreditOnceDeleted = async ({
tenantId, // tenantId,
trx, // trx,
refundCreditId, // refundCreditId,
}: IRefundCreditNoteDeletedPayload) => { // }: IRefundCreditNoteDeletedPayload) => {
await this.refundVendorGLEntries.revertRefundCreditGLEntries( // await this.refundVendorGLEntries.revertRefundCreditGLEntries(
tenantId, // tenantId,
refundCreditId, // refundCreditId,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,27 +1,27 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import BaseVendorCredit from '../commands/VendorCreditDTOTransform.service'; // import BaseVendorCredit from '../commands/VendorCreditDTOTransform.service';
import { IVendorCreditCreatedPayload } from '@/interfaces'; // import { IVendorCreditCreatedPayload } from '@/interfaces';
@Service() // @Service()
export default class VendorCreditAutoSerialSubscriber { // export default class VendorCreditAutoSerialSubscriber {
@Inject() // @Inject()
vendorCreditService: BaseVendorCredit; // vendorCreditService: BaseVendorCredit;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
public attach(bus) { // public attach(bus) {
bus.subscribe(events.vendorCredit.onCreated, this.autoIncrementOnceCreated); // bus.subscribe(events.vendorCredit.onCreated, this.autoIncrementOnceCreated);
} // }
/** // /**
* Auto serial increment once the vendor credit created. // * Auto serial increment once the vendor credit created.
* @param {IVendorCreditCreatedPayload} payload // * @param {IVendorCreditCreatedPayload} payload
*/ // */
private autoIncrementOnceCreated = ({ // private autoIncrementOnceCreated = ({
tenantId, // tenantId,
}: IVendorCreditCreatedPayload) => { // }: IVendorCreditCreatedPayload) => {
this.vendorCreditService.incrementSerialNumber(tenantId); // this.vendorCreditService.incrementSerialNumber(tenantId);
}; // };
} // }

View File

@@ -1,110 +1,110 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { // import {
IVendorCreditCreatedPayload, // IVendorCreditCreatedPayload,
IVendorCreditDeletedPayload, // IVendorCreditDeletedPayload,
IVendorCreditEditedPayload, // IVendorCreditEditedPayload,
IVendorCreditOpenedPayload, // IVendorCreditOpenedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import VendorCreditGLEntries from '../commands/VendorCreditGLEntries'; // import VendorCreditGLEntries from '../commands/VendorCreditGLEntries';
@Service() // @Service()
export default class VendorCreditGlEntriesSubscriber { // export default class VendorCreditGlEntriesSubscriber {
@Inject() // @Inject()
private vendorCreditGLEntries: VendorCreditGLEntries; // private vendorCreditGLEntries: VendorCreditGLEntries;
/*** // /***
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
public attach(bus) { // public attach(bus) {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onCreated, // events.vendorCredit.onCreated,
this.writeGLEntriesOnceVendorCreditCreated // this.writeGLEntriesOnceVendorCreditCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onOpened, // events.vendorCredit.onOpened,
this.writeGLEntgriesOnceVendorCreditOpened // this.writeGLEntgriesOnceVendorCreditOpened
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onEdited, // events.vendorCredit.onEdited,
this.editGLEntriesOnceVendorCreditEdited // this.editGLEntriesOnceVendorCreditEdited
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onDeleted, // events.vendorCredit.onDeleted,
this.revertGLEntriesOnceDeleted // this.revertGLEntriesOnceDeleted
); // );
} // }
/** // /**
* Writes GL entries of vendor credit once the transaction created. // * Writes GL entries of vendor credit once the transaction created.
* @param {IVendorCreditCreatedPayload} payload - // * @param {IVendorCreditCreatedPayload} payload -
*/ // */
private writeGLEntriesOnceVendorCreditCreated = async ({ // private writeGLEntriesOnceVendorCreditCreated = async ({
tenantId, // tenantId,
vendorCredit, // vendorCredit,
trx, // trx,
}: IVendorCreditCreatedPayload): Promise<void> => { // }: IVendorCreditCreatedPayload): Promise<void> => {
// Can't continue if the vendor credit is not open yet. // // Can't continue if the vendor credit is not open yet.
if (!vendorCredit.isPublished) return; // if (!vendorCredit.isPublished) return;
await this.vendorCreditGLEntries.writeVendorCreditGLEntries( // await this.vendorCreditGLEntries.writeVendorCreditGLEntries(
tenantId, // tenantId,
vendorCredit.id, // vendorCredit.id,
trx // trx
); // );
}; // };
/** // /**
* Writes Gl entries of vendor credit once the transaction opened. // * Writes Gl entries of vendor credit once the transaction opened.
* @param {IVendorCreditOpenedPayload} payload - // * @param {IVendorCreditOpenedPayload} payload -
*/ // */
private writeGLEntgriesOnceVendorCreditOpened = async ({ // private writeGLEntgriesOnceVendorCreditOpened = async ({
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
trx, // trx,
}: IVendorCreditOpenedPayload) => { // }: IVendorCreditOpenedPayload) => {
await this.vendorCreditGLEntries.writeVendorCreditGLEntries( // await this.vendorCreditGLEntries.writeVendorCreditGLEntries(
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
trx // trx
); // );
}; // };
/** // /**
* Edits associated GL entries once vendor credit edited. // * Edits associated GL entries once vendor credit edited.
* @param {IVendorCreditEditedPayload} payload // * @param {IVendorCreditEditedPayload} payload
*/ // */
private editGLEntriesOnceVendorCreditEdited = async ({ // private editGLEntriesOnceVendorCreditEdited = async ({
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
vendorCredit, // vendorCredit,
trx, // trx,
}: IVendorCreditEditedPayload) => { // }: IVendorCreditEditedPayload) => {
// Can't continue if the vendor credit is not open yet. // // Can't continue if the vendor credit is not open yet.
if (!vendorCredit.isPublished) return; // if (!vendorCredit.isPublished) return;
await this.vendorCreditGLEntries.rewriteVendorCreditGLEntries( // await this.vendorCreditGLEntries.rewriteVendorCreditGLEntries(
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
trx // trx
); // );
}; // };
/** // /**
* Reverts the GL entries once vendor credit deleted. // * Reverts the GL entries once vendor credit deleted.
* @param {IVendorCreditDeletedPayload} payload - // * @param {IVendorCreditDeletedPayload} payload -
*/ // */
private revertGLEntriesOnceDeleted = async ({ // private revertGLEntriesOnceDeleted = async ({
vendorCreditId, // vendorCreditId,
tenantId, // tenantId,
oldVendorCredit, // oldVendorCredit,
}: IVendorCreditDeletedPayload): Promise<void> => { // }: IVendorCreditDeletedPayload): Promise<void> => {
// Can't continue of the vendor credit is not open yet. // // Can't continue of the vendor credit is not open yet.
if (!oldVendorCredit.isPublished) return; // if (!oldVendorCredit.isPublished) return;
await this.vendorCreditGLEntries.revertVendorCreditGLEntries( // await this.vendorCreditGLEntries.revertVendorCreditGLEntries(
tenantId, // tenantId,
vendorCreditId // vendorCreditId
); // );
}; // };
} // }

View File

@@ -1,93 +1,93 @@
import { Inject, Service } from 'typedi'; // import { Inject, Service } from 'typedi';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { // import {
IVendorCreditCreatedPayload, // IVendorCreditCreatedPayload,
IVendorCreditDeletedPayload, // IVendorCreditDeletedPayload,
IVendorCreditEditedPayload, // IVendorCreditEditedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import VendorCreditInventoryTransactions from '../commands/VendorCreditInventoryTransactions'; // import VendorCreditInventoryTransactions from '../commands/VendorCreditInventoryTransactions';
@Service() // @Service()
export default class VendorCreditInventoryTransactionsSubscriber { // export default class VendorCreditInventoryTransactionsSubscriber {
@Inject() // @Inject()
private inventoryTransactions: VendorCreditInventoryTransactions; // private inventoryTransactions: VendorCreditInventoryTransactions;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
* @param bus // * @param bus
*/ // */
attach(bus) { // attach(bus) {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onCreated, // events.vendorCredit.onCreated,
this.writeInventoryTransactionsOnceCreated // this.writeInventoryTransactionsOnceCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onOpened, // events.vendorCredit.onOpened,
this.writeInventoryTransactionsOnceCreated // this.writeInventoryTransactionsOnceCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onEdited, // events.vendorCredit.onEdited,
this.rewriteInventroyTransactionsOnceEdited // this.rewriteInventroyTransactionsOnceEdited
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onDeleted, // events.vendorCredit.onDeleted,
this.revertInventoryTransactionsOnceDeleted // this.revertInventoryTransactionsOnceDeleted
); // );
} // }
/** // /**
* Writes inventory transactions once vendor created created. // * Writes inventory transactions once vendor created created.
* @param {IVendorCreditCreatedPayload} payload - // * @param {IVendorCreditCreatedPayload} payload -
*/ // */
private writeInventoryTransactionsOnceCreated = async ({ // private writeInventoryTransactionsOnceCreated = async ({
tenantId, // tenantId,
vendorCredit, // vendorCredit,
trx, // trx,
}: IVendorCreditCreatedPayload) => { // }: IVendorCreditCreatedPayload) => {
// Can't continue if vendor credit is not opened. // // Can't continue if vendor credit is not opened.
if (!vendorCredit.openedAt) return null; // if (!vendorCredit.openedAt) return null;
await this.inventoryTransactions.createInventoryTransactions( // await this.inventoryTransactions.createInventoryTransactions(
tenantId, // tenantId,
vendorCredit, // vendorCredit,
trx // trx
); // );
}; // };
/** // /**
* Rewrites inventory transactions once vendor credit edited. // * Rewrites inventory transactions once vendor credit edited.
* @param {IVendorCreditEditedPayload} payload - // * @param {IVendorCreditEditedPayload} payload -
*/ // */
private rewriteInventroyTransactionsOnceEdited = async ({ // private rewriteInventroyTransactionsOnceEdited = async ({
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
vendorCredit, // vendorCredit,
trx, // trx,
}: IVendorCreditEditedPayload) => { // }: IVendorCreditEditedPayload) => {
// Can't continue if vendor credit is not opened. // // Can't continue if vendor credit is not opened.
if (!vendorCredit.openedAt) return null; // if (!vendorCredit.openedAt) return null;
await this.inventoryTransactions.editInventoryTransactions( // await this.inventoryTransactions.editInventoryTransactions(
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
vendorCredit, // vendorCredit,
trx // trx
); // );
}; // };
/** // /**
* Reverts inventory transactions once vendor credit deleted. // * Reverts inventory transactions once vendor credit deleted.
* @param {IVendorCreditDeletedPayload} payload - // * @param {IVendorCreditDeletedPayload} payload -
*/ // */
private revertInventoryTransactionsOnceDeleted = async ({ // private revertInventoryTransactionsOnceDeleted = async ({
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
trx, // trx,
}: IVendorCreditDeletedPayload) => { // }: IVendorCreditDeletedPayload) => {
await this.inventoryTransactions.deleteInventoryTransactions( // await this.inventoryTransactions.deleteInventoryTransactions(
tenantId, // tenantId,
vendorCreditId, // vendorCreditId,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,6 +1,9 @@
import { DiscountType, IDynamicListFilter, IItemEntry, IItemEntryDTO } from '@/interfaces';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { VendorCredit } from '../models/VendorCredit'; import { VendorCredit } from '../models/VendorCredit';
import { AttachmentLinkDTO } from '@/modules/Attachments/Attachments.types';
import { IRefundVendorCreditDTO } from '@/modules/VendorCreditsRefund/types/VendorCreditRefund.types';
import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types';
import { DiscountType } from '@/common/types/Discount';
export enum VendorCreditAction { export enum VendorCreditAction {
Create = 'Create', Create = 'Create',
@@ -10,25 +13,14 @@ export enum VendorCreditAction {
Refund = 'Refund', Refund = 'Refund',
} }
export interface IVendorCreditEntryDTO extends IItemEntryDTO {} export interface IVendorCreditEntryDTO extends IItemEntryDTO {}
export interface IRefundVendorCredit { // export interface IVendorCreditsQueryDTO extends IDynamicListFilter {
id?: number | null; // page: number;
date: Date; // pageSize: number;
referenceNo: string; // searchKeyword?: string;
amount: number; // filterQuery?: (q: any) => void;
currencyCode: string; // }
exchangeRate: number;
depositAccountId: number;
description: string;
vendorCreditId: number;
createdAt: Date | null;
userId: number;
branchId?: number;
vendorCredit?: VendorCredit
}
export interface IVendorCreditDTO { export interface IVendorCreditDTO {
vendorId: number; vendorId: number;
@@ -53,13 +45,12 @@ export interface IVendorCreditDTO {
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {} export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
export interface IVendorCreditEditDTO extends IVendorCreditDTO {} export interface IVendorCreditEditDTO extends IVendorCreditDTO {}
export interface IVendorCreditCreatePayload { export interface IVendorCreditCreatePayload {
// tenantId: number;
refundVendorCreditDTO: IRefundVendorCreditDTO; refundVendorCreditDTO: IRefundVendorCreditDTO;
vendorCreditId: number;
} }
// Create Vendor Credit Events
// ------------------------
export interface IVendorCreditCreatingPayload { export interface IVendorCreditCreatingPayload {
// tenantId: number;
vendorCredit: VendorCredit; vendorCredit: VendorCredit;
vendorCreditId: number; vendorCreditId: number;
vendorCreditCreateDTO: IVendorCreditCreateDTO; vendorCreditCreateDTO: IVendorCreditCreateDTO;
@@ -74,26 +65,22 @@ export interface IVendorCreditCreatedPayload {
} }
export interface IVendorCreditCreatedPayload {} export interface IVendorCreditCreatedPayload {}
// Delete Vendor Credit Events
// ------------------------
export interface IVendorCreditDeletedPayload { export interface IVendorCreditDeletedPayload {
trx: Knex.Transaction; trx: Knex.Transaction;
// tenantId: number;
vendorCreditId: number; vendorCreditId: number;
oldVendorCredit: VendorCredit; oldVendorCredit: VendorCredit;
} }
export interface IVendorCreditDeletingPayload { export interface IVendorCreditDeletingPayload {
trx: Knex.Transaction; trx: Knex.Transaction;
// tenantId: number;
oldVendorCredit: VendorCredit; oldVendorCredit: VendorCredit;
} }
export interface IVendorCreditsQueryDTO extends IDynamicListFilter { // Edit Vendor Credit Events
page: number; // ------------------------
pageSize: number;
searchKeyword?: string;
filterQuery?: (q: any) => void;
}
export interface IVendorCreditEditingPayload { export interface IVendorCreditEditingPayload {
// tenantId: number; // tenantId: number;
oldVendorCredit: VendorCredit; oldVendorCredit: VendorCredit;
@@ -105,64 +92,18 @@ export interface IVendorCreditEditedPayload {
// tenantId: number; // tenantId: number;
oldVendorCredit: VendorCredit; oldVendorCredit: VendorCredit;
vendorCredit: VendorCredit; vendorCredit: VendorCredit;
vendorCreditId: number; // vendorCreditId: number;
vendorCreditDTO: IVendorCreditEditDTO; vendorCreditDTO: IVendorCreditEditDTO;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface IRefundVendorCreditDTO {
amount: number;
exchangeRate?: number;
depositAccountId: number;
description: string;
date: Date;
branchId?: number;
}
export interface IRefundVendorCreditDeletedPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: IRefundVendorCredit;
// tenantId: number;
}
export interface IRefundVendorCreditDeletePayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: IRefundVendorCredit;
// tenantId: number;
}
export interface IRefundVendorCreditDeletingPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: IRefundVendorCredit;
// tenantId: number;
}
export interface IRefundVendorCreditCreatingPayload {
trx: Knex.Transaction;
vendorCredit: VendorCredit;
refundVendorCreditDTO: IRefundVendorCreditDTO;
// tenantId: number;
}
export interface IRefundVendorCreditCreatedPayload {
refundVendorCredit: IRefundVendorCredit;
vendorCredit: VendorCredit;
trx: Knex.Transaction;
// tenantId: number;
}
export interface IRefundVendorCreditPOJO {}
export interface IApplyCreditToBillEntryDTO { export interface IApplyCreditToBillEntryDTO {
amount: number; amount: number;
billId: number; billId: number;
} }
export interface IApplyCreditToBillsDTO { // Open Vendor Credit Events
entries: IApplyCreditToBillEntryDTO[]; // ------------------------
}
export interface IVendorCreditOpenedPayload { export interface IVendorCreditOpenedPayload {
// tenantId: number; // tenantId: number;
vendorCreditId: number; vendorCreditId: number;
@@ -182,48 +123,3 @@ export interface IVendorCreditOpeningPayload {
oldVendorCredit: VendorCredit; oldVendorCredit: VendorCredit;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface IVendorCreditApplyToBillsCreatedPayload {
// tenantId: number;
vendorCredit: VendorCredit;
vendorCreditAppliedBills: IVendorCreditAppliedBill[];
trx: Knex.Transaction;
}
export interface IVendorCreditApplyToBillsCreatingPayload {
trx: Knex.Transaction;
}
export interface IVendorCreditApplyToBillsCreatePayload {
trx: Knex.Transaction;
}
export interface IVendorCreditApplyToBillDeletedPayload {
// tenantId: number;
vendorCredit: VendorCredit;
oldCreditAppliedToBill: IVendorCreditAppliedBill;
trx: Knex.Transaction;
}
export interface IVendorCreditApplyToInvoiceDTO {
amount: number;
billId: number;
}
export interface IVendorCreditApplyToInvoicesDTO {
entries: IVendorCreditApplyToInvoiceDTO[];
}
export interface IVendorCreditApplyToInvoiceModel {
billId: number;
amount: number;
vendorCreditId: number;
}
export interface IVendorCreditApplyToInvoicesModel {
entries: IVendorCreditApplyToInvoiceModel[];
amount: number;
}
export interface IVendorCreditAppliedBill {
billId: number;
amount: number;
vendorCreditId: number;
}

View File

@@ -0,0 +1,48 @@
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { VendorCreditApplyBillsApplicationService } from './VendorCreditApplyBillsApplication.service';
import { IVendorCreditApplyToInvoicesDTO } from './types/VendorCreditApplyBills.types';
@Controller('vendor-credits')
export class VendorCreditApplyBillsController {
constructor(
private readonly vendorCreditApplyBillsApplication: VendorCreditApplyBillsApplicationService,
) {}
@Get(':vendorCreditId/bills-to-apply')
async getVendorCreditToApplyBills(
@Param('vendorCreditId') vendorCreditId: number,
) {
return this.vendorCreditApplyBillsApplication.getVendorCreditToApplyBills(
vendorCreditId,
);
}
@Post(':vendorCreditId/apply-to-bills')
async applyVendorCreditToBills(
@Param('vendorCreditId') vendorCreditId: number,
@Body() applyCreditToBillsDTO: IVendorCreditApplyToInvoicesDTO,
) {
return this.vendorCreditApplyBillsApplication.applyVendorCreditToBills(
vendorCreditId,
applyCreditToBillsDTO,
);
}
@Delete('applied-bills/:vendorCreditAppliedBillId')
async deleteAppliedBillToVendorCredit(
@Param('vendorCreditAppliedBillId') vendorCreditAppliedBillId: number,
) {
return this.vendorCreditApplyBillsApplication.deleteAppliedBillToVendorCredit(
vendorCreditAppliedBillId,
);
}
@Get(':vendorCreditId/applied-bills')
async getAppliedBillsToVendorCredit(
@Param('vendorCreditId') vendorCreditId: number,
) {
return this.vendorCreditApplyBillsApplication.getAppliedBillsToVendorCredit(
vendorCreditId,
);
}
}

View File

@@ -1,20 +1,38 @@
import { Module } from '@nestjs/common';
import { ApplyVendorCreditSyncBillsService } from './command/ApplyVendorCreditSyncBills.service';
import { Module } from "@nestjs/common"; import { ApplyVendorCreditSyncInvoicedService } from './command/ApplyVendorCreditSyncInvoiced.service';
import { ApplyVendorCreditSyncBillsService } from "./command/ApplyVendorCreditSyncBills.service"; import { DeleteApplyVendorCreditToBillService } from './command/DeleteApplyVendorCreditToBill.service';
import { ApplyVendorCreditSyncInvoicedService } from "./command/ApplyVendorCreditSyncInvoiced.service"; import { ApplyVendorCreditToBillsService } from './command/ApplyVendorCreditToBills.service';
import { DeleteApplyVendorCreditToBillService } from "./command/DeleteApplyVendorCreditToBill.service"; import { GetAppliedBillsToVendorCreditService } from './queries/GetAppliedBillsToVendorCredit.service';
import { ApplyVendorCreditToBillsService } from "./command/ApplyVendorCreditToBills.service"; import { GetVendorCreditToApplyBills } from './queries/GetVendorCreditToApplyBills.service';
import { GetAppliedBillsToVendorCreditService } from "./queries/GetAppliedBillsToVendorCredit.service"; import { VendorCreditApplyBillsApplicationService } from './VendorCreditApplyBillsApplication.service';
import { VendorCreditApplyBillsController } from './VendorCreditApplyBills.controller';
import { BillsModule } from '../Bills/Bills.module';
import { BillPaymentsModule } from '../BillPayments/BillPayments.module';
import { VendorCreditDTOTransformService } from '../VendorCredit/commands/VendorCreditDTOTransform.service';
import { ItemsModule } from '../Items/items.module';
import { BranchesModule } from '../Branches/Branches.module';
import { WarehousesModule } from '../Warehouses/Warehouses.module';
import { VendorCreditsModule } from '../VendorCredit/VendorCredits.module';
@Module({ @Module({
imports: [ imports: [
BillsModule,
BillPaymentsModule,
ItemsModule,
BranchesModule,
WarehousesModule,
VendorCreditsModule
],
providers: [
ApplyVendorCreditSyncBillsService, ApplyVendorCreditSyncBillsService,
ApplyVendorCreditSyncInvoicedService, ApplyVendorCreditSyncInvoicedService,
ApplyVendorCreditToBillsService, ApplyVendorCreditToBillsService,
DeleteApplyVendorCreditToBillService, DeleteApplyVendorCreditToBillService,
GetAppliedBillsToVendorCreditService GetAppliedBillsToVendorCreditService,
GetVendorCreditToApplyBills,
VendorCreditApplyBillsApplicationService,
], ],
controllers: [], controllers: [VendorCreditApplyBillsController],
}) })
export class VendorCreditApplyBillsModule {} export class VendorCreditApplyBillsModule {}

View File

@@ -0,0 +1,67 @@
import { ApplyVendorCreditToBillsService } from './command/ApplyVendorCreditToBills.service';
import { DeleteApplyVendorCreditToBillService } from './command/DeleteApplyVendorCreditToBill.service';
import { GetAppliedBillsToVendorCreditService } from './queries/GetAppliedBillsToVendorCredit.service';
import { GetVendorCreditToApplyBills } from './queries/GetVendorCreditToApplyBills.service';
import { IVendorCreditApplyToInvoicesDTO } from './types/VendorCreditApplyBills.types';
export class VendorCreditApplyBillsApplicationService {
/**
* @param {ApplyVendorCreditToBillsService} applyVendorCreditToBillsService
* @param {DeleteApplyVendorCreditToBillService} deleteApplyVendorCreditToBillService
* @param {GetVendorCreditToApplyBills} getVendorCreditToApplyBillsService
* @param {GetAppliedBillsToVendorCreditService} getAppliedBillsToVendorCreditService
*/
constructor(
private readonly applyVendorCreditToBillsService: ApplyVendorCreditToBillsService,
private readonly deleteApplyVendorCreditToBillService: DeleteApplyVendorCreditToBillService,
private readonly getVendorCreditToApplyBillsService: GetVendorCreditToApplyBills,
private readonly getAppliedBillsToVendorCreditService: GetAppliedBillsToVendorCreditService,
) {}
/**
* Retrieve bills that valid apply to the given vendor credit.
* @param {number} vendorCreditId
* @returns {Promise<any[]>}
*/
async getVendorCreditToApplyBills(vendorCreditId: number) {
return this.getVendorCreditToApplyBillsService.getCreditToApplyBills(
vendorCreditId,
);
}
/**
* Apply credit note to the given bills.
* @param {number} vendorCreditId
* @param {IVendorCreditApplyToInvoicesDTO} applyCreditToBillsDTO
*/
async applyVendorCreditToBills(
vendorCreditId: number,
applyCreditToBillsDTO: IVendorCreditApplyToInvoicesDTO,
) {
return this.applyVendorCreditToBillsService.applyVendorCreditToBills(
vendorCreditId,
applyCreditToBillsDTO,
);
}
/**
* Delete applied bill to the given vendor credit.
* @param {number} vendorCreditAppliedBillId
*/
async deleteAppliedBillToVendorCredit(vendorCreditAppliedBillId: number) {
return this.deleteApplyVendorCreditToBillService.deleteApplyVendorCreditToBills(
vendorCreditAppliedBillId,
);
}
/**
* Retrieve applied bills to the given vendor credit.
* @param {number} vendorCreditId
* @returns {Promise<any[]>}
*/
async getAppliedBillsToVendorCredit(vendorCreditId: number) {
return this.getAppliedBillsToVendorCreditService.getAppliedBills(
vendorCreditId,
);
}
}

View File

@@ -4,6 +4,9 @@ import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
@Injectable() @Injectable()
export class ApplyVendorCreditSyncInvoicedService { export class ApplyVendorCreditSyncInvoicedService {
/**
* @param {typeof VendorCredit} vendorCreditModel - The vendor credit model.
*/
constructor( constructor(
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, private readonly vendorCreditModel: typeof VendorCredit,

View File

@@ -14,6 +14,8 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { Bill } from '@/modules/Bills/models/Bill'; import { Bill } from '@/modules/Bills/models/Bill';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
import { events } from '@/common/events/events';
import { VendorCreditDTOTransformService } from '@/modules/VendorCredit/commands/VendorCreditDTOTransform.service';
@Injectable() @Injectable()
export class ApplyVendorCreditToBillsService { export class ApplyVendorCreditToBillsService {
@@ -28,6 +30,9 @@ export class ApplyVendorCreditToBillsService {
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
private readonly billPaymentValidators: BillPaymentValidators, private readonly billPaymentValidators: BillPaymentValidators,
private readonly vendorCreditDTOTransform: VendorCreditDTOTransformService,
@Inject(VendorCreditAppliedBill.name)
private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill, private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill,
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
@@ -68,11 +73,10 @@ export class ApplyVendorCreditToBillsService {
vendorCreditAppliedModel.amount, vendorCreditAppliedModel.amount,
); );
// Validate vendor credit remaining credit amount. // Validate vendor credit remaining credit amount.
this.validateCreditRemainingAmount( this.vendorCreditDTOTransform.validateCreditRemainingAmount(
vendorCredit, vendorCredit,
vendorCreditAppliedModel.amount, vendorCreditAppliedModel.amount,
); );
// Saves vendor credit applied to bills under unit-of-work envirement. // Saves vendor credit applied to bills under unit-of-work envirement.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Inserts vendor credit applied to bills graph to the storage layer. // Inserts vendor credit applied to bills graph to the storage layer.

View File

@@ -19,6 +19,8 @@ export class DeleteApplyVendorCreditToBillService {
constructor( constructor(
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
@Inject(VendorCreditAppliedBill.name)
private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill, private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill,
@Inject(VendorCredit.name) @Inject(VendorCredit.name)

View File

@@ -8,6 +8,8 @@ import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
export class GetAppliedBillsToVendorCreditService { export class GetAppliedBillsToVendorCreditService {
constructor( constructor(
private readonly transformer: TransformerInjectable, private readonly transformer: TransformerInjectable,
@Inject(VendorCreditAppliedBill.name)
private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill, private readonly vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill,
@Inject(VendorCredit.name) @Inject(VendorCredit.name)

View File

@@ -1,61 +1,61 @@
import { Injectable } from '@nestjs/common'; // import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/objection'; // import { InjectModel } from '@nestjs/objection';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { // import {
IVendorCreditApplyToBillDeletedPayload, // IVendorCreditApplyToBillDeletedPayload,
IVendorCreditApplyToBillsCreatedPayload, // IVendorCreditApplyToBillsCreatedPayload,
} from '@/interfaces'; // } from '@/interfaces';
import { ApplyVendorCreditSyncBillsService } from '../command/ApplyVendorCreditSyncBills.service'; // import { ApplyVendorCreditSyncBillsService } from '../command/ApplyVendorCreditSyncBills.service';
import { VendorCreditApplyToBill } from '../models/VendorCreditApplyToBill'; // import { VendorCreditApplyToBill } from '../models/VendorCreditApplyToBill';
@Injectable() // @Injectable()
export default class ApplyVendorCreditSyncBillsSubscriber { // export default class ApplyVendorCreditSyncBillsSubscriber {
constructor( // constructor(
private readonly syncBillsWithVendorCredit: ApplyVendorCreditSyncBillsService, // private readonly syncBillsWithVendorCredit: ApplyVendorCreditSyncBillsService,
@InjectModel(VendorCreditApplyToBill) // @InjectModel(VendorCreditApplyToBill)
private readonly vendorCreditApplyToBillModel: typeof VendorCreditApplyToBill, // private readonly vendorCreditApplyToBillModel: typeof VendorCreditApplyToBill,
) {} // ) {}
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
attach(bus) { // attach(bus) {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onApplyToInvoicesCreated, // events.vendorCredit.onApplyToInvoicesCreated,
this.incrementAppliedBillsOnceCreditCreated // this.incrementAppliedBillsOnceCreditCreated
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onApplyToInvoicesDeleted, // events.vendorCredit.onApplyToInvoicesDeleted,
this.decrementAppliedBillsOnceCreditDeleted // this.decrementAppliedBillsOnceCreditDeleted
); // );
} // }
/** // /**
* Increment credited amount of applied bills once the vendor credit transaction created. // * Increment credited amount of applied bills once the vendor credit transaction created.
* @param {IVendorCreditApplyToBillsCreatedPayload} paylaod - // * @param {IVendorCreditApplyToBillsCreatedPayload} paylaod -
*/ // */
private incrementAppliedBillsOnceCreditCreated = async ({ // private incrementAppliedBillsOnceCreditCreated = async ({
vendorCreditAppliedBills, // vendorCreditAppliedBills,
trx, // trx,
}: IVendorCreditApplyToBillsCreatedPayload) => { // }: IVendorCreditApplyToBillsCreatedPayload) => {
await this.syncBillsWithVendorCredit.incrementBillsCreditedAmount( // await this.syncBillsWithVendorCredit.incrementBillsCreditedAmount(
vendorCreditAppliedBills, // vendorCreditAppliedBills,
trx // trx
); // );
}; // };
/** // /**
* Decrement credited amount of applied bills once the vendor credit // * Decrement credited amount of applied bills once the vendor credit
* transaction delted. // * transaction delted.
* @param {IVendorCreditApplyToBillDeletedPayload} payload // * @param {IVendorCreditApplyToBillDeletedPayload} payload
*/ // */
private decrementAppliedBillsOnceCreditDeleted = async ({ // private decrementAppliedBillsOnceCreditDeleted = async ({
oldCreditAppliedToBill, // oldCreditAppliedToBill,
trx, // trx,
}: IVendorCreditApplyToBillDeletedPayload) => { // }: IVendorCreditApplyToBillDeletedPayload) => {
await this.syncBillsWithVendorCredit.decrementBillCreditedAmount( // await this.syncBillsWithVendorCredit.decrementBillCreditedAmount(
oldCreditAppliedToBill, // oldCreditAppliedToBill,
trx // trx
); // );
}; // };
} // }

View File

@@ -1,70 +1,70 @@
import { Service, Inject } from 'typedi'; // import { Service, Inject } from 'typedi';
import { sumBy } from 'lodash'; // import { sumBy } from 'lodash';
import HasTenancyService from '@/services/Tenancy/TenancyService'; // import HasTenancyService from '@/services/Tenancy/TenancyService';
import ApplyVendorCreditSyncInvoiced from '../command/ApplyVendorCreditSyncInvoiced.service'; // import ApplyVendorCreditSyncInvoiced from '../command/ApplyVendorCreditSyncInvoiced.service';
import events from '@/subscribers/events'; // import events from '@/subscribers/events';
import { // import {
IVendorCreditApplyToBillDeletedPayload, // IVendorCreditApplyToBillDeletedPayload,
IVendorCreditApplyToBillsCreatedPayload, // IVendorCreditApplyToBillsCreatedPayload,
} from '@/interfaces'; // } from '../types/VendorCreditApplyBills.types';
@Service() // @Service()
export default class ApplyVendorCreditSyncInvoicedSubscriber { // export default class ApplyVendorCreditSyncInvoicedSubscriber {
@Inject() // @Inject()
tenancy: HasTenancyService; // tenancy: HasTenancyService;
@Inject() // @Inject()
syncCreditWithInvoiced: ApplyVendorCreditSyncInvoiced; // syncCreditWithInvoiced: ApplyVendorCreditSyncInvoiced;
/** // /**
* Attaches events with handlers. // * Attaches events with handlers.
*/ // */
attach(bus) { // attach(bus) {
bus.subscribe( // bus.subscribe(
events.vendorCredit.onApplyToInvoicesCreated, // events.vendorCredit.onApplyToInvoicesCreated,
this.incrementBillInvoicedOnceCreditApplied // this.incrementBillInvoicedOnceCreditApplied
); // );
bus.subscribe( // bus.subscribe(
events.vendorCredit.onApplyToInvoicesDeleted, // events.vendorCredit.onApplyToInvoicesDeleted,
this.decrementBillInvoicedOnceCreditApplyDeleted // this.decrementBillInvoicedOnceCreditApplyDeleted
); // );
} // }
/** // /**
* Increment vendor credit invoiced amount once the apply transaction created. // * Increment vendor credit invoiced amount once the apply transaction created.
* @param {IVendorCreditApplyToBillsCreatedPayload} payload - // * @param {IVendorCreditApplyToBillsCreatedPayload} payload -
*/ // */
private incrementBillInvoicedOnceCreditApplied = async ({ // private incrementBillInvoicedOnceCreditApplied = async ({
vendorCredit, // vendorCredit,
tenantId, // tenantId,
vendorCreditAppliedBills, // vendorCreditAppliedBills,
trx, // trx,
}: IVendorCreditApplyToBillsCreatedPayload) => { // }: IVendorCreditApplyToBillsCreatedPayload) => {
const amount = sumBy(vendorCreditAppliedBills, 'amount'); // const amount = sumBy(vendorCreditAppliedBills, 'amount');
await this.syncCreditWithInvoiced.incrementVendorCreditInvoicedAmount( // await this.syncCreditWithInvoiced.incrementVendorCreditInvoicedAmount(
tenantId, // tenantId,
vendorCredit.id, // vendorCredit.id,
amount, // amount,
trx // trx
); // );
}; // };
/** // /**
* Decrement vendor credit invoiced amount once the apply transaction deleted. // * Decrement vendor credit invoiced amount once the apply transaction deleted.
* @param {IVendorCreditApplyToBillDeletedPayload} payload - // * @param {IVendorCreditApplyToBillDeletedPayload} payload -
*/ // */
private decrementBillInvoicedOnceCreditApplyDeleted = async ({ // private decrementBillInvoicedOnceCreditApplyDeleted = async ({
tenantId, // tenantId,
vendorCredit, // vendorCredit,
oldCreditAppliedToBill, // oldCreditAppliedToBill,
trx, // trx,
}: IVendorCreditApplyToBillDeletedPayload) => { // }: IVendorCreditApplyToBillDeletedPayload) => {
await this.syncCreditWithInvoiced.decrementVendorCreditInvoicedAmount( // await this.syncCreditWithInvoiced.decrementVendorCreditInvoicedAmount(
tenantId, // tenantId,
oldCreditAppliedToBill.vendorCreditId, // oldCreditAppliedToBill.vendorCreditId,
oldCreditAppliedToBill.amount, // oldCreditAppliedToBill.amount,
trx // trx
); // );
}; // };
} // }

View File

@@ -0,0 +1,44 @@
import { Injectable } from '@nestjs/common';
import { DeleteRefundVendorCreditService } from './commands/DeleteRefundVendorCredit.service';
import { RefundVendorCredit } from './models/RefundVendorCredit';
import { CreateRefundVendorCredit } from './commands/CreateRefundVendorCredit.service';
import { IRefundVendorCreditDTO } from './types/VendorCreditRefund.types';
@Injectable()
export class VendorCreditsRefundApplication {
/**
* @param {CreateRefundVendorCredit} createRefundVendorCreditService
* @param {DeleteRefundVendorCreditService} deleteRefundVendorCreditService
*/
constructor(
private readonly createRefundVendorCreditService: CreateRefundVendorCredit,
private readonly deleteRefundVendorCreditService: DeleteRefundVendorCreditService,
) {}
/**
* Creates a refund vendor credit.
* @param {number} vendorCreditId
* @param {IRefundVendorCreditDTO} refundVendorCreditDTO
* @returns {Promise<RefundVendorCredit>}
*/
public async createRefundVendorCredit(
vendorCreditId: number,
refundVendorCreditDTO: IRefundVendorCreditDTO,
): Promise<RefundVendorCredit> {
return this.createRefundVendorCreditService.createRefund(
vendorCreditId,
refundVendorCreditDTO,
);
}
/**
* Deletes a refund vendor credit.
* @param {number} refundCreditId
* @returns {Promise<void>}
*/
public async deleteRefundVendorCredit(refundCreditId: number): Promise<void> {
return this.deleteRefundVendorCreditService.deleteRefundVendorCreditRefund(
refundCreditId,
);
}
}

View File

@@ -0,0 +1,44 @@
import { Body, Controller, Delete, Param, Post } from '@nestjs/common';
import { VendorCreditsRefundApplication } from './VendorCreditsRefund.application';
import { IRefundVendorCreditDTO } from './types/VendorCreditRefund.types';
import { RefundVendorCredit } from './models/RefundVendorCredit';
@Controller('vendor-credits')
export class VendorCreditsRefundController {
constructor(
private readonly vendorCreditsRefundApplication: VendorCreditsRefundApplication,
) {}
/**
* Creates a refund vendor credit.
* @param {number} vendorCreditId
* @param {IRefundVendorCreditDTO} refundVendorCreditDTO
* @returns {Promise<RefundVendorCredit>}
*/
@Post(':vendorCreditId/refunds')
public async createRefundVendorCredit(
@Param('vendorCreditId') vendorCreditId: string,
@Body() refundVendorCreditDTO: IRefundVendorCreditDTO,
): Promise<RefundVendorCredit> {
return this.vendorCreditsRefundApplication.createRefundVendorCredit(
Number(vendorCreditId),
refundVendorCreditDTO,
);
}
/**
* Deletes a refund vendor credit.
* @param {number} refundCreditId
* @returns {Promise<void>}
*/
@Delete('refunds/:refundCreditId')
public async deleteRefundVendorCredit(
@Param('refundCreditId') refundCreditId: string,
): Promise<void> {
return this.vendorCreditsRefundApplication.deleteRefundVendorCredit(
Number(refundCreditId),
);
}
}

View File

@@ -0,0 +1,20 @@
import { Module } from '@nestjs/common';
import { GetRefundVendorCreditsService } from './queries/GetRefundVendorCredits.service';
import { DeleteRefundVendorCreditService } from './commands/DeleteRefundVendorCredit.service';
import { VendorCreditsRefundController } from './VendorCreditsRefund.controller';
import { VendorCreditsRefundApplication } from './VendorCreditsRefund.application';
import { CreateRefundVendorCredit } from './commands/CreateRefundVendorCredit.service';
import { WarehousesModule } from '../Warehouses/Warehouses.module';
import { BranchesModule } from '../Branches/Branches.module';
@Module({
imports: [WarehousesModule, BranchesModule],
providers: [
GetRefundVendorCreditsService,
DeleteRefundVendorCreditService,
CreateRefundVendorCredit,
VendorCreditsRefundApplication
],
controllers: [VendorCreditsRefundController],
})
export class VendorCreditsRefundModule {}

View File

@@ -3,21 +3,22 @@ import { Knex } from 'knex';
import * as R from 'ramda'; import * as R from 'ramda';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { import {
IRefundVendorCredit,
IRefundVendorCreditCreatedPayload, IRefundVendorCreditCreatedPayload,
IRefundVendorCreditCreatingPayload, IRefundVendorCreditCreatingPayload,
IRefundVendorCreditDTO, IRefundVendorCreditDTO,
IVendorCreditCreatePayload, } from '../types/VendorCreditRefund.types';
} from '@/modules/VendorCredit/types/VendorCredit.types';
import { Account } from '@/modules/Accounts/models/Account.model'; import { Account } from '@/modules/Accounts/models/Account.model';
import { VendorCredit } from '../../models/VendorCredit'; import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { RefundVendorCredit } from '../../models/RefundVendorCredit'; import { RefundVendorCredit } from '../models/RefundVendorCredit';
import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform'; import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform';
import { IVendorCreditCreatePayload } from '@/modules/VendorCredit/types/VendorCredit.types';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { ServiceError } from '@/modules/Items/ServiceError';
import { ERRORS } from '../constants';
@Injectable() @Injectable()
export class CreateRefundVendorCredit { export class CreateRefundVendorCredit {
constructor( constructor(
private readonly uow: UnitOfWork, private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2, private readonly eventPublisher: EventEmitter2,
@@ -31,8 +32,7 @@ export class CreateRefundVendorCredit {
@Inject(VendorCredit.name) @Inject(VendorCredit.name)
private readonly vendorCreditModel: typeof VendorCredit, private readonly vendorCreditModel: typeof VendorCredit,
) { ) {}
}
/** /**
* Creates a refund vendor credit. * Creates a refund vendor credit.
@@ -42,22 +42,24 @@ export class CreateRefundVendorCredit {
*/ */
public createRefund = async ( public createRefund = async (
vendorCreditId: number, vendorCreditId: number,
refundVendorCreditDTO: IRefundVendorCreditDTO refundVendorCreditDTO: IRefundVendorCreditDTO,
): Promise<IRefundVendorCredit> => { ): Promise<RefundVendorCredit> => {
// Retrieve the vendor credit or throw not found service error. // Retrieve the vendor credit or throw not found service error.
const vendorCredit = await this.vendorCreditModel.query() const vendorCredit = await this.vendorCreditModel
.query()
.findById(vendorCreditId) .findById(vendorCreditId)
.throwIfNotFound(); .throwIfNotFound();
// Retrieve the deposit account or throw not found service error. // Retrieve the deposit account or throw not found service error.
const depositAccount = await this.accountModel.query() const depositAccount = await this.accountModel
.query()
.findById(refundVendorCreditDTO.depositAccountId) .findById(refundVendorCreditDTO.depositAccountId)
.throwIfNotFound(); .throwIfNotFound();
// Validate vendor credit has remaining credit. // Validate vendor credit has remaining credit.
this.validateVendorCreditRemainingCredit( this.validateVendorCreditRemainingCredit(
vendorCredit, vendorCredit,
refundVendorCreditDTO.amount refundVendorCreditDTO.amount,
); );
// Validate refund deposit account type. // Validate refund deposit account type.
this.validateRefundDepositAccountType(depositAccount); this.validateRefundDepositAccountType(depositAccount);
@@ -70,7 +72,7 @@ export class CreateRefundVendorCredit {
const refundCreditObj = this.transformDTOToModel( const refundCreditObj = this.transformDTOToModel(
vendorCredit, vendorCredit,
refundVendorCreditDTO refundVendorCreditDTO,
); );
// Saves refund vendor credit with associated transactions. // Saves refund vendor credit with associated transactions.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
@@ -83,12 +85,13 @@ export class CreateRefundVendorCredit {
// Triggers `onVendorCreditRefundCreating` event. // Triggers `onVendorCreditRefundCreating` event.
await this.eventPublisher.emitAsync( await this.eventPublisher.emitAsync(
events.vendorCredit.onRefundCreating, events.vendorCredit.onRefundCreating,
eventPayload as IRefundVendorCreditCreatingPayload eventPayload as IRefundVendorCreditCreatingPayload,
); );
// Inserts refund vendor credit to the storage layer. // Inserts refund vendor credit to the storage layer.
const refundVendorCredit = const refundVendorCredit = await this.refundVendorCreditModel
await this.refundVendorCreditModel.query().insertAndFetch(refundCreditObj); .query()
.insertAndFetch(refundCreditObj);
// Triggers `onVendorCreditCreated` event. // Triggers `onVendorCreditCreated` event.
await this.eventPublisher.emitAsync(events.vendorCredit.onRefundCreated, { await this.eventPublisher.emitAsync(events.vendorCredit.onRefundCreated, {
...eventPayload, ...eventPayload,
@@ -101,13 +104,13 @@ export class CreateRefundVendorCredit {
/** /**
* Transformes the refund DTO to refund vendor credit model. * Transformes the refund DTO to refund vendor credit model.
* @param {IVendorCredit} vendorCredit - * @param {IVendorCredit} vendorCredit -
* @param {IRefundVendorCreditDTO} vendorCreditDTO * @param {IRefundVendorCreditDTO} vendorCreditDTO
* @returns {IRefundVendorCredit} * @returns {IRefundVendorCredit}
*/ */
public transformDTOToModel = ( public transformDTOToModel = (
vendorCredit: VendorCredit, vendorCredit: VendorCredit,
vendorCreditDTO: IRefundVendorCreditDTO vendorCreditDTO: IRefundVendorCreditDTO,
) => { ) => {
const initialDTO = { const initialDTO = {
vendorCreditId: vendorCredit.id, vendorCreditId: vendorCredit.id,
@@ -115,8 +118,32 @@ export class CreateRefundVendorCredit {
currencyCode: vendorCredit.currencyCode, currencyCode: vendorCredit.currencyCode,
exchangeRate: vendorCreditDTO.exchangeRate || 1, exchangeRate: vendorCreditDTO.exchangeRate || 1,
}; };
return R.compose(this.branchDTOTransform.transformDTO())( return R.compose(this.branchDTOTransform.transformDTO)(initialDTO);
initialDTO
);
}; };
/**
* Validate the deposit refund account type.
* @param {IAccount} account
*/
public validateRefundDepositAccountType(account: Account) {
const supportedTypes = ['bank', 'cash', 'fixed-asset'];
if (supportedTypes.indexOf(account.accountType) === -1) {
throw new ServiceError(ERRORS.DEPOSIT_ACCOUNT_INVALID_TYPE);
}
}
/**
* Validate vendor credit has remaining credits.
* @param {IVendorCredit} vendorCredit
* @param {number} amount
*/
public validateVendorCreditRemainingCredit(
vendorCredit: VendorCredit,
amount: number,
) {
if (vendorCredit.creditsRemaining < amount) {
throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_NO_CREDITS_REMAINING);
}
}
} }

View File

@@ -1,12 +1,12 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common';
import { import {
IRefundVendorCreditDeletedPayload, IRefundVendorCreditDeletedPayload,
IRefundVendorCreditDeletePayload, IRefundVendorCreditDeletePayload,
IRefundVendorCreditDeletingPayload, IRefundVendorCreditDeletingPayload,
} from '@/modules/VendorCredit/types/VendorCredit.types'; } from '../types/VendorCreditRefund.types';
import { Inject, Injectable } from '@nestjs/common'; import { RefundVendorCredit } from '../models/RefundVendorCredit';
import { RefundVendorCredit } from '../../models/RefundVendorCredit'; // import { RefundVendorCreditService } from './RefundVendorCredit.service';
import { RefundVendorCreditService } from './RefundVendorCredit.service';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
@@ -24,8 +24,7 @@ export class DeleteRefundVendorCreditService {
@Inject(RefundVendorCredit.name) @Inject(RefundVendorCredit.name)
private readonly refundVendorCreditModel: typeof RefundVendorCredit, private readonly refundVendorCreditModel: typeof RefundVendorCredit,
) { ) {}
}
/** /**
* Deletes the refund vendor credit. * Deletes the refund vendor credit.
@@ -33,12 +32,14 @@ export class DeleteRefundVendorCreditService {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
public async deleteRefundVendorCreditRefund( public async deleteRefundVendorCreditRefund(
refundCreditId: number refundCreditId: number,
): Promise<void> { ): Promise<void> {
// Retrieve the old credit note or throw not found service error. // Retrieve the old credit note or throw not found service error.
const oldRefundCredit = await this.getRefundVendorCreditOrThrowError( const oldRefundCredit = await this.refundVendorCreditModel
refundCreditId .query()
); .findById(refundCreditId)
.throwIfNotFound();
// Triggers `onVendorCreditRefundDelete` event. // Triggers `onVendorCreditRefundDelete` event.
await this.eventPublisher.emitAsync(events.vendorCredit.onRefundDelete, { await this.eventPublisher.emitAsync(events.vendorCredit.onRefundDelete, {
refundCreditId, refundCreditId,
@@ -56,7 +57,7 @@ export class DeleteRefundVendorCreditService {
// Triggers `onVendorCreditRefundDeleting` event. // Triggers `onVendorCreditRefundDeleting` event.
await this.eventPublisher.emitAsync( await this.eventPublisher.emitAsync(
events.vendorCredit.onRefundDeleting, events.vendorCredit.onRefundDeleting,
eventPayload eventPayload,
); );
// Deletes the refund vendor credit graph from the storage. // Deletes the refund vendor credit graph from the storage.
await this.refundVendorCreditModel await this.refundVendorCreditModel
@@ -67,7 +68,7 @@ export class DeleteRefundVendorCreditService {
// Triggers `onVendorCreditRefundDeleted` event. // Triggers `onVendorCreditRefundDeleted` event.
await this.eventPublisher.emitAsync( await this.eventPublisher.emitAsync(
events.vendorCredit.onRefundDeleted, events.vendorCredit.onRefundDeleted,
eventPayload as IRefundVendorCreditDeletedPayload eventPayload as IRefundVendorCreditDeletedPayload,
); );
}); });
} }

View File

@@ -1,7 +1,7 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { IRefundVendorCredit } from '../../types/VendorCredit.types'; import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
import { VendorCredit } from '../../models/VendorCredit'; import { RefundVendorCredit } from '../models/RefundVendorCredit';
@Injectable() @Injectable()
export class RefundSyncVendorCreditBalance { export class RefundSyncVendorCreditBalance {
@@ -12,11 +12,11 @@ export class RefundSyncVendorCreditBalance {
/** /**
* Increment vendor credit refunded amount. * Increment vendor credit refunded amount.
* @param {IRefundVendorCredit} refundCreditNote - * @param {RefundVendorCredit} refundCreditNote -
* @param {Knex.Transaction} trx - * @param {Knex.Transaction} trx -
*/ */
public async incrementVendorCreditRefundAmount( public async incrementVendorCreditRefundAmount(
refundVendorCredit: IRefundVendorCredit, refundVendorCredit: RefundVendorCredit,
trx?: Knex.Transaction trx?: Knex.Transaction
): Promise<void> { ): Promise<void> {
await this.vendorCreditModel await this.vendorCreditModel
@@ -26,11 +26,11 @@ export class RefundSyncVendorCreditBalance {
/** /**
* Decrement vendor credit refunded amount. * Decrement vendor credit refunded amount.
* @param {IRefundVendorCredit} refundCreditNote * @param {RefundVendorCredit} refundCreditNote
* @param {Knex.Transaction} trx * @param {Knex.Transaction} trx
*/ */
public async decrementVendorCreditRefundAmount( public async decrementVendorCreditRefundAmount(
refundVendorCredit: IRefundVendorCredit, refundVendorCredit: RefundVendorCredit,
trx?: Knex.Transaction trx?: Knex.Transaction
): Promise<void> { ): Promise<void> {
await this.vendorCreditModel await this.vendorCreditModel

View File

@@ -1,8 +1,8 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { ERRORS } from '../constants'; import { ERRORS } from '../constants';
import { RefundVendorCredit } from '../../models/RefundVendorCredit';
import { Account } from '@/modules/Accounts/models/Account.model'; import { Account } from '@/modules/Accounts/models/Account.model';
import { VendorCredit } from '../../models/VendorCredit'; import { RefundVendorCredit } from '../models/RefundVendorCredit';
import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
import { ServiceError } from '@/modules/Items/ServiceError'; import { ServiceError } from '@/modules/Items/ServiceError';
@Injectable() @Injectable()

View File

@@ -5,7 +5,7 @@ import { Model, mixin } from 'objection';
// import ModelSearchable from './ModelSearchable'; // import ModelSearchable from './ModelSearchable';
import { BaseModel } from '@/models/Model'; import { BaseModel } from '@/models/Model';
import { Account } from '@/modules/Accounts/models/Account.model'; import { Account } from '@/modules/Accounts/models/Account.model';
import { VendorCredit } from './VendorCredit'; import { VendorCredit } from '../../VendorCredit/models/VendorCredit';
export class RefundVendorCredit extends BaseModel { export class RefundVendorCredit extends BaseModel {
public vendorCreditId!: number; public vendorCreditId!: number;

View File

@@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { RefundVendorCreditTransformer } from '../commands/RefundVendorCreditTransformer'; import { RefundVendorCreditTransformer } from '../commands/RefundVendorCreditTransformer';
import { RefundVendorCredit, RefundVendorCredit as RefundVendorCreditModel } from '../../models/RefundVendorCredit'; import {
RefundVendorCredit,
RefundVendorCredit as RefundVendorCreditModel,
} from '../models/RefundVendorCredit';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
@Injectable() @Injectable()
@@ -11,9 +14,10 @@ export class GetRefundVendorCreditService {
*/ */
constructor( constructor(
private readonly transformer: TransformerInjectable, private readonly transformer: TransformerInjectable,
@Inject(RefundVendorCredit.name)
private readonly refundVendorCreditModel: typeof RefundVendorCreditModel, private readonly refundVendorCreditModel: typeof RefundVendorCreditModel,
) { ) {}
}
/** /**
* Retrieve refund vendor credit transaction. * Retrieve refund vendor credit transaction.

View File

@@ -1,8 +1,8 @@
import { Inject, Injectable } from '@nestjs/common';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
import { RefundVendorCreditTransformer } from '../commands/RefundVendorCreditTransformer'; import { RefundVendorCreditTransformer } from '../commands/RefundVendorCreditTransformer';
import { Injectable } from '@nestjs/common'; import { IRefundVendorCreditPOJO } from '../types/VendorCreditRefund.types';
import { RefundVendorCredit } from '../../models/RefundVendorCredit'; import { RefundVendorCredit } from '../models/RefundVendorCredit';
import { IRefundVendorCreditPOJO } from '../../types/VendorCredit.types';
@Injectable() @Injectable()
export class GetRefundVendorCreditsService { export class GetRefundVendorCreditsService {
@@ -12,6 +12,8 @@ export class GetRefundVendorCreditsService {
*/ */
constructor( constructor(
private readonly transformer: TransformerInjectable, private readonly transformer: TransformerInjectable,
@Inject(RefundVendorCredit.name)
private readonly refundVendorCreditModel: typeof RefundVendorCredit, private readonly refundVendorCreditModel: typeof RefundVendorCredit,
) {} ) {}

View File

@@ -0,0 +1,44 @@
import { Knex } from 'knex';
import { RefundVendorCredit } from '../models/RefundVendorCredit';
import { VendorCredit } from '@/modules/VendorCredit/models/VendorCredit';
export interface IRefundVendorCreditDTO {
amount: number;
exchangeRate?: number;
depositAccountId: number;
description: string;
date: Date;
branchId?: number;
}
export interface IRefundVendorCreditDeletedPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: RefundVendorCredit;
}
export interface IRefundVendorCreditDeletePayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: RefundVendorCredit;
}
export interface IRefundVendorCreditDeletingPayload {
trx: Knex.Transaction;
refundCreditId: number;
oldRefundCredit: RefundVendorCredit;
}
export interface IRefundVendorCreditCreatingPayload {
trx: Knex.Transaction;
vendorCredit: VendorCredit;
refundVendorCreditDTO: IRefundVendorCreditDTO;
}
export interface IRefundVendorCreditCreatedPayload {
refundVendorCredit: RefundVendorCredit;
vendorCredit: VendorCredit;
trx: Knex.Transaction;
}
export interface IRefundVendorCreditPOJO {}