mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat(server): wip tax rate on sale invoice service
This commit is contained in:
@@ -11,14 +11,25 @@ exports.up = (knex) => {
|
|||||||
table.timestamps();
|
table.timestamps();
|
||||||
})
|
})
|
||||||
.table('items_entries', (table) => {
|
.table('items_entries', (table) => {
|
||||||
table.boolean(['is_tax_exclusive']);
|
table.boolean('is_tax_exclusive');
|
||||||
table.string('tax_code');
|
table.string('tax_code');
|
||||||
table.decimal('tax_rate');
|
table.decimal('tax_rate');
|
||||||
table.decimal('tax_amount_withheld')
|
|
||||||
})
|
})
|
||||||
.table('sales_invoices', (table) => {
|
.table('sales_invoices', (table) => {
|
||||||
table.boolean(['is_tax_exclusive']);
|
table.boolean('is_tax_exclusive');
|
||||||
table.decimal('tax_amount_withheld')
|
table.decimal('tax_amount_withheld');
|
||||||
|
})
|
||||||
|
.createTable('tax_rate_transactions', (table) => {
|
||||||
|
table.increments('id');
|
||||||
|
|
||||||
|
table.string('tax_name');
|
||||||
|
table.string('tax_code');
|
||||||
|
|
||||||
|
table.string('reference_type');
|
||||||
|
table.integer('reference_id');
|
||||||
|
|
||||||
|
table.decimal('tax_amount');
|
||||||
|
table.integer('tax_account_id').unsigned();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
|
export const TaxPayableAccount = {
|
||||||
|
name: 'Tax Payable',
|
||||||
|
slug: 'tax-payable',
|
||||||
|
account_type: 'other-current-liability',
|
||||||
|
code: '20006',
|
||||||
|
description: '',
|
||||||
|
active: 1,
|
||||||
|
index: 1,
|
||||||
|
predefined: 1,
|
||||||
|
};
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name:'Bank Account',
|
name: 'Bank Account',
|
||||||
slug: 'bank-account',
|
slug: 'bank-account',
|
||||||
account_type: 'bank',
|
account_type: 'bank',
|
||||||
code: '10001',
|
code: '10001',
|
||||||
@@ -11,7 +21,7 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Saving Bank Account',
|
name: 'Saving Bank Account',
|
||||||
slug: 'saving-bank-account',
|
slug: 'saving-bank-account',
|
||||||
account_type: 'bank',
|
account_type: 'bank',
|
||||||
code: '10002',
|
code: '10002',
|
||||||
@@ -21,7 +31,7 @@ export default [
|
|||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Undeposited Funds',
|
name: 'Undeposited Funds',
|
||||||
slug: 'undeposited-funds',
|
slug: 'undeposited-funds',
|
||||||
account_type: 'cash',
|
account_type: 'cash',
|
||||||
code: '10003',
|
code: '10003',
|
||||||
@@ -31,7 +41,7 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Petty Cash',
|
name: 'Petty Cash',
|
||||||
slug: 'petty-cash',
|
slug: 'petty-cash',
|
||||||
account_type: 'cash',
|
account_type: 'cash',
|
||||||
code: '10004',
|
code: '10004',
|
||||||
@@ -41,7 +51,7 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Computer Equipment',
|
name: 'Computer Equipment',
|
||||||
slug: 'computer-equipment',
|
slug: 'computer-equipment',
|
||||||
code: '10005',
|
code: '10005',
|
||||||
account_type: 'fixed-asset',
|
account_type: 'fixed-asset',
|
||||||
@@ -52,7 +62,7 @@ export default [
|
|||||||
description: '',
|
description: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Office Equipment',
|
name: 'Office Equipment',
|
||||||
slug: 'office-equipment',
|
slug: 'office-equipment',
|
||||||
code: '10006',
|
code: '10006',
|
||||||
account_type: 'fixed-asset',
|
account_type: 'fixed-asset',
|
||||||
@@ -63,7 +73,7 @@ export default [
|
|||||||
description: '',
|
description: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Accounts Receivable (A/R)',
|
name: 'Accounts Receivable (A/R)',
|
||||||
slug: 'accounts-receivable',
|
slug: 'accounts-receivable',
|
||||||
account_type: 'accounts-receivable',
|
account_type: 'accounts-receivable',
|
||||||
code: '10007',
|
code: '10007',
|
||||||
@@ -73,7 +83,7 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Inventory Asset',
|
name: 'Inventory Asset',
|
||||||
slug: 'inventory-asset',
|
slug: 'inventory-asset',
|
||||||
code: '10008',
|
code: '10008',
|
||||||
account_type: 'inventory',
|
account_type: 'inventory',
|
||||||
@@ -81,12 +91,13 @@ export default [
|
|||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
index: 1,
|
index: 1,
|
||||||
active: 1,
|
active: 1,
|
||||||
description:'An account that holds valuation of products or goods that availiable for sale.',
|
description:
|
||||||
|
'An account that holds valuation of products or goods that availiable for sale.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Libilities
|
// Libilities
|
||||||
{
|
{
|
||||||
name:'Accounts Payable (A/P)',
|
name: 'Accounts Payable (A/P)',
|
||||||
slug: 'accounts-payable',
|
slug: 'accounts-payable',
|
||||||
account_type: 'accounts-payable',
|
account_type: 'accounts-payable',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -97,38 +108,39 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Owner A Drawings',
|
name: 'Owner A Drawings',
|
||||||
slug: 'owner-drawings',
|
slug: 'owner-drawings',
|
||||||
account_type: 'other-current-liability',
|
account_type: 'other-current-liability',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
code: '20002',
|
code: '20002',
|
||||||
description:'Withdrawals by the owners.',
|
description: 'Withdrawals by the owners.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Loan',
|
name: 'Loan',
|
||||||
slug: 'owner-drawings',
|
slug: 'owner-drawings',
|
||||||
account_type: 'other-current-liability',
|
account_type: 'other-current-liability',
|
||||||
code: '20003',
|
code: '20003',
|
||||||
description:'Money that has been borrowed from a creditor.',
|
description: 'Money that has been borrowed from a creditor.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Opening Balance Liabilities',
|
name: 'Opening Balance Liabilities',
|
||||||
slug: 'opening-balance-liabilities',
|
slug: 'opening-balance-liabilities',
|
||||||
account_type: 'other-current-liability',
|
account_type: 'other-current-liability',
|
||||||
code: '20004',
|
code: '20004',
|
||||||
description:'This account will hold the difference in the debits and credits entered during the opening balance..',
|
description:
|
||||||
|
'This account will hold the difference in the debits and credits entered during the opening balance..',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Revenue Received in Advance',
|
name: 'Revenue Received in Advance',
|
||||||
slug: 'revenue-received-in-advance',
|
slug: 'revenue-received-in-advance',
|
||||||
account_type: 'other-current-liability',
|
account_type: 'other-current-liability',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -138,34 +150,27 @@ export default [
|
|||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
TaxPayableAccount,
|
||||||
name:'Sales Tax Payable',
|
|
||||||
slug: 'owner-drawings',
|
|
||||||
account_type: 'other-current-liability',
|
|
||||||
code: '20006',
|
|
||||||
description: '',
|
|
||||||
active: 1,
|
|
||||||
index: 1,
|
|
||||||
predefined: 1,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Equity
|
// Equity
|
||||||
{
|
{
|
||||||
name:'Retained Earnings',
|
name: 'Retained Earnings',
|
||||||
slug: 'retained-earnings',
|
slug: 'retained-earnings',
|
||||||
account_type: 'equity',
|
account_type: 'equity',
|
||||||
code: '30001',
|
code: '30001',
|
||||||
description:'Retained earnings tracks net income from previous fiscal years.',
|
description:
|
||||||
|
'Retained earnings tracks net income from previous fiscal years.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Opening Balance Equity',
|
name: 'Opening Balance Equity',
|
||||||
slug: 'opening-balance-equity',
|
slug: 'opening-balance-equity',
|
||||||
account_type: 'equity',
|
account_type: 'equity',
|
||||||
code: '30002',
|
code: '30002',
|
||||||
description:'When you enter opening balances to the accounts, the amounts enter in Opening balance equity. This ensures that you have a correct trial balance sheet for your company, without even specific the second credit or debit entry.',
|
description:
|
||||||
|
'When you enter opening balances to the accounts, the amounts enter in Opening balance equity. This ensures that you have a correct trial balance sheet for your company, without even specific the second credit or debit entry.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
@@ -181,11 +186,12 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:`Drawings`,
|
name: `Drawings`,
|
||||||
slug: 'drawings',
|
slug: 'drawings',
|
||||||
account_type: 'equity',
|
account_type: 'equity',
|
||||||
code: '30003',
|
code: '30003',
|
||||||
description:'Goods purchased with the intention of selling these to customers',
|
description:
|
||||||
|
'Goods purchased with the intention of selling these to customers',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
@@ -193,7 +199,7 @@ export default [
|
|||||||
|
|
||||||
// Expenses
|
// Expenses
|
||||||
{
|
{
|
||||||
name:'Other Expenses',
|
name: 'Other Expenses',
|
||||||
slug: 'other-expenses',
|
slug: 'other-expenses',
|
||||||
account_type: 'other-expense',
|
account_type: 'other-expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -204,18 +210,18 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Cost of Goods Sold',
|
name: 'Cost of Goods Sold',
|
||||||
slug: 'cost-of-goods-sold',
|
slug: 'cost-of-goods-sold',
|
||||||
account_type: 'cost-of-goods-sold',
|
account_type: 'cost-of-goods-sold',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
code: '40002',
|
code: '40002',
|
||||||
description:'Tracks the direct cost of the goods sold.',
|
description: 'Tracks the direct cost of the goods sold.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Office expenses',
|
name: 'Office expenses',
|
||||||
slug: 'office-expenses',
|
slug: 'office-expenses',
|
||||||
account_type: 'expense',
|
account_type: 'expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -226,7 +232,7 @@ export default [
|
|||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Rent',
|
name: 'Rent',
|
||||||
slug: 'rent',
|
slug: 'rent',
|
||||||
account_type: 'expense',
|
account_type: 'expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -237,29 +243,30 @@ export default [
|
|||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Exchange Gain or Loss',
|
name: 'Exchange Gain or Loss',
|
||||||
slug: 'exchange-grain-loss',
|
slug: 'exchange-grain-loss',
|
||||||
account_type: 'other-expense',
|
account_type: 'other-expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
code: '40005',
|
code: '40005',
|
||||||
description:'Tracks the gain and losses of the exchange differences.',
|
description: 'Tracks the gain and losses of the exchange differences.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Bank Fees and Charges',
|
name: 'Bank Fees and Charges',
|
||||||
slug: 'bank-fees-and-charges',
|
slug: 'bank-fees-and-charges',
|
||||||
account_type: 'expense',
|
account_type: 'expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
code: '40006',
|
code: '40006',
|
||||||
description: 'Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.',
|
description:
|
||||||
|
'Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Depreciation Expense',
|
name: 'Depreciation Expense',
|
||||||
slug: 'depreciation-expense',
|
slug: 'depreciation-expense',
|
||||||
account_type: 'expense',
|
account_type: 'expense',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -272,7 +279,7 @@ export default [
|
|||||||
|
|
||||||
// Income
|
// Income
|
||||||
{
|
{
|
||||||
name:'Sales of Product Income',
|
name: 'Sales of Product Income',
|
||||||
slug: 'sales-of-product-income',
|
slug: 'sales-of-product-income',
|
||||||
account_type: 'income',
|
account_type: 'income',
|
||||||
predefined: 1,
|
predefined: 1,
|
||||||
@@ -283,7 +290,7 @@ export default [
|
|||||||
description: '',
|
description: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Sales of Service Income',
|
name: 'Sales of Service Income',
|
||||||
slug: 'sales-of-service-income',
|
slug: 'sales-of-service-income',
|
||||||
account_type: 'income',
|
account_type: 'income',
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
@@ -294,7 +301,7 @@ export default [
|
|||||||
description: '',
|
description: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Uncategorized Income',
|
name: 'Uncategorized Income',
|
||||||
slug: 'uncategorized-income',
|
slug: 'uncategorized-income',
|
||||||
account_type: 'income',
|
account_type: 'income',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
@@ -305,14 +312,15 @@ export default [
|
|||||||
predefined: 1,
|
predefined: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'Other Income',
|
name: 'Other Income',
|
||||||
slug: 'other-income',
|
slug: 'other-income',
|
||||||
account_type: 'other-income',
|
account_type: 'other-income',
|
||||||
parent_account_id: null,
|
parent_account_id: null,
|
||||||
code: '50004',
|
code: '50004',
|
||||||
description:'The income activities are not associated to the core business.',
|
description:
|
||||||
|
'The income activities are not associated to the core business.',
|
||||||
active: 1,
|
active: 1,
|
||||||
index: 1,
|
index: 1,
|
||||||
predefined: 0,
|
predefined: 0,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ export interface IItemDTO {
|
|||||||
sellDescription: string;
|
sellDescription: string;
|
||||||
purchaseDescription: string;
|
purchaseDescription: string;
|
||||||
|
|
||||||
|
// Used as an override if the default Tax Code for the selected `costAccountId` is not correct
|
||||||
|
purchaseTaxCode: string;
|
||||||
|
purchaseTaxId: string;
|
||||||
|
|
||||||
|
// Used as an override if the default Tax Code for the selected `sellAccountId` is not correct
|
||||||
|
saleTaxCode: string;
|
||||||
|
saleTaxId: string;
|
||||||
|
|
||||||
quantityOnHand: number;
|
quantityOnHand: number;
|
||||||
|
|
||||||
note: string;
|
note: string;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export interface IItemEntry {
|
|||||||
|
|
||||||
taxCode: string;
|
taxCode: string;
|
||||||
taxRate: number;
|
taxRate: number;
|
||||||
|
taxAmount: number;
|
||||||
|
|
||||||
item?: IItem;
|
item?: IItem;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { IItemEntry } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
||||||
|
|
||||||
export interface ISaleEstimate {
|
export interface ISaleEstimate {
|
||||||
@@ -29,7 +29,7 @@ export interface ISaleEstimateDTO {
|
|||||||
estimateDate?: Date;
|
estimateDate?: Date;
|
||||||
reference?: string;
|
reference?: string;
|
||||||
estimateNumber?: string;
|
estimateNumber?: string;
|
||||||
entries: IItemEntry[];
|
entries: IItemEntryDTO[];
|
||||||
note: string;
|
note: string;
|
||||||
termsConditions: string;
|
termsConditions: string;
|
||||||
sendToEmail: string;
|
sendToEmail: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { ISystemUser, IAccount } from '@/interfaces';
|
import { ISystemUser, IAccount, ITaxTransaction } from '@/interfaces';
|
||||||
import { IDynamicListFilter } from '@/interfaces/DynamicFilter';
|
import { IDynamicListFilter } from '@/interfaces/DynamicFilter';
|
||||||
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
|
|
||||||
@@ -33,6 +33,9 @@ export interface ISaleInvoice {
|
|||||||
writtenoffExpenseAccountId?: number;
|
writtenoffExpenseAccountId?: number;
|
||||||
|
|
||||||
writtenoffExpenseAccount?: IAccount;
|
writtenoffExpenseAccount?: IAccount;
|
||||||
|
|
||||||
|
taxAmountWithheld: number;
|
||||||
|
taxes: ITaxTransaction[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleInvoiceDTO {
|
export interface ISaleInvoiceDTO {
|
||||||
|
|||||||
@@ -47,3 +47,10 @@ export interface ITaxRateDeletedPayload {
|
|||||||
tenantId: number;
|
tenantId: number;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ITaxTransaction {
|
||||||
|
taxAmount: number;
|
||||||
|
taxName: string;
|
||||||
|
taxCode: string;
|
||||||
|
}
|
||||||
@@ -81,6 +81,9 @@ import { ProjectBillableExpensesSubscriber } from '@/services/Projects/Projects/
|
|||||||
import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/ProjectBillableBillSubscriber';
|
import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/ProjectBillableBillSubscriber';
|
||||||
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
||||||
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
||||||
|
import { SaleEstimateTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleEstimateTaxRateValidateSubscriber';
|
||||||
|
import { SaleReceiptTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleReceiptTaxRateValidateSubscriber';
|
||||||
|
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -188,6 +191,11 @@ export const susbcribers = () => {
|
|||||||
ProjectBillableTasksSubscriber,
|
ProjectBillableTasksSubscriber,
|
||||||
ProjectBillableExpensesSubscriber,
|
ProjectBillableExpensesSubscriber,
|
||||||
ProjectBillableBillSubscriber,
|
ProjectBillableBillSubscriber,
|
||||||
SaleInvoiceTaxRateValidateSubscriber
|
|
||||||
|
// Tax Rates
|
||||||
|
SaleInvoiceTaxRateValidateSubscriber,
|
||||||
|
SaleEstimateTaxRateValidateSubscriber,
|
||||||
|
SaleReceiptTaxRateValidateSubscriber,
|
||||||
|
WriteInvoiceTaxTransactionsSubscriber
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import Project from 'models/Project';
|
|||||||
import Time from 'models/Time';
|
import Time from 'models/Time';
|
||||||
import Task from 'models/Task';
|
import Task from 'models/Task';
|
||||||
import TaxRate from 'models/TaxRate';
|
import TaxRate from 'models/TaxRate';
|
||||||
|
import TaxRateTransaction from 'models/TaxRateTransaction';
|
||||||
|
|
||||||
export default (knex) => {
|
export default (knex) => {
|
||||||
const models = {
|
const models = {
|
||||||
@@ -121,6 +122,7 @@ export default (knex) => {
|
|||||||
Time,
|
Time,
|
||||||
Task,
|
Task,
|
||||||
TaxRate,
|
TaxRate,
|
||||||
|
TaxRateTransaction,
|
||||||
};
|
};
|
||||||
return mapValues(models, (model) => model.bindKnex(knex));
|
return mapValues(models, (model) => model.bindKnex(knex));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Model } from 'objection';
|
|||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
|
|
||||||
export default class ItemEntry extends TenantModel {
|
export default class ItemEntry extends TenantModel {
|
||||||
|
public taxRate: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -17,7 +19,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return ['amount'];
|
return ['amount', 'taxAmount'];
|
||||||
}
|
}
|
||||||
|
|
||||||
get amount() {
|
get amount() {
|
||||||
@@ -31,6 +33,22 @@ export default class ItemEntry extends TenantModel {
|
|||||||
return discount ? total - total * discount * 0.01 : total;
|
return discount ? total - total * discount * 0.01 : total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag rate fraction.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get tagRateFraction() {
|
||||||
|
return this.taxRate / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax amount withheld.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get taxAmount() {
|
||||||
|
return this.amount * this.tagRateFraction;
|
||||||
|
}
|
||||||
|
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const Item = require('models/Item');
|
const Item = require('models/Item');
|
||||||
const BillLandedCostEntry = require('models/BillLandedCostEntry');
|
const BillLandedCostEntry = require('models/BillLandedCostEntry');
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
|
taxAmountWithheld: number;
|
||||||
|
balance: number;
|
||||||
|
paymentAmount: number;
|
||||||
|
exchangeRate: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -51,12 +56,115 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice total FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalFcy() {
|
||||||
|
return this.amountFcy + this.taxAmountWithheldFcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice total BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get totalBcy() {
|
||||||
|
return this.amountBcy + this.taxAmountWithheldBcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax amount withheld FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get taxAmountWithheldFcy() {
|
||||||
|
return this.taxAmountWithheld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax amount withheld BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get taxAmountWithheldBcy() {
|
||||||
|
return this.taxAmountWithheld;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtotal FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalFcy() {
|
||||||
|
return this.amountFcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtotal BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotalBcy() {
|
||||||
|
return this.amountBcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice due amount FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get dueAmountFcy() {
|
||||||
|
return this.amountFcy - this.paymentAmountFcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice due amount BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get dueAmountBcy() {
|
||||||
|
return this.amountBcy - this.paymentAmountBcy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice amount FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get amountFcy() {
|
||||||
|
return this.balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice amount BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get amountBcy() {
|
||||||
|
return this.balance * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice payment amount FCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get paymentAmountFcy() {
|
||||||
|
return this.paymentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice payment amount BCY.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get paymentAmountBcy() {
|
||||||
|
return this.paymentAmount * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get total() {
|
||||||
|
return this.balance + this.taxAmountWithheld;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice amount in local currency.
|
* Invoice amount in local currency.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get localAmount() {
|
get localAmount() {
|
||||||
return this.balance * this.exchangeRate;
|
return this.total * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -333,6 +441,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
const PaymentReceiveEntry = require('models/PaymentReceiveEntry');
|
const PaymentReceiveEntry = require('models/PaymentReceiveEntry');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Account = require('models/Account');
|
const Account = require('models/Account');
|
||||||
|
const TaxRateTransaction = require('models/TaxRateTransaction');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -428,6 +537,21 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
taxes: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: TaxRateTransaction.default,
|
||||||
|
join: {
|
||||||
|
from: 'sales_invoices.id',
|
||||||
|
to: 'tax_rate_transactions.referenceId',
|
||||||
|
},
|
||||||
|
filter(builder) {
|
||||||
|
builder.where('reference_type', 'SaleInvoice');
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
packages/server/src/models/TaxRateTransaction.ts
Normal file
42
packages/server/src/models/TaxRateTransaction.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { mixin, Model, raw } from 'objection';
|
||||||
|
import TenantModel from 'models/TenantModel';
|
||||||
|
import ModelSearchable from './ModelSearchable';
|
||||||
|
|
||||||
|
export default class TaxRateTransaction extends mixin(TenantModel, [
|
||||||
|
ModelSearchable,
|
||||||
|
]) {
|
||||||
|
/**
|
||||||
|
* Table name
|
||||||
|
*/
|
||||||
|
static get tableName() {
|
||||||
|
return 'tax_rate_transactions';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamps columns.
|
||||||
|
*/
|
||||||
|
get timestamps() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual attributes.
|
||||||
|
*/
|
||||||
|
static get virtualAttributes() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model modifiers.
|
||||||
|
*/
|
||||||
|
static get modifiers() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relationship mapping.
|
||||||
|
*/
|
||||||
|
static get relationMappings() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { Account } from 'models';
|
|||||||
import TenantRepository from '@/repositories/TenantRepository';
|
import TenantRepository from '@/repositories/TenantRepository';
|
||||||
import { IAccount } from '@/interfaces';
|
import { IAccount } from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
|
import { TaxPayableAccount } from '@/database/seeds/data/accounts';
|
||||||
|
|
||||||
export default class AccountRepository extends TenantRepository {
|
export default class AccountRepository extends TenantRepository {
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +117,7 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
if (!result) {
|
if (!result) {
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
name: this.i18n.__('account.accounts_receivable.currency', {
|
name: this.i18n.__('account.accounts_receivable.currency', {
|
||||||
currency: currencyCode
|
currency: currencyCode,
|
||||||
}),
|
}),
|
||||||
accountType: 'accounts-receivable',
|
accountType: 'accounts-receivable',
|
||||||
currencyCode,
|
currencyCode,
|
||||||
@@ -127,6 +128,29 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find or create tax payable account.
|
||||||
|
* @param {Record<string, string>}extraAttrs
|
||||||
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async findOrCreateTaxPayable(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: TaxPayableAccount.slug, ...extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...TaxPayableAccount,
|
||||||
|
...extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
findOrCreateAccountsPayable = async (
|
findOrCreateAccountsPayable = async (
|
||||||
currencyCode: string = '',
|
currencyCode: string = '',
|
||||||
extraAttrs = {},
|
extraAttrs = {},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import HasTenancyService from '@/services/Tenancy/TenancyService';
|
|||||||
import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators';
|
import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators';
|
||||||
import { SaleInvoiceIncrement } from './SaleInvoiceIncrement';
|
import { SaleInvoiceIncrement } from './SaleInvoiceIncrement';
|
||||||
import { formatDateFields } from 'utils';
|
import { formatDateFields } from 'utils';
|
||||||
|
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CommandSaleInvoiceDTOTransformer {
|
export class CommandSaleInvoiceDTOTransformer {
|
||||||
@@ -38,6 +39,9 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private invoiceIncrement: SaleInvoiceIncrement;
|
private invoiceIncrement: SaleInvoiceIncrement;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private taxDTOTransformer: ItemEntriesTaxTransactions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the create DTO to invoice object model.
|
* Transformes the create DTO to invoice object model.
|
||||||
* @param {ISaleInvoiceCreateDTO} saleInvoiceDTO - Sale invoice DTO.
|
* @param {ISaleInvoiceCreateDTO} saleInvoiceDTO - Sale invoice DTO.
|
||||||
@@ -96,6 +100,7 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
} as ISaleInvoice;
|
} as ISaleInvoice;
|
||||||
|
|
||||||
return R.compose(
|
return R.compose(
|
||||||
|
this.taxDTOTransformer.assocTaxAmountWithheldFromEntries,
|
||||||
this.branchDTOTransform.transformDTO<ISaleInvoice>(tenantId),
|
this.branchDTOTransform.transformDTO<ISaleInvoice>(tenantId),
|
||||||
this.warehouseDTOTransform.transformDTO<ISaleInvoice>(tenantId)
|
this.warehouseDTOTransform.transformDTO<ISaleInvoice>(tenantId)
|
||||||
)(initialDTO);
|
)(initialDTO);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
import { Knex } from 'knex';
|
||||||
import {
|
import {
|
||||||
ISaleInvoice,
|
ISaleInvoice,
|
||||||
IItemEntry,
|
IItemEntry,
|
||||||
ILedgerEntry,
|
ILedgerEntry,
|
||||||
AccountNormal,
|
AccountNormal,
|
||||||
ILedger,
|
ILedger,
|
||||||
|
ITaxTransaction,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
|
||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import Ledger from '@/services/Accounting/Ledger';
|
import Ledger from '@/services/Accounting/Ledger';
|
||||||
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||||
@@ -22,8 +23,8 @@ export class SaleInvoiceGLEntries {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a sale invoice GL entries.
|
* Writes a sale invoice GL entries.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId - Tenant id.
|
||||||
* @param {number} saleInvoiceId
|
* @param {number} saleInvoiceId - Sale invoice id.
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
*/
|
*/
|
||||||
public writeInvoiceGLEntries = async (
|
public writeInvoiceGLEntries = async (
|
||||||
@@ -42,9 +43,17 @@ export class SaleInvoiceGLEntries {
|
|||||||
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
||||||
saleInvoice.currencyCode
|
saleInvoice.currencyCode
|
||||||
);
|
);
|
||||||
|
// Find or create tax payable account.
|
||||||
|
const taxPayableAccount = await accountRepository.findOrCreateTaxPayable(
|
||||||
|
{},
|
||||||
|
trx
|
||||||
|
);
|
||||||
// Retrieves the ledger of the invoice.
|
// Retrieves the ledger of the invoice.
|
||||||
const ledger = this.getInvoiceGLedger(saleInvoice, ARAccount.id);
|
const ledger = this.getInvoiceGLedger(
|
||||||
|
saleInvoice,
|
||||||
|
ARAccount.id,
|
||||||
|
taxPayableAccount.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);
|
||||||
};
|
};
|
||||||
@@ -94,10 +103,14 @@ export class SaleInvoiceGLEntries {
|
|||||||
*/
|
*/
|
||||||
public getInvoiceGLedger = (
|
public getInvoiceGLedger = (
|
||||||
saleInvoice: ISaleInvoice,
|
saleInvoice: ISaleInvoice,
|
||||||
ARAccountId: number
|
ARAccountId: number,
|
||||||
|
taxPayableAccountId: number
|
||||||
): ILedger => {
|
): ILedger => {
|
||||||
const entries = this.getInvoiceGLEntries(saleInvoice, ARAccountId);
|
const entries = this.getInvoiceGLEntries(
|
||||||
|
saleInvoice,
|
||||||
|
ARAccountId,
|
||||||
|
taxPayableAccountId
|
||||||
|
);
|
||||||
return new Ledger(entries);
|
return new Ledger(entries);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,7 +156,7 @@ export class SaleInvoiceGLEntries {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
debit: saleInvoice.localAmount,
|
debit: saleInvoice.totalBcy,
|
||||||
accountId: ARAccountId,
|
accountId: ARAccountId,
|
||||||
contactId: saleInvoice.customerId,
|
contactId: saleInvoice.customerId,
|
||||||
accountNormal: AccountNormal.DEBIT,
|
accountNormal: AccountNormal.DEBIT,
|
||||||
@@ -176,7 +189,27 @@ export class SaleInvoiceGLEntries {
|
|||||||
itemId: entry.itemId,
|
itemId: entry.itemId,
|
||||||
itemQuantity: entry.quantity,
|
itemQuantity: entry.quantity,
|
||||||
accountNormal: AccountNormal.CREDIT,
|
accountNormal: AccountNormal.CREDIT,
|
||||||
projectId: entry.projectId || saleInvoice.projectId
|
projectId: entry.projectId || saleInvoice.projectId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreives the GL entry of tax payable.
|
||||||
|
* @param {ISaleInvoice} saleInvoice -
|
||||||
|
* @param {number} taxPayableAccountId -
|
||||||
|
* @returns {ILedgerEntry}
|
||||||
|
*/
|
||||||
|
private getInvoiceTaxEntry = R.curry(
|
||||||
|
(saleInvoice: ISaleInvoice, taxPayableAccountId: number): ILedgerEntry => {
|
||||||
|
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonEntry,
|
||||||
|
credit: saleInvoice.taxAmountWithheld,
|
||||||
|
accountId: taxPayableAccountId,
|
||||||
|
index: saleInvoice.entries.length + 3,
|
||||||
|
accountNormal: AccountNormal.CREDIT,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -189,15 +222,18 @@ export class SaleInvoiceGLEntries {
|
|||||||
*/
|
*/
|
||||||
public getInvoiceGLEntries = (
|
public getInvoiceGLEntries = (
|
||||||
saleInvoice: ISaleInvoice,
|
saleInvoice: ISaleInvoice,
|
||||||
ARAccountId: number
|
ARAccountId: number,
|
||||||
|
taxPayableAccountId: number
|
||||||
): ILedgerEntry[] => {
|
): ILedgerEntry[] => {
|
||||||
const receivableEntry = this.getInvoiceReceivableEntry(
|
const receivableEntry = this.getInvoiceReceivableEntry(
|
||||||
saleInvoice,
|
saleInvoice,
|
||||||
ARAccountId
|
ARAccountId
|
||||||
);
|
);
|
||||||
const transformItemEntry = this.getInvoiceItemEntry(saleInvoice);
|
const transformItemEntry = this.getInvoiceItemEntry(saleInvoice);
|
||||||
const creditEntries = saleInvoice.entries.map(transformItemEntry);
|
|
||||||
|
|
||||||
return [receivableEntry, ...creditEntries];
|
const creditEntries = saleInvoice.entries.map(transformItemEntry);
|
||||||
|
const taxEntry = this.getInvoiceTaxEntry(saleInvoice, taxPayableAccountId);
|
||||||
|
|
||||||
|
return [receivableEntry, ...creditEntries, taxEntry];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { ItemEntry } from "@/models";
|
||||||
|
import { sumBy } from "lodash";
|
||||||
|
import { Service } from "typedi";
|
||||||
|
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ItemEntriesTaxTransactions {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public assocTaxAmountWithheldFromEntries(model: any) {
|
||||||
|
const entries = model.entries.map((entry) => ItemEntry.fromJson(entry));
|
||||||
|
const taxAmountWithheld = sumBy(entries, 'taxAmount');
|
||||||
|
|
||||||
|
if (taxAmountWithheld) {
|
||||||
|
model.taxAmountWithheld = taxAmountWithheld;
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { sumBy, chain } from 'lodash';
|
||||||
|
import { IItemEntry } from '@/interfaces';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class WriteTaxTransactionsItemEntries {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the tax transactions from the given item entries.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {IItemEntry[]} itemEntries
|
||||||
|
*/
|
||||||
|
public async writeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId: number,
|
||||||
|
itemEntries: IItemEntry[]
|
||||||
|
) {
|
||||||
|
const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
||||||
|
const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
||||||
|
|
||||||
|
const taxTransactions = aggregatedEntries.map((entry) => ({
|
||||||
|
taxName: 'TAX NAME',
|
||||||
|
taxCode: 'TAG_CODE',
|
||||||
|
referenceType: entry.referenceType,
|
||||||
|
referenceId: entry.referenceId,
|
||||||
|
taxAmount: entry.taxAmount,
|
||||||
|
}));
|
||||||
|
await TaxRateTransaction.query().upsertGraph(taxTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IItemEntry[]} itemEntries
|
||||||
|
* @returns {}
|
||||||
|
*/
|
||||||
|
private aggregateItemEntriesByTaxCode(itemEntries: IItemEntry[]) {
|
||||||
|
return chain(itemEntries.filter((item) => item.taxCode))
|
||||||
|
.groupBy((item) => item.taxCode)
|
||||||
|
.values()
|
||||||
|
.map((group) => ({ ...group[0], amount: sumBy(group, 'amount') }))
|
||||||
|
.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param itemEntries
|
||||||
|
*/
|
||||||
|
private aggregateItemEntriesByReferenceTypeId(itemEntries: IItemEntry) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the tax transactions from the given item entries.
|
||||||
|
* @param tenantId
|
||||||
|
* @param itemEntries
|
||||||
|
*/
|
||||||
|
public removeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId: number,
|
||||||
|
itemEntries: IItemEntry[]
|
||||||
|
) {
|
||||||
|
const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const filteredEntries = itemEntries.filter((item) => item.taxCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import {
|
||||||
|
ISaleInvoiceCreatedPayload,
|
||||||
|
ISaleInvoiceDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class WriteInvoiceTaxTransactionsSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches events with handlers.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onCreated,
|
||||||
|
this.writeInvoiceTaxTransactionsOnCreated
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onDeleted,
|
||||||
|
this.removeInvoiceTaxTransactionsOnDeleted
|
||||||
|
);
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate receipt entries tax rate code existance.
|
||||||
|
* @param {ISaleInvoiceCreatingPaylaod}
|
||||||
|
*/
|
||||||
|
private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||||
|
tenantId,
|
||||||
|
saleInvoice,
|
||||||
|
}: ISaleInvoiceCreatedPayload) => {
|
||||||
|
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId,
|
||||||
|
saleInvoice.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the invoice tax transactions on invoice deleted.
|
||||||
|
* @param {ISaleInvoiceEditingPayload}
|
||||||
|
*/
|
||||||
|
private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||||
|
tenantId,
|
||||||
|
oldSaleInvoice,
|
||||||
|
}: ISaleInvoiceDeletedPayload) => {
|
||||||
|
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||||
|
tenantId,
|
||||||
|
oldSaleInvoice.entries
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user