feat: wip line-level discount

This commit is contained in:
Ahmed Bouhuolia
2024-12-11 12:37:15 +02:00
parent 6323e2ffec
commit 5a8d9cc7e8
8 changed files with 67 additions and 14 deletions

View File

@@ -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 })

View File

@@ -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');
});
};

View File

@@ -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;

View File

@@ -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;
} }
/** /**

View File

@@ -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 {

View File

@@ -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);
}; };
} }

View File

@@ -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,

View File

@@ -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 {