From f958e63f50ed8bbb698611e29056b48846d68ab6 Mon Sep 17 00:00:00 2001 From: Gadha2311 Date: Tue, 24 Feb 2026 12:40:40 +0530 Subject: [PATCH] fix: resolve batch quantity mismatch during return --- models/baseModels/Invoice/Invoice.ts | 49 +++++++++++-------- .../baseModels/SalesInvoice/SalesInvoice.ts | 6 --- models/helpers.ts | 13 +---- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index 0756a587..f91c176f 100644 --- a/models/baseModels/Invoice/Invoice.ts +++ b/models/baseModels/Invoice/Invoice.ts @@ -199,6 +199,23 @@ export abstract class Invoice extends Transactional { if (this.isQuote) { return; } + if (!this.submitted && this.loyaltyProgram) { + const isExpiredOrMaxed = await isLoyaltyProgramExpiredAndMaxed( + this.fyo, + this.loyaltyProgram + ); + + if (isExpiredOrMaxed) { + const { showToast } = await import('src/utils/interactive'); + + showToast({ + type: 'warning', + message: t`Loyalty program has expired or reached maximum usage`, + duration: 'short', + }); + } + } + if ( this.enableDiscounting && !this.fyo.singles?.AccountingSettings?.discountAccount @@ -759,14 +776,20 @@ export abstract class Invoice extends Transactional { if (item.batch) { const returnData = totalQtyOfReturnedItems[item.item as string]; if (typeof returnData === 'object' && returnData?.batches) { - returnDocItems = docItems.map((docItem) => ({ - ...docItem, - name: undefined, - quantity: -returnData?.batches![docItem.batch as string] || 0, - })); + returnDocItems = docItems.map((docItem: DocValueMap) => { + const qty = -returnData?.batches![docItem.batch as string] || 0; + const transferQty = + qty / ((docItem.unitConversionFactor as number) || 1); + return { + ...docItem, + name: undefined, + quantity: qty, + transferQuantity: transferQty, + }; + }); } } else { - returnDocItems = docItems.map((docItem) => ({ + returnDocItems = docItems.map((docItem: DocValueMap) => ({ ...docItem, name: undefined, quantity: -(totalQtyOfReturnedItems[docItem.item as string] || 0), @@ -1615,20 +1638,6 @@ export abstract class Invoice extends Transactional { async beforeSync(): Promise { await super.beforeSync(); - if (this.loyaltyProgram) { - const isExpiredOrMaxed = await isLoyaltyProgramExpiredAndMaxed( - this.fyo, - this.loyaltyProgram - ); - if (isExpiredOrMaxed) { - const { showToast } = await import('src/utils/interactive'); - showToast({ - type: 'warning', - message: t`Loyalty program has expired or reached maximum usage`, - duration: 'short', - }); - } - } if (this.pricingRuleDetail?.length) { await this.applyProductDiscount(); diff --git a/models/baseModels/SalesInvoice/SalesInvoice.ts b/models/baseModels/SalesInvoice/SalesInvoice.ts index 5024d495..9d4014d7 100644 --- a/models/baseModels/SalesInvoice/SalesInvoice.ts +++ b/models/baseModels/SalesInvoice/SalesInvoice.ts @@ -118,12 +118,6 @@ export class SalesInvoice extends Invoice { today.setHours(0, 0, 0, 0); if (toDate && new Date(toDate).getTime() < today.getTime()) { - const { showToast } = await import('src/utils/interactive'); - showToast({ - type: 'warning', - message: t`Loyalty program has expired and cannot be applied`, - duration: 'short', - }); return; } diff --git a/models/helpers.ts b/models/helpers.ts index 88ba7bb5..519b6e5c 100644 --- a/models/helpers.ts +++ b/models/helpers.ts @@ -1637,12 +1637,6 @@ export async function validateLoyaltyProgram( (loyaltyProgram[0]?.used as number) >= (loyaltyProgram[0]?.maximumUse as number) ) { - const { showToast } = await import('src/utils/interactive'); - showToast({ - type: 'warning', - message: t`Loyalty program has reached maximum usage`, - duration: 'short', - }); return; } @@ -1661,12 +1655,7 @@ export async function validateLoyaltyProgram( normalizedToDate.setHours(0, 0, 0, 0); if (normalizedToDate.getTime() < today.getTime()) { - const { showToast } = await import('src/utils/interactive'); - showToast({ - type: 'warning', - message: t`Loyalty program has expired`, - duration: 'short', - }); + // Toast is already shown in beforeSync(), no need to duplicate return; } }