mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
[UI] Improve order parts wizard (#9389)
* [UI] Improve order parts wizard - Enhance placeholder text - Precalculate order quantity * Tweak playwright tests * Simplify tests
This commit is contained in:
parent
7b994a3d07
commit
66d5180d8f
@ -38,11 +38,13 @@ interface PartOrderRecord {
|
|||||||
function SelectPartsStep({
|
function SelectPartsStep({
|
||||||
records,
|
records,
|
||||||
onRemovePart,
|
onRemovePart,
|
||||||
|
onSelectQuantity,
|
||||||
onSelectSupplierPart,
|
onSelectSupplierPart,
|
||||||
onSelectPurchaseOrder
|
onSelectPurchaseOrder
|
||||||
}: {
|
}: {
|
||||||
records: PartOrderRecord[];
|
records: PartOrderRecord[];
|
||||||
onRemovePart: (part: any) => void;
|
onRemovePart: (part: any) => void;
|
||||||
|
onSelectQuantity: (partId: number, quantity: number) => void;
|
||||||
onSelectSupplierPart: (partId: number, supplierPart: any) => void;
|
onSelectSupplierPart: (partId: number, supplierPart: any) => void;
|
||||||
onSelectPurchaseOrder: (partId: number, purchaseOrder: any) => void;
|
onSelectPurchaseOrder: (partId: number, purchaseOrder: any) => void;
|
||||||
}) {
|
}) {
|
||||||
@ -151,6 +153,7 @@ function SelectPartsStep({
|
|||||||
field_type: 'related field',
|
field_type: 'related field',
|
||||||
api_url: apiUrl(ApiEndpoints.supplier_part_list),
|
api_url: apiUrl(ApiEndpoints.supplier_part_list),
|
||||||
model: ModelType.supplierpart,
|
model: ModelType.supplierpart,
|
||||||
|
placeholder: t`Select supplier part`,
|
||||||
required: true,
|
required: true,
|
||||||
value: record.supplier_part?.pk,
|
value: record.supplier_part?.pk,
|
||||||
onValueChange: (value, instance) => {
|
onValueChange: (value, instance) => {
|
||||||
@ -189,6 +192,7 @@ function SelectPartsStep({
|
|||||||
field_type: 'related field',
|
field_type: 'related field',
|
||||||
api_url: apiUrl(ApiEndpoints.purchase_order_list),
|
api_url: apiUrl(ApiEndpoints.purchase_order_list),
|
||||||
model: ModelType.purchaseorder,
|
model: ModelType.purchaseorder,
|
||||||
|
placeholder: t`Select purchase order`,
|
||||||
disabled: !record.supplier_part?.supplier,
|
disabled: !record.supplier_part?.supplier,
|
||||||
value: record.purchase_order?.pk,
|
value: record.purchase_order?.pk,
|
||||||
filters: {
|
filters: {
|
||||||
@ -213,6 +217,26 @@ function SelectPartsStep({
|
|||||||
</Group>
|
</Group>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessor: 'quantity',
|
||||||
|
title: t`Quantity`,
|
||||||
|
width: 125,
|
||||||
|
render: (record: PartOrderRecord) => (
|
||||||
|
<StandaloneField
|
||||||
|
fieldName='quantity'
|
||||||
|
hideLabels={true}
|
||||||
|
error={record.errors?.quantity}
|
||||||
|
fieldDefinition={{
|
||||||
|
field_type: 'number',
|
||||||
|
required: true,
|
||||||
|
value: record.quantity,
|
||||||
|
onValueChange: (value) => {
|
||||||
|
onSelectQuantity(record.part.pk, value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessor: 'right_actions',
|
accessor: 'right_actions',
|
||||||
title: ' ',
|
title: ' ',
|
||||||
@ -288,6 +312,22 @@ export default function OrderPartsWizard({
|
|||||||
[selectedParts]
|
[selectedParts]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Select a quantity to order
|
||||||
|
const selectQuantity = useCallback(
|
||||||
|
(partId: number, quantity: number) => {
|
||||||
|
const records = [...selectedParts];
|
||||||
|
|
||||||
|
records.forEach((record: PartOrderRecord, index: number) => {
|
||||||
|
if (record.part.pk === partId) {
|
||||||
|
records[index].quantity = quantity;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedParts(records);
|
||||||
|
},
|
||||||
|
[selectedParts]
|
||||||
|
);
|
||||||
|
|
||||||
// Select a supplier part for a part
|
// Select a supplier part for a part
|
||||||
const selectSupplierPart = useCallback(
|
const selectSupplierPart = useCallback(
|
||||||
(partId: number, supplierPart: any) => {
|
(partId: number, supplierPart: any) => {
|
||||||
@ -327,6 +367,7 @@ export default function OrderPartsWizard({
|
|||||||
<SelectPartsStep
|
<SelectPartsStep
|
||||||
records={selectedParts}
|
records={selectedParts}
|
||||||
onRemovePart={removePart}
|
onRemovePart={removePart}
|
||||||
|
onSelectQuantity={selectQuantity}
|
||||||
onSelectSupplierPart={selectSupplierPart}
|
onSelectSupplierPart={selectSupplierPart}
|
||||||
onSelectPurchaseOrder={selectPurchaseOrder}
|
onSelectPurchaseOrder={selectPurchaseOrder}
|
||||||
/>
|
/>
|
||||||
@ -400,11 +441,23 @@ export default function OrderPartsWizard({
|
|||||||
(record: PartOrderRecord) => record.part?.pk === part.pk
|
(record: PartOrderRecord) => record.part?.pk === part.pk
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
// TODO: Make this calculation generic and reusable
|
||||||
|
// Calculate the "to order" quantity
|
||||||
|
const required =
|
||||||
|
(part.minimum_stock ?? 0) +
|
||||||
|
(part.required_for_build_orders ?? 0) +
|
||||||
|
(part.required_for_sales_orders ?? 0);
|
||||||
|
const on_hand = part.total_in_stock ?? 0;
|
||||||
|
const on_order = part.ordering ?? 0;
|
||||||
|
const in_production = part.building ?? 0;
|
||||||
|
|
||||||
|
const to_order = required - on_hand - on_order - in_production;
|
||||||
|
|
||||||
records.push({
|
records.push({
|
||||||
part: part,
|
part: part,
|
||||||
supplier_part: undefined,
|
supplier_part: undefined,
|
||||||
purchase_order: undefined,
|
purchase_order: undefined,
|
||||||
quantity: 1,
|
quantity: Math.max(to_order, 0),
|
||||||
errors: {}
|
errors: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -283,6 +283,8 @@ test('Purchase Orders - Order Parts', async ({ browser }) => {
|
|||||||
await page.getByText('PRJ-PHO').click();
|
await page.getByText('PRJ-PHO').click();
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
|
await page.getByLabel('number-field-quantity').fill('100');
|
||||||
|
|
||||||
// Add the part to the purchase order
|
// Add the part to the purchase order
|
||||||
await page.getByLabel('action-button-add-to-selected').click();
|
await page.getByLabel('action-button-add-to-selected').click();
|
||||||
await page.getByLabel('number-field-quantity').fill('100');
|
await page.getByLabel('number-field-quantity').fill('100');
|
||||||
|
@ -126,8 +126,6 @@ test('Forms - Supplier Validation', async ({ browser }) => {
|
|||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
// Is prevented, due to uniqueness requirements
|
// Is prevented, due to uniqueness requirements
|
||||||
await page
|
await page.getByText('Form Error').waitFor();
|
||||||
.getByText('Company with this Company name and Email already exists')
|
|
||||||
.waitFor();
|
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user