mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
fix: prevent multiple pricing rules on same item across batches
This commit is contained in:
parent
9347acc0aa
commit
3f88b38d4a
@ -1,4 +1,4 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { Fyo, t } from 'fyo';
|
||||
import { DocValueMap } from 'fyo/core/types';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
@ -1186,6 +1186,7 @@ export abstract class Invoice extends Transactional {
|
||||
if (!this.isSales || !this.items) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pricingRules: ApplicablePricingRules[] = [];
|
||||
|
||||
for (const item of this.items) {
|
||||
@ -1193,6 +1194,23 @@ export abstract class Invoice extends Transactional {
|
||||
continue;
|
||||
}
|
||||
|
||||
const duplicatePricingRule = this.pricingRuleDetail?.filter(
|
||||
(pricingrule: PricingRuleDetail) =>
|
||||
pricingrule.referenceItem == item.item
|
||||
);
|
||||
|
||||
if (duplicatePricingRule && duplicatePricingRule?.length >= 2) {
|
||||
const { showToast } = await import('src/utils/interactive');
|
||||
const message = t`Pricing Rule '${
|
||||
duplicatePricingRule[0]?.referenceName as string
|
||||
}' is already applied to item '${
|
||||
item.item as string
|
||||
}' in another batch.`;
|
||||
showToast({ type: 'error', message });
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const pricingRuleDocNames = (
|
||||
await this.fyo.db.getAll(ModelNameEnum.PricingRuleItem, {
|
||||
fields: ['parent'],
|
||||
@ -1227,21 +1245,16 @@ export abstract class Invoice extends Transactional {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const filteredDoc of filtered) {
|
||||
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
|
||||
filteredDoc,
|
||||
filteredDoc.priority as number
|
||||
);
|
||||
const isPricingRuleHasConflicts = getPricingRulesConflicts(filtered);
|
||||
|
||||
if (isPricingRuleHasConflicts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pricingRules.push({
|
||||
applyOnItem: item.item as string,
|
||||
pricingRule: filtered[0],
|
||||
});
|
||||
if (isPricingRuleHasConflicts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pricingRules.push({
|
||||
applyOnItem: item.item as string,
|
||||
pricingRule: filtered[0],
|
||||
});
|
||||
}
|
||||
|
||||
return pricingRules;
|
||||
|
@ -24,7 +24,6 @@ import { InvoiceStatus, ModelNameEnum } from './types';
|
||||
import { Lead } from './baseModels/Lead/Lead';
|
||||
import { PricingRule } from './baseModels/PricingRule/PricingRule';
|
||||
import { ApplicablePricingRules } from './baseModels/Invoice/types';
|
||||
import { PricingRuleItem } from './baseModels/PricingRuleItem/PricingRuleItem';
|
||||
|
||||
export function getQuoteActions(
|
||||
fyo: Fyo,
|
||||
@ -713,23 +712,18 @@ export async function getPricingRule(
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const filteredPricingRule of filtered) {
|
||||
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
|
||||
filteredPricingRule,
|
||||
filteredPricingRule.priority as number
|
||||
);
|
||||
const isPricingRuleHasConflicts = getPricingRulesConflicts(filtered);
|
||||
|
||||
if (isPricingRuleHasConflicts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pricingRules.push({
|
||||
applyOnItem: item.item as string,
|
||||
pricingRule: filtered[0],
|
||||
});
|
||||
if (isPricingRuleHasConflicts) {
|
||||
continue;
|
||||
}
|
||||
return pricingRules;
|
||||
|
||||
pricingRules.push({
|
||||
applyOnItem: item.item as string,
|
||||
pricingRule: filtered[0],
|
||||
});
|
||||
}
|
||||
return pricingRules;
|
||||
}
|
||||
|
||||
export function filterPricingRules(
|
||||
@ -801,72 +795,30 @@ export function canApplyPricingRule(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export function getPricingRulesConflicts(
|
||||
pricingRules: PricingRule[]
|
||||
): undefined | boolean {
|
||||
const pricingRuleDocs = Array.from(pricingRules);
|
||||
|
||||
export async function getPricingRulesConflicts(
|
||||
pricingRule: PricingRule,
|
||||
priority: number
|
||||
): Promise<{ item: string; pricingRule: string } | undefined> {
|
||||
const items = pricingRule.appliedItems?.map((item) => item.item) as string[];
|
||||
|
||||
for (const item of items) {
|
||||
const duplicatePricingRuleItems = (
|
||||
await pricingRule.fyo.db.getAll(ModelNameEnum.PricingRuleItem, {
|
||||
fields: ['parent'],
|
||||
filters: {
|
||||
item: item,
|
||||
},
|
||||
})
|
||||
).filter(
|
||||
(doc) => doc.parent !== (pricingRule.name as string)
|
||||
) as PricingRuleItem[];
|
||||
|
||||
const pricingRuleNames = duplicatePricingRuleItems.map(
|
||||
(item) => item.parent
|
||||
) as string[];
|
||||
|
||||
const pricingRuleDocs = (await pricingRule.fyo.db.getAll(
|
||||
ModelNameEnum.PricingRule,
|
||||
{
|
||||
fields: ['*'],
|
||||
filters: {
|
||||
name: ['in', pricingRuleNames],
|
||||
},
|
||||
}
|
||||
)) as PricingRule[];
|
||||
|
||||
for (const pricingRuleDoc of pricingRuleDocs) {
|
||||
const minQtys = [
|
||||
pricingRuleDoc.minQuantity,
|
||||
pricingRule.minQuantity,
|
||||
].sort() as number[];
|
||||
|
||||
const maxQtys = [
|
||||
pricingRuleDoc.maxQuantity,
|
||||
pricingRule.maxQuantity,
|
||||
].sort() as number[];
|
||||
|
||||
const qtyHasConflicts = minQtys[1] <= maxQtys[0];
|
||||
|
||||
const minAmounts = [
|
||||
pricingRuleDoc.minAmount?.float,
|
||||
pricingRule.minAmount?.float,
|
||||
].sort() as number[];
|
||||
|
||||
const maxAmounts = [
|
||||
pricingRuleDoc.maxAmount?.float,
|
||||
pricingRule.maxAmount?.float,
|
||||
].sort() as number[];
|
||||
|
||||
const amountHasConflicts = minAmounts[1] <= maxAmounts[0];
|
||||
|
||||
if (
|
||||
(amountHasConflicts || qtyHasConflicts) &&
|
||||
pricingRuleDoc.priority === priority
|
||||
) {
|
||||
return { pricingRule: pricingRuleDoc.name as string, item: item };
|
||||
}
|
||||
}
|
||||
const firstPricingRule = pricingRuleDocs.shift();
|
||||
if (!firstPricingRule) {
|
||||
return;
|
||||
}
|
||||
|
||||
const conflictingPricingRuleNames: string[] = [];
|
||||
for (const pricingRuleDoc of pricingRuleDocs.slice(0)) {
|
||||
if (pricingRuleDoc.priority !== firstPricingRule?.priority) {
|
||||
continue;
|
||||
}
|
||||
|
||||
conflictingPricingRuleNames.push(pricingRuleDoc.name as string);
|
||||
}
|
||||
|
||||
if (!conflictingPricingRuleNames.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function roundFreeItemQty(
|
||||
|
@ -417,6 +417,9 @@ export default defineComponent({
|
||||
invItem.quantity = (invItem.quantity as number) + 1;
|
||||
invItem.rate = item.rate as Money;
|
||||
|
||||
await this.applyPricingRule();
|
||||
await this.sinvDoc.runFormulas();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -432,6 +435,7 @@ export default defineComponent({
|
||||
message: t`${error as string}`,
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user