2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 19:09:01 +00:00

fix: pricingRule validation

This commit is contained in:
akshayitzme 2024-09-09 09:38:02 +05:30
parent 733f60247d
commit 9741c54458
3 changed files with 99 additions and 85 deletions

View File

@ -1227,19 +1227,21 @@ export abstract class Invoice extends Transactional {
continue;
}
const isPricingRuleHasConflicts = getPricingRulesConflicts(
filtered,
filtered[0].priority as number
);
for (const filteredDoc of filtered) {
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
filteredDoc,
filteredDoc.priority as number
);
if (isPricingRuleHasConflicts) {
continue;
if (isPricingRuleHasConflicts) {
continue;
}
pricingRules.push({
applyOnItem: item.item as string,
pricingRule: filtered[0],
});
}
pricingRules.push({
applyOnItem: item.item as string,
pricingRule: filtered[0],
});
}
return pricingRules;

View File

@ -14,7 +14,6 @@ import {
import { DocValue } from 'fyo/core/types';
import { ValidationError } from 'fyo/utils/errors';
import { t } from 'fyo';
import { ModelNameEnum } from 'models/types';
export class PricingRule extends Doc {
isEnabled?: boolean;
@ -130,46 +129,18 @@ export class PricingRule extends Doc {
}
},
priority: async (value: DocValue) => {
const items = this.appliedItems?.map((item) => item.item) as string[];
const pricingRuleConflicts = await getPricingRulesConflicts(
this,
value as number
);
for (const item of items) {
const duplicatePricingRuleItems = (await this.fyo.db.getAll(
ModelNameEnum.PricingRuleItem,
{
fields: ['parent'],
filters: {
item: item,
},
}
)) as PricingRuleItem[];
const pricingRules = duplicatePricingRuleItems.map(
(item) => item.parent
);
const pricingRuleItems = (await this.fyo.db.getAll(
ModelNameEnum.PricingRule,
{
fields: ['*'],
filters: {
name: ['in', pricingRules as string[]],
},
}
)) as PricingRule[];
const isPricingRuleHasConflicts = getPricingRulesConflicts(
pricingRuleItems,
value as number
);
if (isPricingRuleHasConflicts) {
throw new ValidationError(
t`Pricing Rules ${isPricingRuleHasConflicts.join(
', '
)} has the same Priority for the Item ${item}.`
);
}
if (!pricingRuleConflicts) {
return;
}
throw new ValidationError(
t`Pricing Rules ${pricingRuleConflicts.pricingRule} has the same Priority for the Item ${pricingRuleConflicts.item}.`
);
},
};

View File

@ -24,6 +24,7 @@ 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,
@ -662,13 +663,13 @@ export async function addItem<M extends ModelsWithItems>(name: string, doc: M) {
export async function getPricingRule(
doc: Invoice
): Promise<ApplicablePricingRules[] | null> {
): Promise<ApplicablePricingRules[] | undefined> {
if (
!doc.fyo.singles.AccountingSettings?.enablePricingRule ||
!doc.isSales ||
!doc.items
) {
return null;
return;
}
const pricingRules: ApplicablePricingRules[] = [];
@ -712,22 +713,23 @@ export async function getPricingRule(
continue;
}
const isPricingRuleHasConflicts = getPricingRulesConflicts(
filtered,
filtered[0].priority as number
);
for (const filteredPricingRule of filtered) {
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
filteredPricingRule,
filteredPricingRule.priority as number
);
if (isPricingRuleHasConflicts) {
continue;
if (isPricingRuleHasConflicts) {
continue;
}
pricingRules.push({
applyOnItem: item.item as string,
pricingRule: filtered[0],
});
}
pricingRules.push({
applyOnItem: item.item as string,
pricingRule: filtered[0],
});
return pricingRules;
}
return pricingRules;
}
export function filterPricingRules(
@ -800,32 +802,71 @@ export function canApplyPricingRule(
return true;
}
export function getPricingRulesConflicts(
pricingRules: PricingRule[],
export async function getPricingRulesConflicts(
pricingRule: PricingRule,
priority: number
): string[] | undefined {
const pricingRuleDocs = Array.from(pricingRules);
): Promise<{ item: string; pricingRule: string } | undefined> {
const items = pricingRule.appliedItems?.map((item) => item.item) as string[];
const firstPricingRule = pricingRuleDocs.shift();
if (!priority) {
return;
}
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 conflictingPricingRuleNames: string[] = [];
const pricingRuleNames = duplicatePricingRuleItems.map(
(item) => item.parent
) as string[];
for (const pricingRuleDoc of pricingRuleDocs.slice(0)) {
if (pricingRuleDoc.priority !== firstPricingRule?.priority) {
continue;
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 };
}
}
conflictingPricingRuleNames.push(pricingRuleDoc.name as string);
}
if (!conflictingPricingRuleNames.length) {
return;
}
return conflictingPricingRuleNames;
}
export function roundFreeItemQty(