mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-22 07:40:32 +00:00
fix(server): tax tracking on sale invoices
This commit is contained in:
@@ -19,6 +19,7 @@ exports.up = (knex) => {
|
|||||||
.unsigned()
|
.unsigned()
|
||||||
.references('id')
|
.references('id')
|
||||||
.inTable('tax_rates');
|
.inTable('tax_rates');
|
||||||
|
table.decimal('tax_rate').unsigned();
|
||||||
})
|
})
|
||||||
.table('sales_invoices', (table) => {
|
.table('sales_invoices', (table) => {
|
||||||
table.boolean('is_inclusive_tax').defaultTo(false);
|
table.boolean('is_inclusive_tax').defaultTo(false);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
public taxAmountWithheld: number;
|
public taxAmountWithheld: number;
|
||||||
public amount: number;
|
public balance: number;
|
||||||
public paymentAmount: number;
|
public paymentAmount: number;
|
||||||
public exchangeRate: number;
|
public exchangeRate: number;
|
||||||
public writtenoffAmount: number;
|
public writtenoffAmount: number;
|
||||||
@@ -74,6 +74,23 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice amount.
|
||||||
|
* @todo Sugger attribute to balance, we need to rename the balance to amount.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get amount() {
|
||||||
|
return this.balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice amount in base currency.
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get amountLocal() {
|
||||||
|
return this.amount * this.exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtotal. (Tax inclusive) if the tax inclusive is enabled.
|
* Subtotal. (Tax inclusive) if the tax inclusive is enabled.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
@@ -87,7 +104,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get subtotalLocal() {
|
get subtotalLocal() {
|
||||||
return this.amount * this.exchangeRate;
|
return this.amountLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class SalesTaxLiabilitySummaryTable extends R.compose(
|
|||||||
key: 'collectedTax',
|
key: 'collectedTax',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Tax Rate',
|
label: 'Tax Amount',
|
||||||
key: 'taxRate',
|
key: 'taxRate',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
...entry,
|
...entry,
|
||||||
}));
|
}));
|
||||||
const asyncEntries = await composeAsync(
|
const asyncEntries = await composeAsync(
|
||||||
|
// Associate tax rate from tax id to entries.
|
||||||
|
this.taxDTOTransformer.assocTaxRateFromTaxIdToEntries(tenantId),
|
||||||
// Associate tax rate id from tax code to entries.
|
// Associate tax rate id from tax code to entries.
|
||||||
this.taxDTOTransformer.assocTaxRateIdFromCodeToEntries(tenantId),
|
this.taxDTOTransformer.assocTaxRateIdFromCodeToEntries(tenantId),
|
||||||
// Sets default cost and sell account to invoice items entries.
|
// Sets default cost and sell account to invoice items entries.
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ export class SaleInvoiceGLEntries {
|
|||||||
index: number
|
index: number
|
||||||
): ILedgerEntry => {
|
): ILedgerEntry => {
|
||||||
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
||||||
const localAmount = entry.amount * saleInvoice.exchangeRate;
|
const localAmount = entry.amountExludingTax * saleInvoice.exchangeRate;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import { keyBy, sumBy } from 'lodash';
|
import { keyBy, sumBy } from 'lodash';
|
||||||
import { ItemEntry } from '@/models';
|
import { ItemEntry } from '@/models';
|
||||||
import HasTenancyService from '../Tenancy/TenancyService';
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
import { IItem, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class ItemEntriesTaxTransactions {
|
export class ItemEntriesTaxTransactions {
|
||||||
@@ -45,4 +46,27 @@ export class ItemEntriesTaxTransactions {
|
|||||||
return entry;
|
return entry;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates tax rate from tax id to entries.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @returns {Promise<IItemEntry[]>}
|
||||||
|
*/
|
||||||
|
public assocTaxRateFromTaxIdToEntries =
|
||||||
|
(tenantId: number) => async (entries: IItemEntry[]) => {
|
||||||
|
const entriesWithId = entries.filter((e) => e.taxRateId);
|
||||||
|
const taxRateIds = entriesWithId.map((e) => e.taxRateId);
|
||||||
|
|
||||||
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
|
const foundTaxes = await TaxRate.query().whereIn('id', taxRateIds);
|
||||||
|
|
||||||
|
const taxRatesMap = keyBy(foundTaxes, 'id');
|
||||||
|
|
||||||
|
return entries.map((entry) => {
|
||||||
|
if (entry.taxRateId) {
|
||||||
|
entry.taxRate = taxRatesMap[entry.taxRateId]?.rate;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user