diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index 049470af..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,17 +776,26 @@ 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), + qty: + -(totalQtyOfReturnedItems[docItem.item as string] as number) / + (item.unitConversionFactor as number), transferQuantity: -( (totalQtyOfReturnedItems[docItem.item as string] as number) / (item.unitConversionFactor as number) @@ -835,6 +861,7 @@ export abstract class Invoice extends Transactional { serialNumber, name: undefined, quantity: quantity, + qty: transferQuantity, transferQuantity, }); } diff --git a/models/baseModels/SalesInvoice/SalesInvoice.ts b/models/baseModels/SalesInvoice/SalesInvoice.ts index 642712dc..9d4014d7 100644 --- a/models/baseModels/SalesInvoice/SalesInvoice.ts +++ b/models/baseModels/SalesInvoice/SalesInvoice.ts @@ -118,9 +118,7 @@ export class SalesInvoice extends Invoice { today.setHours(0, 0, 0, 0); if (toDate && new Date(toDate).getTime() < today.getTime()) { - throw new ValidationError( - t`Loyalty program has expired and cannot be applied` - ); + return; } if (!this?.grandTotal) { diff --git a/models/helpers.ts b/models/helpers.ts index 2b0529ed..aaa3fcbc 100644 --- a/models/helpers.ts +++ b/models/helpers.ts @@ -1642,20 +1642,12 @@ export async function validateLoyaltyProgram( filters: { name: loyaltyProgramName }, }); - if (!loyaltyProgram[0]?.isEnabled) { - throw new ValidationError( - 'Loyalty program cannot be applied as it is not enabled' - ); - } - if ( (loyaltyProgram[0]?.maximumUse as number) > 0 && (loyaltyProgram[0]?.used as number) >= (loyaltyProgram[0]?.maximumUse as number) ) { - throw new ValidationError( - 'Loyalty program has reached maximum usage limit' - ); + return; } if ( @@ -1672,9 +1664,8 @@ export async function validateLoyaltyProgram( const normalizedToDate = new Date(toDate); normalizedToDate.setHours(0, 0, 0, 0); - // Only throw error if toDate is clearly in the past if (normalizedToDate.getTime() < today.getTime()) { - throw new ValidationError('Loyalty program has expired'); + return; } } }