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:
parent
733f60247d
commit
9741c54458
@ -1227,19 +1227,21 @@ export abstract class Invoice extends Transactional {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPricingRuleHasConflicts = getPricingRulesConflicts(
|
for (const filteredDoc of filtered) {
|
||||||
filtered,
|
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
|
||||||
filtered[0].priority as number
|
filteredDoc,
|
||||||
);
|
filteredDoc.priority as number
|
||||||
|
);
|
||||||
|
|
||||||
if (isPricingRuleHasConflicts) {
|
if (isPricingRuleHasConflicts) {
|
||||||
continue;
|
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;
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
import { DocValue } from 'fyo/core/types';
|
import { DocValue } from 'fyo/core/types';
|
||||||
import { ValidationError } from 'fyo/utils/errors';
|
import { ValidationError } from 'fyo/utils/errors';
|
||||||
import { t } from 'fyo';
|
import { t } from 'fyo';
|
||||||
import { ModelNameEnum } from 'models/types';
|
|
||||||
|
|
||||||
export class PricingRule extends Doc {
|
export class PricingRule extends Doc {
|
||||||
isEnabled?: boolean;
|
isEnabled?: boolean;
|
||||||
@ -130,46 +129,18 @@ export class PricingRule extends Doc {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
priority: async (value: DocValue) => {
|
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) {
|
if (!pricingRuleConflicts) {
|
||||||
const duplicatePricingRuleItems = (await this.fyo.db.getAll(
|
return;
|
||||||
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}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new ValidationError(
|
||||||
|
t`Pricing Rules ${pricingRuleConflicts.pricingRule} has the same Priority for the Item ${pricingRuleConflicts.item}.`
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import { InvoiceStatus, ModelNameEnum } from './types';
|
|||||||
import { Lead } from './baseModels/Lead/Lead';
|
import { Lead } from './baseModels/Lead/Lead';
|
||||||
import { PricingRule } from './baseModels/PricingRule/PricingRule';
|
import { PricingRule } from './baseModels/PricingRule/PricingRule';
|
||||||
import { ApplicablePricingRules } from './baseModels/Invoice/types';
|
import { ApplicablePricingRules } from './baseModels/Invoice/types';
|
||||||
|
import { PricingRuleItem } from './baseModels/PricingRuleItem/PricingRuleItem';
|
||||||
|
|
||||||
export function getQuoteActions(
|
export function getQuoteActions(
|
||||||
fyo: Fyo,
|
fyo: Fyo,
|
||||||
@ -662,13 +663,13 @@ export async function addItem<M extends ModelsWithItems>(name: string, doc: M) {
|
|||||||
|
|
||||||
export async function getPricingRule(
|
export async function getPricingRule(
|
||||||
doc: Invoice
|
doc: Invoice
|
||||||
): Promise<ApplicablePricingRules[] | null> {
|
): Promise<ApplicablePricingRules[] | undefined> {
|
||||||
if (
|
if (
|
||||||
!doc.fyo.singles.AccountingSettings?.enablePricingRule ||
|
!doc.fyo.singles.AccountingSettings?.enablePricingRule ||
|
||||||
!doc.isSales ||
|
!doc.isSales ||
|
||||||
!doc.items
|
!doc.items
|
||||||
) {
|
) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pricingRules: ApplicablePricingRules[] = [];
|
const pricingRules: ApplicablePricingRules[] = [];
|
||||||
@ -712,22 +713,23 @@ export async function getPricingRule(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPricingRuleHasConflicts = getPricingRulesConflicts(
|
for (const filteredPricingRule of filtered) {
|
||||||
filtered,
|
const isPricingRuleHasConflicts = await getPricingRulesConflicts(
|
||||||
filtered[0].priority as number
|
filteredPricingRule,
|
||||||
);
|
filteredPricingRule.priority as number
|
||||||
|
);
|
||||||
|
|
||||||
if (isPricingRuleHasConflicts) {
|
if (isPricingRuleHasConflicts) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pricingRules.push({
|
||||||
|
applyOnItem: item.item as string,
|
||||||
|
pricingRule: filtered[0],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
return pricingRules;
|
||||||
pricingRules.push({
|
|
||||||
applyOnItem: item.item as string,
|
|
||||||
pricingRule: filtered[0],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pricingRules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterPricingRules(
|
export function filterPricingRules(
|
||||||
@ -800,32 +802,71 @@ export function canApplyPricingRule(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPricingRulesConflicts(
|
export async function getPricingRulesConflicts(
|
||||||
pricingRules: PricingRule[],
|
pricingRule: PricingRule,
|
||||||
priority: number
|
priority: number
|
||||||
): string[] | undefined {
|
): Promise<{ item: string; pricingRule: string } | undefined> {
|
||||||
const pricingRuleDocs = Array.from(pricingRules);
|
const items = pricingRule.appliedItems?.map((item) => item.item) as string[];
|
||||||
|
|
||||||
const firstPricingRule = pricingRuleDocs.shift();
|
for (const item of items) {
|
||||||
if (!priority) {
|
const duplicatePricingRuleItems = (
|
||||||
return;
|
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)) {
|
const pricingRuleDocs = (await pricingRule.fyo.db.getAll(
|
||||||
if (pricingRuleDoc.priority !== firstPricingRule?.priority) {
|
ModelNameEnum.PricingRule,
|
||||||
continue;
|
{
|
||||||
|
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(
|
export function roundFreeItemQty(
|
||||||
|
Loading…
Reference in New Issue
Block a user