mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
Compare commits
12 Commits
fix-total-
...
v0.22.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baf4c691d6 | ||
|
|
c633fa8522 | ||
|
|
1d54947764 | ||
|
|
477da0e7c0 | ||
|
|
b9963aa241 | ||
|
|
994c441bb8 | ||
|
|
0a5115fc20 | ||
|
|
11d7a40326 | ||
|
|
46719ef361 | ||
|
|
14ae978bde | ||
|
|
beec09788e | ||
|
|
391dc77071 |
@@ -1,3 +1,14 @@
|
|||||||
|
export const OtherExpensesAccount = {
|
||||||
|
name: 'Other Expenses',
|
||||||
|
slug: 'other-expenses',
|
||||||
|
account_type: 'other-expense',
|
||||||
|
code: '40011',
|
||||||
|
description: '',
|
||||||
|
active: 1,
|
||||||
|
index: 1,
|
||||||
|
predefined: 1,
|
||||||
|
};
|
||||||
|
|
||||||
export const TaxPayableAccount = {
|
export const TaxPayableAccount = {
|
||||||
name: 'Tax Payable',
|
name: 'Tax Payable',
|
||||||
slug: 'tax-payable',
|
slug: 'tax-payable',
|
||||||
@@ -39,8 +50,38 @@ export const StripeClearingAccount = {
|
|||||||
code: '100020',
|
code: '100020',
|
||||||
active: true,
|
active: true,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: true,
|
predefined: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const DiscountExpenseAccount = {
|
||||||
|
name: 'Discount',
|
||||||
|
slug: 'discount',
|
||||||
|
account_type: 'other-income',
|
||||||
|
code: '40008',
|
||||||
|
active: true,
|
||||||
|
index: 1,
|
||||||
|
predefined: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PurchaseDiscountAccount = {
|
||||||
|
name: 'Purchase Discount',
|
||||||
|
slug: 'purchase-discount',
|
||||||
|
account_type: 'other-expense',
|
||||||
|
code: '40009',
|
||||||
|
active: true,
|
||||||
|
index: 1,
|
||||||
|
predefined: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OtherChargesAccount = {
|
||||||
|
name: 'Other Charges',
|
||||||
|
slug: 'other-charges',
|
||||||
|
account_type: 'other-income',
|
||||||
|
code: '40010',
|
||||||
|
active: true,
|
||||||
|
index: 1,
|
||||||
|
predefined: true,
|
||||||
|
};
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@@ -231,17 +272,7 @@ export default [
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Expenses
|
// Expenses
|
||||||
{
|
OtherExpensesAccount,
|
||||||
name: 'Other Expenses',
|
|
||||||
slug: 'other-expenses',
|
|
||||||
account_type: 'other-expense',
|
|
||||||
parent_account_id: null,
|
|
||||||
code: '40001',
|
|
||||||
description: '',
|
|
||||||
active: 1,
|
|
||||||
index: 1,
|
|
||||||
predefined: 1,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Cost of Goods Sold',
|
name: 'Cost of Goods Sold',
|
||||||
slug: 'cost-of-goods-sold',
|
slug: 'cost-of-goods-sold',
|
||||||
@@ -358,4 +389,7 @@ export default [
|
|||||||
},
|
},
|
||||||
UnearnedRevenueAccount,
|
UnearnedRevenueAccount,
|
||||||
PrepardExpenses,
|
PrepardExpenses,
|
||||||
|
DiscountExpenseAccount,
|
||||||
|
PurchaseDiscountAccount,
|
||||||
|
OtherChargesAccount,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -80,6 +80,13 @@ export interface ISaleInvoice {
|
|||||||
pdfTemplateId?: number;
|
pdfTemplateId?: number;
|
||||||
|
|
||||||
paymentMethods?: Array<PaymentIntegrationTransactionLink>;
|
paymentMethods?: Array<PaymentIntegrationTransactionLink>;
|
||||||
|
|
||||||
|
adjustment?: number;
|
||||||
|
adjustmentLocal?: number | null;
|
||||||
|
|
||||||
|
discount?: number;
|
||||||
|
discountAmount?: number;
|
||||||
|
discountAmountLocal?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DiscountType {
|
export enum DiscountType {
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ export interface ISaleReceipt {
|
|||||||
discountPercentage?: number | null;
|
discountPercentage?: number | null;
|
||||||
|
|
||||||
adjustment?: number;
|
adjustment?: number;
|
||||||
|
adjustmentLocal?: number | null;
|
||||||
|
|
||||||
|
discountAmountLocal?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesReceiptsFilter {
|
export interface ISalesReceiptsFilter {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Model, raw, mixin } from 'objection';
|
import { Model, raw, mixin } from 'objection';
|
||||||
import { castArray, defaultTo, difference } from 'lodash';
|
import { castArray, defaultTo, difference } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import * as R from 'ramda';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import BillSettings from './Bill.Settings';
|
import BillSettings from './Bill.Settings';
|
||||||
import ModelSetting from './ModelSetting';
|
import ModelSetting from './ModelSetting';
|
||||||
@@ -55,8 +56,11 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
'amountLocal',
|
'amountLocal',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
|
'adjustmentLocal',
|
||||||
|
|
||||||
'subtotal',
|
'subtotal',
|
||||||
'subtotalLocal',
|
'subtotalLocal',
|
||||||
'subtotalExludingTax',
|
'subtotalExludingTax',
|
||||||
@@ -118,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}
|
||||||
@@ -126,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}
|
||||||
@@ -133,12 +154,11 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
return this.isInclusiveTax
|
return R.compose(
|
||||||
? this.subtotal - this.discountAmount - adjustmentAmount
|
R.add(adjustmentAmount),
|
||||||
: this.subtotal +
|
R.subtract(R.__, this.discountAmount),
|
||||||
this.taxAmountWithheld -
|
R.when(R.always(this.isInclusiveTax), R.add(this.taxAmountWithheld))
|
||||||
this.discountAmount -
|
)(this.subtotal);
|
||||||
adjustmentAmount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,7 +124,7 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
return this.subtotal - this.discountAmount - this.adjustment;
|
return this.subtotal - this.discountAmount + this.adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
return this.subtotal - this.discountAmount - adjustmentAmount;
|
return this.subtotal - this.discountAmount + adjustmentAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { mixin, Model, raw } from 'objection';
|
import { mixin, Model, raw } from 'objection';
|
||||||
|
import * as R from 'ramda';
|
||||||
import { castArray, defaultTo, takeWhile } from 'lodash';
|
import { castArray, defaultTo, takeWhile } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
@@ -72,12 +73,14 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
|
|
||||||
'taxAmountWithheldLocal',
|
'taxAmountWithheldLocal',
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|
||||||
'writtenoffAmountLocal',
|
'writtenoffAmountLocal',
|
||||||
|
'adjustmentLocal',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,14 +145,28 @@ 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}
|
||||||
*/
|
*/
|
||||||
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 | null}
|
||||||
|
*/
|
||||||
|
get adjustmentLocal(): number | null {
|
||||||
|
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,11 +175,12 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
const differencies = this.discountAmount + adjustmentAmount;
|
|
||||||
|
|
||||||
return this.isInclusiveTax
|
return R.compose(
|
||||||
? this.subtotal - differencies
|
R.add(adjustmentAmount),
|
||||||
: this.subtotal + this.taxAmountWithheld - differencies;
|
R.subtract(R.__, this.discountAmount),
|
||||||
|
R.when(R.always(this.isInclusiveTax), R.add(this.taxAmountWithheld))
|
||||||
|
)(this.subtotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,9 +49,16 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|
||||||
|
'adjustment',
|
||||||
|
'adjustmentLocal',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
|
'paid',
|
||||||
|
'paidLocal',
|
||||||
|
|
||||||
'isClosed',
|
'isClosed',
|
||||||
'isDraft',
|
'isDraft',
|
||||||
];
|
];
|
||||||
@@ -91,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,7 +121,7 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
||||||
|
|
||||||
return this.subtotal - this.discountAmount - adjustmentAmount;
|
return this.subtotal - this.discountAmount + adjustmentAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,6 +132,30 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
return this.total * this.exchangeRate;
|
return this.total * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjustment amount in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get adjustmentLocal() {
|
||||||
|
return this.adjustment * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt paid amount.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get paid() {
|
||||||
|
return this.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt paid amount in local currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get paidLocal() {
|
||||||
|
return this.paid * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmine whether the sale receipt closed.
|
* Detarmine whether the sale receipt closed.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
|
|||||||
@@ -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,12 +76,20 @@ 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}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
return this.subtotal - this.discountAmount - this.adjustment;
|
return this.subtotal - this.discountAmount + this.adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,8 +196,11 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
'localAmount',
|
'localAmount',
|
||||||
|
|
||||||
'discountAmount',
|
'discountAmount',
|
||||||
|
'discountAmountLocal',
|
||||||
'discountPercentage',
|
'discountPercentage',
|
||||||
|
|
||||||
|
'adjustmentLocal',
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import TenantRepository from '@/repositories/TenantRepository';
|
|||||||
import { IAccount } from '@/interfaces';
|
import { IAccount } from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import {
|
import {
|
||||||
|
DiscountExpenseAccount,
|
||||||
|
OtherChargesAccount,
|
||||||
|
OtherExpensesAccount,
|
||||||
PrepardExpenses,
|
PrepardExpenses,
|
||||||
|
PurchaseDiscountAccount,
|
||||||
StripeClearingAccount,
|
StripeClearingAccount,
|
||||||
TaxPayableAccount,
|
TaxPayableAccount,
|
||||||
UnearnedRevenueAccount,
|
UnearnedRevenueAccount,
|
||||||
@@ -188,9 +192,9 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or creates the unearned revenue.
|
* Finds or creates the unearned revenue.
|
||||||
* @param {Record<string, string>} extraAttrs
|
* @param {Record<string, string>} extraAttrs
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async findOrCreateUnearnedRevenue(
|
public async findOrCreateUnearnedRevenue(
|
||||||
extraAttrs: Record<string, string> = {},
|
extraAttrs: Record<string, string> = {},
|
||||||
@@ -219,9 +223,9 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or creates the prepard expenses account.
|
* Finds or creates the prepard expenses account.
|
||||||
* @param {Record<string, string>} extraAttrs
|
* @param {Record<string, string>} extraAttrs
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async findOrCreatePrepardExpenses(
|
public async findOrCreatePrepardExpenses(
|
||||||
extraAttrs: Record<string, string> = {},
|
extraAttrs: Record<string, string> = {},
|
||||||
@@ -249,12 +253,11 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or creates the stripe clearing account.
|
* Finds or creates the stripe clearing account.
|
||||||
* @param {Record<string, string>} extraAttrs
|
* @param {Record<string, string>} extraAttrs
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async findOrCreateStripeClearing(
|
public async findOrCreateStripeClearing(
|
||||||
extraAttrs: Record<string, string> = {},
|
extraAttrs: Record<string, string> = {},
|
||||||
@@ -281,4 +284,114 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds or creates the discount expense account.
|
||||||
|
* @param {Record<string, string>} extraAttrs
|
||||||
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async findOrCreateDiscountAccount(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
// Retrieves the given tenant metadata.
|
||||||
|
const tenantMeta = await TenantMetadata.query().findOne({
|
||||||
|
tenantId: this.tenantId,
|
||||||
|
});
|
||||||
|
const _extraAttrs = {
|
||||||
|
currencyCode: tenantMeta.baseCurrency,
|
||||||
|
...extraAttrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: DiscountExpenseAccount.slug, ..._extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...DiscountExpenseAccount,
|
||||||
|
..._extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findOrCreatePurchaseDiscountAccount(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
// Retrieves the given tenant metadata.
|
||||||
|
const tenantMeta = await TenantMetadata.query().findOne({
|
||||||
|
tenantId: this.tenantId,
|
||||||
|
});
|
||||||
|
const _extraAttrs = {
|
||||||
|
currencyCode: tenantMeta.baseCurrency,
|
||||||
|
...extraAttrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: PurchaseDiscountAccount.slug, ..._extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...PurchaseDiscountAccount,
|
||||||
|
..._extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findOrCreateOtherChargesAccount(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
// Retrieves the given tenant metadata.
|
||||||
|
const tenantMeta = await TenantMetadata.query().findOne({
|
||||||
|
tenantId: this.tenantId,
|
||||||
|
});
|
||||||
|
const _extraAttrs = {
|
||||||
|
currencyCode: tenantMeta.baseCurrency,
|
||||||
|
...extraAttrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: OtherChargesAccount.slug, ..._extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...OtherChargesAccount,
|
||||||
|
..._extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findOrCreateOtherExpensesAccount(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
// Retrieves the given tenant metadata.
|
||||||
|
const tenantMeta = await TenantMetadata.query().findOne({
|
||||||
|
tenantId: this.tenantId,
|
||||||
|
});
|
||||||
|
const _extraAttrs = {
|
||||||
|
currencyCode: tenantMeta.baseCurrency,
|
||||||
|
...extraAttrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: OtherExpensesAccount.slug, ..._extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...OtherExpensesAccount,
|
||||||
|
..._extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ export default class Ledger implements ILedger {
|
|||||||
return {
|
return {
|
||||||
credit: defaultTo(entry.credit, 0),
|
credit: defaultTo(entry.credit, 0),
|
||||||
debit: defaultTo(entry.debit, 0),
|
debit: defaultTo(entry.debit, 0),
|
||||||
|
|
||||||
exchangeRate: entry.exchangeRate,
|
exchangeRate: entry.exchangeRate,
|
||||||
currencyCode: entry.currencyCode,
|
currencyCode: entry.currencyCode,
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,18 @@ import {
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { transformLedgerEntryToTransaction } from './utils';
|
import { transformLedgerEntryToTransaction } from './utils';
|
||||||
|
|
||||||
|
// Filter the blank entries.
|
||||||
|
const filterBlankEntry = (entry: ILedgerEntry) => Boolean(entry.credit || entry.debit);
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class LedgerEntriesStorage {
|
export class LedgerEntriesStorage {
|
||||||
@Inject()
|
@Inject()
|
||||||
tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
/**
|
/**
|
||||||
* Saves entries of the given ledger.
|
* Saves entries of the given ledger.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {ILedger} ledger
|
* @param {ILedger} ledger
|
||||||
* @param {Knex.Transaction} knex
|
* @param {Knex.Transaction} knex
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public saveEntries = async (
|
public saveEntries = async (
|
||||||
@@ -26,7 +29,7 @@ export class LedgerEntriesStorage {
|
|||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
) => {
|
) => {
|
||||||
const saveEntryQueue = async.queue(this.saveEntryTask, 10);
|
const saveEntryQueue = async.queue(this.saveEntryTask, 10);
|
||||||
const entries = ledger.getEntries();
|
const entries = ledger.filter(filterBlankEntry).getEntries();
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
saveEntryQueue.push({ tenantId, entry, trx });
|
saveEntryQueue.push({ tenantId, entry, trx });
|
||||||
@@ -57,8 +60,8 @@ export class LedgerEntriesStorage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the ledger entry to the account transactions repository.
|
* Saves the ledger entry to the account transactions repository.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {ILedgerEntry} entry
|
* @param {ILedgerEntry} entry
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
private saveEntry = async (
|
private saveEntry = async (
|
||||||
|
|||||||
@@ -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',
|
||||||
];
|
];
|
||||||
@@ -39,7 +46,7 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted created at date.
|
* Retrieve formatted created at date.
|
||||||
* @param credit
|
* @param credit
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected formattedCreatedAt = (credit): string => {
|
protected formattedCreatedAt = (credit): string => {
|
||||||
@@ -90,7 +97,7 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves formatted discount amount.
|
* Retrieves formatted discount amount.
|
||||||
* @param credit
|
* @param credit
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected discountAmountFormatted = (credit): string => {
|
protected discountAmountFormatted = (credit): string => {
|
||||||
@@ -100,20 +107,30 @@ 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}%`
|
|
||||||
: '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves formatted adjustment amount.
|
* Retrieves formatted adjustment amount.
|
||||||
* @param credit
|
* @param credit
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected adjustmentFormatted = (credit): string => {
|
protected adjustmentFormatted = (credit): string => {
|
||||||
@@ -123,9 +140,21 @@ 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
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected totalFormatted = (credit): string => {
|
protected totalFormatted = (credit): string => {
|
||||||
@@ -136,7 +165,7 @@ export class CreditNoteTransformer extends Transformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the formatted total in local currency.
|
* Retrieves the formatted total in local currency.
|
||||||
* @param credit
|
* @param credit
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected totalLocalFormatted = (credit): string => {
|
protected totalLocalFormatted = (credit): string => {
|
||||||
|
|||||||
@@ -52,10 +52,18 @@ export class BillGLEntries {
|
|||||||
{},
|
{},
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
|
// Find or create other expenses account.
|
||||||
|
const otherExpensesAccount =
|
||||||
|
await accountRepository.findOrCreateOtherExpensesAccount({}, trx);
|
||||||
|
// Find or create purchase discount account.
|
||||||
|
const purchaseDiscountAccount =
|
||||||
|
await accountRepository.findOrCreatePurchaseDiscountAccount({}, trx);
|
||||||
const billLedger = this.getBillLedger(
|
const billLedger = this.getBillLedger(
|
||||||
bill,
|
bill,
|
||||||
APAccount.id,
|
APAccount.id,
|
||||||
taxPayableAccount.id
|
taxPayableAccount.id,
|
||||||
|
purchaseDiscountAccount.id,
|
||||||
|
otherExpensesAccount.id
|
||||||
);
|
);
|
||||||
// Commit the GL enties on the storage.
|
// Commit the GL enties on the storage.
|
||||||
await this.ledgerStorage.commit(tenantId, billLedger, trx);
|
await this.ledgerStorage.commit(tenantId, billLedger, trx);
|
||||||
@@ -102,6 +110,7 @@ export class BillGLEntries {
|
|||||||
return {
|
return {
|
||||||
debit: 0,
|
debit: 0,
|
||||||
credit: 0,
|
credit: 0,
|
||||||
|
|
||||||
currencyCode: bill.currencyCode,
|
currencyCode: bill.currencyCode,
|
||||||
exchangeRate: bill.exchangeRate || 1,
|
exchangeRate: bill.exchangeRate || 1,
|
||||||
|
|
||||||
@@ -240,6 +249,52 @@ export class BillGLEntries {
|
|||||||
return nonZeroTaxEntries.map(transformTaxEntry);
|
return nonZeroTaxEntries.map(transformTaxEntry);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the purchase discount GL entry.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @param {number} purchaseDiscountAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getPurchaseDiscountEntry = (
|
||||||
|
bill: IBill,
|
||||||
|
purchaseDiscountAccountId: number
|
||||||
|
) => {
|
||||||
|
const commonEntry = this.getBillCommonEntry(bill);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: bill.discountAmountLocal,
|
||||||
|
accountId: purchaseDiscountAccountId,
|
||||||
|
accountNormal: AccountNormal.DEBIT,
|
||||||
|
index: 1,
|
||||||
|
indexGroup: 40,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the purchase other charges GL entry.
|
||||||
|
* @param {IBill} bill
|
||||||
|
* @param {number} otherChargesAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getAdjustmentEntry = (
|
||||||
|
bill: IBill,
|
||||||
|
otherExpensesAccountId: number
|
||||||
|
) => {
|
||||||
|
const commonEntry = this.getBillCommonEntry(bill);
|
||||||
|
const adjustmentAmount = Math.abs(bill.adjustmentLocal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: bill.adjustmentLocal > 0 ? adjustmentAmount : 0,
|
||||||
|
credit: bill.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||||
|
accountId: otherExpensesAccountId,
|
||||||
|
accountNormal: AccountNormal.DEBIT,
|
||||||
|
index: 1,
|
||||||
|
indexGroup: 40,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the given bill GL entries.
|
* Retrieves the given bill GL entries.
|
||||||
* @param {IBill} bill
|
* @param {IBill} bill
|
||||||
@@ -249,7 +304,9 @@ export class BillGLEntries {
|
|||||||
private getBillGLEntries = (
|
private getBillGLEntries = (
|
||||||
bill: IBill,
|
bill: IBill,
|
||||||
payableAccountId: number,
|
payableAccountId: number,
|
||||||
taxPayableAccountId: number
|
taxPayableAccountId: number,
|
||||||
|
purchaseDiscountAccountId: number,
|
||||||
|
otherExpensesAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const payableEntry = this.getBillPayableEntry(payableAccountId, bill);
|
const payableEntry = this.getBillPayableEntry(payableAccountId, bill);
|
||||||
|
|
||||||
@@ -262,8 +319,24 @@ export class BillGLEntries {
|
|||||||
);
|
);
|
||||||
const taxEntries = this.getBillTaxEntries(bill, taxPayableAccountId);
|
const taxEntries = this.getBillTaxEntries(bill, taxPayableAccountId);
|
||||||
|
|
||||||
|
const purchaseDiscountEntry = this.getPurchaseDiscountEntry(
|
||||||
|
bill,
|
||||||
|
purchaseDiscountAccountId
|
||||||
|
);
|
||||||
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
bill,
|
||||||
|
otherExpensesAccountId
|
||||||
|
);
|
||||||
|
|
||||||
// Allocate cost entries journal entries.
|
// Allocate cost entries journal entries.
|
||||||
return [payableEntry, ...itemsEntries, ...landedCostEntries, ...taxEntries];
|
return [
|
||||||
|
payableEntry,
|
||||||
|
...itemsEntries,
|
||||||
|
...landedCostEntries,
|
||||||
|
...taxEntries,
|
||||||
|
purchaseDiscountEntry,
|
||||||
|
adjustmentEntry,
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,14 +348,17 @@ export class BillGLEntries {
|
|||||||
private getBillLedger = (
|
private getBillLedger = (
|
||||||
bill: IBill,
|
bill: IBill,
|
||||||
payableAccountId: number,
|
payableAccountId: number,
|
||||||
taxPayableAccountId: number
|
taxPayableAccountId: number,
|
||||||
|
purchaseDiscountAccountId: number,
|
||||||
|
otherExpensesAccountId: number
|
||||||
) => {
|
) => {
|
||||||
const entries = this.getBillGLEntries(
|
const entries = this.getBillGLEntries(
|
||||||
bill,
|
bill,
|
||||||
payableAccountId,
|
payableAccountId,
|
||||||
taxPayableAccountId
|
taxPayableAccountId,
|
||||||
|
purchaseDiscountAccountId,
|
||||||
|
otherExpensesAccountId
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Ledger(entries);
|
return new Ledger(entries);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default class VendorCreditGLEntries {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntity,
|
...commonEntity,
|
||||||
debit: vendorCredit.localAmount,
|
debit: vendorCredit.totalLocal,
|
||||||
accountId: APAccountId,
|
accountId: APAccountId,
|
||||||
contactId: vendorCredit.vendorId,
|
contactId: vendorCredit.vendorId,
|
||||||
accountNormal: AccountNormal.CREDIT,
|
accountNormal: AccountNormal.CREDIT,
|
||||||
@@ -94,6 +94,52 @@ export default class VendorCreditGLEntries {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the vendor credit discount GL entry.
|
||||||
|
* @param {IVendorCredit} vendorCredit
|
||||||
|
* @param {number} discountAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
public getDiscountEntry = (
|
||||||
|
vendorCredit: IVendorCredit,
|
||||||
|
purchaseDiscountAccountId: number
|
||||||
|
) => {
|
||||||
|
const commonEntry = this.getVendorCreditGLCommonEntry(vendorCredit);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: vendorCredit.discountAmountLocal,
|
||||||
|
accountId: purchaseDiscountAccountId,
|
||||||
|
accountNormal: AccountNormal.DEBIT,
|
||||||
|
index: 1,
|
||||||
|
indexGroup: 40,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the vendor credit adjustment GL entry.
|
||||||
|
* @param {IVendorCredit} vendorCredit
|
||||||
|
* @param {number} adjustmentAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
public getAdjustmentEntry = (
|
||||||
|
vendorCredit: IVendorCredit,
|
||||||
|
otherExpensesAccountId: number
|
||||||
|
) => {
|
||||||
|
const commonEntry = this.getVendorCreditGLCommonEntry(vendorCredit);
|
||||||
|
const adjustmentAmount = Math.abs(vendorCredit.adjustmentLocal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: vendorCredit.adjustmentLocal > 0 ? adjustmentAmount : 0,
|
||||||
|
debit: vendorCredit.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||||
|
accountId: otherExpensesAccountId,
|
||||||
|
accountNormal: AccountNormal.DEBIT,
|
||||||
|
index: 1,
|
||||||
|
indexGroup: 40,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the vendor credit GL entries.
|
* Retrieve the vendor credit GL entries.
|
||||||
* @param {IVendorCredit} vendorCredit -
|
* @param {IVendorCredit} vendorCredit -
|
||||||
@@ -102,7 +148,9 @@ export default class VendorCreditGLEntries {
|
|||||||
*/
|
*/
|
||||||
public getVendorCreditGLEntries = (
|
public getVendorCreditGLEntries = (
|
||||||
vendorCredit: IVendorCredit,
|
vendorCredit: IVendorCredit,
|
||||||
payableAccountId: number
|
payableAccountId: number,
|
||||||
|
purchaseDiscountAccountId: number,
|
||||||
|
otherExpensesAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const payableEntry = this.getVendorCreditPayableGLEntry(
|
const payableEntry = this.getVendorCreditPayableGLEntry(
|
||||||
vendorCredit,
|
vendorCredit,
|
||||||
@@ -111,7 +159,15 @@ export default class VendorCreditGLEntries {
|
|||||||
const getItemEntry = this.getVendorCreditGLItemEntry(vendorCredit);
|
const getItemEntry = this.getVendorCreditGLItemEntry(vendorCredit);
|
||||||
const itemsEntries = vendorCredit.entries.map(getItemEntry);
|
const itemsEntries = vendorCredit.entries.map(getItemEntry);
|
||||||
|
|
||||||
return [payableEntry, ...itemsEntries];
|
const discountEntry = this.getDiscountEntry(
|
||||||
|
vendorCredit,
|
||||||
|
purchaseDiscountAccountId
|
||||||
|
);
|
||||||
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
vendorCredit,
|
||||||
|
otherExpensesAccountId
|
||||||
|
);
|
||||||
|
return [payableEntry, discountEntry, adjustmentEntry, ...itemsEntries];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,10 +214,17 @@ export default class VendorCreditGLEntries {
|
|||||||
{},
|
{},
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
|
const purchaseDiscountAccount =
|
||||||
|
await accountRepository.findOrCreatePurchaseDiscountAccount({}, trx);
|
||||||
|
|
||||||
|
const otherExpensesAccount =
|
||||||
|
await accountRepository.findOrCreateOtherExpensesAccount({}, trx);
|
||||||
// Saves the vendor credit GL entries.
|
// Saves the vendor credit GL entries.
|
||||||
const ledgerEntries = this.getVendorCreditGLEntries(
|
const ledgerEntries = this.getVendorCreditGLEntries(
|
||||||
vendorCredit,
|
vendorCredit,
|
||||||
APAccount.id
|
APAccount.id,
|
||||||
|
purchaseDiscountAccount.id,
|
||||||
|
otherExpensesAccount.id
|
||||||
);
|
);
|
||||||
const ledger = new Ledger(ledgerEntries);
|
const ledger = new Ledger(ledgerEntries);
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,15 @@ export class VendorCreditTransformer extends Transformer {
|
|||||||
'formattedCreatedAt',
|
'formattedCreatedAt',
|
||||||
'formattedCreditsRemaining',
|
'formattedCreditsRemaining',
|
||||||
'formattedInvoicedAmount',
|
'formattedInvoicedAmount',
|
||||||
|
|
||||||
'discountAmountFormatted',
|
'discountAmountFormatted',
|
||||||
'discountPercentageFormatted',
|
'discountPercentageFormatted',
|
||||||
|
'discountAmountLocalFormatted',
|
||||||
|
|
||||||
'adjustmentFormatted',
|
'adjustmentFormatted',
|
||||||
|
'adjustmentLocalFormatted',
|
||||||
|
|
||||||
|
'totalFormatted',
|
||||||
'entries',
|
'entries',
|
||||||
'attachments',
|
'attachments',
|
||||||
];
|
];
|
||||||
@@ -86,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
|
||||||
@@ -107,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
|
||||||
@@ -118,6 +148,15 @@ export class VendorCreditTransformer extends Transformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted total.
|
||||||
|
* @param {IVendorCredit} credit
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected totalFormatted = (credit) => {
|
||||||
|
return formatNumber(credit.total, { currencyCode: credit.currencyCode });
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the entries of the bill.
|
* Retrieves the entries of the bill.
|
||||||
* @param {IVendorCredit} vendorCredit
|
* @param {IVendorCredit} vendorCredit
|
||||||
|
|||||||
@@ -44,18 +44,31 @@ export class SaleInvoiceGLEntries {
|
|||||||
|
|
||||||
// Find or create the A/R account.
|
// Find or create the A/R account.
|
||||||
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
||||||
saleInvoice.currencyCode, {}, trx
|
saleInvoice.currencyCode,
|
||||||
|
{},
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
// Find or create tax payable account.
|
// Find or create tax payable account.
|
||||||
const taxPayableAccount = await accountRepository.findOrCreateTaxPayable(
|
const taxPayableAccount = await accountRepository.findOrCreateTaxPayable(
|
||||||
{},
|
{},
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
|
// 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);
|
||||||
|
|
||||||
// Retrieves the ledger of the invoice.
|
// Retrieves the ledger of the invoice.
|
||||||
const ledger = this.getInvoiceGLedger(
|
const ledger = this.getInvoiceGLedger(
|
||||||
saleInvoice,
|
saleInvoice,
|
||||||
ARAccount.id,
|
ARAccount.id,
|
||||||
taxPayableAccount.id
|
taxPayableAccount.id,
|
||||||
|
discountAccount.id,
|
||||||
|
otherChargesAccount.id
|
||||||
);
|
);
|
||||||
// Commits the ledger entries to the storage as UOW.
|
// Commits the ledger entries to the storage as UOW.
|
||||||
await this.ledegrRepository.commit(tenantId, ledger, trx);
|
await this.ledegrRepository.commit(tenantId, ledger, trx);
|
||||||
@@ -107,12 +120,16 @@ export class SaleInvoiceGLEntries {
|
|||||||
public getInvoiceGLedger = (
|
public getInvoiceGLedger = (
|
||||||
saleInvoice: ISaleInvoice,
|
saleInvoice: ISaleInvoice,
|
||||||
ARAccountId: number,
|
ARAccountId: number,
|
||||||
taxPayableAccountId: number
|
taxPayableAccountId: number,
|
||||||
|
discountAccountId: number,
|
||||||
|
otherChargesAccountId: number
|
||||||
): ILedger => {
|
): ILedger => {
|
||||||
const entries = this.getInvoiceGLEntries(
|
const entries = this.getInvoiceGLEntries(
|
||||||
saleInvoice,
|
saleInvoice,
|
||||||
ARAccountId,
|
ARAccountId,
|
||||||
taxPayableAccountId
|
taxPayableAccountId,
|
||||||
|
discountAccountId,
|
||||||
|
otherChargesAccountId
|
||||||
);
|
);
|
||||||
return new Ledger(entries);
|
return new Ledger(entries);
|
||||||
};
|
};
|
||||||
@@ -127,6 +144,7 @@ export class SaleInvoiceGLEntries {
|
|||||||
): Partial<ILedgerEntry> => ({
|
): Partial<ILedgerEntry> => ({
|
||||||
credit: 0,
|
credit: 0,
|
||||||
debit: 0,
|
debit: 0,
|
||||||
|
|
||||||
currencyCode: saleInvoice.currencyCode,
|
currencyCode: saleInvoice.currencyCode,
|
||||||
exchangeRate: saleInvoice.exchangeRate,
|
exchangeRate: saleInvoice.exchangeRate,
|
||||||
|
|
||||||
@@ -249,6 +267,50 @@ export class SaleInvoiceGLEntries {
|
|||||||
return nonZeroTaxEntries.map(transformTaxEntry);
|
return nonZeroTaxEntries.map(transformTaxEntry);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the invoice discount GL entry.
|
||||||
|
* @param {ISaleInvoice} saleInvoice
|
||||||
|
* @param {number} discountAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getInvoiceDiscountEntry = (
|
||||||
|
saleInvoice: ISaleInvoice,
|
||||||
|
discountAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: saleInvoice.discountAmountLocal,
|
||||||
|
accountId: discountAccountId,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
index: 1,
|
||||||
|
} as ILedgerEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the invoice adjustment GL entry.
|
||||||
|
* @param {ISaleInvoice} saleInvoice
|
||||||
|
* @param {number} adjustmentAccountId
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getAdjustmentEntry = (
|
||||||
|
saleInvoice: ISaleInvoice,
|
||||||
|
otherChargesAccountId: number
|
||||||
|
): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
||||||
|
const adjustmentAmount = Math.abs(saleInvoice.adjustmentLocal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: saleInvoice.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||||
|
credit: saleInvoice.adjustmentLocal > 0 ? adjustmentAmount : 0,
|
||||||
|
accountId: otherChargesAccountId,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the invoice GL entries.
|
* Retrieves the invoice GL entries.
|
||||||
* @param {ISaleInvoice} saleInvoice
|
* @param {ISaleInvoice} saleInvoice
|
||||||
@@ -258,7 +320,9 @@ export class SaleInvoiceGLEntries {
|
|||||||
public getInvoiceGLEntries = (
|
public getInvoiceGLEntries = (
|
||||||
saleInvoice: ISaleInvoice,
|
saleInvoice: ISaleInvoice,
|
||||||
ARAccountId: number,
|
ARAccountId: number,
|
||||||
taxPayableAccountId: number
|
taxPayableAccountId: number,
|
||||||
|
discountAccountId: number,
|
||||||
|
otherChargesAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const receivableEntry = this.getInvoiceReceivableEntry(
|
const receivableEntry = this.getInvoiceReceivableEntry(
|
||||||
saleInvoice,
|
saleInvoice,
|
||||||
@@ -271,6 +335,20 @@ export class SaleInvoiceGLEntries {
|
|||||||
saleInvoice,
|
saleInvoice,
|
||||||
taxPayableAccountId
|
taxPayableAccountId
|
||||||
);
|
);
|
||||||
return [receivableEntry, ...creditEntries, ...taxEntries];
|
const discountEntry = this.getInvoiceDiscountEntry(
|
||||||
|
saleInvoice,
|
||||||
|
discountAccountId
|
||||||
|
);
|
||||||
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
saleInvoice,
|
||||||
|
otherChargesAccountId
|
||||||
|
);
|
||||||
|
return [
|
||||||
|
receivableEntry,
|
||||||
|
...creditEntries,
|
||||||
|
...taxEntries,
|
||||||
|
discountEntry,
|
||||||
|
adjustmentEntry,
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,76 @@ 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.discountAmountLocal,
|
||||||
|
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.adjustmentLocal);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
debit: saleReceipt.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||||
|
credit: saleReceipt.adjustmentLocal > 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);
|
||||||
return [depositEntry, ...creditEntries];
|
const adjustmentEntry = this.getAdjustmentEntry(
|
||||||
|
saleReceipt,
|
||||||
|
otherChargesAccountId
|
||||||
|
);
|
||||||
|
return [depositEntry, ...creditEntries, discountEntry, adjustmentEntry];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,22 @@ 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',
|
||||||
'formattedCreatedAt',
|
'formattedCreatedAt',
|
||||||
|
'paidFormatted',
|
||||||
'entries',
|
'entries',
|
||||||
'attachments',
|
'attachments',
|
||||||
];
|
];
|
||||||
@@ -130,6 +137,18 @@ export class SaleReceiptTransformer extends Transformer {
|
|||||||
return receipt.discountPercentage ? `${receipt.discountPercentage}%` : '';
|
return receipt.discountPercentage ? `${receipt.discountPercentage}%` : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves formatted paid amount.
|
||||||
|
* @param receipt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
protected paidFormatted = (receipt: ISaleReceipt): string => {
|
||||||
|
return formatNumber(receipt.paid, {
|
||||||
|
currencyCode: receipt.currencyCode,
|
||||||
|
excerptZero: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves formatted adjustment amount.
|
* Retrieves formatted adjustment amount.
|
||||||
* @param receipt
|
* @param receipt
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function BillDetailTableFooter() {
|
|||||||
textStyle={TotalLineTextStyle.Regular}
|
textStyle={TotalLineTextStyle.Regular}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{bill.adjustment > 0 && (
|
{bill.adjustment_formatted && (
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={'Adjustment'}
|
title={'Adjustment'}
|
||||||
value={bill.adjustment_formatted}
|
value={bill.adjustment_formatted}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default function CreditNoteDetailTableFooter() {
|
|||||||
value={creditNote.discount_amount_formatted}
|
value={creditNote.discount_amount_formatted}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{creditNote.adjustment > 0 && (
|
{creditNote.adjustment_formatted && (
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={'Adjustment'}
|
title={'Adjustment'}
|
||||||
value={creditNote.adjustment_formatted}
|
value={creditNote.adjustment_formatted}
|
||||||
|
|||||||
@@ -5,14 +5,12 @@ import styled from 'styled-components';
|
|||||||
import { defaultTo } from 'lodash';
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ButtonLink,
|
|
||||||
CustomerDrawerLink,
|
CustomerDrawerLink,
|
||||||
CommercialDocHeader,
|
CommercialDocHeader,
|
||||||
CommercialDocTopHeader,
|
CommercialDocTopHeader,
|
||||||
ExchangeRateDetailItem,
|
ExchangeRateDetailItem,
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
FormatDate,
|
|
||||||
DetailsMenu,
|
DetailsMenu,
|
||||||
DetailItem,
|
DetailItem,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
@@ -66,6 +64,7 @@ export default function ReceiptDetailHeader() {
|
|||||||
/>
|
/>
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu
|
<DetailsMenu
|
||||||
direction={'horizantal'}
|
direction={'horizantal'}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
TotalLine,
|
TotalLine,
|
||||||
TotalLineBorderStyle,
|
TotalLineBorderStyle,
|
||||||
TotalLineTextStyle,
|
TotalLineTextStyle,
|
||||||
FormatNumber,
|
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ export default function ReceiptDetailTableFooter() {
|
|||||||
textStyle={TotalLineTextStyle.Regular}
|
textStyle={TotalLineTextStyle.Regular}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{receipt.adjustment > 0 && (
|
{receipt.adjustment_formatted && (
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={'Adjustment'}
|
title={'Adjustment'}
|
||||||
value={receipt.adjustment_formatted}
|
value={receipt.adjustment_formatted}
|
||||||
@@ -51,8 +50,8 @@ export default function ReceiptDetailTableFooter() {
|
|||||||
/>
|
/>
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'receipt.details.payment_amount'} />}
|
title={<T id={'receipt.details.payment_amount'} />}
|
||||||
value={receipt.formatted_amount}
|
value={receipt.paid_formatted}
|
||||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||||
/>
|
/>
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'receipt.details.due_amount'} />}
|
title={<T id={'receipt.details.due_amount'} />}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default function VendorCreditDetailDrawerFooter() {
|
|||||||
)}
|
)}
|
||||||
<TotalLine
|
<TotalLine
|
||||||
title={<T id={'vendor_credit.drawer.label_total'} />}
|
title={<T id={'vendor_credit.drawer.label_total'} />}
|
||||||
value={vendorCredit.formatted_amount}
|
value={vendorCredit.total_formatted}
|
||||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||||
textStyle={TotalLineTextStyle.Bold}
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import styled from 'styled-components';
|
|||||||
import { defaultTo } from 'lodash';
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormatDate,
|
|
||||||
T,
|
T,
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
@@ -29,13 +28,14 @@ export default function VendorCreditDetailHeader() {
|
|||||||
<CommercialDocTopHeader>
|
<CommercialDocTopHeader>
|
||||||
<DetailsMenu>
|
<DetailsMenu>
|
||||||
<AmountItem label={intl.get('amount')}>
|
<AmountItem label={intl.get('amount')}>
|
||||||
<span class="big-number">{vendorCredit.formatted_amount}</span>
|
<span class="big-number">{vendorCredit.total_formatted}</span>
|
||||||
</AmountItem>
|
</AmountItem>
|
||||||
<StatusItem>
|
<StatusItem>
|
||||||
<VendorCreditDetailsStatus vendorCredit={vendorCredit} />
|
<VendorCreditDetailsStatus vendorCredit={vendorCredit} />
|
||||||
</StatusItem>
|
</StatusItem>
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</CommercialDocTopHeader>
|
</CommercialDocTopHeader>
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ export const useBillTotal = () => {
|
|||||||
return R.compose(
|
return R.compose(
|
||||||
R.when(R.always(isExclusiveTax), R.add(totalTaxAmount)),
|
R.when(R.always(isExclusiveTax), R.add(totalTaxAmount)),
|
||||||
R.subtract(R.__, discountAmount),
|
R.subtract(R.__, discountAmount),
|
||||||
R.subtract(R.__, adjustmentAmount),
|
R.add(R.__, adjustmentAmount),
|
||||||
)(subtotal);
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -259,7 +259,10 @@ export const useVendorCreditTotal = () => {
|
|||||||
const discountAmount = useVendorCreditDiscountAmount();
|
const discountAmount = useVendorCreditDiscountAmount();
|
||||||
const adjustment = useVendorCreditAdjustment();
|
const adjustment = useVendorCreditAdjustment();
|
||||||
|
|
||||||
return subtotal - discountAmount - adjustment;
|
return R.compose(
|
||||||
|
R.subtract(R.__, discountAmount),
|
||||||
|
R.add(R.__, adjustment),
|
||||||
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -263,7 +263,10 @@ export const useCreditNoteTotal = () => {
|
|||||||
const discountAmount = useCreditNoteDiscountAmount();
|
const discountAmount = useCreditNoteDiscountAmount();
|
||||||
const adjustmentAmount = useCreditNoteAdjustmentAmount();
|
const adjustmentAmount = useCreditNoteAdjustmentAmount();
|
||||||
|
|
||||||
return subtotal - discountAmount - adjustmentAmount;
|
return R.compose(
|
||||||
|
R.subtract(R.__, discountAmount),
|
||||||
|
R.add(R.__, adjustmentAmount),
|
||||||
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -299,7 +299,10 @@ export const useEstimateTotal = () => {
|
|||||||
const discount = useEstimateDiscount();
|
const discount = useEstimateDiscount();
|
||||||
const adjustment = useEstimateAdjustment();
|
const adjustment = useEstimateAdjustment();
|
||||||
|
|
||||||
return subtotal - discount - adjustment;
|
return R.compose(
|
||||||
|
R.subtract(R.__, discount),
|
||||||
|
R.add(R.__, adjustment),
|
||||||
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ export const useInvoiceTotal = () => {
|
|||||||
return R.compose(
|
return R.compose(
|
||||||
R.when(R.always(isExclusiveTax), R.add(totalTaxAmount)),
|
R.when(R.always(isExclusiveTax), R.add(totalTaxAmount)),
|
||||||
R.subtract(R.__, discountAmount),
|
R.subtract(R.__, discountAmount),
|
||||||
R.subtract(R.__, adjustmentAmount),
|
R.add(adjustmentAmount),
|
||||||
)(subtotal);
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,10 @@ export const useReceiptTotal = () => {
|
|||||||
const adjustmentAmount = useReceiptAdjustmentAmount();
|
const adjustmentAmount = useReceiptAdjustmentAmount();
|
||||||
const discountAmount = useReceiptDiscountAmount();
|
const discountAmount = useReceiptDiscountAmount();
|
||||||
|
|
||||||
return subtotal - discountAmount - adjustmentAmount;
|
return R.compose(
|
||||||
|
R.add(R.__, adjustmentAmount),
|
||||||
|
R.subtract(R.__, discountAmount),
|
||||||
|
)(subtotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user