Skip to content

Commit

Permalink
fix: prevent multiple pricing rules on same item across batches
Browse files Browse the repository at this point in the history
  • Loading branch information
AbleKSaju committed Sep 11, 2024
1 parent 9347acc commit 3f88b38
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 90 deletions.
41 changes: 27 additions & 14 deletions models/baseModels/Invoice/Invoice.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -1186,13 +1186,31 @@ export abstract class Invoice extends Transactional {
if (!this.isSales || !this.items) {
return;
}

const pricingRules: ApplicablePricingRules[] = [];

for (const item of this.items) {
if (item.isFreeItem) {
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'],
Expand Down Expand Up @@ -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;
Expand Down
104 changes: 28 additions & 76 deletions models/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 firstPricingRule = pricingRuleDocs.shift();
if (!firstPricingRule) {
return;
}

const maxAmounts = [
pricingRuleDoc.maxAmount?.float,
pricingRule.maxAmount?.float,
].sort() as number[];
const conflictingPricingRuleNames: string[] = [];
for (const pricingRuleDoc of pricingRuleDocs.slice(0)) {
if (pricingRuleDoc.priority !== firstPricingRule?.priority) {
continue;
}

const amountHasConflicts = minAmounts[1] <= maxAmounts[0];
conflictingPricingRuleNames.push(pricingRuleDoc.name as string);
}

if (
(amountHasConflicts || qtyHasConflicts) &&
pricingRuleDoc.priority === priority
) {
return { pricingRule: pricingRuleDoc.name as string, item: item };
}
}
if (!conflictingPricingRuleNames.length) {
return;
}

return true;
}

export function roundFreeItemQty(
Expand Down
4 changes: 4 additions & 0 deletions src/pages/POS/POS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -432,6 +435,7 @@ export default defineComponent({
message: t`${error as string}`,
});
}
return;
}
Expand Down

0 comments on commit 3f88b38

Please sign in to comment.