From e12bdcfb699edd5ad1243a4661996350ea5e737a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 24 Aug 2026 22:20:18 +1000 Subject: [PATCH] [UI] Data import for order lines (#12692) * [UI] Data import for order lines * Adjust playwright tests --- .../components/items/LineItemCreationMenu.tsx | 48 +++++++++++++++++ .../pages/purchasing/PurchaseOrderDetail.tsx | 1 + .../src/pages/sales/ReturnOrderDetail.tsx | 1 + .../src/pages/sales/SalesOrderDetail.tsx | 1 + .../src/tables/general/ExtraLineItemTable.tsx | 47 ++++++++++++++--- .../purchasing/PurchaseOrderLineItemTable.tsx | 22 ++++---- .../tables/sales/ReturnOrderLineItemTable.tsx | 51 +++++++++++++++++-- .../tables/sales/SalesOrderLineItemTable.tsx | 47 ++++++++++++++--- .../tests/pages/pui_purchasing.spec.ts | 4 +- src/frontend/tests/pages/pui_sales.spec.ts | 4 +- src/frontend/tests/pui_importing.spec.ts | 10 +++- 11 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 src/frontend/src/components/items/LineItemCreationMenu.tsx diff --git a/src/frontend/src/components/items/LineItemCreationMenu.tsx b/src/frontend/src/components/items/LineItemCreationMenu.tsx new file mode 100644 index 0000000000..0b110ade02 --- /dev/null +++ b/src/frontend/src/components/items/LineItemCreationMenu.tsx @@ -0,0 +1,48 @@ +import { IconFileUpload, IconPlus } from '@tabler/icons-react'; + +import { ActionDropdown } from './ActionDropdown'; + +/** + * A split "add" button which allows either direct creation of a single line item, + * or bulk creation via a data import session. + */ +export function LineItemCreationMenu({ + tooltip, + addLabel, + importLabel, + hidden = false, + enableImport = true, + onAdd, + onImport +}: Readonly<{ + tooltip: string; + addLabel: string; + importLabel: string; + hidden?: boolean; + enableImport?: boolean; + onAdd: () => void; + onImport: () => void; +}>) { + return ( + } + hidden={hidden} + actions={[ + { + name: addLabel, + icon: , + onClick: onAdd + }, + { + name: importLabel, + icon: , + hidden: !enableImport, + onClick: onImport + } + ]} + /> + ); +} diff --git a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx index ce2549bdf6..ae321be63f 100644 --- a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx +++ b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx @@ -171,6 +171,7 @@ export default function PurchaseOrderDetail() { void; @@ -49,6 +54,7 @@ export default function ExtraLineItemTable({ }>) { const table = useTable('extra-line-item'); const user = useUserState(); + const openImporter = useImporterState((state) => state.openImporter); const tableColumns: TableColumn[] = useMemo(() => { return [ @@ -126,6 +132,31 @@ export default function ExtraLineItemTable({ table: table }); + const importSessionFields = useMemo(() => { + const fields = dataImporterSessionFields({ modelType: importModelType }); + + fields.field_overrides.value = { + order: orderId + }; + + fields.field_defaults.value = { + price_currency: currency + }; + + return fields; + }, [orderId, currency, importModelType]); + + const importLineItems = useCreateApiFormModal({ + url: ApiEndpoints.import_session_list, + title: t`Import Line Items`, + fields: importSessionFields, + onFormSuccess: (response: any) => { + openImporter(response.pk, { + onClose: table.refreshTable + }); + } + }); + const rowActions = useCallback( (record: any): RowAction[] => { return [ @@ -157,25 +188,29 @@ export default function ExtraLineItemTable({ const tableActions = useMemo(() => { return [ -