diff --git a/src/frontend/src/components/previews/models/PurchaseOrderPreview.tsx b/src/frontend/src/components/previews/models/PurchaseOrderPreview.tsx
new file mode 100644
index 0000000000..c5033022be
--- /dev/null
+++ b/src/frontend/src/components/previews/models/PurchaseOrderPreview.tsx
@@ -0,0 +1,25 @@
+import { t } from '@lingui/core/macro';
+import { PurchaseOrderDetailsPanel } from '../../../pages/purchasing/PurchaseOrderDetailsPanel';
+import type { PreviewType } from '../PreviewType';
+
+export function PurchaseOrderPreviewComponent({
+ instance,
+ modelId
+}: Readonly<{
+ instance: any;
+ modelId: number;
+}>): PreviewType {
+ const supplier = instance?.supplier_detail?.name ?? instance?.supplier_name;
+ const ref = instance?.reference ?? `#${modelId}`;
+
+ let title = `${t`Purchase Order`} ${ref}`;
+
+ if (supplier) {
+ title += ` (${supplier})`;
+ }
+
+ return {
+ title: title,
+ preview:
+ };
+}
diff --git a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx
index 43f5e84301..ce2549bdf6 100644
--- a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx
+++ b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx
@@ -1,5 +1,5 @@
import { t } from '@lingui/core/macro';
-import { Accordion, Grid, Skeleton, Stack } from '@mantine/core';
+import { Accordion, Stack } from '@mantine/core';
import { IconInfoCircle, IconList, IconPackages } from '@tabler/icons-react';
import { type ReactNode, useMemo } from 'react';
import { useParams } from 'react-router-dom';
@@ -9,17 +9,10 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
-import { TagsList } from '@lib/index';
import type { PanelType } from '@lib/types/Panel';
import AdminButton from '../../components/buttons/AdminButton';
import PrimaryActionButton from '../../components/buttons/PrimaryActionButton';
import { PrintingActions } from '../../components/buttons/PrintingActions';
-import {
- type DetailsField,
- DetailsTable
-} from '../../components/details/Details';
-import { DetailsImage } from '../../components/details/DetailsImage';
-import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import {
BarcodeActionDropdown,
CancelItemAction,
@@ -35,7 +28,6 @@ import NotesPanel from '../../components/panels/NotesPanel';
import { PanelGroup } from '../../components/panels/PanelGroup';
import ParametersPanel from '../../components/panels/ParametersPanel';
import { StatusRenderer } from '../../components/render/StatusRenderer';
-import { formatCurrency } from '../../defaults/formatters';
import { usePurchaseOrderFields } from '../../forms/PurchaseOrderForms';
import {
useCreateApiFormModal,
@@ -48,6 +40,7 @@ import { useUserState } from '../../states/UserState';
import ExtraLineItemTable from '../../tables/general/ExtraLineItemTable';
import { PurchaseOrderLineItemTable } from '../../tables/purchasing/PurchaseOrderLineItemTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
+import { PurchaseOrderDetailsPanel } from './PurchaseOrderDetailsPanel';
/**
* Detail page for a single PurchaseOrder
@@ -72,13 +65,13 @@ export default function PurchaseOrderDetail() {
refetchOnMount: true
});
- const orderCurrency = useMemo(() => {
- return (
+ const orderCurrency = useMemo(
+ () =>
order.order_currency ||
order.supplier_detail?.currency ||
- globalSettings.getSetting('INVENTREE_DEFAULT_CURRENCY')
- );
- }, [order, globalSettings]);
+ globalSettings.getSetting('INVENTREE_DEFAULT_CURRENCY'),
+ [order, globalSettings]
+ );
const purchaseOrderFields = usePurchaseOrderFields({});
@@ -133,222 +126,19 @@ export default function PurchaseOrderDetail() {
modelType: ModelType.purchaseorder
});
- const detailsPanel = useMemo(() => {
- if (instanceQuery.isFetching) {
- return ;
- }
-
- const tl: DetailsField[] = [
- {
- type: 'text',
- name: 'reference',
- label: t`Reference`,
- copy: true
- },
- {
- type: 'text',
- name: 'supplier_reference',
- label: t`Supplier Reference`,
- icon: 'reference',
- hidden: !order.supplier_reference,
- copy: true
- },
- {
- type: 'link',
- name: 'supplier',
- icon: 'suppliers',
- label: t`Supplier`,
- model: ModelType.company
- },
- {
- type: 'text',
- name: 'description',
- label: t`Description`,
- copy: true
- },
- {
- type: 'status',
- name: 'status',
- label: t`Status`,
- model: ModelType.purchaseorder
- },
- {
- type: 'status',
- name: 'status_custom_key',
- label: t`Custom Status`,
- model: ModelType.purchaseorder,
- icon: 'status',
- hidden:
- !order.status_custom_key || order.status_custom_key == order.status
- }
- ];
-
- const tr: DetailsField[] = [
- {
- type: 'progressbar',
- name: 'completed',
- icon: 'progress',
- label: t`Completed Line Items`,
- total: order.line_items,
- progress: order.completed_lines
- },
- {
- type: 'link',
- model: ModelType.stocklocation,
- link: true,
- name: 'destination',
- label: t`Destination`,
- hidden: !order.destination
- },
- {
- type: 'text',
- name: 'currency',
- label: t`Order Currency`,
- value_formatter: () => orderCurrency
- },
- {
- type: 'text',
- name: 'total_price',
- label: t`Total Cost`,
- value_formatter: () => {
- return formatCurrency(order?.total_price, {
- currency: order?.order_currency || order?.supplier_detail?.currency
- });
- }
- }
- ];
-
- const bl: DetailsField[] = [
- {
- type: 'link',
- external: true,
- name: 'link',
- label: t`Link`,
- copy: true,
- hidden: !order.link
- },
- {
- type: 'text',
- name: 'contact_detail.name',
- label: t`Contact`,
- icon: 'user',
- copy: true,
- hidden: !order.contact
- },
- {
- type: 'text',
- name: 'contact_detail.email',
- label: t`Contact Email`,
- icon: 'email',
- copy: true,
- hidden: !order.contact_detail?.email
- },
- {
- type: 'text',
- name: 'contact_detail.phone',
- label: t`Contact Phone`,
- icon: 'phone',
- copy: true,
- hidden: !order.contact_detail?.phone
- },
- {
- type: 'text',
- name: 'project_code_label',
- label: t`Project Code`,
- icon: 'reference',
- copy: true,
- hidden: !order.project_code
- },
- {
- type: 'text',
- name: 'responsible',
- label: t`Responsible`,
- badge: 'owner',
- hidden: !order.responsible
- }
- ];
-
- const br: DetailsField[] = [
- {
- type: 'date',
- name: 'creation_date',
- label: t`Creation Date`,
- copy: true,
- icon: 'calendar'
- },
- {
- type: 'date',
- name: 'issue_date',
- label: t`Issue Date`,
- icon: 'calendar',
- copy: true,
- hidden: !order.issue_date
- },
- {
- type: 'date',
- name: 'start_date',
- label: t`Start Date`,
- icon: 'calendar',
- copy: true,
- hidden: !order.start_date
- },
- {
- type: 'date',
- name: 'target_date',
- label: t`Target Date`,
- icon: 'calendar',
- copy: true,
- hidden: !order.target_date
- },
- {
- type: 'date',
- name: 'complete_date',
- icon: 'calendar_check',
- label: t`Completion Date`,
- copy: true,
- hidden: !order.complete_date
- },
- {
- type: 'date',
- name: 'updated_at',
- label: t`Last Updated`,
- icon: 'calendar',
- copy: true,
- showTime: true,
- hidden: !order.updated_at
- }
- ];
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }, [order, orderCurrency, instanceQuery]);
-
const orderPanels: PanelType[] = useMemo(() => {
return [
{
name: 'detail',
label: t`Order Details`,
icon: ,
- content: detailsPanel
+ content: (
+
+ )
},
{
name: 'line-items',
diff --git a/src/frontend/src/pages/purchasing/PurchaseOrderDetailsPanel.tsx b/src/frontend/src/pages/purchasing/PurchaseOrderDetailsPanel.tsx
new file mode 100644
index 0000000000..60156bf3dd
--- /dev/null
+++ b/src/frontend/src/pages/purchasing/PurchaseOrderDetailsPanel.tsx
@@ -0,0 +1,258 @@
+import { t } from '@lingui/core/macro';
+import { Grid, Skeleton, Stack } from '@mantine/core';
+import { useMemo } from 'react';
+
+import TagsList from '@lib/components/TagsList';
+import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
+import { ModelType } from '@lib/enums/ModelType';
+import { UserRoles } from '@lib/enums/Roles';
+import { apiUrl } from '@lib/functions/Api';
+
+import {
+ type DetailsField,
+ DetailsTable
+} from '../../components/details/Details';
+import { DetailsImage } from '../../components/details/DetailsImage';
+import { ItemDetailsGrid } from '../../components/details/ItemDetails';
+import { useParameterDetailsGrid } from '../../components/details/ParameterDetailsGrid';
+import { formatCurrency } from '../../defaults/formatters';
+import { useGlobalSettingsState } from '../../states/SettingsStates';
+
+export function PurchaseOrderDetailsPanel({
+ instance,
+ allowImageEdit = false,
+ refreshInstance
+}: Readonly<{
+ instance: any;
+ allowImageEdit?: boolean;
+ refreshInstance?: () => void;
+}>) {
+ const globalSettings = useGlobalSettingsState();
+
+ const orderCurrency = useMemo(
+ () =>
+ instance?.order_currency ||
+ instance?.supplier_detail?.currency ||
+ globalSettings.getSetting('INVENTREE_DEFAULT_CURRENCY'),
+ [instance, globalSettings]
+ );
+
+ const tl: DetailsField[] = [
+ {
+ type: 'text',
+ name: 'reference',
+ label: t`Reference`,
+ copy: true
+ },
+ {
+ type: 'text',
+ name: 'supplier_reference',
+ label: t`Supplier Reference`,
+ icon: 'reference',
+ hidden: !instance?.supplier_reference,
+ copy: true
+ },
+ {
+ type: 'link',
+ name: 'supplier',
+ icon: 'suppliers',
+ label: t`Supplier`,
+ model: ModelType.company
+ },
+ {
+ type: 'text',
+ name: 'description',
+ label: t`Description`,
+ copy: true
+ },
+ {
+ type: 'status',
+ name: 'status',
+ label: t`Status`,
+ model: ModelType.purchaseorder
+ },
+ {
+ type: 'status',
+ name: 'status_custom_key',
+ label: t`Custom Status`,
+ model: ModelType.purchaseorder,
+ icon: 'status',
+ hidden:
+ !instance?.status_custom_key ||
+ instance?.status_custom_key == instance?.status
+ }
+ ];
+
+ const tr: DetailsField[] = [
+ {
+ type: 'progressbar',
+ name: 'completed',
+ icon: 'progress',
+ label: t`Completed Line Items`,
+ total: instance?.line_items,
+ progress: instance?.completed_lines
+ },
+ {
+ type: 'link',
+ model: ModelType.stocklocation,
+ link: true,
+ name: 'destination',
+ label: t`Destination`,
+ hidden: !instance?.destination
+ },
+ {
+ type: 'text',
+ name: 'currency',
+ label: t`Order Currency`,
+ value_formatter: () => orderCurrency
+ },
+ {
+ type: 'text',
+ name: 'total_price',
+ label: t`Total Cost`,
+ value_formatter: () =>
+ formatCurrency(instance?.total_price, {
+ currency:
+ instance?.order_currency || instance?.supplier_detail?.currency
+ })
+ }
+ ];
+
+ const bl: DetailsField[] = [
+ {
+ type: 'link',
+ external: true,
+ name: 'link',
+ label: t`Link`,
+ copy: true,
+ hidden: !instance?.link
+ },
+ {
+ type: 'text',
+ name: 'contact_detail.name',
+ label: t`Contact`,
+ icon: 'user',
+ copy: true,
+ hidden: !instance?.contact
+ },
+ {
+ type: 'text',
+ name: 'contact_detail.email',
+ label: t`Contact Email`,
+ icon: 'email',
+ copy: true,
+ hidden: !instance?.contact_detail?.email
+ },
+ {
+ type: 'text',
+ name: 'contact_detail.phone',
+ label: t`Contact Phone`,
+ icon: 'phone',
+ copy: true,
+ hidden: !instance?.contact_detail?.phone
+ },
+ {
+ type: 'text',
+ name: 'project_code_label',
+ label: t`Project Code`,
+ icon: 'reference',
+ copy: true,
+ hidden: !instance?.project_code
+ },
+ {
+ type: 'text',
+ name: 'responsible',
+ label: t`Responsible`,
+ badge: 'owner',
+ hidden: !instance?.responsible
+ }
+ ];
+
+ const br: DetailsField[] = [
+ {
+ type: 'date',
+ name: 'creation_date',
+ label: t`Creation Date`,
+ copy: true,
+ icon: 'calendar'
+ },
+ {
+ type: 'date',
+ name: 'issue_date',
+ label: t`Issue Date`,
+ icon: 'calendar',
+ copy: true,
+ hidden: !instance?.issue_date
+ },
+ {
+ type: 'date',
+ name: 'start_date',
+ label: t`Start Date`,
+ icon: 'calendar',
+ copy: true,
+ hidden: !instance?.start_date
+ },
+ {
+ type: 'date',
+ name: 'target_date',
+ label: t`Target Date`,
+ icon: 'calendar',
+ copy: true,
+ hidden: !instance?.target_date
+ },
+ {
+ type: 'date',
+ name: 'complete_date',
+ icon: 'calendar_check',
+ label: t`Completion Date`,
+ copy: true,
+ hidden: !instance?.complete_date
+ },
+ {
+ type: 'date',
+ name: 'updated_at',
+ label: t`Last Updated`,
+ icon: 'calendar',
+ copy: true,
+ showTime: true,
+ hidden: !instance?.updated_at
+ }
+ ];
+
+ const parametersTable = useParameterDetailsGrid({
+ model_type: ModelType.purchaseorder,
+ model_id: instance?.pk
+ });
+
+ if (!instance?.pk) return ;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}