diff --git a/packages/server/src/modules/App/App.module.ts b/packages/server/src/modules/App/App.module.ts index 0d9884a64..59a9103ea 100644 --- a/packages/server/src/modules/App/App.module.ts +++ b/packages/server/src/modules/App/App.module.ts @@ -92,6 +92,7 @@ import { ContactsModule } from '../Contacts/Contacts.module'; import { BankingPlaidModule } from '../BankingPlaid/BankingPlaid.module'; import { BankingCategorizeModule } from '../BankingCategorize/BankingCategorize.module'; import { TenantModelsInitializeModule } from '../Tenancy/TenantModelsInitialize.module'; +import { BillLandedCostsModule } from '../BillLandedCosts/BillLandedCosts.module'; @Module({ imports: [ @@ -174,6 +175,7 @@ import { TenantModelsInitializeModule } from '../Tenancy/TenantModelsInitialize. SaleEstimatesModule, SaleReceiptsModule, BillsModule, + BillLandedCostsModule, ManualJournalsModule, CreditNotesModule, VendorCreditsModule, diff --git a/packages/server/src/modules/BillLandedCosts/BaseLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/BaseLandedCost.service.ts index 037a25bd0..44a1da677 100644 --- a/packages/server/src/modules/BillLandedCosts/BaseLandedCost.service.ts +++ b/packages/server/src/modules/BillLandedCosts/BaseLandedCost.service.ts @@ -1,11 +1,10 @@ import { Inject } from '@nestjs/common'; import { difference, sumBy } from 'lodash'; import { - ILandedCostItemDTO, - ILandedCostDTO, - IBillLandedCostTransaction, ILandedCostTransaction, ILandedCostTransactionEntry, + LandedCostTransactionModel, + LandedCostTransactionType, } from './types/BillLandedCosts.types'; import { TenantModelProxy } from '../System/models/TenantBaseModel'; import { BillLandedCost } from './models/BillLandedCost'; @@ -14,13 +13,19 @@ import { CONFIG, ERRORS } from './utils'; import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry'; import { Bill } from '../Bills/models/Bill'; import { TransactionLandedCost } from './commands/TransctionLandedCost.service'; +import { + AllocateBillLandedCostDto, + AllocateBillLandedCostItemDto, +} from './dtos/AllocateBillLandedCost.dto'; export class BaseLandedCostService { @Inject() - public readonly transactionLandedCost: TransactionLandedCost; + protected readonly transactionLandedCost: TransactionLandedCost; @Inject(BillLandedCost.name) - private readonly billLandedCostModel: TenantModelProxy; + protected readonly billLandedCostModel: TenantModelProxy< + typeof BillLandedCost + >; /** * Validates allocate cost items association with the purchase invoice entries. @@ -29,7 +34,7 @@ export class BaseLandedCostService { */ protected validateAllocateCostItems = ( purchaseInvoiceEntries: ItemEntry[], - landedCostItems: ILandedCostItemDTO[], + landedCostItems: AllocateBillLandedCostItemDto[], ): void => { // Purchase invoice entries items ids. const purchaseInvoiceItems = purchaseInvoiceEntries.map((e) => e.id); @@ -55,7 +60,7 @@ export class BaseLandedCostService { * @returns */ protected transformToBillLandedCost( - landedCostDTO: ILandedCostDTO, + landedCostDTO: AllocateBillLandedCostDto, bill: Bill, costTransaction: ILandedCostTransaction, costTransactionEntry: ILandedCostTransactionEntry, @@ -88,20 +93,18 @@ export class BaseLandedCostService { * @param {transactionId} transactionId - */ public getLandedCostOrThrowError = async ( - transactionType: string, + transactionType: LandedCostTransactionType, transactionId: number, ) => { - const Model = this.transactionLandedCost.getModel( - transactionType, - ); - const model = await Model.query().findById(transactionId); + const Model = await this.transactionLandedCost.getModel(transactionType); + const model = await Model().query().findById(transactionId); if (!model) { throw new ServiceError(ERRORS.LANDED_COST_TRANSACTION_NOT_FOUND); } return this.transactionLandedCost.transformToLandedCost( transactionType, - model, + model as LandedCostTransactionModel, ); }; @@ -117,13 +120,11 @@ export class BaseLandedCostService { transactionId: number, transactionEntryId: number, ): Promise => { - const Model = this.transactionLandedCost.getModel( - tenantId, - transactionType, - ); + const Model = await this.transactionLandedCost.getModel(transactionType); const relation = CONFIG.COST_TYPES[transactionType].entries; - const entry = await Model.relatedQuery(relation) + const entry = await Model() + .relatedQuery(relation) .for(transactionId) .findOne('id', transactionEntryId) .where('landedCost', true) @@ -139,7 +140,7 @@ export class BaseLandedCostService { throw new ServiceError(ERRORS.LANDED_COST_ENTRY_NOT_FOUND); } return this.transactionLandedCost.transformToLandedCostEntry( - transactionType, + transactionType as LandedCostTransactionType, entry, ); }; @@ -150,7 +151,7 @@ export class BaseLandedCostService { * @returns {number} */ protected getAllocateItemsCostTotal = ( - landedCostDTO: ILandedCostDTO, + landedCostDTO: AllocateBillLandedCostDto, ): number => { return sumBy(landedCostDTO.items, 'cost'); }; diff --git a/packages/server/src/modules/BillLandedCosts/BillLandedCosts.module.ts b/packages/server/src/modules/BillLandedCosts/BillLandedCosts.module.ts index 7402b2933..b8a33502d 100644 --- a/packages/server/src/modules/BillLandedCosts/BillLandedCosts.module.ts +++ b/packages/server/src/modules/BillLandedCosts/BillLandedCosts.module.ts @@ -1,25 +1,30 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { TransactionLandedCostEntriesService } from './TransactionLandedCostEntries.service'; import { AllocateLandedCostService } from './commands/AllocateLandedCost.service'; import { LandedCostGLEntriesSubscriber } from './commands/LandedCostGLEntries.subscriber'; -import { LandedCostGLEntries } from './commands/LandedCostGLEntries.service'; +// import { LandedCostGLEntries } from './commands/LandedCostGLEntries.service'; import { LandedCostSyncCostTransactions } from './commands/LandedCostSyncCostTransactions.service'; import { LandedCostSyncCostTransactionsSubscriber } from './commands/LandedCostSyncCostTransactions.subscriber'; import { BillAllocatedLandedCostTransactions } from './commands/BillAllocatedLandedCostTransactions.service'; import { BillAllocateLandedCostController } from './LandedCost.controller'; import { RevertAllocatedLandedCost } from './commands/RevertAllocatedLandedCost.service'; -import LandedCostTranasctions from './commands/LandedCostTransactions.service'; +import { LandedCostTranasctions } from './commands/LandedCostTransactions.service'; import { LandedCostInventoryTransactions } from './commands/LandedCostInventoryTransactions.service'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; +import { TransactionLandedCost } from './commands/TransctionLandedCost.service'; +import { ExpenseLandedCost } from './commands/ExpenseLandedCost.service'; +import { BillLandedCost } from './commands/BillLandedCost.service'; @Module({ - imports: [InventoryCostModule], + imports: [forwardRef(() => InventoryCostModule)], providers: [ AllocateLandedCostService, TransactionLandedCostEntriesService, BillAllocatedLandedCostTransactions, LandedCostGLEntriesSubscriber, - LandedCostGLEntries, + TransactionLandedCost, + BillLandedCost, + ExpenseLandedCost, LandedCostSyncCostTransactions, RevertAllocatedLandedCost, LandedCostInventoryTransactions, diff --git a/packages/server/src/modules/BillLandedCosts/LandedCost.controller.ts b/packages/server/src/modules/BillLandedCosts/LandedCost.controller.ts index fd94c6164..caaec566e 100644 --- a/packages/server/src/modules/BillLandedCosts/LandedCost.controller.ts +++ b/packages/server/src/modules/BillLandedCosts/LandedCost.controller.ts @@ -7,32 +7,45 @@ import { Post, Query, } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { AllocateBillLandedCostDto } from './dtos/AllocateBillLandedCost.dto'; import { AllocateLandedCostService } from './commands/AllocateLandedCost.service'; import { BillAllocatedLandedCostTransactions } from './commands/BillAllocatedLandedCostTransactions.service'; import { RevertAllocatedLandedCost } from './commands/RevertAllocatedLandedCost.service'; import { LandedCostTranasctions } from './commands/LandedCostTransactions.service'; +import { LandedCostTransactionsQueryDto } from './dtos/LandedCostTransactionsQuery.dto'; +@ApiTags('Landed Cost') @Controller('landed-cost') export class BillAllocateLandedCostController { constructor( private allocateLandedCost: AllocateLandedCostService, private billAllocatedCostTransactions: BillAllocatedLandedCostTransactions, private revertAllocatedLandedCost: RevertAllocatedLandedCost, - private landedCostTranasctions: LandedCostTranasctions, + private landedCostTransactions: LandedCostTranasctions, ) {} @Get('/transactions') + @ApiOperation({ summary: 'Get landed cost transactions' }) + @ApiResponse({ + status: 200, + description: 'List of landed cost transactions.', + }) async getLandedCostTransactions( - @Query('transaction_type') transactionType: string, + @Query() query: LandedCostTransactionsQueryDto, ) { const transactions = - await this.landedCostTranasctions.getLandedCostTransactions(transactionType); + await this.landedCostTransactions.getLandedCostTransactions(query); return transactions; } @Post('/bills/:billId/allocate') + @ApiOperation({ summary: 'Allocate landed cost to bill items' }) + @ApiResponse({ + status: 201, + description: 'Landed cost allocated successfully.', + }) public async calculateLandedCost( @Param('billId') billId: number, @Body() landedCostDTO: AllocateBillLandedCostDto, @@ -48,37 +61,37 @@ export class BillAllocateLandedCostController { } @Delete('/:allocatedLandedCostId') + @ApiOperation({ summary: 'Delete allocated landed cost' }) + @ApiResponse({ + status: 200, + description: 'Allocated landed cost deleted successfully.', + }) public async deleteAllocatedLandedCost( @Param('allocatedLandedCostId') allocatedLandedCostId: number, ) { await this.revertAllocatedLandedCost.deleteAllocatedLandedCost( allocatedLandedCostId, ); - return { id: allocatedLandedCostId, message: 'The allocated landed cost are delete successfully.', }; } - public async listLandedCosts( - ) { - const transactions = - await this.landedCostTranasctions.getLandedCostTransactions(query); - - return transactions; - }; - @Get('/bills/:billId/transactions') + @ApiOperation({ summary: 'Get bill landed cost transactions' }) + @ApiResponse({ + status: 200, + description: 'List of bill landed cost transactions.', + }) async getBillLandedCostTransactions(@Param('billId') billId: number) { - const transactions = + const data = await this.billAllocatedCostTransactions.getBillLandedCostTransactions( billId, ); - return { billId, - transactions, + data, }; } } diff --git a/packages/server/src/modules/BillLandedCosts/commands/AllocateLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/commands/AllocateLandedCost.service.ts index 7951d620e..cf5ef877a 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/AllocateLandedCost.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/AllocateLandedCost.service.ts @@ -23,7 +23,7 @@ export class AllocateLandedCostService extends BaseLandedCostService { private readonly billModel: TenantModelProxy, @Inject(BillLandedCost.name) - private readonly billLandedCostModel: TenantModelProxy + protected readonly billLandedCostModel: TenantModelProxy ) { super(); } @@ -54,7 +54,7 @@ export class AllocateLandedCostService extends BaseLandedCostService { const amount = this.getAllocateItemsCostTotal(allocateCostDTO); // Retrieve the purchase invoice or throw not found error. - const bill = await Bill.query() + const bill = await this.billModel().query() .findById(billId) .withGraphFetched('entries') .throwIfNotFound(); diff --git a/packages/server/src/modules/BillLandedCosts/commands/BillAllocatedLandedCostTransactions.service.ts b/packages/server/src/modules/BillLandedCosts/commands/BillAllocatedLandedCostTransactions.service.ts index 2360538b0..49764b6a8 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/BillAllocatedLandedCostTransactions.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/BillAllocatedLandedCostTransactions.service.ts @@ -6,6 +6,8 @@ import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { Bill } from '@/modules/Bills/models/Bill'; import { BillLandedCost } from '../models/BillLandedCost'; import { IBillLandedCostTransaction } from '../types/BillLandedCosts.types'; +import { ModelObject } from 'objection'; +import { formatNumber } from '@/utils/format-number'; @Injectable() export class BillAllocatedLandedCostTransactions { @@ -23,19 +25,17 @@ export class BillAllocatedLandedCostTransactions { /** * Retrieve the bill associated landed cost transactions. - * @param {number} tenantId - Tenant id. * @param {number} billId - Bill id. * @return {Promise} */ public getBillLandedCostTransactions = async ( billId: number, - ): Promise => { + ): Promise> => { // Retrieve the given bill id or throw not found service error. const bill = await this.billModel() .query() .findById(billId) .throwIfNotFound(); - // Retrieve the bill associated allocated landed cost with bill and expense entry. const landedCostTransactions = await this.billLandedCostModel() .query() @@ -45,11 +45,8 @@ export class BillAllocatedLandedCostTransactions { .withGraphFetched('allocatedFromExpenseEntry.expenseAccount') .withGraphFetched('bill'); - const transactionsJson = this.i18nService.i18nApply( - [[qim.$each, 'allocationMethodFormatted']], - landedCostTransactions.map((a) => a.toJSON()), - tenantId, - ); + const transactionsJson = landedCostTransactions.map((a) => a.toJSON()); + return this.transformBillLandedCostTransactions(transactionsJson); }; @@ -59,7 +56,7 @@ export class BillAllocatedLandedCostTransactions { * @returns */ private transformBillLandedCostTransactions = ( - landedCostTransactions: IBillLandedCostTransaction[], + landedCostTransactions: ModelObject[], ) => { return landedCostTransactions.map(this.transformBillLandedCostTransaction); }; @@ -70,15 +67,16 @@ export class BillAllocatedLandedCostTransactions { * @returns */ private transformBillLandedCostTransaction = ( - transaction: IBillLandedCostTransaction, - ) => { - const getTransactionName = R.curry(this.condBillLandedTransactionName)( + transaction: ModelObject, + ): IBillLandedCostTransaction => { + const name = this.condBillLandedTransactionName( transaction.fromTransactionType, + transaction, + ); + const description = this.condBillLandedTransactionDescription( + transaction.fromTransactionType, + transaction, ); - const getTransactionDesc = R.curry( - this.condBillLandedTransactionDescription, - )(transaction.fromTransactionType); - return { formattedAmount: formatNumber(transaction.amount, { currencyCode: transaction.currencyCode, @@ -87,8 +85,8 @@ export class BillAllocatedLandedCostTransactions { 'allocatedFromBillEntry', 'allocatedFromExpenseEntry', ]), - name: getTransactionName(transaction), - description: getTransactionDesc(transaction), + name, + description, formattedLocalAmount: formatNumber(transaction.localAmount, { currencyCode: 'USD', }), diff --git a/packages/server/src/modules/BillLandedCosts/commands/BillLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/commands/BillLandedCost.service.ts new file mode 100644 index 000000000..41f28c47f --- /dev/null +++ b/packages/server/src/modules/BillLandedCosts/commands/BillLandedCost.service.ts @@ -0,0 +1,61 @@ +import { isEmpty } from 'lodash'; +import { + ILandedCostTransactionEntry, + ILandedCostTransaction, +} from '../types/BillLandedCosts.types'; +import { Injectable } from '@nestjs/common'; +import { Bill } from '@/modules/Bills/models/Bill'; +import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; +import { Item } from '@/modules/Items/models/Item'; +import { ModelObject } from 'objection'; + +@Injectable() +export class BillLandedCost { + /** + * Retrieve the landed cost transaction from the given bill transaction. + * @param {IBill} bill - Bill transaction. + * @returns {ILandedCostTransaction} - Landed cost transaction. + */ + public transformToLandedCost = ( + bill: ModelObject, + ): ILandedCostTransaction => { + const name = bill.billNumber || bill.referenceNo; + + return { + id: bill.id, + name, + allocatedCostAmount: bill.allocatedCostAmount, + amount: bill.landedCostAmount, + unallocatedCostAmount: bill.unallocatedCostAmount, + transactionType: 'Bill', + currencyCode: bill.currencyCode, + exchangeRate: bill.exchangeRate, + + ...(!isEmpty(bill.entries) && { + entries: bill.entries.map(this.transformToLandedCostEntry), + }), + }; + }; + + /** + * Transformes bill entry to landed cost entry. + * @param {IBill} bill - Bill model. + * @param {IItemEntry} billEntry - Bill entry. + * @return {ILandedCostTransactionEntry} + */ + public transformToLandedCostEntry( + billEntry: ItemEntry & { item: Item }, + ): ILandedCostTransactionEntry { + return { + id: billEntry.id, + name: billEntry.item.name, + code: billEntry.item.code, + amount: billEntry.amount, + + unallocatedCostAmount: billEntry.unallocatedCostAmount, + allocatedCostAmount: billEntry.allocatedCostAmount, + description: billEntry.description, + costAccountId: billEntry.costAccountId || billEntry.item.costAccountId, + }; + } +} diff --git a/packages/server/src/modules/BillLandedCosts/commands/ExpenseLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/commands/ExpenseLandedCost.service.ts new file mode 100644 index 000000000..3e454e50d --- /dev/null +++ b/packages/server/src/modules/BillLandedCosts/commands/ExpenseLandedCost.service.ts @@ -0,0 +1,59 @@ +import { Expense } from '@/modules/Expenses/models/Expense.model'; +import { Injectable } from '@nestjs/common'; +import { isEmpty } from 'lodash'; +import { ModelObject } from 'objection'; +import { + ILandedCostTransaction, + ILandedCostTransactionEntry, +} from '../types/BillLandedCosts.types'; +import { ExpenseCategory } from '@/modules/Expenses/models/ExpenseCategory.model'; +import { Account } from '@/modules/Accounts/models/Account.model'; + +@Injectable() +export class ExpenseLandedCost { + /** + * Retrieve the landed cost transaction from the given expense transaction. + * @param {IExpense} expense + * @returns {ILandedCostTransaction} + */ + public transformToLandedCost = ( + expense: ModelObject, + ): ILandedCostTransaction => { + const name = 'EXP-100'; + + return { + id: expense.id, + name, + amount: expense.landedCostAmount, + allocatedCostAmount: expense.allocatedCostAmount, + unallocatedCostAmount: expense.unallocatedCostAmount, + transactionType: 'Expense', + currencyCode: expense.currencyCode, + exchangeRate: expense.exchangeRate || 1, + + ...(!isEmpty(expense.categories) && { + entries: expense.categories.map(this.transformToLandedCostEntry), + }), + }; + }; + + /** + * Transformes expense entry to landed cost entry. + * @param {IExpenseCategory & { expenseAccount: IAccount }} expenseEntry - + * @return {ILandedCostTransactionEntry} + */ + public transformToLandedCostEntry = ( + expenseEntry: ExpenseCategory & { expenseAccount: Account }, + ): ILandedCostTransactionEntry => { + return { + id: expenseEntry.id, + name: expenseEntry.expenseAccount.name, + code: expenseEntry.expenseAccount.code, + amount: expenseEntry.amount, + description: expenseEntry.description, + allocatedCostAmount: expenseEntry.allocatedCostAmount, + unallocatedCostAmount: expenseEntry.unallocatedCostAmount, + costAccountId: expenseEntry.expenseAccount.id, + }; + }; +} diff --git a/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.service.ts b/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.service.ts index 50325061c..530f4ad96 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.service.ts @@ -1,234 +1,236 @@ -import * as R from 'ramda'; -import { Knex } from 'knex'; -import { Inject, Injectable } from '@nestjs/common'; -import { BaseLandedCostService } from '../BaseLandedCost.service'; -import { BillLandedCost } from '../models/BillLandedCost'; -import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; -import { Bill } from '@/modules/Bills/models/Bill'; -import { BillLandedCostEntry } from '../models/BillLandedCostEntry'; -import { ILedger, ILedgerEntry } from '@/modules/Ledger/types/Ledger.types'; -import { Ledger } from '@/modules/Ledger/Ledger'; +// import * as R from 'ramda'; +// import { Knex } from 'knex'; +// import { Inject, Injectable } from '@nestjs/common'; +// import { BaseLandedCostService } from '../BaseLandedCost.service'; +// import { BillLandedCost } from '../models/BillLandedCost'; +// import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; +// import { Bill } from '@/modules/Bills/models/Bill'; +// import { BillLandedCostEntry } from '../models/BillLandedCostEntry'; +// import { ILedger, ILedgerEntry } from '@/modules/Ledger/types/Ledger.types'; +// import { Ledger } from '@/modules/Ledger/Ledger'; +// import { AccountNormal } from '@/interfaces/Account'; +// import { ILandedCostTransactionEntry } from '../types/BillLandedCosts.types'; -@Injectable() -export class LandedCostGLEntries extends BaseLandedCostService { - constructor( - private readonly journalService: JournalPosterService, - private readonly ledgerRepository: LedgerRepository, +// @Injectable() +// export class LandedCostGLEntries extends BaseLandedCostService { +// constructor( +// private readonly journalService: JournalPosterService, +// private readonly ledgerRepository: LedgerRepository, - @Inject(BillLandedCost.name) - private readonly billLandedCostModel: TenantModelProxy, - ) { - super(); - } +// @Inject(BillLandedCost.name) +// private readonly billLandedCostModel: TenantModelProxy, +// ) { +// super(); +// } - /** - * Retrieves the landed cost GL common entry. - * @param {IBill} bill - * @param {IBillLandedCost} allocatedLandedCost - * @returns - */ - private getLandedCostGLCommonEntry = ( - bill: Bill, - allocatedLandedCost: BillLandedCost - ) => { - return { - date: bill.billDate, - currencyCode: allocatedLandedCost.currencyCode, - exchangeRate: allocatedLandedCost.exchangeRate, +// /** +// * Retrieves the landed cost GL common entry. +// * @param {IBill} bill +// * @param {IBillLandedCost} allocatedLandedCost +// * @returns +// */ +// private getLandedCostGLCommonEntry = ( +// bill: Bill, +// allocatedLandedCost: BillLandedCost +// ) => { +// return { +// date: bill.billDate, +// currencyCode: allocatedLandedCost.currencyCode, +// exchangeRate: allocatedLandedCost.exchangeRate, - transactionType: 'LandedCost', - transactionId: allocatedLandedCost.id, - transactionNumber: bill.billNumber, +// transactionType: 'LandedCost', +// transactionId: allocatedLandedCost.id, +// transactionNumber: bill.billNumber, - referenceNumber: bill.referenceNo, +// referenceNumber: bill.referenceNo, - credit: 0, - debit: 0, - }; - }; +// credit: 0, +// debit: 0, +// }; +// }; - /** - * Retrieves the landed cost GL inventory entry. - * @param {IBill} bill - * @param {IBillLandedCost} allocatedLandedCost - * @param {IBillLandedCostEntry} allocatedEntry - * @returns {ILedgerEntry} - */ - private getLandedCostGLInventoryEntry = ( - bill: Bill, - allocatedLandedCost: BillLandedCost, - allocatedEntry: BillLandedCostEntry - ): ILedgerEntry => { - const commonEntry = this.getLandedCostGLCommonEntry( - bill, - allocatedLandedCost - ); - return { - ...commonEntry, - debit: allocatedLandedCost.localAmount, - accountId: allocatedEntry.itemEntry.item.inventoryAccountId, - index: 1, - accountNormal: AccountNormal.DEBIT, - }; - }; +// /** +// * Retrieves the landed cost GL inventory entry. +// * @param {IBill} bill +// * @param {IBillLandedCost} allocatedLandedCost +// * @param {IBillLandedCostEntry} allocatedEntry +// * @returns {ILedgerEntry} +// */ +// private getLandedCostGLInventoryEntry = ( +// bill: Bill, +// allocatedLandedCost: BillLandedCost, +// allocatedEntry: BillLandedCostEntry +// ): ILedgerEntry => { +// const commonEntry = this.getLandedCostGLCommonEntry( +// bill, +// allocatedLandedCost +// ); +// return { +// ...commonEntry, +// debit: allocatedLandedCost.localAmount, +// accountId: allocatedEntry.itemEntry.item.inventoryAccountId, +// index: 1, +// accountNormal: AccountNormal.DEBIT, +// }; +// }; - /** - * Retrieves the landed cost GL cost entry. - * @param {IBill} bill - * @param {IBillLandedCost} allocatedLandedCost - * @param {ILandedCostTransactionEntry} fromTransactionEntry - * @returns {ILedgerEntry} - */ - private getLandedCostGLCostEntry = ( - bill: Bill, - allocatedLandedCost: BillLandedCost, - fromTransactionEntry: ILandedCostTransactionEntry - ): ILedgerEntry => { - const commonEntry = this.getLandedCostGLCommonEntry( - bill, - allocatedLandedCost - ); - return { - ...commonEntry, - credit: allocatedLandedCost.localAmount, - accountId: fromTransactionEntry.costAccountId, - index: 2, - accountNormal: AccountNormal.CREDIT, - }; - }; +// /** +// * Retrieves the landed cost GL cost entry. +// * @param {IBill} bill +// * @param {IBillLandedCost} allocatedLandedCost +// * @param {ILandedCostTransactionEntry} fromTransactionEntry +// * @returns {ILedgerEntry} +// */ +// private getLandedCostGLCostEntry = ( +// bill: Bill, +// allocatedLandedCost: BillLandedCost, +// fromTransactionEntry: ILandedCostTransactionEntry +// ): ILedgerEntry => { +// const commonEntry = this.getLandedCostGLCommonEntry( +// bill, +// allocatedLandedCost +// ); +// return { +// ...commonEntry, +// credit: allocatedLandedCost.localAmount, +// accountId: fromTransactionEntry.costAccountId, +// index: 2, +// accountNormal: AccountNormal.CREDIT, +// }; +// }; - /** - * Retrieve allocated landed cost entry GL entries. - * @param {IBill} bill - * @param {IBillLandedCost} allocatedLandedCost - * @param {ILandedCostTransactionEntry} fromTransactionEntry - * @param {IBillLandedCostEntry} allocatedEntry - * @returns {ILedgerEntry} - */ - private getLandedCostGLAllocateEntry = R.curry( - ( - bill: Bill, - allocatedLandedCost: BillLandedCost, - fromTransactionEntry: LandedCostTransactionEntry, - allocatedEntry: BillLandedCostEntry - ): ILedgerEntry[] => { - const inventoryEntry = this.getLandedCostGLInventoryEntry( - bill, - allocatedLandedCost, - allocatedEntry - ); - const costEntry = this.getLandedCostGLCostEntry( - bill, - allocatedLandedCost, - fromTransactionEntry - ); - return [inventoryEntry, costEntry]; - } - ); +// /** +// * Retrieve allocated landed cost entry GL entries. +// * @param {IBill} bill +// * @param {IBillLandedCost} allocatedLandedCost +// * @param {ILandedCostTransactionEntry} fromTransactionEntry +// * @param {IBillLandedCostEntry} allocatedEntry +// * @returns {ILedgerEntry} +// */ +// private getLandedCostGLAllocateEntry = R.curry( +// ( +// bill: Bill, +// allocatedLandedCost: BillLandedCost, +// fromTransactionEntry: ILandedCostTransactionEntry, +// allocatedEntry: BillLandedCostEntry +// ): ILedgerEntry[] => { +// const inventoryEntry = this.getLandedCostGLInventoryEntry( +// bill, +// allocatedLandedCost, +// allocatedEntry +// ); +// const costEntry = this.getLandedCostGLCostEntry( +// bill, +// allocatedLandedCost, +// fromTransactionEntry +// ); +// return [inventoryEntry, costEntry]; +// } +// ); - /** - * Compose the landed cost GL entries. - * @param {BillLandedCost} allocatedLandedCost - * @param {Bill} bill - * @param {ILandedCostTransactionEntry} fromTransactionEntry - * @returns {ILedgerEntry[]} - */ - public getLandedCostGLEntries = ( - allocatedLandedCost: BillLandedCost, - bill: Bill, - fromTransactionEntry: LandedCostTransactionEntry - ): ILedgerEntry[] => { - const getEntry = this.getLandedCostGLAllocateEntry( - bill, - allocatedLandedCost, - fromTransactionEntry - ); - return allocatedLandedCost.allocateEntries.map(getEntry).flat(); - }; +// /** +// * Compose the landed cost GL entries. +// * @param {BillLandedCost} allocatedLandedCost +// * @param {Bill} bill +// * @param {ILandedCostTransactionEntry} fromTransactionEntry +// * @returns {ILedgerEntry[]} +// */ +// public getLandedCostGLEntries = ( +// allocatedLandedCost: BillLandedCost, +// bill: Bill, +// fromTransactionEntry: ILandedCostTransactionEntry +// ): ILedgerEntry[] => { +// const getEntry = this.getLandedCostGLAllocateEntry( +// bill, +// allocatedLandedCost, +// fromTransactionEntry +// ); +// return allocatedLandedCost.allocateEntries.map(getEntry).flat(); +// }; - /** - * Retrieves the landed cost GL ledger. - * @param {IBillLandedCost} allocatedLandedCost - * @param {Bill} bill - * @param {ILandedCostTransactionEntry} fromTransactionEntry - * @returns {ILedger} - */ - public getLandedCostLedger = ( - allocatedLandedCost: BillLandedCost, - bill: Bill, - fromTransactionEntry: LandedCostTransactionEntry - ): ILedger => { - const entries = this.getLandedCostGLEntries( - allocatedLandedCost, - bill, - fromTransactionEntry - ); - return new Ledger(entries); - }; +// /** +// * Retrieves the landed cost GL ledger. +// * @param {BillLandedCost} allocatedLandedCost +// * @param {Bill} bill +// * @param {ILandedCostTransactionEntry} fromTransactionEntry +// * @returns {ILedger} +// */ +// public getLandedCostLedger = ( +// allocatedLandedCost: BillLandedCost, +// bill: Bill, +// fromTransactionEntry: ILandedCostTransactionEntry +// ): ILedger => { +// const entries = this.getLandedCostGLEntries( +// allocatedLandedCost, +// bill, +// fromTransactionEntry +// ); +// return new Ledger(entries); +// }; - /** - * Writes landed cost GL entries to the storage layer. - * @param {number} tenantId - - */ - public writeLandedCostGLEntries = async ( - allocatedLandedCost: BillLandedCost, - bill: Bill, - fromTransactionEntry: ILandedCostTransactionEntry, - trx?: Knex.Transaction - ) => { - const ledgerEntries = this.getLandedCostGLEntries( - allocatedLandedCost, - bill, - fromTransactionEntry - ); - await this.ledgerRepository.saveLedgerEntries(ledgerEntries, trx); - }; +// /** +// * Writes landed cost GL entries to the storage layer. +// * @param {number} tenantId - +// */ +// public writeLandedCostGLEntries = async ( +// allocatedLandedCost: BillLandedCost, +// bill: Bill, +// fromTransactionEntry: ILandedCostTransactionEntry, +// trx?: Knex.Transaction +// ) => { +// const ledgerEntries = this.getLandedCostGLEntries( +// allocatedLandedCost, +// bill, +// fromTransactionEntry +// ); +// await this.ledgerRepository.saveLedgerEntries(ledgerEntries, trx); +// }; - /** - * Generates and writes GL entries of the given landed cost. - * @param {number} billLandedCostId - * @param {Knex.Transaction} trx - */ - public createLandedCostGLEntries = async ( - billLandedCostId: number, - trx?: Knex.Transaction - ) => { - // Retrieve the bill landed cost transacion with associated - // allocated entries and items. - const allocatedLandedCost = await this.billLandedCostModel().query(trx) - .findById(billLandedCostId) - .withGraphFetched('bill') - .withGraphFetched('allocateEntries.itemEntry.item'); +// /** +// * Generates and writes GL entries of the given landed cost. +// * @param {number} billLandedCostId +// * @param {Knex.Transaction} trx +// */ +// public createLandedCostGLEntries = async ( +// billLandedCostId: number, +// trx?: Knex.Transaction +// ) => { +// // Retrieve the bill landed cost transacion with associated +// // allocated entries and items. +// const allocatedLandedCost = await this.billLandedCostModel().query(trx) +// .findById(billLandedCostId) +// .withGraphFetched('bill') +// .withGraphFetched('allocateEntries.itemEntry.item'); - // Retrieve the allocated from transactione entry. - const transactionEntry = await this.getLandedCostEntry( - allocatedLandedCost.fromTransactionType, - allocatedLandedCost.fromTransactionId, - allocatedLandedCost.fromTransactionEntryId - ); - // Writes the given landed cost GL entries to the storage layer. - await this.writeLandedCostGLEntries( - allocatedLandedCost, - allocatedLandedCost.bill, - transactionEntry, - trx - ); - }; +// // Retrieve the allocated from transactione entry. +// const transactionEntry = await this.getLandedCostEntry( +// allocatedLandedCost.fromTransactionType, +// allocatedLandedCost.fromTransactionId, +// allocatedLandedCost.fromTransactionEntryId +// ); +// // Writes the given landed cost GL entries to the storage layer. +// await this.writeLandedCostGLEntries( +// allocatedLandedCost, +// allocatedLandedCost.bill, +// transactionEntry, +// trx +// ); +// }; - /** - * Reverts GL entries of the given allocated landed cost transaction. - * @param {number} tenantId - * @param {number} landedCostId - * @param {Knex.Transaction} trx - */ - public revertLandedCostGLEntries = async ( - landedCostId: number, - trx: Knex.Transaction - ) => { - await this.journalService.revertJournalTransactions( - landedCostId, - 'LandedCost', - trx - ); - }; -} \ No newline at end of file +// /** +// * Reverts GL entries of the given allocated landed cost transaction. +// * @param {number} tenantId +// * @param {number} landedCostId +// * @param {Knex.Transaction} trx +// */ +// public revertLandedCostGLEntries = async ( +// landedCostId: number, +// trx: Knex.Transaction +// ) => { +// await this.journalService.revertJournalTransactions( +// landedCostId, +// 'LandedCost', +// trx +// ); +// }; +// } \ No newline at end of file diff --git a/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.subscriber.ts b/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.subscriber.ts index c793f6be2..22bc49f37 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.subscriber.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/LandedCostGLEntries.subscriber.ts @@ -3,15 +3,14 @@ import { IAllocatedLandedCostDeletedPayload, } from '../types/BillLandedCosts.types'; import { OnEvent } from '@nestjs/event-emitter'; -import { LandedCostGLEntries } from './LandedCostGLEntries.service'; +// import { LandedCostGLEntries } from './LandedCostGLEntries.service'; import { Injectable } from '@nestjs/common'; import { events } from '@/common/events/events'; @Injectable() export class LandedCostGLEntriesSubscriber { - constructor( - private readonly billLandedCostGLEntries: LandedCostGLEntries, - ) {} + constructor() // private readonly billLandedCostGLEntries: LandedCostGLEntries, + {} /** * Writes GL entries once landed cost transaction created. @@ -22,11 +21,11 @@ export class LandedCostGLEntriesSubscriber { billLandedCost, trx, }: IAllocatedLandedCostCreatedPayload) { - await this.billLandedCostGLEntries.createLandedCostGLEntries( - billLandedCost.id, - trx - ); - }; + // await this.billLandedCostGLEntries.createLandedCostGLEntries( + // billLandedCost.id, + // trx + // ); + } /** * Reverts GL entries associated to landed cost transaction once deleted. @@ -37,9 +36,9 @@ export class LandedCostGLEntriesSubscriber { oldBillLandedCost, trx, }: IAllocatedLandedCostDeletedPayload) { - await this.billLandedCostGLEntries.revertLandedCostGLEntries( - oldBillLandedCost.id, - trx - ); - }; -} \ No newline at end of file + // await this.billLandedCostGLEntries.revertLandedCostGLEntries( + // oldBillLandedCost.id, + // trx + // ); + } +} diff --git a/packages/server/src/modules/BillLandedCosts/commands/LandedCostSyncCostTransactions.service.ts b/packages/server/src/modules/BillLandedCosts/commands/LandedCostSyncCostTransactions.service.ts index d41814b5b..1b0480ec2 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/LandedCostSyncCostTransactions.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/LandedCostSyncCostTransactions.service.ts @@ -11,9 +11,8 @@ export class LandedCostSyncCostTransactions { /** * Allocate the landed cost amount to cost transactions. - * @param {number} tenantId - - * @param {string} transactionType - * @param {number} transactionId + * @param {string} transactionType - Transaction type. + * @param {number} transactionId - Transaction id. */ public incrementLandedCostAmount = async ( transactionType: string, @@ -22,18 +21,18 @@ export class LandedCostSyncCostTransactions { amount: number, trx?: Knex.Transaction ): Promise => { - const Model = this.transactionLandedCost.getModel( + const Model = await this.transactionLandedCost.getModel( transactionType ); const relation = CONFIG.COST_TYPES[transactionType].entries; // Increment the landed cost transaction amount. - await Model.query(trx) + await Model().query(trx) .where('id', transactionId) .increment('allocatedCostAmount', amount); // Increment the landed cost entry. - await Model.relatedQuery(relation, trx) + await Model().relatedQuery(relation, trx) .for(transactionId) .where('id', transactionEntryId) .increment('allocatedCostAmount', amount); @@ -54,18 +53,18 @@ export class LandedCostSyncCostTransactions { amount: number, trx?: Knex.Transaction ) => { - const Model = this.transactionLandedCost.getModel( + const Model = await this.transactionLandedCost.getModel( transactionType ); const relation = CONFIG.COST_TYPES[transactionType].entries; // Decrement the allocate cost amount of cost transaction. - await Model.query(trx) + await Model().query(trx) .where('id', transactionId) .decrement('allocatedCostAmount', amount); // Decrement the allocated cost amount cost transaction entry. - await Model.relatedQuery(relation, trx) + await Model().relatedQuery(relation, trx) .for(transactionId) .where('id', transactionEntryId) .decrement('allocatedCostAmount', amount); diff --git a/packages/server/src/modules/BillLandedCosts/commands/LandedCostTransactions.service.ts b/packages/server/src/modules/BillLandedCosts/commands/LandedCostTransactions.service.ts index 3af3ba8c9..c15c83da5 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/LandedCostTransactions.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/LandedCostTransactions.service.ts @@ -1,70 +1,73 @@ -import { Inject, Service } from 'typedi'; +import { Injectable } from '@nestjs/common'; import { ref } from 'objection'; +import { curry, pipe, map } from 'lodash/fp'; import * as R from 'ramda'; import { - ILandedCostTransactionsQueryDTO, ILandedCostTransaction, ILandedCostTransactionDOJO, ILandedCostTransactionEntry, ILandedCostTransactionEntryDOJO, -} from '@/interfaces'; -import TransactionLandedCost from './TransctionLandedCost'; -import { formatNumber } from 'utils'; +} from '../types/BillLandedCosts.types'; +import { TransactionLandedCost } from './TransctionLandedCost.service'; +import { formatNumber } from '@/utils/format-number'; +import { LandedCostTransactionsQueryDto } from '../dtos/LandedCostTransactionsQuery.dto'; -@Service() -export default class LandedCostTranasctions { - @Inject() - private transactionLandedCost: TransactionLandedCost; +@Injectable() +export class LandedCostTranasctions { + constructor(private readonly transactionLandedCost: TransactionLandedCost) {} /** * Retrieve the landed costs based on the given query. - * @param {number} tenantId - * @param {ILandedCostTransactionsQueryDTO} query + * @param {LandedCostTransactionsQueryDto} query - * @returns {Promise} */ public getLandedCostTransactions = async ( - query: ILandedCostTransactionsQueryDTO + query: LandedCostTransactionsQueryDto, ): Promise => { const { transactionType } = query; - const Model = this.transactionLandedCost.getModel( - query.transactionType + const Model = await this.transactionLandedCost.getModel( + query.transactionType, ); // Retrieve the model entities. - const transactions = await Model.query().onBuild((q) => { - q.where('allocated_cost_amount', '<', ref('landed_cost_amount')); + const transactions = await Model() + .query() + .onBuild((q) => { + q.where('allocated_cost_amount', '<', ref('landed_cost_amount')); - if (query.transactionType === 'Bill') { - q.withGraphFetched('entries.item'); - } else if (query.transactionType === 'Expense') { - q.withGraphFetched('categories.expenseAccount'); - } - }); - const transformLandedCost = - this.transactionLandedCost.transformToLandedCost(transactionType); + if (query.transactionType === 'Bill') { + q.withGraphFetched('entries.item'); + } else if (query.transactionType === 'Expense') { + q.withGraphFetched('categories.expenseAccount'); + } + }); + const transformLandedCost = curry( + this.transactionLandedCost.transformToLandedCost, + )(transactionType); - return R.compose( + return pipe( this.transformLandedCostTransactions, - R.map(transformLandedCost) + R.map(transformLandedCost), )(transactions); }; /** - * - * @param transactions - * @returns + * Transformes the landed cost transactions. + * @param {ILandedCostTransaction[]} transactions + * @returns {ILandedCostTransactionDOJO[]} */ public transformLandedCostTransactions = ( - transactions: ILandedCostTransaction[] + transactions: ILandedCostTransaction[], ) => { return R.map(this.transformLandedCostTransaction)(transactions); }; /** * Transformes the landed cost transaction. - * @param {ILandedCostTransaction} transaction + * @param {ILandedCostTransaction} transaction - Landed cost transaction. + * @returns {ILandedCostTransactionDOJO} */ public transformLandedCostTransaction = ( - transaction: ILandedCostTransaction + transaction: ILandedCostTransaction, ): ILandedCostTransactionDOJO => { const { currencyCode } = transaction; @@ -74,57 +77,60 @@ export default class LandedCostTranasctions { // Formatted transaction unallocated cost amount. const formattedUnallocatedCostAmount = formatNumber( transaction.unallocatedCostAmount, - { currencyCode } + { currencyCode }, ); // Formatted transaction allocated cost amount. const formattedAllocatedCostAmount = formatNumber( transaction.allocatedCostAmount, - { currencyCode } + { currencyCode }, ); + const transformLandedCostEntry = R.curry(this.transformLandedCostEntry)( + transaction, + ); + const entries = R.map< + ILandedCostTransactionEntry, + ILandedCostTransactionEntryDOJO + >(transformLandedCostEntry)(transaction.entries); return { ...transaction, formattedAmount, formattedUnallocatedCostAmount, formattedAllocatedCostAmount, - entries: R.map(this.transformLandedCostEntry(transaction))( - transaction.entries - ), + entries, }; }; /** - * - * @param {ILandedCostTransaction} transaction - * @param {ILandedCostTransactionEntry} entry + * Transformes the landed cost transaction entry. + * @param {ILandedCostTransaction} transaction - Landed cost transaction. + * @param {ILandedCostTransactionEntry} entry - Landed cost transaction entry. * @returns {ILandedCostTransactionEntryDOJO} */ - public transformLandedCostEntry = R.curry( - ( - transaction: ILandedCostTransaction, - entry: ILandedCostTransactionEntry - ): ILandedCostTransactionEntryDOJO => { - const { currencyCode } = transaction; + public transformLandedCostEntry = ( + transaction: ILandedCostTransaction, + entry: ILandedCostTransactionEntry, + ): ILandedCostTransactionEntryDOJO => { + const { currencyCode } = transaction; - // Formatted entry amount. - const formattedAmount = formatNumber(entry.amount, { currencyCode }); + // Formatted entry amount. + const formattedAmount = formatNumber(entry.amount, { currencyCode }); - // Formatted entry unallocated cost amount. - const formattedUnallocatedCostAmount = formatNumber( - entry.unallocatedCostAmount, - { currencyCode } - ); - // Formatted entry allocated cost amount. - const formattedAllocatedCostAmount = formatNumber( - entry.allocatedCostAmount, - { currencyCode } - ); - return { - ...entry, - formattedAmount, - formattedUnallocatedCostAmount, - formattedAllocatedCostAmount, - }; - } - ); -} \ No newline at end of file + // Formatted entry unallocated cost amount. + const formattedUnallocatedCostAmount = formatNumber( + entry.unallocatedCostAmount, + { currencyCode }, + ); + // Formatted entry allocated cost amount. + const formattedAllocatedCostAmount = formatNumber( + entry.allocatedCostAmount, + { currencyCode }, + ); + return { + ...entry, + formattedAmount, + formattedUnallocatedCostAmount, + formattedAllocatedCostAmount, + }; + }; +} diff --git a/packages/server/src/modules/BillLandedCosts/commands/RevertAllocatedLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/commands/RevertAllocatedLandedCost.service.ts index 4d02004c2..24599ef24 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/RevertAllocatedLandedCost.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/RevertAllocatedLandedCost.service.ts @@ -7,7 +7,6 @@ import { events } from '@/common/events/events'; import { IAllocatedLandedCostDeletedPayload } from '../types/BillLandedCosts.types'; import { BillLandedCostEntry } from '../models/BillLandedCostEntry'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; -import { BillLandedCost } from '../models/BillLandedCost'; @Injectable() export class RevertAllocatedLandedCost extends BaseLandedCostService { @@ -15,11 +14,6 @@ export class RevertAllocatedLandedCost extends BaseLandedCostService { private readonly eventPublisher: EventEmitter2, private readonly uow: UnitOfWork, - @Inject(BillLandedCost.name) - private readonly billLandedCostModel: TenantModelProxy< - typeof BillLandedCost - >, - @Inject(BillLandedCostEntry.name) private readonly billLandedCostEntryModel: TenantModelProxy< typeof BillLandedCostEntry diff --git a/packages/server/src/modules/BillLandedCosts/commands/TransctionLandedCost.service.ts b/packages/server/src/modules/BillLandedCosts/commands/TransctionLandedCost.service.ts index 720cbc343..e328658e0 100644 --- a/packages/server/src/modules/BillLandedCosts/commands/TransctionLandedCost.service.ts +++ b/packages/server/src/modules/BillLandedCosts/commands/TransctionLandedCost.service.ts @@ -3,35 +3,46 @@ import { Model } from 'objection'; import { ILandedCostTransaction, ILandedCostTransactionEntry, + LandedCostTransactionModel, + LandedCostTransactionType, } from '../types/BillLandedCosts.types'; import { Injectable } from '@nestjs/common'; -import { BillLandedCost } from '../models/BillLandedCost'; import { Bill } from '@/modules/Bills/models/Bill'; import { Expense } from '@/modules/Expenses/models/Expense.model'; import { ServiceError } from '@/modules/Items/ServiceError'; +import { ContextIdFactory, ModuleRef } from '@nestjs/core'; +import { sanitizeModelName } from '@/utils/sanitize-model-name'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; +import { ExpenseLandedCost } from './ExpenseLandedCost.service'; +import { BillLandedCost } from './BillLandedCost.service'; import { ERRORS } from '../utils'; -import { ExpenseLandedCost } from '../models/ExpenseLandedCost'; @Injectable() export class TransactionLandedCost { constructor( private readonly billLandedCost: BillLandedCost, private readonly expenseLandedCost: ExpenseLandedCost, + private readonly moduleRef: ModuleRef, ) {} + /** * Retrieve the cost transaction code model. - * @param {number} tenantId - Tenant id. * @param {string} transactionType - Transaction type. * @returns */ - public getModel = (tenantId: number, transactionType: string): Model => { - const Models = this.tenancy.models(tenantId); - const Model = Models[transactionType]; + public getModel = async ( + transactionType: string, + ): Promise> => { + const contextId = ContextIdFactory.create(); + const modelName = sanitizeModelName(transactionType); - if (!Model) { + const instance = await this.moduleRef.resolve(modelName, contextId, { + strict: false, + }); + if (!instance) { throw new ServiceError(ERRORS.COST_TYPE_UNDEFINED); } - return Model; + return instance; }; /** @@ -40,10 +51,10 @@ export class TransactionLandedCost { * @param {IBill|IExpense} transaction - Expense or bill transaction. * @returns {ILandedCostTransaction} */ - public transformToLandedCost = R.curry( + public transformToLandedCost = ( - transactionType: string, - transaction: Bill | Expense, + transactionType: LandedCostTransactionType, + transaction: LandedCostTransactionModel, ): ILandedCostTransaction => { return R.compose( R.when( @@ -54,9 +65,8 @@ export class TransactionLandedCost { R.always(transactionType === 'Expense'), this.expenseLandedCost.transformToLandedCost, ), - )(transaction); - }, - ); + )(transaction) as ILandedCostTransaction; + }; /** * Transformes the given expense or bill entry to landed cost transaction entry. @@ -65,7 +75,7 @@ export class TransactionLandedCost { * @returns {ILandedCostTransactionEntry} */ public transformToLandedCostEntry = ( - transactionType: 'Bill' | 'Expense', + transactionType: LandedCostTransactionType, transactionEntry, ): ILandedCostTransactionEntry => { return R.compose( @@ -77,6 +87,6 @@ export class TransactionLandedCost { R.always(transactionType === 'Expense'), this.expenseLandedCost.transformToLandedCostEntry, ), - )(transactionEntry); + )(transactionEntry) as ILandedCostTransactionEntry; }; } diff --git a/packages/server/src/modules/BillLandedCosts/dtos/AllocateBillLandedCost.dto.ts b/packages/server/src/modules/BillLandedCosts/dtos/AllocateBillLandedCost.dto.ts index 91ca3f089..063157e96 100644 --- a/packages/server/src/modules/BillLandedCosts/dtos/AllocateBillLandedCost.dto.ts +++ b/packages/server/src/modules/BillLandedCosts/dtos/AllocateBillLandedCost.dto.ts @@ -10,8 +10,9 @@ import { } from 'class-validator'; import { Type } from 'class-transformer'; import { ToNumber } from '@/common/decorators/Validators'; +import { LandedCostTransactionType } from '../types/BillLandedCosts.types'; -class AllocateBillLandedCostItemDto { +export class AllocateBillLandedCostItemDto { @IsInt() @ToNumber() entryId: number; @@ -26,7 +27,7 @@ export class AllocateBillLandedCostDto { transactionId: number; @IsIn(['Expense', 'Bill']) - transactionType: string; + transactionType: LandedCostTransactionType; @IsInt() transactionEntryId: number; diff --git a/packages/server/src/modules/BillLandedCosts/dtos/LandedCostTransactionsQuery.dto.ts b/packages/server/src/modules/BillLandedCosts/dtos/LandedCostTransactionsQuery.dto.ts new file mode 100644 index 000000000..3f50a2f32 --- /dev/null +++ b/packages/server/src/modules/BillLandedCosts/dtos/LandedCostTransactionsQuery.dto.ts @@ -0,0 +1,14 @@ +import { IsDateString, IsEnum, IsIn, IsNotEmpty, IsOptional, IsString } from "class-validator"; +import { LandedCostTransactionType } from "../types/BillLandedCosts.types"; + + +export class LandedCostTransactionsQueryDto { + @IsString() + @IsNotEmpty() + @IsIn(['Expense', 'Bill']) + transactionType: LandedCostTransactionType; + + @IsDateString() + @IsOptional() + date: string; +} \ No newline at end of file diff --git a/packages/server/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts b/packages/server/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts index c1647d097..9ac309db5 100644 --- a/packages/server/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts +++ b/packages/server/src/modules/BillLandedCosts/types/BillLandedCosts.types.ts @@ -1,5 +1,7 @@ import { Knex } from 'knex'; import { Bill } from '@/modules/Bills/models/Bill'; +import { ModelObject } from 'objection'; +import { Expense } from '@/modules/Expenses/models/Expense.model'; export interface ILandedCostItemDTO { entryId: number; @@ -140,3 +142,7 @@ interface ICommonEntryDTO { export interface ICommonLandedCostEntryDTO extends ICommonEntryDTO { landedCost?: boolean; } + + +export type LandedCostTransactionType = 'Bill' | 'Expense'; +export type LandedCostTransactionModel = Bill | Expense; \ No newline at end of file diff --git a/packages/server/src/modules/BillLandedCosts/utils.ts b/packages/server/src/modules/BillLandedCosts/utils.ts index f7ea7da07..e121c16cb 100644 --- a/packages/server/src/modules/BillLandedCosts/utils.ts +++ b/packages/server/src/modules/BillLandedCosts/utils.ts @@ -1,5 +1,7 @@ -import { IItemEntry, IBillLandedCostTransactionEntry } from '@/interfaces'; -import { transformToMap } from 'utils'; +import { ModelObject } from 'objection'; +import { transformToMap } from '@/utils/transform-to-key'; +import { IBillLandedCostTransactionEntry } from './types/BillLandedCosts.types'; +import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry'; export const ERRORS = { COST_TYPE_UNDEFINED: 'COST_TYPE_UNDEFINED', @@ -23,8 +25,8 @@ export const ERRORS = { */ export const mergeLocatedWithBillEntries = ( locatedEntries: IBillLandedCostTransactionEntry[], - billEntries: IItemEntry[] -): (IBillLandedCostTransactionEntry & { entry: IItemEntry })[] => { + billEntries: ModelObject[] +): (IBillLandedCostTransactionEntry & { entry: ModelObject })[] => { const billEntriesByEntryId = transformToMap(billEntries, 'id'); return locatedEntries.map((entry) => ({ diff --git a/packages/server/src/modules/Bills/Bills.application.ts b/packages/server/src/modules/Bills/Bills.application.ts index 9d389293b..5c02bbc39 100644 --- a/packages/server/src/modules/Bills/Bills.application.ts +++ b/packages/server/src/modules/Bills/Bills.application.ts @@ -8,6 +8,7 @@ import { OpenBillService } from './commands/OpenBill.service'; import { Injectable } from '@nestjs/common'; import { GetBillsService } from './queries/GetBills.service'; import { CreateBillDto, EditBillDto } from './dtos/Bill.dto'; +import { GetBillPaymentTransactionsService } from './queries/GetBillPayments'; // import { GetBillPayments } from './queries/GetBillPayments'; // import { GetBills } from './queries/GetBills'; @@ -21,7 +22,7 @@ export class BillsApplication { private getDueBillsService: GetDueBills, private openBillService: OpenBillService, private getBillsService: GetBillsService, - // private getBillPaymentsService: GetBillPayments, + private getBillPaymentTransactionsService: GetBillPaymentTransactionsService, ) {} /** @@ -71,7 +72,6 @@ export class BillsApplication { /** * Open the given bill. - * @param {number} tenantId * @param {number} billId * @returns {Promise} */ @@ -91,10 +91,11 @@ export class BillsApplication { /** * Retrieve the specific bill associated payment transactions. - * @param {number} tenantId * @param {number} billId */ - // public getBillPayments(billId: number) { - // return this.getBillPaymentsService.getBillPayments(billId); - // } + public getBillPaymentTransactions(billId: number) { + return this.getBillPaymentTransactionsService.getBillPaymentTransactions( + billId, + ); + } } diff --git a/packages/server/src/modules/Bills/Bills.controller.ts b/packages/server/src/modules/Bills/Bills.controller.ts index 753fdd884..5c0667417 100644 --- a/packages/server/src/modules/Bills/Bills.controller.ts +++ b/packages/server/src/modules/Bills/Bills.controller.ts @@ -60,6 +60,18 @@ export class BillsController { return this.billsApplication.getBills(filterDTO); } + @Get(':id/payment-transactions') + @ApiOperation({ summary: 'Retrieve the specific bill associated payment transactions.' }) + @ApiParam({ + name: 'id', + required: true, + type: Number, + description: 'The bill id', + }) + getBillPaymentTransactions(@Param('id') billId: number) { + return this.billsApplication.getBillPaymentTransactions(billId); + } + @Get(':id') @ApiOperation({ summary: 'Retrieves the bill details.' }) @ApiParam({ diff --git a/packages/server/src/modules/Bills/Bills.module.ts b/packages/server/src/modules/Bills/Bills.module.ts index df4d35975..a9599cea9 100644 --- a/packages/server/src/modules/Bills/Bills.module.ts +++ b/packages/server/src/modules/Bills/Bills.module.ts @@ -28,6 +28,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; import { BillsExportable } from './commands/BillsExportable'; import { BillsImportable } from './commands/BillsImportable'; +import { GetBillPaymentTransactionsService } from './queries/GetBillPayments'; @Module({ imports: [ @@ -60,7 +61,8 @@ import { BillsImportable } from './commands/BillsImportable'; BillInventoryTransactions, BillWriteInventoryTransactionsSubscriber, BillsExportable, - BillsImportable + BillsImportable, + GetBillPaymentTransactionsService, ], controllers: [BillsController], exports: [BillsExportable, BillsImportable], diff --git a/packages/server/src/modules/Bills/queries/GetBillPayments.ts b/packages/server/src/modules/Bills/queries/GetBillPayments.ts index 6a1814bba..3ded5eba0 100644 --- a/packages/server/src/modules/Bills/queries/GetBillPayments.ts +++ b/packages/server/src/modules/Bills/queries/GetBillPayments.ts @@ -2,12 +2,13 @@ import { Inject, Injectable } from '@nestjs/common'; import { BillPaymentEntry } from '@/modules/BillPayments/models/BillPaymentEntry'; import { BillPaymentTransactionTransformer } from '@/modules/BillPayments/queries/BillPaymentTransactionTransformer'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @Injectable() -export class GetBillPayments { +export class GetBillPaymentTransactionsService { constructor( @Inject(BillPaymentEntry.name) - private billPaymentEntryModel: typeof BillPaymentEntry, + private billPaymentEntryModel: TenantModelProxy, private transformer: TransformerInjectable, ) {} @@ -15,8 +16,8 @@ export class GetBillPayments { * Retrieve the specific bill associated payment transactions. * @param {number} billId - Bill id. */ - public getBillPayments = async (billId: number) => { - const billsEntries = await this.billPaymentEntryModel + public getBillPaymentTransactions = async (billId: number) => { + const billsEntries = await this.billPaymentEntryModel() .query() .where('billId', billId) .withGraphJoined('payment.paymentAccount') diff --git a/packages/server/src/modules/TransactionItemEntry/models/ItemEntry.ts b/packages/server/src/modules/TransactionItemEntry/models/ItemEntry.ts index fdc82d6bd..73b5fba37 100644 --- a/packages/server/src/modules/TransactionItemEntry/models/ItemEntry.ts +++ b/packages/server/src/modules/TransactionItemEntry/models/ItemEntry.ts @@ -162,6 +162,14 @@ export class ItemEntry extends BaseModel { : getExlusiveTaxAmount(this.amount, this.taxRate); } + /** + * Remain unallocated landed cost. + * @return {number} + */ + get unallocatedCostAmount() { + return Math.max(this.amount - this.allocatedCostAmount, 0); + } + static calcAmount(itemEntry) { const { discount, quantity, rate } = itemEntry; const total = quantity * rate; diff --git a/packages/server/src/utils/sanitize-model-name.ts b/packages/server/src/utils/sanitize-model-name.ts new file mode 100644 index 000000000..2dd7a0715 --- /dev/null +++ b/packages/server/src/utils/sanitize-model-name.ts @@ -0,0 +1,5 @@ +import { camelCase, upperFirst } from 'lodash'; + +export const sanitizeModelName = (modelName: string) => { + return upperFirst(camelCase(modelName)); +} \ No newline at end of file diff --git a/packages/webapp/src/containers/Drawers/BillDrawer/BillDrawerProvider.tsx b/packages/webapp/src/containers/Drawers/BillDrawer/BillDrawerProvider.tsx index 4ed8620a8..6cfdf4561 100644 --- a/packages/webapp/src/containers/Drawers/BillDrawer/BillDrawerProvider.tsx +++ b/packages/webapp/src/containers/Drawers/BillDrawer/BillDrawerProvider.tsx @@ -27,6 +27,8 @@ function BillDrawerProvider({ billId, ...props }) { enabled: !!billId, }); + console.log(transactions, 'ahmed'); + //provider. const provider = { billId, diff --git a/packages/webapp/src/containers/Drawers/BillDrawer/LocatedLandedCostTable.tsx b/packages/webapp/src/containers/Drawers/BillDrawer/LocatedLandedCostTable.tsx index 7b0d25ab1..07fcdbe3d 100644 --- a/packages/webapp/src/containers/Drawers/BillDrawer/LocatedLandedCostTable.tsx +++ b/packages/webapp/src/containers/Drawers/BillDrawer/LocatedLandedCostTable.tsx @@ -34,6 +34,8 @@ function LocatedLandedCostTable({ // Bill drawer context. const { transactions, billId } = useBillDrawerContext(); + console.log(transactions, 'ahmed'); + // Handle the transaction delete action. const handleDeleteTransaction = ({ id }) => { openAlert('bill-located-cost-delete', { BillId: id }); diff --git a/packages/webapp/src/hooks/query/bills.tsx b/packages/webapp/src/hooks/query/bills.tsx index 3a5455225..20a852904 100644 --- a/packages/webapp/src/hooks/query/bills.tsx +++ b/packages/webapp/src/hooks/query/bills.tsx @@ -163,7 +163,7 @@ export function useBill(id, props) { [t.BILL, id], { method: 'get', url: `/bills/${id}` }, { - select: (res) => res.data.bill, + select: (res) => res.data, defaultData: {}, ...props, }, @@ -208,7 +208,7 @@ export function useBillPaymentTransactions(id, props) { url: `bills/${id}/payment-transactions`, }, { - select: (res) => res.data.data, + select: (res) => res.data, defaultData: [], ...props, }, diff --git a/packages/webapp/src/hooks/query/landedCost.tsx b/packages/webapp/src/hooks/query/landedCost.tsx index 72a91ae7d..1d6279c05 100644 --- a/packages/webapp/src/hooks/query/landedCost.tsx +++ b/packages/webapp/src/hooks/query/landedCost.tsx @@ -23,7 +23,7 @@ export function useCreateLandedCost(props) { return useMutation( ([id, values]) => - apiRequest.post(`purchases/landed-cost/bills/${id}/allocate`, values), + apiRequest.post(`landed-cost/bills/${id}/allocate`, values), { onSuccess: (res, id) => { // Common invalidate queries. @@ -43,7 +43,7 @@ export function useDeleteLandedCost(props) { return useMutation( (landedCostId) => - apiRequest.delete(`purchases/landed-cost/${landedCostId}`), + apiRequest.delete(`landed-cost/${landedCostId}`), { onSuccess: (res, id) => { // Common invalidate queries. @@ -62,7 +62,7 @@ export function useLandedCostTransaction(query, props) { [t.LANDED_COST, query], { method: 'get', - url: 'purchases/landed-cost/transactions', + url: 'landed-cost/transactions', params: { transaction_type: query }, }, { @@ -81,10 +81,10 @@ export function useLandedCostTransaction(query, props) { export function useBillLocatedLandedCost(id, props) { return useRequestQuery( [t.LANDED_COST_TRANSACTION, id], - { method: 'get', url: `purchases/landed-cost/bills/${id}/transactions` }, + { method: 'get', url: `landed-cost/bills/${id}/transactions` }, { - select: (res) => res.data.transactions, - defaultData: {}, + select: (res) => res.data?.data, + defaultData: [], ...props, }, );