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:
@@ -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]);
|
||||
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user