mirror of
https://github.com/inventree/InvenTree.git
synced 2026-08-30 08:56:41 +00:00
[UI] Data import for order lines (#12692)
* [UI] Data import for order lines * Adjust playwright tests
This commit is contained in:
@@ -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 (
|
||||||
|
<ActionDropdown
|
||||||
|
key='add-line-item-actions'
|
||||||
|
tooltip={tooltip}
|
||||||
|
position='bottom-start'
|
||||||
|
icon={<IconPlus />}
|
||||||
|
hidden={hidden}
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
name: addLabel,
|
||||||
|
icon: <IconPlus />,
|
||||||
|
onClick: onAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: importLabel,
|
||||||
|
icon: <IconFileUpload />,
|
||||||
|
hidden: !enableImport,
|
||||||
|
onClick: onImport
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -171,6 +171,7 @@ export default function PurchaseOrderDetail() {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<ExtraLineItemTable
|
<ExtraLineItemTable
|
||||||
endpoint={ApiEndpoints.purchase_order_extra_line_list}
|
endpoint={ApiEndpoints.purchase_order_extra_line_list}
|
||||||
|
importModelType='purchaseorderextraline'
|
||||||
orderId={order.pk}
|
orderId={order.pk}
|
||||||
orderDetailRefresh={refreshInstance}
|
orderDetailRefresh={refreshInstance}
|
||||||
currency={orderCurrency}
|
currency={orderCurrency}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ export default function ReturnOrderDetail() {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<ExtraLineItemTable
|
<ExtraLineItemTable
|
||||||
endpoint={ApiEndpoints.return_order_extra_line_list}
|
endpoint={ApiEndpoints.return_order_extra_line_list}
|
||||||
|
importModelType='returnorderextraline'
|
||||||
orderId={order.pk}
|
orderId={order.pk}
|
||||||
orderDetailRefresh={refreshInstance}
|
orderDetailRefresh={refreshInstance}
|
||||||
currency={orderCurrency}
|
currency={orderCurrency}
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ export default function SalesOrderDetail() {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<ExtraLineItemTable
|
<ExtraLineItemTable
|
||||||
endpoint={ApiEndpoints.sales_order_extra_line_list}
|
endpoint={ApiEndpoints.sales_order_extra_line_list}
|
||||||
|
importModelType='salesorderextraline'
|
||||||
orderId={order.pk}
|
orderId={order.pk}
|
||||||
editable={lineItemsEditable}
|
editable={lineItemsEditable}
|
||||||
orderDetailRefresh={refreshInstance}
|
orderDetailRefresh={refreshInstance}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
|
||||||
import {
|
import {
|
||||||
type RowAction,
|
type RowAction,
|
||||||
RowDeleteAction,
|
RowDeleteAction,
|
||||||
RowDuplicateAction,
|
RowDuplicateAction,
|
||||||
RowEditAction
|
RowEditAction
|
||||||
} from '@lib/components/RowActions';
|
} from '@lib/components/RowActions';
|
||||||
import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
|
import type { ModelType } from '@lib/enums/ModelType';
|
||||||
import type { UserRoles } from '@lib/enums/Roles';
|
import type { UserRoles } from '@lib/enums/Roles';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
|
import { LineItemCreationMenu } from '../../components/items/LineItemCreationMenu';
|
||||||
import {
|
import {
|
||||||
DecimalColumn,
|
DecimalColumn,
|
||||||
DescriptionColumn,
|
DescriptionColumn,
|
||||||
@@ -25,15 +26,18 @@ import {
|
|||||||
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
||||||
import { formatCurrency } from '../../defaults/formatters';
|
import { formatCurrency } from '../../defaults/formatters';
|
||||||
import { extraLineItemFields } from '../../forms/CommonForms';
|
import { extraLineItemFields } from '../../forms/CommonForms';
|
||||||
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
import {
|
import {
|
||||||
useCreateApiFormModal,
|
useCreateApiFormModal,
|
||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
|
|
||||||
export default function ExtraLineItemTable({
|
export default function ExtraLineItemTable({
|
||||||
endpoint,
|
endpoint,
|
||||||
|
importModelType,
|
||||||
orderId,
|
orderId,
|
||||||
orderDetailRefresh,
|
orderDetailRefresh,
|
||||||
currency,
|
currency,
|
||||||
@@ -41,6 +45,7 @@ export default function ExtraLineItemTable({
|
|||||||
role
|
role
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
endpoint: ApiEndpoints;
|
endpoint: ApiEndpoints;
|
||||||
|
importModelType: ModelType | string;
|
||||||
orderId: number;
|
orderId: number;
|
||||||
editable: boolean;
|
editable: boolean;
|
||||||
orderDetailRefresh: () => void;
|
orderDetailRefresh: () => void;
|
||||||
@@ -49,6 +54,7 @@ export default function ExtraLineItemTable({
|
|||||||
}>) {
|
}>) {
|
||||||
const table = useTable('extra-line-item');
|
const table = useTable('extra-line-item');
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
|
|
||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@@ -126,6 +132,31 @@ export default function ExtraLineItemTable({
|
|||||||
table: table
|
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(
|
const rowActions = useCallback(
|
||||||
(record: any): RowAction[] => {
|
(record: any): RowAction[] => {
|
||||||
return [
|
return [
|
||||||
@@ -157,25 +188,29 @@ export default function ExtraLineItemTable({
|
|||||||
|
|
||||||
const tableActions = useMemo(() => {
|
const tableActions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
<AddItemButton
|
<LineItemCreationMenu
|
||||||
key='add-line-item'
|
key='add-line-item-actions'
|
||||||
tooltip={t`Add Extra Line Item`}
|
tooltip={t`Add Extra Line Item`}
|
||||||
|
addLabel={t`Add Extra Line Item`}
|
||||||
|
importLabel={t`Import Line Items`}
|
||||||
hidden={!editable || !user.hasAddRole(role)}
|
hidden={!editable || !user.hasAddRole(role)}
|
||||||
onClick={() => {
|
onAdd={() => {
|
||||||
setInitialData({
|
setInitialData({
|
||||||
order: orderId
|
order: orderId
|
||||||
});
|
});
|
||||||
newLineItem.open();
|
newLineItem.open();
|
||||||
}}
|
}}
|
||||||
|
onImport={() => importLineItems.open()}
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
}, [editable, user, role]);
|
}, [editable, user, role, orderId, importLineItems]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{newLineItem.modal}
|
{newLineItem.modal}
|
||||||
{editLineItem.modal}
|
{editLineItem.modal}
|
||||||
{deleteLineItem.modal}
|
{deleteLineItem.modal}
|
||||||
|
{importLineItems.modal}
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
tableState={table}
|
tableState={table}
|
||||||
url={apiUrl(endpoint)}
|
url={apiUrl(endpoint)}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { Text } from '@mantine/core';
|
import { Text } from '@mantine/core';
|
||||||
import { IconFileArrowLeft, IconSquareArrowRight } from '@tabler/icons-react';
|
import { IconSquareArrowRight } from '@tabler/icons-react';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { ActionButton } from '@lib/components/ActionButton';
|
import { ActionButton } from '@lib/components/ActionButton';
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
|
||||||
import { ProgressBar } from '@lib/components/ProgressBar';
|
import { ProgressBar } from '@lib/components/ProgressBar';
|
||||||
import {
|
import {
|
||||||
type RowAction,
|
type RowAction,
|
||||||
@@ -37,6 +36,7 @@ import {
|
|||||||
} from '../../components/tables/ColumnRenderers';
|
} from '../../components/tables/ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
||||||
|
|
||||||
|
import { LineItemCreationMenu } from '../../components/items/LineItemCreationMenu';
|
||||||
import { AppRowViewAction } from '../../components/tables/AppRowActions';
|
import { AppRowViewAction } from '../../components/tables/AppRowActions';
|
||||||
import { TableHoverCard } from '../../components/tables/TableHoverCard';
|
import { TableHoverCard } from '../../components/tables/TableHoverCard';
|
||||||
import { formatCurrency } from '../../defaults/formatters';
|
import { formatCurrency } from '../../defaults/formatters';
|
||||||
@@ -397,23 +397,19 @@ export function PurchaseOrderLineItemTable({
|
|||||||
// Custom table actions
|
// Custom table actions
|
||||||
const tableActions = useMemo(() => {
|
const tableActions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
<ActionButton
|
<LineItemCreationMenu
|
||||||
key='import-line-items'
|
key='add-line-item-actions'
|
||||||
hidden={!editable || !user.hasAddRole(UserRoles.purchase_order)}
|
|
||||||
tooltip={t`Import Line Items`}
|
|
||||||
icon={<IconFileArrowLeft />}
|
|
||||||
onClick={() => importLineItems.open()}
|
|
||||||
/>,
|
|
||||||
<AddItemButton
|
|
||||||
key='add-line-item'
|
|
||||||
tooltip={t`Add Line Item`}
|
tooltip={t`Add Line Item`}
|
||||||
onClick={() => {
|
addLabel={t`Add Line Item`}
|
||||||
|
importLabel={t`Import Line Items`}
|
||||||
|
hidden={!editable || !user.hasAddRole(UserRoles.purchase_order)}
|
||||||
|
onAdd={() => {
|
||||||
setInitialData({
|
setInitialData({
|
||||||
order: orderId
|
order: orderId
|
||||||
});
|
});
|
||||||
newLine.open();
|
newLine.open();
|
||||||
}}
|
}}
|
||||||
hidden={!editable || !user?.hasAddRole(UserRoles.purchase_order)}
|
onImport={() => importLineItems.open()}
|
||||||
/>,
|
/>,
|
||||||
<ActionButton
|
<ActionButton
|
||||||
key='receive-items'
|
key='receive-items'
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { IconFlag, IconSquareArrowRight } from '@tabler/icons-react';
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { ActionButton } from '@lib/components/ActionButton';
|
import { ActionButton } from '@lib/components/ActionButton';
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
|
||||||
import {
|
import {
|
||||||
type RowAction,
|
type RowAction,
|
||||||
RowDeleteAction,
|
RowDeleteAction,
|
||||||
@@ -17,6 +16,7 @@ import useTable from '@lib/hooks/UseTable';
|
|||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
import { Alert } from '@mantine/core';
|
import { Alert } from '@mantine/core';
|
||||||
|
import { LineItemCreationMenu } from '../../components/items/LineItemCreationMenu';
|
||||||
import {
|
import {
|
||||||
DateColumn,
|
DateColumn,
|
||||||
DescriptionColumn,
|
DescriptionColumn,
|
||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
import { StatusFilterOptions } from '../../components/tables/Filter';
|
import { StatusFilterOptions } from '../../components/tables/Filter';
|
||||||
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
||||||
import { formatCurrency } from '../../defaults/formatters';
|
import { formatCurrency } from '../../defaults/formatters';
|
||||||
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
import {
|
import {
|
||||||
useReceiveReturnOrderLineItems,
|
useReceiveReturnOrderLineItems,
|
||||||
useReturnOrderLineItemFields
|
useReturnOrderLineItemFields
|
||||||
@@ -44,6 +45,7 @@ import {
|
|||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import useStatusCodes from '../../hooks/UseStatusCodes';
|
import useStatusCodes from '../../hooks/UseStatusCodes';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
|
|
||||||
export default function ReturnOrderLineItemTable({
|
export default function ReturnOrderLineItemTable({
|
||||||
@@ -63,6 +65,7 @@ export default function ReturnOrderLineItemTable({
|
|||||||
}>) {
|
}>) {
|
||||||
const table = useTable('return-order-line-item');
|
const table = useTable('return-order-line-item');
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
|
|
||||||
const roStatus = useStatusCodes({ modelType: ModelType.returnorder });
|
const roStatus = useStatusCodes({ modelType: ModelType.returnorder });
|
||||||
|
|
||||||
@@ -112,6 +115,33 @@ export default function ReturnOrderLineItemTable({
|
|||||||
table: table
|
table: table
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const importSessionFields = useMemo(() => {
|
||||||
|
const fields = dataImporterSessionFields({
|
||||||
|
modelType: ModelType.returnorderlineitem
|
||||||
|
});
|
||||||
|
|
||||||
|
fields.field_overrides.value = {
|
||||||
|
order: orderId
|
||||||
|
};
|
||||||
|
|
||||||
|
fields.field_defaults.value = {
|
||||||
|
price_currency: currency
|
||||||
|
};
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}, [orderId, currency]);
|
||||||
|
|
||||||
|
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 setOutcome = useBulkEditApiFormModal({
|
const setOutcome = useBulkEditApiFormModal({
|
||||||
url: ApiEndpoints.return_order_line_list,
|
url: ApiEndpoints.return_order_line_list,
|
||||||
items: table.selectedIds,
|
items: table.selectedIds,
|
||||||
@@ -204,13 +234,16 @@ export default function ReturnOrderLineItemTable({
|
|||||||
|
|
||||||
const tableActions = useMemo(() => {
|
const tableActions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
<AddItemButton
|
<LineItemCreationMenu
|
||||||
key='add-line-item'
|
key='add-line-item-actions'
|
||||||
tooltip={t`Add Line Item`}
|
tooltip={t`Add Line Item`}
|
||||||
|
addLabel={t`Add Line Item`}
|
||||||
|
importLabel={t`Import Line Items`}
|
||||||
hidden={!editable || !user.hasAddRole(UserRoles.return_order)}
|
hidden={!editable || !user.hasAddRole(UserRoles.return_order)}
|
||||||
onClick={() => {
|
onAdd={() => {
|
||||||
newLine.open();
|
newLine.open();
|
||||||
}}
|
}}
|
||||||
|
onImport={() => importLineItems.open()}
|
||||||
/>,
|
/>,
|
||||||
<ActionButton
|
<ActionButton
|
||||||
key='receive-items'
|
key='receive-items'
|
||||||
@@ -240,7 +273,14 @@ export default function ReturnOrderLineItemTable({
|
|||||||
disabled={table.selectedRecords.length == 0}
|
disabled={table.selectedRecords.length == 0}
|
||||||
/>
|
/>
|
||||||
];
|
];
|
||||||
}, [user, editable, inProgress, orderId, table.selectedRecords]);
|
}, [
|
||||||
|
user,
|
||||||
|
editable,
|
||||||
|
inProgress,
|
||||||
|
orderId,
|
||||||
|
table.selectedRecords,
|
||||||
|
importLineItems
|
||||||
|
]);
|
||||||
|
|
||||||
const [selectedItems, setSelectedItems] = useState<any[]>([]);
|
const [selectedItems, setSelectedItems] = useState<any[]>([]);
|
||||||
|
|
||||||
@@ -294,6 +334,7 @@ export default function ReturnOrderLineItemTable({
|
|||||||
{deleteLine.modal}
|
{deleteLine.modal}
|
||||||
{receiveLineItems.modal}
|
{receiveLineItems.modal}
|
||||||
{setOutcome.modal}
|
{setOutcome.modal}
|
||||||
|
{importLineItems.modal}
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={apiUrl(ApiEndpoints.return_order_line_list)}
|
url={apiUrl(ApiEndpoints.return_order_line_list)}
|
||||||
tableState={table}
|
tableState={table}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { ActionButton } from '@lib/components/ActionButton';
|
import { ActionButton } from '@lib/components/ActionButton';
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
|
||||||
import { ProgressBar } from '@lib/components/ProgressBar';
|
import { ProgressBar } from '@lib/components/ProgressBar';
|
||||||
import {
|
import {
|
||||||
type RowAction,
|
type RowAction,
|
||||||
@@ -44,12 +43,14 @@ import {
|
|||||||
} from '../../components/tables/ColumnRenderers';
|
} from '../../components/tables/ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
||||||
|
|
||||||
|
import { LineItemCreationMenu } from '../../components/items/LineItemCreationMenu';
|
||||||
import { AppRowViewAction } from '../../components/tables/AppRowActions';
|
import { AppRowViewAction } from '../../components/tables/AppRowActions';
|
||||||
import RowExpansionIcon from '../../components/tables/RowExpansionIcon';
|
import RowExpansionIcon from '../../components/tables/RowExpansionIcon';
|
||||||
import { TableHoverCard } from '../../components/tables/TableHoverCard';
|
import { TableHoverCard } from '../../components/tables/TableHoverCard';
|
||||||
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
||||||
import { formatCurrency, formatDecimal } from '../../defaults/formatters';
|
import { formatCurrency, formatDecimal } from '../../defaults/formatters';
|
||||||
import { useBuildOrderFields } from '../../forms/BuildForms';
|
import { useBuildOrderFields } from '../../forms/BuildForms';
|
||||||
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
import {
|
import {
|
||||||
useAllocateToSalesOrderForm,
|
useAllocateToSalesOrderForm,
|
||||||
useSalesOrderAllocateSerialsFields,
|
useSalesOrderAllocateSerialsFields,
|
||||||
@@ -62,6 +63,7 @@ import {
|
|||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import SalesOrderAllocationTable from './SalesOrderAllocationTable';
|
import SalesOrderAllocationTable from './SalesOrderAllocationTable';
|
||||||
|
|
||||||
@@ -81,6 +83,34 @@ export default function SalesOrderLineItemTable({
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
const table = useTable('sales-order-line-item');
|
const table = useTable('sales-order-line-item');
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
|
|
||||||
|
const importSessionFields = useMemo(() => {
|
||||||
|
const fields = dataImporterSessionFields({
|
||||||
|
modelType: 'salesorderlineitem'
|
||||||
|
});
|
||||||
|
|
||||||
|
fields.field_overrides.value = {
|
||||||
|
order: orderId
|
||||||
|
};
|
||||||
|
|
||||||
|
fields.field_defaults.value = {
|
||||||
|
sale_price_currency: currency
|
||||||
|
};
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}, [orderId, currency]);
|
||||||
|
|
||||||
|
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 tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@@ -408,16 +438,19 @@ export default function SalesOrderLineItemTable({
|
|||||||
|
|
||||||
const tableActions = useMemo(() => {
|
const tableActions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
<AddItemButton
|
<LineItemCreationMenu
|
||||||
key='add-line-item'
|
key='add-line-item-actions'
|
||||||
tooltip={t`Add Line Item`}
|
tooltip={t`Add Line Item`}
|
||||||
onClick={() => {
|
addLabel={t`Add Line Item`}
|
||||||
|
importLabel={t`Import Line Items`}
|
||||||
|
hidden={!editable || !user.hasAddRole(UserRoles.sales_order)}
|
||||||
|
onAdd={() => {
|
||||||
setInitialData({
|
setInitialData({
|
||||||
order: orderId
|
order: orderId
|
||||||
});
|
});
|
||||||
newLine.open();
|
newLine.open();
|
||||||
}}
|
}}
|
||||||
hidden={!editable || !user.hasAddRole(UserRoles.sales_order)}
|
onImport={() => importLineItems.open()}
|
||||||
/>,
|
/>,
|
||||||
<ActionButton
|
<ActionButton
|
||||||
key='order-parts'
|
key='order-parts'
|
||||||
@@ -463,7 +496,8 @@ export default function SalesOrderLineItemTable({
|
|||||||
user,
|
user,
|
||||||
orderId,
|
orderId,
|
||||||
table.hasSelectedRecords,
|
table.hasSelectedRecords,
|
||||||
table.selectedRecords
|
table.selectedRecords,
|
||||||
|
importLineItems
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const rowActions = useCallback(
|
const rowActions = useCallback(
|
||||||
@@ -603,6 +637,7 @@ export default function SalesOrderLineItemTable({
|
|||||||
{editLine.modal}
|
{editLine.modal}
|
||||||
{deleteLine.modal}
|
{deleteLine.modal}
|
||||||
{newLine.modal}
|
{newLine.modal}
|
||||||
|
{importLineItems.modal}
|
||||||
{newBuildOrder.modal}
|
{newBuildOrder.modal}
|
||||||
{allocateBySerials.modal}
|
{allocateBySerials.modal}
|
||||||
{allocateStock.modal}
|
{allocateStock.modal}
|
||||||
|
|||||||
@@ -379,9 +379,11 @@ test('Purchase Orders - Price Breaks', async ({ browser }) => {
|
|||||||
url: 'purchasing/purchase-order/14/line-items'
|
url: 'purchasing/purchase-order/14/line-items'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'action-menu-add-line-item' }).click();
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'action-button-add-line-item' })
|
.getByRole('menuitem', { name: 'action-menu-add-line-item-add' })
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
await page.getByLabel('related-field-part').fill('002.01');
|
await page.getByLabel('related-field-part').fill('002.01');
|
||||||
await page.getByRole('option', { name: 'PCBWOY PCB-002.01' }).click();
|
await page.getByRole('option', { name: 'PCBWOY PCB-002.01' }).click();
|
||||||
|
|
||||||
|
|||||||
@@ -435,9 +435,11 @@ test('Sales Orders - Price Breaks', async ({ browser }) => {
|
|||||||
url: 'sales/sales-order/14/line-items'
|
url: 'sales/sales-order/14/line-items'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'action-menu-add-line-item' }).click();
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'action-button-add-line-item' })
|
.getByRole('menuitem', { name: 'action-menu-add-line-item-add' })
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
await page.getByLabel('related-field-part').fill('software');
|
await page.getByLabel('related-field-part').fill('software');
|
||||||
await page.getByRole('option', { name: 'Software License' }).click();
|
await page.getByRole('option', { name: 'Software License' }).click();
|
||||||
|
|
||||||
|
|||||||
@@ -162,8 +162,11 @@ test('Importing - Purchase Order', async ({ browser }) => {
|
|||||||
url: 'purchasing/purchase-order/15/line-items'
|
url: 'purchasing/purchase-order/15/line-items'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'action-menu-add-line-item' }).click();
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'action-button-import-line-' })
|
.getByRole('menuitem', {
|
||||||
|
name: 'action-menu-add-line-item-import-line-items'
|
||||||
|
})
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
const fileInput = await page.locator('input[type="file"]');
|
const fileInput = await page.locator('input[type="file"]');
|
||||||
@@ -181,8 +184,11 @@ test('Importing - Natural Keys', async ({ browser }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Import line item data, but use natural keys as the import fields
|
// Import line item data, but use natural keys as the import fields
|
||||||
|
await page.getByRole('button', { name: 'action-menu-add-line-item' }).click();
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'action-button-import-line-' })
|
.getByRole('menuitem', {
|
||||||
|
name: 'action-menu-add-line-item-import-line-items'
|
||||||
|
})
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
const fileInput = await page.locator('input[type="file"]');
|
const fileInput = await page.locator('input[type="file"]');
|
||||||
|
|||||||
Reference in New Issue
Block a user