mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
feat: wip prepard expenses from vendors
This commit is contained in:
@@ -111,6 +111,7 @@ export default class BillsPayments extends BaseController {
|
|||||||
check('vendor_id').exists().isNumeric().toInt(),
|
check('vendor_id').exists().isNumeric().toInt(),
|
||||||
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
check('exchange_rate').optional().isFloat({ gt: 0 }).toFloat(),
|
||||||
|
|
||||||
|
check('amount').exists().isNumeric().toFloat(),
|
||||||
check('payment_account_id').exists().isNumeric().toInt(),
|
check('payment_account_id').exists().isNumeric().toInt(),
|
||||||
check('payment_number').optional({ nullable: true }).trim().escape(),
|
check('payment_number').optional({ nullable: true }).trim().escape(),
|
||||||
check('payment_date').exists(),
|
check('payment_date').exists(),
|
||||||
@@ -125,6 +126,8 @@ export default class BillsPayments extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
|
check('prepard_expenses_account_id').optional().isNumeric().toInt(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ export interface IBillPayment {
|
|||||||
|
|
||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
|
|
||||||
|
prepardExpensesAccountId?: number;
|
||||||
|
isPrepardExpense: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillPaymentEntryDTO {
|
export interface IBillPaymentEntryDTO {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export default class BillPayment extends mixin(TenantModel, [
|
|||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
prepardExpensesAccountId: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -47,6 +49,14 @@ export default class BillPayment extends mixin(TenantModel, [
|
|||||||
return BillPaymentSettings;
|
return BillPaymentSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines whether the payment is prepard expense.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
get isPrepardExpense() {
|
||||||
|
return !!this.prepardExpensesAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { sumBy } from 'lodash';
|
import { sumBy, chain } from 'lodash';
|
||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { Knex } from 'knex';
|
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 Ledger from '@/services/Accounting/Ledger';
|
||||||
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
@@ -21,6 +27,7 @@ export class BillPaymentGLEntries {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} billPaymentId
|
* @param {number} billPaymentId
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public writePaymentGLEntries = async (
|
public writePaymentGLEntries = async (
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -65,6 +72,7 @@ export class BillPaymentGLEntries {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} billPaymentId
|
* @param {number} billPaymentId
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public rewritePaymentGLEntries = async (
|
public rewritePaymentGLEntries = async (
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -102,7 +110,7 @@ export class BillPaymentGLEntries {
|
|||||||
* @param {IBillPayment} billPayment
|
* @param {IBillPayment} billPayment
|
||||||
* @returns {}
|
* @returns {}
|
||||||
*/
|
*/
|
||||||
private getPaymentCommonEntry = (billPayment: IBillPayment) => {
|
private getPaymentCommonEntry = (billPayment: IBillPayment): ILedgerEntry => {
|
||||||
const formattedDate = moment(billPayment.paymentDate).format('YYYY-MM-DD');
|
const formattedDate = moment(billPayment.paymentDate).format('YYYY-MM-DD');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -127,7 +135,7 @@ export class BillPaymentGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the payment total exchange gain/loss.
|
* Calculates the payment total exchange gain/loss.
|
||||||
* @param {IBillPayment} paymentReceive - Payment receive with entries.
|
* @param {IBillPayment} paymentReceive - Payment receive with entries.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
private getPaymentExGainOrLoss = (billPayment: IBillPayment): number => {
|
private getPaymentExGainOrLoss = (billPayment: IBillPayment): number => {
|
||||||
@@ -141,10 +149,10 @@ export class BillPaymentGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the payment exchange gain/loss entries.
|
* Retrieves the payment exchange gain/loss entries.
|
||||||
* @param {IBillPayment} billPayment -
|
* @param {IBillPayment} billPayment -
|
||||||
* @param {number} APAccountId -
|
* @param {number} APAccountId -
|
||||||
* @param {number} gainLossAccountId -
|
* @param {number} gainLossAccountId -
|
||||||
* @param {string} baseCurrency -
|
* @param {string} baseCurrency -
|
||||||
* @returns {ILedgerEntry[]}
|
* @returns {ILedgerEntry[]}
|
||||||
*/
|
*/
|
||||||
private getPaymentExGainOrLossEntries = (
|
private getPaymentExGainOrLossEntries = (
|
||||||
@@ -186,7 +194,7 @@ export class BillPaymentGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the payment deposit GL entry.
|
* Retrieves the payment deposit GL entry.
|
||||||
* @param {IBillPayment} billPayment
|
* @param {IBillPayment} billPayment
|
||||||
* @returns {ILedgerEntry}
|
* @returns {ILedgerEntry}
|
||||||
*/
|
*/
|
||||||
private getPaymentGLEntry = (billPayment: IBillPayment): ILedgerEntry => {
|
private getPaymentGLEntry = (billPayment: IBillPayment): ILedgerEntry => {
|
||||||
@@ -198,6 +206,7 @@ export class BillPaymentGLEntries {
|
|||||||
accountId: billPayment.paymentAccountId,
|
accountId: billPayment.paymentAccountId,
|
||||||
accountNormal: AccountNormal.DEBIT,
|
accountNormal: AccountNormal.DEBIT,
|
||||||
index: 2,
|
index: 2,
|
||||||
|
indexGroup: 10,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -226,8 +235,8 @@ export class BillPaymentGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the payment GL entries.
|
* Retrieves the payment GL entries.
|
||||||
* @param {IBillPayment} billPayment
|
* @param {IBillPayment} billPayment
|
||||||
* @param {number} APAccountId
|
* @param {number} APAccountId
|
||||||
* @returns {ILedgerEntry[]}
|
* @returns {ILedgerEntry[]}
|
||||||
*/
|
*/
|
||||||
private getPaymentGLEntries = (
|
private getPaymentGLEntries = (
|
||||||
@@ -254,10 +263,53 @@ export class BillPaymentGLEntries {
|
|||||||
return [paymentEntry, payableEntry, ...exGainLossEntries];
|
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.
|
* Retrieves the bill payment ledger.
|
||||||
* @param {IBillPayment} billPayment
|
* @param {IBillPayment} billPayment
|
||||||
* @param {number} APAccountId
|
* @param {number} APAccountId
|
||||||
* @returns {Ledger}
|
* @returns {Ledger}
|
||||||
*/
|
*/
|
||||||
private getBillPaymentLedger = (
|
private getBillPaymentLedger = (
|
||||||
@@ -266,12 +318,79 @@ export class BillPaymentGLEntries {
|
|||||||
gainLossAccountId: number,
|
gainLossAccountId: number,
|
||||||
baseCurrency: string
|
baseCurrency: string
|
||||||
): Ledger => {
|
): Ledger => {
|
||||||
const entries = this.getPaymentGLEntries(
|
const entries = billPayment.isPrepardExpense
|
||||||
billPayment,
|
? this.getPrepardExpenseGLEntries(APAccountId, billPayment)
|
||||||
APAccountId,
|
: this.getPaymentGLEntries(
|
||||||
gainLossAccountId,
|
billPayment,
|
||||||
baseCurrency
|
APAccountId,
|
||||||
);
|
gainLossAccountId,
|
||||||
|
baseCurrency
|
||||||
|
);
|
||||||
return new Ledger(entries);
|
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,
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ export class PaymentWriteGLEntriesSubscriber {
|
|||||||
*/
|
*/
|
||||||
public attach(bus) {
|
public attach(bus) {
|
||||||
bus.subscribe(events.billPayment.onCreated, this.handleWriteJournalEntries);
|
bus.subscribe(events.billPayment.onCreated, this.handleWriteJournalEntries);
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onPrepardExpensesApplied,
|
||||||
|
this.handleWritePrepardExpenseGLEntries
|
||||||
|
);
|
||||||
bus.subscribe(
|
bus.subscribe(
|
||||||
events.billPayment.onEdited,
|
events.billPayment.onEdited,
|
||||||
this.handleRewriteJournalEntriesOncePaymentEdited
|
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 ({
|
private handleWriteJournalEntries = async ({
|
||||||
tenantId,
|
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.
|
* Handle bill payment re-writing journal entries once the payment transaction be edited.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ export class CommandBillPaymentDTOTransformer {
|
|||||||
vendor: IVendor,
|
vendor: IVendor,
|
||||||
oldBillPayment?: IBillPayment
|
oldBillPayment?: IBillPayment
|
||||||
): Promise<IBillPayment> {
|
): Promise<IBillPayment> {
|
||||||
|
const appliedAmount = sumBy(billPaymentDTO.entries, 'paymentAmount');
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...formatDateFields(omit(billPaymentDTO, ['attachments']), [
|
...formatDateFields(omit(billPaymentDTO, ['attachments']), [
|
||||||
'paymentDate',
|
'paymentDate',
|
||||||
]),
|
]),
|
||||||
amount: sumBy(billPaymentDTO.entries, 'paymentAmount'),
|
appliedAmount,
|
||||||
currencyCode: vendor.currencyCode,
|
currencyCode: vendor.currencyCode,
|
||||||
exchangeRate: billPaymentDTO.exchangeRate || 1,
|
exchangeRate: billPaymentDTO.exchangeRate || 1,
|
||||||
entries: billPaymentDTO.entries,
|
entries: billPaymentDTO.entries,
|
||||||
|
|||||||
Reference in New Issue
Block a user