mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
feat: wip line-level discount
This commit is contained in:
@@ -243,6 +243,10 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
|
check('entries.*.discount_type')
|
||||||
|
.default(DiscountType.Percentage)
|
||||||
|
.isString()
|
||||||
|
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description').optional({ nullable: true }).trim(),
|
||||||
check('entries.*.tax_code')
|
check('entries.*.tax_code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.up = function (knex) {
|
||||||
|
return knex.schema.alterTable('items_entries', (table) => {
|
||||||
|
table.string('discount_type').defaultTo('percentage').after('discount');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { import("knex").Knex } knex
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
exports.down = function (knex) {
|
||||||
|
return knex.schema.alterTable('items_entries', (table) => {
|
||||||
|
table.dropColumn('discount_type');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -19,8 +19,8 @@ export interface IItemEntry {
|
|||||||
amount: number;
|
amount: number;
|
||||||
|
|
||||||
total: number;
|
total: number;
|
||||||
amountInclusingTax: number;
|
subtotalInclusingTax: number;
|
||||||
amountExludingTax: number;
|
subtotalExcludingTax: number;
|
||||||
discountAmount: number;
|
discountAmount: number;
|
||||||
|
|
||||||
landedCost: number;
|
landedCost: number;
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { Model } from 'objection';
|
import { Model } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
|
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
|
||||||
|
import { DiscountType } from '@/interfaces';
|
||||||
|
|
||||||
|
// Subtotal (qty * rate) (tax inclusive)
|
||||||
|
// Subtotal Tax Exclusive (Subtotal - Tax Amount)
|
||||||
|
// Discount (Is percentage ? amount * discount : discount)
|
||||||
|
// Total (Subtotal - Discount)
|
||||||
|
|
||||||
export default class ItemEntry extends TenantModel {
|
export default class ItemEntry extends TenantModel {
|
||||||
public taxRate: number;
|
public taxRate: number;
|
||||||
@@ -8,7 +14,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
public quantity: number;
|
public quantity: number;
|
||||||
public rate: number;
|
public rate: number;
|
||||||
public isInclusiveTax: number;
|
public isInclusiveTax: number;
|
||||||
|
public discountType: DiscountType;
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
@@ -31,10 +37,24 @@ export default class ItemEntry extends TenantModel {
|
|||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return [
|
||||||
|
// Amount (qty * rate)
|
||||||
'amount',
|
'amount',
|
||||||
|
|
||||||
'taxAmount',
|
'taxAmount',
|
||||||
'amountExludingTax',
|
|
||||||
'amountInclusingTax',
|
// Subtotal (qty * rate) + (tax inclusive)
|
||||||
|
'subtotalInclusingTax',
|
||||||
|
|
||||||
|
// Subtotal Tax Exclusive (Subtotal - Tax Amount)
|
||||||
|
'subtotalExcludingTax',
|
||||||
|
|
||||||
|
// Subtotal (qty * rate) + (tax inclusive)
|
||||||
|
'subtotal',
|
||||||
|
|
||||||
|
// Discount (Is percentage ? amount * discount : discount)
|
||||||
|
'discountAmount',
|
||||||
|
|
||||||
|
// Total (Subtotal - Discount)
|
||||||
'total',
|
'total',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -45,7 +65,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
return this.amountInclusingTax;
|
return this.subtotal - this.discountAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,19 +77,27 @@ export default class ItemEntry extends TenantModel {
|
|||||||
return this.quantity * this.rate;
|
return this.quantity * this.rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtotal amount (tax inclusive).
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
get subtotal() {
|
||||||
|
return this.subtotalInclusingTax;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item entry amount including tax.
|
* Item entry amount including tax.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get amountInclusingTax() {
|
get subtotalInclusingTax() {
|
||||||
return this.isInclusiveTax ? this.amount : this.amount + this.taxAmount;
|
return this.isInclusiveTax ? this.amount : this.amount + this.taxAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item entry amount excluding tax.
|
* Subtotal amount (tax exclusive).
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get amountExludingTax() {
|
get subtotalExcludingTax() {
|
||||||
return this.isInclusiveTax ? this.amount - this.taxAmount : this.amount;
|
return this.isInclusiveTax ? this.amount - this.taxAmount : this.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +106,9 @@ export default class ItemEntry extends TenantModel {
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get discountAmount() {
|
get discountAmount() {
|
||||||
return this.amount * (this.discount / 100);
|
return this.discountType === DiscountType.Percentage
|
||||||
|
? this.amount * (this.discount / 100)
|
||||||
|
: this.discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export class BillGLEntries {
|
|||||||
(bill: IBill, entry: IItemEntry, index: number): ILedgerEntry => {
|
(bill: IBill, entry: IItemEntry, index: number): ILedgerEntry => {
|
||||||
const commonJournalMeta = this.getBillCommonEntry(bill);
|
const commonJournalMeta = this.getBillCommonEntry(bill);
|
||||||
|
|
||||||
const localAmount = bill.exchangeRate * entry.amountExludingTax;
|
const localAmount = bill.exchangeRate * entry.subtotalExcludingTax;
|
||||||
const landedCostAmount = sumBy(entry.allocatedCostEntries, 'cost');
|
const landedCostAmount = sumBy(entry.allocatedCostEntries, 'cost');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -154,6 +154,6 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
private getDueBalanceItemEntries = (entries: ItemEntry[]) => {
|
private getDueBalanceItemEntries = (entries: ItemEntry[]) => {
|
||||||
return sumBy(entries, (e) => e.amount);
|
return sumBy(entries, (e) => e.total);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ export class SaleInvoiceGLEntries {
|
|||||||
index: number
|
index: number
|
||||||
): ILedgerEntry => {
|
): ILedgerEntry => {
|
||||||
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
const commonEntry = this.getInvoiceGLCommonEntry(saleInvoice);
|
||||||
const localAmount = entry.amountExludingTax * saleInvoice.exchangeRate;
|
const localAmount = entry.total * saleInvoice.exchangeRate;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...commonEntry,
|
...commonEntry,
|
||||||
|
|||||||
@@ -2,7 +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';
|
import { IItemEntry } from '@/interfaces';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class ItemEntriesTaxTransactions {
|
export class ItemEntriesTaxTransactions {
|
||||||
|
|||||||
Reference in New Issue
Block a user