mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-23 16:19:49 +00:00
feat: add local discount and adjustment calculations to financial models and transformers
- Introduced `discountAmountLocal` and `adjustmentLocal` properties across Bill, CreditNote, SaleInvoice, SaleReceipt, and VendorCredit models to calculate amounts in local currency. - Updated transformers for CreditNote, PurchaseInvoice, and VendorCredit to include formatted representations of local discount and adjustment amounts. - Enhanced GL entry services to handle discount and adjustment entries for SaleReceipt and CreditNote, ensuring accurate ledger entries. - Improved overall consistency in handling financial calculations across various models and services.
This commit is contained in:
@@ -56,8 +56,11 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
'amountLocal',
|
'amountLocal',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
|
'adjustmentLocal',
|
||||||
|
|
||||||
'subtotal',
|
'subtotal',
|
||||||
'subtotalLocal',
|
'subtotalLocal',
|
||||||
'subtotalExludingTax',
|
'subtotalExludingTax',
|
||||||
@@ -119,6 +122,15 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
: this.subtotal * (this.discount / 100);
|
: 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.
|
* Discount percentage.
|
||||||
* @returns {number | null}
|
* @returns {number | null}
|
||||||
@@ -127,6 +139,14 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
return this.discountType === DiscountType.Percentage ? this.discount : 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice total. (Tax included)
|
* Invoice total. (Tax included)
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
|
|||||||
@@ -51,10 +51,13 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
'subtotalLocal',
|
'subtotalLocal',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|
||||||
|
'adjustmentLocal',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,14 +95,28 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
: this.subtotal * (this.discount / 100);
|
: this.subtotal * (this.discount / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discount amount in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get discountAmountLocal() {
|
||||||
|
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discount percentage.
|
* Discount percentage.
|
||||||
* @returns {number | null}
|
* @returns {number | null}
|
||||||
*/
|
*/
|
||||||
get discountPercentage(): number | null {
|
get discountPercentage(): number | null {
|
||||||
return this.discountType === DiscountType.Percentage
|
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
||||||
? this.discount
|
}
|
||||||
: null;
|
|
||||||
|
/**
|
||||||
|
* Adjustment amount in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get adjustmentLocal() {
|
||||||
|
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -73,12 +73,14 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
|
|
||||||
'taxAmountWithheldLocal',
|
'taxAmountWithheldLocal',
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|
||||||
'writtenoffAmountLocal',
|
'writtenoffAmountLocal',
|
||||||
|
'adjustmentLocal',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,14 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
: this.subtotal * (this.discount / 100);
|
: this.subtotal * (this.discount / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local discount amount.
|
||||||
|
* @returns {number | null}
|
||||||
|
*/
|
||||||
|
get discountAmountLocal() {
|
||||||
|
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discount percentage.
|
* Discount percentage.
|
||||||
* @returns {number | null}
|
* @returns {number | null}
|
||||||
@@ -151,6 +161,14 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjustment amount in local currency.
|
||||||
|
* @returns {number | null}
|
||||||
|
*/
|
||||||
|
get adjustmentLocal(): number | null {
|
||||||
|
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice total. (Tax included)
|
* Invoice total. (Tax included)
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
'adjustmentLocal',
|
'adjustmentLocal',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
'paid',
|
'paid',
|
||||||
@@ -97,14 +98,20 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
: this.subtotal * (this.discount / 100);
|
: 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.
|
* Discount percentage.
|
||||||
* @returns {number | null}
|
* @returns {number | null}
|
||||||
*/
|
*/
|
||||||
get discountPercentage(): number | null {
|
get discountPercentage(): number | null {
|
||||||
return this.discountType === DiscountType.Percentage
|
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
||||||
? this.discount
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
: this.subtotal * (this.discount / 100);
|
: 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.
|
* Discount percentage.
|
||||||
* @returns {number | null}
|
* @returns {number | null}
|
||||||
@@ -68,6 +76,14 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
return this.discountType === DiscountType.Percentage ? this.discount : 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.
|
* Vendor credit total.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
@@ -180,8 +196,11 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
'localAmount',
|
'localAmount',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
|
'adjustmentLocal',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
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 { SaleReceipt } from '@/models';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CreditNoteGLEntries {
|
export default class CreditNoteGLEntries {
|
||||||
@@ -29,11 +30,15 @@ export default class CreditNoteGLEntries {
|
|||||||
*/
|
*/
|
||||||
private getCreditNoteGLedger = (
|
private getCreditNoteGLedger = (
|
||||||
creditNote: ICreditNote,
|
creditNote: ICreditNote,
|
||||||
receivableAccount: number
|
receivableAccount: number,
|
||||||
|
discountAccount: number,
|
||||||
|
adjustmentAccount: number
|
||||||
): Ledger => {
|
): Ledger => {
|
||||||
const ledgerEntries = this.getCreditNoteGLEntries(
|
const ledgerEntries = this.getCreditNoteGLEntries(
|
||||||
creditNote,
|
creditNote,
|
||||||
receivableAccount
|
receivableAccount,
|
||||||
|
discountAccount,
|
||||||
|
adjustmentAccount
|
||||||
);
|
);
|
||||||
return new Ledger(ledgerEntries);
|
return new Ledger(ledgerEntries);
|
||||||
};
|
};
|
||||||
@@ -49,9 +54,16 @@ export default class CreditNoteGLEntries {
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
creditNote: ICreditNote,
|
creditNote: ICreditNote,
|
||||||
payableAccount: number,
|
payableAccount: number,
|
||||||
|
discountAccount: number,
|
||||||
|
adjustmentAccount: number,
|
||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const ledger = this.getCreditNoteGLedger(creditNote, payableAccount);
|
const ledger = this.getCreditNoteGLedger(
|
||||||
|
creditNote,
|
||||||
|
payableAccount,
|
||||||
|
discountAccount,
|
||||||
|
adjustmentAccount
|
||||||
|
);
|
||||||
|
|
||||||
await this.ledgerStorage.commit(tenantId, ledger, trx);
|
await this.ledgerStorage.commit(tenantId, ledger, trx);
|
||||||
};
|
};
|
||||||
@@ -98,11 +110,18 @@ export default class CreditNoteGLEntries {
|
|||||||
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
||||||
creditNoteWithItems.currencyCode
|
creditNoteWithItems.currencyCode
|
||||||
);
|
);
|
||||||
|
const discountAccount = await accountRepository.findOrCreateDiscountAccount(
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
const adjustmentAccount =
|
||||||
|
await accountRepository.findOrCreateOtherChargesAccount({});
|
||||||
// Saves the credit note GL entries.
|
// Saves the credit note GL entries.
|
||||||
await this.saveCreditNoteGLEntries(
|
await this.saveCreditNoteGLEntries(
|
||||||
tenantId,
|
tenantId,
|
||||||
creditNoteWithItems,
|
creditNoteWithItems,
|
||||||
ARAccount.id,
|
ARAccount.id,
|
||||||
|
discountAccount.id,
|
||||||
|
adjustmentAccount.id,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -169,7 +188,7 @@ export default class CreditNoteGLEntries {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
credit: creditNote.localAmount,
|
credit: creditNote.totalLocal,
|
||||||
accountId: ARAccountId,
|
accountId: ARAccountId,
|
||||||
contactId: creditNote.customerId,
|
contactId: creditNote.customerId,
|
||||||
index: 1,
|
index: 1,
|
||||||
@@ -206,6 +225,50 @@ export default class CreditNoteGLEntries {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the credit note discount entry.
|
||||||
|
* @param {ICreditNote} creditNote
|
||||||
|
* @param {number} discountAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getDiscountEntry = (
|
||||||
|
creditNote: ICreditNote,
|
||||||
|
discountAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: creditNote.discountAmountLocal,
|
||||||
|
accountId: discountAccountId,
|
||||||
|
index: 1,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the credit note adjustment entry.
|
||||||
|
* @param {ICreditNote} creditNote
|
||||||
|
* @param {number} adjustmentAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getAdjustmentEntry = (
|
||||||
|
creditNote: ICreditNote,
|
||||||
|
adjustmentAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
|
||||||
|
const adjustmentAmount = Math.abs(creditNote.adjustmentLocal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: creditNote.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||||
|
debit: creditNote.adjustmentLocal > 0 ? adjustmentAmount : 0,
|
||||||
|
accountId: adjustmentAccountId,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the credit note GL entries.
|
* Retrieve the credit note GL entries.
|
||||||
* @param {ICreditNote} creditNote - Credit note.
|
* @param {ICreditNote} creditNote - Credit note.
|
||||||
@@ -214,13 +277,21 @@ export default class CreditNoteGLEntries {
|
|||||||
*/
|
*/
|
||||||
public getCreditNoteGLEntries = (
|
public getCreditNoteGLEntries = (
|
||||||
creditNote: ICreditNote,
|
creditNote: ICreditNote,
|
||||||
ARAccountId: number
|
ARAccountId: number,
|
||||||
|
discountAccountId: number,
|
||||||
|
adjustmentAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const AREntry = this.getCreditNoteAREntry(creditNote, ARAccountId);
|
const AREntry = this.getCreditNoteAREntry(creditNote, ARAccountId);
|
||||||
|
|
||||||
const getItemEntry = this.getCreditNoteItemEntry(creditNote);
|
const getItemEntry = this.getCreditNoteItemEntry(creditNote);
|
||||||
const itemsEntries = creditNote.entries.map(getItemEntry);
|
const itemsEntries = creditNote.entries.map(getItemEntry);
|
||||||
|
|
||||||
return [AREntry, ...itemsEntries];
|
const discountEntry = this.getDiscountEntry(creditNote, discountAccountId);
|
||||||
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
creditNote,
|
||||||
|
adjustmentAccountId
|
||||||
|
);
|
||||||
|
|
||||||
|
return [AREntry, discountEntry, adjustmentEntry, ...itemsEntries];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,18 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
'formattedAmount',
|
'formattedAmount',
|
||||||
'formattedCreditsUsed',
|
'formattedCreditsUsed',
|
||||||
'formattedSubtotal',
|
'formattedSubtotal',
|
||||||
|
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
|
'discountAmountLocalFormatted',
|
||||||
|
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'adjustmentLocalFormatted',
|
||||||
|
|
||||||
'totalFormatted',
|
'totalFormatted',
|
||||||
'totalLocalFormatted',
|
'totalLocalFormatted',
|
||||||
|
|
||||||
'entries',
|
'entries',
|
||||||
'attachments',
|
'attachments',
|
||||||
];
|
];
|
||||||
@@ -100,15 +107,25 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted discount amount in local currency.
|
||||||
|
* @param {ICreditNote} credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected discountAmountLocalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.discountAmountLocal, {
|
||||||
|
currencyCode: credit.currencyCode,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves formatted discount percentage.
|
* Retrieves formatted discount percentage.
|
||||||
* @param credit
|
* @param credit
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected discountPercentageFormatted = (credit): string => {
|
protected discountPercentageFormatted = (credit): string => {
|
||||||
return credit.discountPercentage
|
return credit.discountPercentage ? `${credit.discountPercentage}%` : '';
|
||||||
? `${credit.discountPercentage}%`
|
|
||||||
: '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,6 +140,18 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted adjustment amount in local currency.
|
||||||
|
* @param {ICreditNote} credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected adjustmentLocalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.adjustmentLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the formatted total.
|
* Retrieves the formatted total.
|
||||||
* @param credit
|
* @param credit
|
||||||
|
|||||||
@@ -20,13 +20,21 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
'formattedBalance',
|
'formattedBalance',
|
||||||
'formattedDueAmount',
|
'formattedDueAmount',
|
||||||
'formattedExchangeRate',
|
'formattedExchangeRate',
|
||||||
|
|
||||||
'subtotalFormatted',
|
'subtotalFormatted',
|
||||||
'subtotalLocalFormatted',
|
'subtotalLocalFormatted',
|
||||||
|
|
||||||
'subtotalExcludingTaxFormatted',
|
'subtotalExcludingTaxFormatted',
|
||||||
'taxAmountWithheldLocalFormatted',
|
'taxAmountWithheldLocalFormatted',
|
||||||
|
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
|
'discountAmountLocalFormatted',
|
||||||
|
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'adjustmentLocalFormatted',
|
||||||
|
|
||||||
'totalFormatted',
|
'totalFormatted',
|
||||||
'totalLocalFormatted',
|
'totalLocalFormatted',
|
||||||
'taxes',
|
'taxes',
|
||||||
@@ -175,15 +183,25 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted discount amount in local currency.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected discountAmountLocalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.discountAmountLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the formatted discount percentage.
|
* Retrieves the formatted discount percentage.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected discountPercentageFormatted = (bill): string => {
|
protected discountPercentageFormatted = (bill): string => {
|
||||||
return bill.discountPercentage
|
return bill.discountPercentage ? `${bill.discountPercentage}%` : '';
|
||||||
? `${bill.discountPercentage}%`
|
|
||||||
: '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,6 +216,18 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted adjustment amount in local currency.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected adjustmentLocalFormatted = (bill): string => {
|
||||||
|
return formatNumber(bill.adjustmentLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the total formatted.
|
* Retrieves the total formatted.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
|
|||||||
@@ -17,9 +17,14 @@ export class VendorCreditTransformer extends Transformer {
|
|||||||
'formattedCreatedAt',
|
'formattedCreatedAt',
|
||||||
'formattedCreditsRemaining',
|
'formattedCreditsRemaining',
|
||||||
'formattedInvoicedAmount',
|
'formattedInvoicedAmount',
|
||||||
|
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
'discountAmountLocalFormatted',
|
||||||
|
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'adjustmentLocalFormatted',
|
||||||
|
|
||||||
'totalFormatted',
|
'totalFormatted',
|
||||||
'entries',
|
'entries',
|
||||||
'attachments',
|
'attachments',
|
||||||
@@ -87,6 +92,18 @@ export class VendorCreditTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted discount amount in local currency.
|
||||||
|
* @param {IVendorCredit} credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected discountAmountLocalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.discountAmountLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the formatted discount percentage.
|
* Retrieves the formatted discount percentage.
|
||||||
* @param {IVendorCredit} credit
|
* @param {IVendorCredit} credit
|
||||||
@@ -108,6 +125,18 @@ export class VendorCreditTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted adjustment amount in local currency.
|
||||||
|
* @param {IVendorCredit} credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected adjustmentLocalFormatted = (credit): string => {
|
||||||
|
return formatNumber(credit.adjustmentLocal, {
|
||||||
|
currencyCode: this.context.organization.baseCurrency,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the formatted invoiced amount.
|
* Retrieves the formatted invoiced amount.
|
||||||
* @param credit
|
* @param credit
|
||||||
|
|||||||
@@ -31,13 +31,27 @@ export class SaleReceiptGLEntries {
|
|||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const { SaleReceipt } = this.tenancy.models(tenantId);
|
const { SaleReceipt } = this.tenancy.models(tenantId);
|
||||||
|
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
|
||||||
const saleReceipt = await SaleReceipt.query(trx)
|
const saleReceipt = await SaleReceipt.query(trx)
|
||||||
.findById(saleReceiptId)
|
.findById(saleReceiptId)
|
||||||
.withGraphFetched('entries.item');
|
.withGraphFetched('entries.item');
|
||||||
|
|
||||||
|
// Find or create the discount expense account.
|
||||||
|
const discountAccount = await accountRepository.findOrCreateDiscountAccount(
|
||||||
|
{},
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
// Find or create the other charges account.
|
||||||
|
const otherChargesAccount =
|
||||||
|
await accountRepository.findOrCreateOtherChargesAccount({}, trx);
|
||||||
|
|
||||||
// Retrieve the income entries ledger.
|
// Retrieve the income entries ledger.
|
||||||
const incomeLedger = this.getIncomeEntriesLedger(saleReceipt);
|
const incomeLedger = this.getIncomeEntriesLedger(
|
||||||
|
saleReceipt,
|
||||||
|
discountAccount.id,
|
||||||
|
otherChargesAccount.id
|
||||||
|
);
|
||||||
|
|
||||||
// Commits the ledger entries to the storage.
|
// Commits the ledger entries to the storage.
|
||||||
await this.ledgerStorage.commit(tenantId, incomeLedger, trx);
|
await this.ledgerStorage.commit(tenantId, incomeLedger, trx);
|
||||||
@@ -87,8 +101,16 @@ export class SaleReceiptGLEntries {
|
|||||||
* @param {ISaleReceipt} saleReceipt
|
* @param {ISaleReceipt} saleReceipt
|
||||||
* @returns {Ledger}
|
* @returns {Ledger}
|
||||||
*/
|
*/
|
||||||
private getIncomeEntriesLedger = (saleReceipt: ISaleReceipt): Ledger => {
|
private getIncomeEntriesLedger = (
|
||||||
const entries = this.getIncomeGLEntries(saleReceipt);
|
saleReceipt: ISaleReceipt,
|
||||||
|
discountAccountId: number,
|
||||||
|
otherChargesAccountId: number
|
||||||
|
): Ledger => {
|
||||||
|
const entries = this.getIncomeGLEntries(
|
||||||
|
saleReceipt,
|
||||||
|
discountAccountId,
|
||||||
|
otherChargesAccountId
|
||||||
|
);
|
||||||
|
|
||||||
return new Ledger(entries);
|
return new Ledger(entries);
|
||||||
};
|
};
|
||||||
@@ -161,24 +183,77 @@ export class SaleReceiptGLEntries {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
debit: saleReceipt.localAmount,
|
debit: saleReceipt.totalLocal,
|
||||||
accountId: saleReceipt.depositAccountId,
|
accountId: saleReceipt.depositAccountId,
|
||||||
index: 1,
|
index: 1,
|
||||||
accountNormal: AccountNormal.DEBIT,
|
accountNormal: AccountNormal.DEBIT,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the discount GL entry.
|
||||||
|
* @param {ISaleReceipt} saleReceipt
|
||||||
|
* @param {number} discountAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getDiscountEntry = (
|
||||||
|
saleReceipt: ISaleReceipt,
|
||||||
|
discountAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getIncomeGLCommonEntry(saleReceipt);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: saleReceipt.discountAmount,
|
||||||
|
accountId: discountAccountId,
|
||||||
|
index: 1,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the adjustment GL entry.
|
||||||
|
* @param {ISaleReceipt} saleReceipt
|
||||||
|
* @param {number} adjustmentAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getAdjustmentEntry = (
|
||||||
|
saleReceipt: ISaleReceipt,
|
||||||
|
adjustmentAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getIncomeGLCommonEntry(saleReceipt);
|
||||||
|
const adjustmentAmount = Math.abs(saleReceipt.adjustment);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: saleReceipt.adjustment < 0 ? adjustmentAmount : 0,
|
||||||
|
credit: saleReceipt.adjustment > 0 ? adjustmentAmount : 0,
|
||||||
|
accountId: adjustmentAccountId,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the income GL entries.
|
* Retrieves the income GL entries.
|
||||||
* @param {ISaleReceipt} saleReceipt -
|
* @param {ISaleReceipt} saleReceipt -
|
||||||
* @returns {ILedgerEntry[]}
|
* @returns {ILedgerEntry[]}
|
||||||
*/
|
*/
|
||||||
private getIncomeGLEntries = (saleReceipt: ISaleReceipt): ILedgerEntry[] => {
|
private getIncomeGLEntries = (
|
||||||
|
saleReceipt: ISaleReceipt,
|
||||||
|
discountAccountId: number,
|
||||||
|
otherChargesAccountId: number
|
||||||
|
): ILedgerEntry[] => {
|
||||||
const getItemEntry = this.getReceiptIncomeItemEntry(saleReceipt);
|
const getItemEntry = this.getReceiptIncomeItemEntry(saleReceipt);
|
||||||
|
|
||||||
const creditEntries = saleReceipt.entries.map(getItemEntry);
|
const creditEntries = saleReceipt.entries.map(getItemEntry);
|
||||||
const depositEntry = this.getReceiptDepositEntry(saleReceipt);
|
const depositEntry = this.getReceiptDepositEntry(saleReceipt);
|
||||||
|
const discountEntry = this.getDiscountEntry(saleReceipt, discountAccountId);
|
||||||
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
saleReceipt,
|
||||||
|
otherChargesAccountId
|
||||||
|
);
|
||||||
|
|
||||||
return [depositEntry, ...creditEntries];
|
return [depositEntry, ...creditEntries, discountEntry, adjustmentEntry];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,17 @@ export class SaleReceiptTransformer extends Transformer {
|
|||||||
return [
|
return [
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
'discountAmountLocalFormatted',
|
||||||
|
|
||||||
'subtotalFormatted',
|
'subtotalFormatted',
|
||||||
'subtotalLocalFormatted',
|
'subtotalLocalFormatted',
|
||||||
|
|
||||||
'totalFormatted',
|
'totalFormatted',
|
||||||
'totalLocalFormatted',
|
'totalLocalFormatted',
|
||||||
|
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'adjustmentLocalFormatted',
|
||||||
|
|
||||||
'formattedAmount',
|
'formattedAmount',
|
||||||
'formattedReceiptDate',
|
'formattedReceiptDate',
|
||||||
'formattedClosedAtDate',
|
'formattedClosedAtDate',
|
||||||
|
|||||||
Reference in New Issue
Block a user