2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-30 12:45:42 +00:00

CreateSalesOrderLineItem: auto-apply sales price based on part price_breaks, currency, and quantity (#10549)

* updated part api mixin and part serializer to include salepricebreaks when explicitly queried

* fixed bug in ApiForm that prevents form field value from updating correctly

* CreateSalesOrderLineItem form now automatically applies price break based on currency and quantity for a part

* bumped API version due to PartsList api price_breaks query param

* fixed incorrect field names

* Remove whitespace

* Increase database query limit from 20 to 25

* updated ApiForm to propagate false and 0 as values to their respective fields, updated ApiFormField to eagerly apply AdjustValue to apply adjustments when onChange does not fire (when the value does not truly change)

* updated pagination number check to a range instead of discreet values.

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
karan Lala
2025-10-19 17:47:05 -07:00
committed by GitHub
parent 2cae87d138
commit 5425ace1fa
8 changed files with 159 additions and 21 deletions

View File

@@ -174,8 +174,14 @@ export function ApiForm({
);
const defaultValues: FieldValues = useMemo(() => {
const defaultValuesMap = mapFields(fields ?? {}, (_path, field) => {
return field.value ?? field.default ?? undefined;
const defaultValuesMap = mapFields(props.fields ?? {}, (_path, field) => {
if (field.value !== undefined && field.value !== null) {
return field.value;
}
if (field.default !== undefined && field.default !== null) {
return field.default;
}
return undefined;
});
// If the user has specified initial data, that overrides default values
@@ -188,7 +194,6 @@ export function ApiForm({
}
});
}
return defaultValuesMap;
}, [props.fields, props.initialData]);

View File

@@ -56,7 +56,11 @@ export function ApiFormField({
// hook up the value state to the input field
if (definition.value !== undefined) {
field.onChange(definition.value);
field.onChange(
definition.adjustValue
? definition.adjustValue(definition.value)
: definition.value
);
}
}, [definition.value]);
@@ -112,7 +116,7 @@ export function ApiFormField({
switch (definition.field_type) {
case 'integer':
val = Number.parseInt(value) ?? '';
val = Number.parseInt(value, 10) ?? '';
break;
case 'decimal':
case 'float':

View File

@@ -101,14 +101,36 @@ export function useSalesOrderFields({
export function useSalesOrderLineItemFields({
customerId,
orderId,
create
create,
currency
}: {
customerId?: number;
orderId?: number;
create?: boolean;
currency?: string;
}): ApiFormFieldSet {
const fields = useMemo(() => {
return {
const [salePrice, setSalePrice] = useState<string>('0');
const [partCurrency, setPartCurrency] = useState<string>(currency ?? '');
const [part, setPart] = useState<any>({});
const [quantity, setQuantity] = useState<string>('');
useEffect(() => {
if (!create || !part || !part.price_breaks) return;
const qty = quantity ? Number.parseInt(quantity, 10) : 0;
const applicablePriceBreaks = part.price_breaks
.filter(
(pb: any) => pb.price_currency == partCurrency && qty <= pb.quantity
)
.sort((a: any, b: any) => a.quantity - b.quantity);
if (applicablePriceBreaks.length)
setSalePrice(applicablePriceBreaks[0].price);
}, [part, quantity, partCurrency, create]);
return useMemo(() => {
const fields: ApiFormFieldSet = {
order: {
filters: {
customer_detail: true
@@ -119,20 +141,29 @@ export function useSalesOrderLineItemFields({
part: {
filters: {
active: true,
salable: true
}
salable: true,
price_breaks: true
},
onValueChange: (_: any, record?: any) => setPart(record)
},
reference: {},
quantity: {},
sale_price: {},
sale_price_currency: {},
quantity: {
onValueChange: setQuantity
},
sale_price: {
value: salePrice
},
sale_price_currency: {
value: partCurrency,
onValueChange: setPartCurrency
},
target_date: {},
notes: {},
link: {}
};
}, []);
return fields;
return fields;
}, [salePrice, partCurrency, orderId, create]);
}
function SalesOrderAllocateLineRow({

View File

@@ -148,7 +148,7 @@ export default function SalesOrderLineItemTable({
0
);
let color: string | undefined = undefined;
let color: string | undefined;
let text = `${formatDecimal(available)}`;
const extra: ReactNode[] = [];
@@ -241,7 +241,8 @@ export default function SalesOrderLineItemTable({
const createLineFields = useSalesOrderLineItemFields({
orderId: orderId,
customerId: customerId,
create: true
create: true,
currency: currency
});
const newLine = useCreateApiFormModal({