From f3af3843ddd1d5ee039dcbbe3f8de232b77522b9 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 24 Jul 2024 18:57:51 +0200 Subject: [PATCH] feat: wip prepard expenses from vendors --- .../controllers/Purchases/BillsPayments.ts | 3 + packages/server/src/interfaces/BillPayment.ts | 3 + packages/server/src/models/BillPayment.ts | 10 ++ .../BillPayments/BillPaymentGLEntries.ts | 157 +++++++++++++++--- .../BillPaymentGLEntriesSubscriber.ts | 23 ++- .../CommandBillPaymentDTOTransformer.ts | 4 +- 6 files changed, 179 insertions(+), 21 deletions(-) diff --git a/packages/server/src/api/controllers/Purchases/BillsPayments.ts b/packages/server/src/api/controllers/Purchases/BillsPayments.ts index 2bfb38383..1bf0925c4 100644 --- a/packages/server/src/api/controllers/Purchases/BillsPayments.ts +++ b/packages/server/src/api/controllers/Purchases/BillsPayments.ts @@ -111,6 +111,7 @@ export default class BillsPayments extends BaseController { check('vendor_id').exists().isNumeric().toInt(), check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(), + check('amount').exists().isNumeric().toFloat(), check('payment_account_id').exists().isNumeric().toInt(), check('payment_number').optional({ nullable: true }).trim().escape(), check('payment_date').exists(), @@ -125,6 +126,8 @@ export default class BillsPayments extends BaseController { check('attachments').isArray().optional(), check('attachments.*.key').exists().isString(), + + check('prepard_expenses_account_id').optional().isNumeric().toInt(), ]; } diff --git a/packages/server/src/interfaces/BillPayment.ts b/packages/server/src/interfaces/BillPayment.ts index 2a8e37626..094f534d4 100644 --- a/packages/server/src/interfaces/BillPayment.ts +++ b/packages/server/src/interfaces/BillPayment.ts @@ -29,6 +29,9 @@ export interface IBillPayment { localAmount?: number; branchId?: number; + + prepardExpensesAccountId?: number; + isPrepardExpense: boolean; } export interface IBillPaymentEntryDTO { diff --git a/packages/server/src/models/BillPayment.ts b/packages/server/src/models/BillPayment.ts index d3f0dfe21..35fa2789e 100644 --- a/packages/server/src/models/BillPayment.ts +++ b/packages/server/src/models/BillPayment.ts @@ -11,6 +11,8 @@ export default class BillPayment extends mixin(TenantModel, [ CustomViewBaseModel, ModelSearchable, ]) { + prepardExpensesAccountId: number; + /** * Table name */ @@ -47,6 +49,14 @@ export default class BillPayment extends mixin(TenantModel, [ return BillPaymentSettings; } + /** + * Detarmines whether the payment is prepard expense. + * @returns {boolean} + */ + get isPrepardExpense() { + return !!this.prepardExpensesAccountId; + } + /** * Relationship mapping. */ diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntries.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntries.ts index 57f4966d7..2314b712d 100644 --- a/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntries.ts +++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntries.ts @@ -1,8 +1,14 @@ import moment from 'moment'; -import { sumBy } from 'lodash'; +import { sumBy, chain } from 'lodash'; import { Service, Inject } from 'typedi'; import { Knex } from 'knex'; -import { AccountNormal, IBillPayment, ILedgerEntry } from '@/interfaces'; +import { + AccountNormal, + IBillPayment, + IBillPaymentEntry, + ILedger, + ILedgerEntry, +} from '@/interfaces'; import Ledger from '@/services/Accounting/Ledger'; import LedgerStorageService from '@/services/Accounting/LedgerStorageService'; import HasTenancyService from '@/services/Tenancy/TenancyService'; @@ -21,6 +27,7 @@ export class BillPaymentGLEntries { * @param {number} tenantId * @param {number} billPaymentId * @param {Knex.Transaction} trx + * @returns {Promise} */ public writePaymentGLEntries = async ( tenantId: number, @@ -65,6 +72,7 @@ export class BillPaymentGLEntries { * @param {number} tenantId * @param {number} billPaymentId * @param {Knex.Transaction} trx + * @returns {Promise} */ public rewritePaymentGLEntries = async ( tenantId: number, @@ -102,7 +110,7 @@ export class BillPaymentGLEntries { * @param {IBillPayment} billPayment * @returns {} */ - private getPaymentCommonEntry = (billPayment: IBillPayment) => { + private getPaymentCommonEntry = (billPayment: IBillPayment): ILedgerEntry => { const formattedDate = moment(billPayment.paymentDate).format('YYYY-MM-DD'); return { @@ -127,7 +135,7 @@ export class BillPaymentGLEntries { /** * Calculates the payment total exchange gain/loss. - * @param {IBillPayment} paymentReceive - Payment receive with entries. + * @param {IBillPayment} paymentReceive - Payment receive with entries. * @returns {number} */ private getPaymentExGainOrLoss = (billPayment: IBillPayment): number => { @@ -141,10 +149,10 @@ export class BillPaymentGLEntries { /** * Retrieves the payment exchange gain/loss entries. - * @param {IBillPayment} billPayment - - * @param {number} APAccountId - - * @param {number} gainLossAccountId - - * @param {string} baseCurrency - + * @param {IBillPayment} billPayment - + * @param {number} APAccountId - + * @param {number} gainLossAccountId - + * @param {string} baseCurrency - * @returns {ILedgerEntry[]} */ private getPaymentExGainOrLossEntries = ( @@ -186,7 +194,7 @@ export class BillPaymentGLEntries { /** * Retrieves the payment deposit GL entry. - * @param {IBillPayment} billPayment + * @param {IBillPayment} billPayment * @returns {ILedgerEntry} */ private getPaymentGLEntry = (billPayment: IBillPayment): ILedgerEntry => { @@ -198,6 +206,7 @@ export class BillPaymentGLEntries { accountId: billPayment.paymentAccountId, accountNormal: AccountNormal.DEBIT, index: 2, + indexGroup: 10, }; }; @@ -226,8 +235,8 @@ export class BillPaymentGLEntries { /** * Retrieves the payment GL entries. - * @param {IBillPayment} billPayment - * @param {number} APAccountId + * @param {IBillPayment} billPayment + * @param {number} APAccountId * @returns {ILedgerEntry[]} */ private getPaymentGLEntries = ( @@ -254,10 +263,53 @@ export class BillPaymentGLEntries { return [paymentEntry, payableEntry, ...exGainLossEntries]; }; + /** + * + * BEFORE APPLYING TO PAYMENT TO BILLS. + * ----------------------------------------- + * - Cash/Bank - Credit. + * - Prepard Expenses - Debit + * + * AFTER APPLYING BILLS TO PAYMENT. + * ----------------------------------------- + * - Prepard Expenses - Credit + * - A/P - Debit + * + * @param {number} APAccountId - A/P account id. + * @param {IBillPayment} billPayment + */ + private getPrepardExpenseGLEntries = ( + APAccountId: number, + billPayment: IBillPayment + ) => { + const prepardExpenseEntry = this.getPrepardExpenseEntry(billPayment); + const withdrawalEntry = this.getPaymentGLEntry(billPayment); + + const paymentLinesEntries = chain(billPayment.entries) + .map((billPaymentEntry) => { + const APEntry = this.getAccountPayablePaymentLineEntry( + APAccountId, + billPayment, + billPaymentEntry + ); + const creditPrepardExpenseEntry = this.getCreditPrepardExpenseEntry( + billPayment, + billPaymentEntry + ); + return [creditPrepardExpenseEntry, APEntry]; + }) + .flatten() + .value(); + const prepardExpenseEntries = [prepardExpenseEntry, withdrawalEntry]; + const combinedEntries = [...prepardExpenseEntries, ...paymentLinesEntries]; + + return combinedEntries; + }; + /** * Retrieves the bill payment ledger. - * @param {IBillPayment} billPayment - * @param {number} APAccountId + * @param {IBillPayment} billPayment + * @param {number} APAccountId * @returns {Ledger} */ private getBillPaymentLedger = ( @@ -266,12 +318,79 @@ export class BillPaymentGLEntries { gainLossAccountId: number, baseCurrency: string ): Ledger => { - const entries = this.getPaymentGLEntries( - billPayment, - APAccountId, - gainLossAccountId, - baseCurrency - ); + const entries = billPayment.isPrepardExpense + ? this.getPrepardExpenseGLEntries(APAccountId, billPayment) + : this.getPaymentGLEntries( + billPayment, + APAccountId, + gainLossAccountId, + baseCurrency + ); return new Ledger(entries); }; + + /** + * Retrieves the prepard expense GL entry. + * @param {IBillPayment} billPayment + * @returns {ILedgerEntry} + */ + private getPrepardExpenseEntry = ( + billPayment: IBillPayment + ): ILedgerEntry => { + const commonJournal = this.getPaymentCommonEntry(billPayment); + + return { + ...commonJournal, + debit: billPayment.localAmount, + accountId: billPayment.prepardExpensesAccountId, + accountNormal: AccountNormal.DEBIT, + indexGroup: 10, + index: 1, + }; + }; + + /** + * Retrieves the GL entries of credit prepard expense for the give payment line. + * @param {IBillPayment} billPayment + * @param {IBillPaymentEntry} billPaymentEntry + * @returns {ILedgerEntry} + */ + private getCreditPrepardExpenseEntry = ( + billPayment: IBillPayment, + billPaymentEntry: IBillPaymentEntry + ) => { + const commonJournal = this.getPaymentCommonEntry(billPayment); + + return { + ...commonJournal, + credit: billPaymentEntry.paymentAmount, + accountId: billPayment.prepardExpensesAccountId, + accountNormal: AccountNormal.DEBIT, + index: 2, + indexGroup: 20, + }; + }; + + /** + * Retrieves the A/P debit of the payment line. + * @param {number} APAccountId + * @param {IBillPayment} billPayment + * @param {IBillPaymentEntry} billPaymentEntry + * @returns {ILedgerEntry} + */ + private getAccountPayablePaymentLineEntry = ( + APAccountId: number, + billPayment: IBillPayment, + billPaymentEntry: IBillPaymentEntry + ): ILedgerEntry => { + const commonJournal = this.getPaymentCommonEntry(billPayment); + + return { + ...commonJournal, + debit: billPaymentEntry.paymentAmount, + accountId: APAccountId, + index: 1, + indexGroup: 20, + }; + }; } diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntriesSubscriber.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntriesSubscriber.ts index cdfb456d5..f150b5563 100644 --- a/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntriesSubscriber.ts +++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentGLEntriesSubscriber.ts @@ -17,6 +17,10 @@ export class PaymentWriteGLEntriesSubscriber { */ public attach(bus) { bus.subscribe(events.billPayment.onCreated, this.handleWriteJournalEntries); + bus.subscribe( + events.billPayment.onPrepardExpensesApplied, + this.handleWritePrepardExpenseGLEntries + ); bus.subscribe( events.billPayment.onEdited, this.handleRewriteJournalEntriesOncePaymentEdited @@ -28,7 +32,8 @@ export class PaymentWriteGLEntriesSubscriber { } /** - * Handle bill payment writing journal entries once created. + * Handles bill payment writing journal entries once created. + * @param {IBillPaymentEventCreatedPayload} payload - */ private handleWriteJournalEntries = async ({ tenantId, @@ -44,6 +49,22 @@ export class PaymentWriteGLEntriesSubscriber { ); }; + /** + * Handles rewrite prepard expense GL entries once the bill payment applying to bills. + * @param {IBillPaymentEventCreatedPayload} payload - + */ + private handleWritePrepardExpenseGLEntries = async ({ + tenantId, + billPaymentId, + trx, + }: IBillPaymentEventCreatedPayload) => { + await this.billPaymentGLEntries.rewritePaymentGLEntries( + tenantId, + billPaymentId, + trx + ); + }; + /** * Handle bill payment re-writing journal entries once the payment transaction be edited. */ diff --git a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts index 5b6f1451d..c9834da6c 100644 --- a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts +++ b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts @@ -23,11 +23,13 @@ export class CommandBillPaymentDTOTransformer { vendor: IVendor, oldBillPayment?: IBillPayment ): Promise { + const appliedAmount = sumBy(billPaymentDTO.entries, 'paymentAmount'); + const initialDTO = { ...formatDateFields(omit(billPaymentDTO, ['attachments']), [ 'paymentDate', ]), - amount: sumBy(billPaymentDTO.entries, 'paymentAmount'), + appliedAmount, currencyCode: vendor.currencyCode, exchangeRate: billPaymentDTO.exchangeRate || 1, entries: billPaymentDTO.entries,