From acfc84da6806e90d03ca2bae301064ed5cc8cd4f Mon Sep 17 00:00:00 2001 From: akshayitzme Date: Mon, 19 Aug 2024 13:00:25 +0530 Subject: [PATCH] fix: pricing rule not applied in pos --- models/baseModels/Invoice/Invoice.ts | 37 ++++++++++++++---- .../baseModels/tests/testPricingRule.spec.ts | 3 +- models/helpers.ts | 10 +++-- src/pages/POS/POS.vue | 39 ++++++++++++++++--- src/utils/pos.ts | 3 +- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index b3a291d03..c235912fd 100644 --- a/models/baseModels/Invoice/Invoice.ts +++ b/models/baseModels/Invoice/Invoice.ts @@ -642,11 +642,12 @@ export abstract class Invoice extends Transactional { } const pricingRule = await this.getPricingRule(); - if (pricingRule) { - await this.appendPricingRuleDetail(pricingRule); + if (!pricingRule) { + return false; } - return !!pricingRule?.length; + await this.appendPricingRuleDetail(pricingRule); + return !!pricingRule; }, dependsOn: ['items'], }, @@ -948,6 +949,8 @@ export abstract class Invoice extends Transactional { if (this.pricingRuleDetail?.length) { await this.applyProductDiscount(); + } else { + this.clearFreeItems(); } } @@ -1093,22 +1096,40 @@ export abstract class Invoice extends Transactional { } } - async applyProductDiscount() { - if (!this.pricingRuleDetail || !this.items) { + clearFreeItems() { + if (this.pricingRuleDetail?.length || !this.items) { return; } - this.items = this.items.filter((item) => !item.isFreeItem); - for (const item of this.items) { if (item.isFreeItem) { - continue; + this.items = this.items?.filter( + (invoiceItem) => invoiceItem.name !== item.name + ); } + } + } + + async applyProductDiscount() { + if (!this.items) { + return; + } + + if (!this.pricingRuleDetail?.length || !this.pricingRuleDetail.length) { + return; + } + this.items = this.items.filter((item) => !item.isFreeItem); + + for (const item of this.items) { const pricingRuleDetailForItem = this.pricingRuleDetail.filter( (doc) => doc.referenceItem === item.item ); + if (!pricingRuleDetailForItem.length) { + return; + } + const pricingRuleDoc = (await this.fyo.doc.getDoc( ModelNameEnum.PricingRule, pricingRuleDetailForItem[0].referenceName diff --git a/models/baseModels/tests/testPricingRule.spec.ts b/models/baseModels/tests/testPricingRule.spec.ts index f17a1a28c..dfffab3cc 100644 --- a/models/baseModels/tests/testPricingRule.spec.ts +++ b/models/baseModels/tests/testPricingRule.spec.ts @@ -141,7 +141,7 @@ test('pricing rule is applied when filtered by min and max qty', async (t) => { ); }); -test('pricing rule is not applied when item qty is < min qty ', async (t) => { +test('pricing rule is not applied when item qty is < min qty', async (t) => { const sinv = fyo.doc.getNewDoc(ModelNameEnum.SalesInvoice, { date: new Date(), party: partyMap.partyOne.name, @@ -548,7 +548,6 @@ test('create a product discount, recurse 2', async (t) => { await sinv.runFormulas(); await sinv.sync(); - console.log('freeQty', sinv.items![1].quantity); t.equal(!!sinv.items![1].isFreeItem, true); t.equal(sinv.items![1].rate!.float, pricingRuleMap[1].freeItemRate); t.equal(sinv.items![1].quantity, pricingRuleMap[1].freeItemQuantity); diff --git a/models/helpers.ts b/models/helpers.ts index c051fd50a..277db6869 100644 --- a/models/helpers.ts +++ b/models/helpers.ts @@ -568,13 +568,13 @@ export async function addItem(name: string, doc: M) { export async function getPricingRule( doc: Invoice -): Promise { +): Promise { if ( !doc.fyo.singles.AccountingSettings?.enablePricingRule || !doc.isSales || !doc.items ) { - return; + return null; } const pricingRules: ApplicablePricingRules[] = []; @@ -691,13 +691,15 @@ export function canApplyPricingRule( // Filter by Validity if ( pricingRuleDoc.validFrom && - sinvDate.toISOString() < pricingRuleDoc.validFrom.toISOString() + new Date(sinvDate.setHours(0, 0, 0, 0)).toISOString() < + pricingRuleDoc.validFrom.toISOString() ) { return false; } if ( pricingRuleDoc.validTo && - sinvDate.toISOString() > pricingRuleDoc.validTo.toISOString() + new Date(sinvDate.setHours(0, 0, 0, 0)).toISOString() > + pricingRuleDoc.validTo.toISOString() ) { return false; } diff --git a/src/pages/POS/POS.vue b/src/pages/POS/POS.vue index 64ab4ccb1..cc84db677 100644 --- a/src/pages/POS/POS.vue +++ b/src/pages/POS/POS.vue @@ -357,6 +357,23 @@ export default defineComponent({ setTransferRefNo(ref: string) { this.transferRefNo = ref; }, + removeFreeItems() { + if (!this.sinvDoc || !this.sinvDoc.items) { + return; + } + + if (!!this.sinvDoc.isPricingRuleApplied) { + return; + } + + for (const item of this.sinvDoc.items) { + if (item.isFreeItem) { + this.sinvDoc.items = this.sinvDoc.items?.filter( + (invoiceItem) => invoiceItem.name !== item.name + ); + } + } + }, async addItem(item: POSItem | Item | undefined) { // eslint-disable-next-line @typescript-eslint/no-floating-promises @@ -380,17 +397,21 @@ export default defineComponent({ const existingItems = this.sinvDoc.items?.filter( - (invoiceItem) => invoiceItem.item === item.name + (invoiceItem) => + invoiceItem.item === item.name && !invoiceItem.isFreeItem ) ?? []; if (item.hasBatch) { - for (const item of existingItems) { - const itemQty = item.quantity ?? 0; + for (const invItem of existingItems) { + const itemQty = invItem.quantity ?? 0; const qtyInBatch = - this.itemQtyMap[item.item as string][item.batch as string] ?? 0; + this.itemQtyMap[invItem.item as string][invItem.batch as string] ?? + 0; if (itemQty < qtyInBatch) { - item.quantity = (item.quantity as number) + 1; + invItem.quantity = (invItem.quantity as number) + 1; + invItem.rate = item.rate as Money; + return; } } @@ -410,8 +431,10 @@ export default defineComponent({ } if (existingItems.length) { + existingItems[0].rate = item.rate as Money; existingItems[0].quantity = (existingItems[0].quantity as number) + 1; await this.applyPricingRule(); + await this.sinvDoc.runFormulas(); return; } @@ -563,7 +586,11 @@ export default defineComponent({ const hasPricingRules = await getPricingRule( this.sinvDoc as SalesInvoice ); - if (!hasPricingRules) { + + if (!hasPricingRules || !hasPricingRules.length) { + this.sinvDoc.pricingRuleDetail = undefined; + this.sinvDoc.isPricingRuleApplied = false; + this.removeFreeItems(); return; } diff --git a/src/utils/pos.ts b/src/utils/pos.ts index 250475278..7a4b4d3db 100644 --- a/src/utils/pos.ts +++ b/src/utils/pos.ts @@ -21,7 +21,8 @@ import { showToast } from './interactive'; export async function getItemQtyMap(): Promise { const itemQtyMap: ItemQtyMap = {}; const valuationMethod = - fyo.singles.InventorySettings?.valuationMethod ?? ValuationMethod.FIFO; + (fyo.singles.InventorySettings?.valuationMethod as ValuationMethod) ?? + ValuationMethod.FIFO; const rawSLEs = await getRawStockLedgerEntries(fyo); const rawData = getStockLedgerEntries(rawSLEs, valuationMethod);