mirror of
https://github.com/frappe/books.git
synced 2026-08-24 02:24:17 -05:00
Merge pull request #1305 from frappe/fix-loyaltypoints-in-batch
fix: correct loyalty points calculation for returned batch items
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
removeLoyaltyPoint,
|
||||
roundFreeItemQty,
|
||||
getReturnQtyTotal,
|
||||
getReturnLoyaltyPoints,
|
||||
} from 'models/helpers';
|
||||
import { StockTransfer } from 'models/inventory/StockTransfer';
|
||||
import { validateBatch } from 'models/inventory/helpers';
|
||||
@@ -58,6 +59,13 @@ export type TaxDetail = {
|
||||
rate: number;
|
||||
};
|
||||
|
||||
export type ReturnedItemData =
|
||||
| number
|
||||
| {
|
||||
quantity?: number;
|
||||
batches?: Record<string, number>;
|
||||
};
|
||||
|
||||
export type InvoiceTaxItem = {
|
||||
details: TaxDetail;
|
||||
exchangeRate?: number;
|
||||
@@ -683,34 +691,30 @@ export abstract class Invoice extends Transactional {
|
||||
);
|
||||
|
||||
for (const item of docItems) {
|
||||
const itemName = item.item as string;
|
||||
|
||||
let balQuantity: number;
|
||||
if (!returnBalanceItemsQty) {
|
||||
if (totalQtyOfReturnedItems) {
|
||||
if (item.batch) {
|
||||
const returnData = totalQtyOfReturnedItems[item.item as string];
|
||||
|
||||
if (typeof returnData === 'object' && returnData?.batches) {
|
||||
balQuantity = -returnData.batches[item.batch as string] || 0;
|
||||
returnDocItems = docItems.map((docItem) => ({
|
||||
...docItem,
|
||||
name: undefined,
|
||||
quantity: -returnData?.batches![docItem.batch as string] || 0,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
balQuantity = -(totalQtyOfReturnedItems[itemName] || 0);
|
||||
returnDocItems = docItems.map((docItem) => ({
|
||||
...docItem,
|
||||
name: undefined,
|
||||
quantity: -(totalQtyOfReturnedItems[docItem.item as string] || 0),
|
||||
}));
|
||||
}
|
||||
|
||||
const returnDocs = docItems.map((docItem) => ({
|
||||
...docItem,
|
||||
name: undefined,
|
||||
quantity: balQuantity,
|
||||
}));
|
||||
|
||||
returnDocItems.push(returnDocs[0]);
|
||||
|
||||
for (const row of returnDocItems) {
|
||||
row.itemDiscountedTotal = await this.getItemsDiscountedTotal(
|
||||
row as InvoiceItem
|
||||
);
|
||||
}
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
const isItemExist = !!returnDocItems.filter(
|
||||
@@ -722,7 +726,7 @@ export abstract class Invoice extends Transactional {
|
||||
}
|
||||
|
||||
const returnedItem: ReturnDocItem | undefined =
|
||||
returnBalanceItemsQty[item.item as string];
|
||||
returnBalanceItemsQty![item.item as string];
|
||||
|
||||
if (!returnedItem) {
|
||||
continue;
|
||||
@@ -745,12 +749,15 @@ export abstract class Invoice extends Transactional {
|
||||
'\n'
|
||||
);
|
||||
}
|
||||
const returnedItemsData = totalQtyOfReturnedItems[itemName];
|
||||
const returnedItemsData = totalQtyOfReturnedItems[
|
||||
item.item as string
|
||||
] as ReturnedItemData;
|
||||
|
||||
if (
|
||||
typeof returnedItemsData === 'object' &&
|
||||
returnedItemsData?.batches
|
||||
returnedItemsData.batches
|
||||
) {
|
||||
quantity = -returnedItemsData?.batches?.[item.batch as string];
|
||||
quantity = -returnedItemsData?.batches[item.batch as string];
|
||||
transferQuantity = quantity / (item.unitConversionFactor as number);
|
||||
}
|
||||
}
|
||||
@@ -922,33 +929,26 @@ export abstract class Invoice extends Transactional {
|
||||
this.loyaltyPoints as number
|
||||
);
|
||||
|
||||
const result = baseTotal.sub(totalLoyaltyAmount);
|
||||
return result;
|
||||
return baseTotal.sub(totalLoyaltyAmount);
|
||||
}
|
||||
|
||||
if (this.isReturn) {
|
||||
const originalInvoice = (await this.fyo.doc.getDoc(
|
||||
this.schemaName,
|
||||
this.returnAgainst
|
||||
)) as Invoice;
|
||||
const loyaltyAmount = await getReturnLoyaltyPoints(this);
|
||||
|
||||
const returnRatio = baseTotal
|
||||
.abs()
|
||||
.div(originalInvoice.netTotal as Money);
|
||||
const totalAmount = baseTotal.abs().sub(loyaltyAmount);
|
||||
|
||||
const originalLoyaltyAmount = await getAddedLPWithGrandTotal(
|
||||
this.fyo,
|
||||
originalInvoice.loyaltyProgram as string,
|
||||
originalInvoice.loyaltyPoints as number
|
||||
);
|
||||
this.loyaltyPoints = loyaltyAmount;
|
||||
if (totalAmount.isNegative()) {
|
||||
this.loyaltyPoints = totalAmount.abs().float - Math.abs(loyaltyAmount);
|
||||
return this.fyo.pesa(0);
|
||||
}
|
||||
|
||||
const proportionalLoyaltyAmount = originalLoyaltyAmount.mul(returnRatio);
|
||||
|
||||
return baseTotal.abs().sub(proportionalLoyaltyAmount).neg();
|
||||
return baseTotal.abs().sub(loyaltyAmount);
|
||||
}
|
||||
|
||||
return baseTotal;
|
||||
}
|
||||
|
||||
formulas: FormulaMap = {
|
||||
account: {
|
||||
formula: async () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ModelNameEnum } from 'models/types';
|
||||
import {
|
||||
getAddedLPWithGrandTotal,
|
||||
getInvoiceActions,
|
||||
getReturnLoyaltyPoints,
|
||||
getTransactionStatusColumn,
|
||||
} from '../../helpers';
|
||||
import { Invoice } from '../Invoice/Invoice';
|
||||
@@ -42,11 +43,17 @@ export class SalesInvoice extends Invoice {
|
||||
this.loyaltyProgram
|
||||
)) as LoyaltyProgram;
|
||||
|
||||
const totalAmount = await getAddedLPWithGrandTotal(
|
||||
this.fyo,
|
||||
this.loyaltyProgram as string,
|
||||
this.loyaltyPoints as number
|
||||
);
|
||||
let totalAmount;
|
||||
|
||||
if (this.isReturn) {
|
||||
totalAmount = this.fyo.pesa(await getReturnLoyaltyPoints(this));
|
||||
} else {
|
||||
totalAmount = await getAddedLPWithGrandTotal(
|
||||
this.fyo,
|
||||
this.loyaltyProgram as string,
|
||||
this.loyaltyPoints as number
|
||||
);
|
||||
}
|
||||
|
||||
await posting.debit(
|
||||
loyaltyProgramDoc.expenseAccount as string,
|
||||
|
||||
@@ -746,6 +746,29 @@ export async function addItem<M extends ModelsWithItems>(name: string, doc: M) {
|
||||
await item.set('item', name);
|
||||
}
|
||||
|
||||
export async function getReturnLoyaltyPoints(doc: Invoice) {
|
||||
const returnDocs = await doc.fyo.db.getAll(doc.schemaName, {
|
||||
fields: ['*'],
|
||||
filters: {
|
||||
returnAgainst: doc.returnAgainst as string,
|
||||
submitted: true,
|
||||
},
|
||||
});
|
||||
|
||||
const totalLoyaltyPoints = returnDocs.reduce(
|
||||
(sum, doc) => sum + Math.abs(doc.loyaltyPoints as number),
|
||||
0
|
||||
);
|
||||
|
||||
const loyaltyPoints = await doc.fyo.getValue(
|
||||
ModelNameEnum.SalesInvoice,
|
||||
doc.returnAgainst as string,
|
||||
'loyaltyPoints'
|
||||
);
|
||||
|
||||
return Math.abs((loyaltyPoints as number) - Math.abs(totalLoyaltyPoints));
|
||||
}
|
||||
|
||||
export async function getReturnQtyTotal(
|
||||
doc: Invoice
|
||||
): Promise<
|
||||
|
||||
Reference in New Issue
Block a user