mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-01 13:06:45 +00:00
[React] Order tables (#5860)
* Factor out custom component for displaying project code information in a table * Bump API version * Update order serializers - Annotate 'completed_lines' to each order type * Build out columns for ReturnOrderTable * Improvements to PurchaseOrderTable * Building out SalesOrderTable * Column tweaks * Factor out project code column * Factor out status column * Factor out description column * Factor out more columns * More refactoring * Center status labels * Fix for PurchaseOrderLineItemTable * Improve rendering * Remove unused imports * Refactor TotalPriceColumn * Add generic currency column for rendering currency / money values
This commit is contained in:
parent
93f642c790
commit
dbf1baf0ed
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 145
|
INVENTREE_API_VERSION = 147
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||||
|
|
||||||
|
v147 -> 2023-11-04: https://github.com/inventree/InvenTree/pull/5860
|
||||||
|
- Adds "completed_lines" field to SalesOrder API endpoint
|
||||||
|
- Adds "completed_lines" field to PurchaseOrder API endpoint
|
||||||
|
|
||||||
v146 -> 2023-11-02: https://github.com/inventree/InvenTree/pull/5822
|
v146 -> 2023-11-02: https://github.com/inventree/InvenTree/pull/5822
|
||||||
- Extended SSO Provider endpoint to contain if a provider is configured
|
- Extended SSO Provider endpoint to contain if a provider is configured
|
||||||
- Adds API endpoints for Email Address model
|
- Adds API endpoints for Email Address model
|
||||||
|
@ -29,8 +29,8 @@ from InvenTree.serializers import (InvenTreeAttachmentSerializer,
|
|||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
InvenTreeMoneySerializer)
|
InvenTreeMoneySerializer)
|
||||||
from InvenTree.status_codes import (PurchaseOrderStatusGroups,
|
from InvenTree.status_codes import (PurchaseOrderStatusGroups,
|
||||||
ReturnOrderStatus, SalesOrderStatusGroups,
|
ReturnOrderLineStatus, ReturnOrderStatus,
|
||||||
StockStatus)
|
SalesOrderStatusGroups, StockStatus)
|
||||||
from part.serializers import PartBriefSerializer
|
from part.serializers import PartBriefSerializer
|
||||||
from users.serializers import OwnerSerializer
|
from users.serializers import OwnerSerializer
|
||||||
|
|
||||||
@ -58,6 +58,9 @@ class AbstractOrderSerializer(serializers.Serializer):
|
|||||||
# Number of line items in this order
|
# Number of line items in this order
|
||||||
line_items = serializers.IntegerField(read_only=True)
|
line_items = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
|
# Number of completed line items (this is an annotated field)
|
||||||
|
completed_lines = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
# Human-readable status text (read-only)
|
# Human-readable status text (read-only)
|
||||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||||
|
|
||||||
@ -107,6 +110,7 @@ class AbstractOrderSerializer(serializers.Serializer):
|
|||||||
'target_date',
|
'target_date',
|
||||||
'description',
|
'description',
|
||||||
'line_items',
|
'line_items',
|
||||||
|
'completed_lines',
|
||||||
'link',
|
'link',
|
||||||
'project_code',
|
'project_code',
|
||||||
'project_code_detail',
|
'project_code_detail',
|
||||||
@ -211,6 +215,10 @@ class PurchaseOrderSerializer(TotalPriceMixin, AbstractOrderSerializer, InvenTre
|
|||||||
"""
|
"""
|
||||||
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
completed_lines=SubqueryCount('lines', filter=Q(quantity__lte=F('received')))
|
||||||
|
)
|
||||||
|
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
overdue=Case(
|
overdue=Case(
|
||||||
When(
|
When(
|
||||||
@ -743,10 +751,15 @@ class SalesOrderSerializer(TotalPriceMixin, AbstractOrderSerializer, InvenTreeMo
|
|||||||
"""Add extra information to the queryset.
|
"""Add extra information to the queryset.
|
||||||
|
|
||||||
- Number of line items in the SalesOrder
|
- Number of line items in the SalesOrder
|
||||||
|
- Number of completed line items in the SalesOrder
|
||||||
- Overdue status of the SalesOrder
|
- Overdue status of the SalesOrder
|
||||||
"""
|
"""
|
||||||
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
completed_lines=SubqueryCount('lines', filter=Q(quantity__lte=F('shipped')))
|
||||||
|
)
|
||||||
|
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
overdue=Case(
|
overdue=Case(
|
||||||
When(
|
When(
|
||||||
@ -1503,6 +1516,10 @@ class ReturnOrderSerializer(AbstractOrderSerializer, TotalPriceMixin, InvenTreeM
|
|||||||
"""Custom annotation for the serializer queryset"""
|
"""Custom annotation for the serializer queryset"""
|
||||||
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
queryset = AbstractOrderSerializer.annotate_queryset(queryset)
|
||||||
|
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
completed_lines=SubqueryCount('lines', filter=~Q(outcome=ReturnOrderLineStatus.PENDING.value))
|
||||||
|
)
|
||||||
|
|
||||||
queryset = queryset.annotate(
|
queryset = queryset.annotate(
|
||||||
overdue=Case(
|
overdue=Case(
|
||||||
When(
|
When(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Badge, MantineSize } from '@mantine/core';
|
import { Badge, Center, MantineSize } from '@mantine/core';
|
||||||
|
|
||||||
import { colorMap } from '../../defaults/backendMappings';
|
import { colorMap } from '../../defaults/backendMappings';
|
||||||
import { useServerApiState } from '../../states/ApiState';
|
import { useServerApiState } from '../../states/ApiState';
|
||||||
@ -99,5 +99,8 @@ export const StatusRenderer = ({
|
|||||||
export function TableStatusRenderer(
|
export function TableStatusRenderer(
|
||||||
type: ModelType
|
type: ModelType
|
||||||
): ((record: any) => any) | undefined {
|
): ((record: any) => any) | undefined {
|
||||||
return (record: any) => StatusRenderer({ status: record.status, type: type });
|
return (record: any) =>
|
||||||
|
record.status && (
|
||||||
|
<Center>{StatusRenderer({ status: record.status, type: type })}</Center>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
134
src/frontend/src/components/tables/ColumnRenderers.tsx
Normal file
134
src/frontend/src/components/tables/ColumnRenderers.tsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* Common rendering functions for table column data.
|
||||||
|
*/
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
|
||||||
|
import { ProgressBar } from '../items/ProgressBar';
|
||||||
|
import { ModelType } from '../render/ModelType';
|
||||||
|
import { RenderOwner } from '../render/User';
|
||||||
|
import { TableStatusRenderer } from '../renderers/StatusRenderer';
|
||||||
|
import { TableColumn } from './Column';
|
||||||
|
import { ProjectCodeHoverCard } from './TableHoverCard';
|
||||||
|
|
||||||
|
export function DescriptionColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'description',
|
||||||
|
title: t`Description`,
|
||||||
|
sortable: false,
|
||||||
|
switchable: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LinkColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'link',
|
||||||
|
title: t`Link`,
|
||||||
|
sortable: false
|
||||||
|
// TODO: Custom URL hyperlink renderer?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LineItemsProgressColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'line_items',
|
||||||
|
title: t`Line Items`,
|
||||||
|
sortable: true,
|
||||||
|
render: (record: any) => (
|
||||||
|
<ProgressBar
|
||||||
|
progressLabel={true}
|
||||||
|
value={record.completed_lines}
|
||||||
|
maximum={record.line_items}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProjectCodeColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'project_code',
|
||||||
|
title: t`Project Code`,
|
||||||
|
sortable: true,
|
||||||
|
render: (record: any) => (
|
||||||
|
<ProjectCodeHoverCard projectCode={record.project_code_detail} />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatusColumn(model: ModelType) {
|
||||||
|
return {
|
||||||
|
accessor: 'status',
|
||||||
|
sortable: true,
|
||||||
|
title: t`Status`,
|
||||||
|
render: TableStatusRenderer(model)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ResponsibleColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'responsible',
|
||||||
|
title: t`Responsible`,
|
||||||
|
sortable: true,
|
||||||
|
render: (record: any) =>
|
||||||
|
record.responsible && RenderOwner({ instance: record.responsible_detail })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TargetDateColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'target_date',
|
||||||
|
title: t`Target Date`,
|
||||||
|
sortable: true
|
||||||
|
// TODO: custom renderer which alerts user if target date is overdue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CreationDateColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'creation_date',
|
||||||
|
title: t`Creation Date`,
|
||||||
|
sortable: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ShipmentDateColumn(): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: 'shipment_date',
|
||||||
|
title: t`Shipment Date`,
|
||||||
|
sortable: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CurrencyColumn({
|
||||||
|
accessor,
|
||||||
|
title,
|
||||||
|
currency,
|
||||||
|
currency_accessor,
|
||||||
|
sortable
|
||||||
|
}: {
|
||||||
|
accessor: string;
|
||||||
|
title?: string;
|
||||||
|
currency?: string;
|
||||||
|
currency_accessor?: string;
|
||||||
|
sortable?: boolean;
|
||||||
|
}): TableColumn {
|
||||||
|
return {
|
||||||
|
accessor: accessor,
|
||||||
|
title: title ?? t`Currency`,
|
||||||
|
sortable: sortable ?? true,
|
||||||
|
render: (record: any) => {
|
||||||
|
let value = record[accessor];
|
||||||
|
let currency_key = currency_accessor ?? `${accessor}_currency`;
|
||||||
|
currency = currency ?? record[currency_key];
|
||||||
|
|
||||||
|
// TODO: A better render which correctly formats money values
|
||||||
|
return `${value} ${currency}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TotalPriceColumn(): TableColumn {
|
||||||
|
return CurrencyColumn({
|
||||||
|
accessor: 'total_price',
|
||||||
|
title: t`Total Price`
|
||||||
|
});
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { t } from '@lingui/macro';
|
||||||
import { Divider, Group, HoverCard, Stack, Text } from '@mantine/core';
|
import { Divider, Group, HoverCard, Stack, Text } from '@mantine/core';
|
||||||
import { IconInfoCircle } from '@tabler/icons-react';
|
import { IconInfoCircle } from '@tabler/icons-react';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
@ -21,6 +22,10 @@ export function TableHoverCard({
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(extra) && extra.length == 0) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCard.Target>
|
<HoverCard.Target>
|
||||||
@ -42,3 +47,18 @@ export function TableHoverCard({
|
|||||||
</HoverCard>
|
</HoverCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hovercard for displaying projectcode detail in a table
|
||||||
|
*/
|
||||||
|
export function ProjectCodeHoverCard({ projectCode }: { projectCode: any }) {
|
||||||
|
return projectCode ? (
|
||||||
|
<TableHoverCard
|
||||||
|
value={projectCode?.code}
|
||||||
|
title={t`Project Code`}
|
||||||
|
extra={projectCode?.description}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Text } from '@mantine/core';
|
import { useMemo } from 'react';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { buildOrderFields } from '../../../forms/BuildForms';
|
|
||||||
import { openCreateApiForm } from '../../../functions/forms';
|
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
|
||||||
import { ThumbnailHoverCard } from '../../images/Thumbnail';
|
import { ThumbnailHoverCard } from '../../images/Thumbnail';
|
||||||
import { ProgressBar } from '../../items/ProgressBar';
|
import { ProgressBar } from '../../items/ProgressBar';
|
||||||
import { ModelType } from '../../render/ModelType';
|
import { ModelType } from '../../render/ModelType';
|
||||||
import { RenderOwner, RenderUser } from '../../render/User';
|
import { RenderUser } from '../../render/User';
|
||||||
import { TableStatusRenderer } from '../../renderers/StatusRenderer';
|
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { TableFilter } from '../Filter';
|
import {
|
||||||
|
CreationDateColumn,
|
||||||
|
ProjectCodeColumn,
|
||||||
|
ResponsibleColumn,
|
||||||
|
StatusColumn,
|
||||||
|
TargetDateColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { TableHoverCard } from '../TableHoverCard';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a list of columns for the build order table
|
* Construct a list of columns for the build order table
|
||||||
@ -66,47 +66,15 @@ function buildOrderTableColumns(): TableColumn[] {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
StatusColumn(ModelType.build),
|
||||||
accessor: 'status',
|
ProjectCodeColumn(),
|
||||||
sortable: true,
|
|
||||||
title: t`Status`,
|
|
||||||
|
|
||||||
render: TableStatusRenderer(ModelType.build)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'project_code',
|
|
||||||
title: t`Project Code`,
|
|
||||||
sortable: true,
|
|
||||||
// TODO: Hide this if project code is not enabled
|
|
||||||
render: (record: any) => {
|
|
||||||
let project = record.project_code_detail;
|
|
||||||
|
|
||||||
return project ? (
|
|
||||||
<TableHoverCard
|
|
||||||
value={project.code}
|
|
||||||
title={t`Project Code`}
|
|
||||||
extra={<Text>{project.description}</Text>}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
'-'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'priority',
|
accessor: 'priority',
|
||||||
title: t`Priority`,
|
title: t`Priority`,
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
CreationDateColumn(),
|
||||||
accessor: 'creation_date',
|
TargetDateColumn(),
|
||||||
sortable: true,
|
|
||||||
title: t`Created`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'target_date',
|
|
||||||
sortable: true,
|
|
||||||
title: t`Target Date`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'completion_date',
|
accessor: 'completion_date',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
@ -120,14 +88,7 @@ function buildOrderTableColumns(): TableColumn[] {
|
|||||||
<RenderUser instance={record?.issued_by_detail} />
|
<RenderUser instance={record?.issued_by_detail} />
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
ResponsibleColumn()
|
||||||
accessor: 'responsible',
|
|
||||||
sortable: true,
|
|
||||||
title: t`Responsible`,
|
|
||||||
render: (record: any) => (
|
|
||||||
<RenderOwner instance={record?.responsible_detail} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,11 +43,7 @@ export function CompanyTable({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`,
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'website',
|
accessor: 'website',
|
||||||
title: t`Website`,
|
title: t`Website`,
|
||||||
|
@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,11 +24,7 @@ export function PartCategoryTable({ params = {} }: { params?: any }) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: false
|
switchable: false
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`,
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'pathstring',
|
accessor: 'pathstring',
|
||||||
title: t`Path`,
|
title: t`Path`,
|
||||||
|
@ -8,6 +8,7 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { DescriptionColumn, LinkColumn } from '../ColumnRenderers';
|
||||||
import { TableFilter } from '../Filter';
|
import { TableFilter } from '../Filter';
|
||||||
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';
|
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';
|
||||||
import { TableHoverCard } from '../TableHoverCard';
|
import { TableHoverCard } from '../TableHoverCard';
|
||||||
@ -42,11 +43,7 @@ function partTableColumns(): TableColumn[] {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
title: t`Units`
|
title: t`Units`
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`,
|
|
||||||
sortable: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'category',
|
accessor: 'category',
|
||||||
title: t`Category`,
|
title: t`Category`,
|
||||||
@ -155,10 +152,7 @@ function partTableColumns(): TableColumn[] {
|
|||||||
return '-- price --';
|
return '-- price --';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
LinkColumn()
|
||||||
accessor: 'link',
|
|
||||||
title: t`Link`
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,13 @@ import { useUserState } from '../../../states/UserState';
|
|||||||
import { ActionButton } from '../../buttons/ActionButton';
|
import { ActionButton } from '../../buttons/ActionButton';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
|
import { RenderStockLocation } from '../../render/Stock';
|
||||||
|
import {
|
||||||
|
CurrencyColumn,
|
||||||
|
LinkColumn,
|
||||||
|
TargetDateColumn,
|
||||||
|
TotalPriceColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import {
|
import {
|
||||||
RowDeleteAction,
|
RowDeleteAction,
|
||||||
@ -112,8 +119,8 @@ export function PurchaseOrderLineItemTable({
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: false,
|
switchable: false,
|
||||||
render: (record: any) => {
|
render: (record: any) => {
|
||||||
let part = record?.part_detail;
|
|
||||||
let supplier_part = record?.supplier_part_detail ?? {};
|
let supplier_part = record?.supplier_part_detail ?? {};
|
||||||
|
let part = record?.part_detail ?? supplier_part?.part_detail ?? {};
|
||||||
let extra = [];
|
let extra = [];
|
||||||
|
|
||||||
if (supplier_part.pack_quantity_native != 1) {
|
if (supplier_part.pack_quantity_native != 1) {
|
||||||
@ -127,8 +134,7 @@ export function PurchaseOrderLineItemTable({
|
|||||||
|
|
||||||
extra.push(
|
extra.push(
|
||||||
<Text key="total-quantity">
|
<Text key="total-quantity">
|
||||||
{t`Total Quantity`}: {total}
|
{t`Total Quantity`}: {total} {part?.units}
|
||||||
{part.units}
|
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -158,7 +164,6 @@ export function PurchaseOrderLineItemTable({
|
|||||||
{
|
{
|
||||||
accessor: 'pack_quantity',
|
accessor: 'pack_quantity',
|
||||||
sortable: false,
|
sortable: false,
|
||||||
|
|
||||||
title: t`Pack Quantity`,
|
title: t`Pack Quantity`,
|
||||||
render: (record: any) => record?.supplier_part_detail?.pack_quantity
|
render: (record: any) => record?.supplier_part_detail?.pack_quantity
|
||||||
},
|
},
|
||||||
@ -166,7 +171,8 @@ export function PurchaseOrderLineItemTable({
|
|||||||
accessor: 'SKU',
|
accessor: 'SKU',
|
||||||
title: t`Supplier Code`,
|
title: t`Supplier Code`,
|
||||||
switchable: false,
|
switchable: false,
|
||||||
sortable: true
|
sortable: true,
|
||||||
|
render: (record: any) => record?.supplier_part_detail?.SKU
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: 'supplier_link',
|
accessor: 'supplier_link',
|
||||||
@ -183,43 +189,26 @@ export function PurchaseOrderLineItemTable({
|
|||||||
render: (record: any) =>
|
render: (record: any) =>
|
||||||
record?.supplier_part_detail?.manufacturer_part_detail?.MPN
|
record?.supplier_part_detail?.manufacturer_part_detail?.MPN
|
||||||
},
|
},
|
||||||
|
CurrencyColumn({
|
||||||
{
|
|
||||||
accessor: 'purchase_price',
|
accessor: 'purchase_price',
|
||||||
title: t`Unit Price`,
|
title: t`Unit Price`
|
||||||
sortable: true
|
}),
|
||||||
|
TotalPriceColumn(),
|
||||||
// TODO: custom renderer
|
TargetDateColumn(),
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'total_price',
|
|
||||||
title: t`Total Price`,
|
|
||||||
sortable: true
|
|
||||||
|
|
||||||
// TODO: custom renderer
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'target_date',
|
|
||||||
title: t`Target Date`,
|
|
||||||
sortable: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'destination',
|
accessor: 'destination',
|
||||||
title: t`Destination`,
|
title: t`Destination`,
|
||||||
sortable: false
|
sortable: false,
|
||||||
|
render: (record: any) =>
|
||||||
// TODO: Custom renderer
|
record.destination
|
||||||
|
? RenderStockLocation({ instance: record.destination_detail })
|
||||||
|
: '-'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: 'notes',
|
accessor: 'notes',
|
||||||
title: t`Notes`
|
title: t`Notes`
|
||||||
},
|
},
|
||||||
{
|
LinkColumn()
|
||||||
accessor: 'link',
|
|
||||||
title: t`Link`
|
|
||||||
|
|
||||||
// TODO: custom renderer
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}, [orderId, user]);
|
}, [orderId, user]);
|
||||||
|
|
||||||
|
@ -6,7 +6,16 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { ModelType } from '../../render/ModelType';
|
import { ModelType } from '../../render/ModelType';
|
||||||
import { StatusRenderer } from '../../renderers/StatusRenderer';
|
import {
|
||||||
|
CreationDateColumn,
|
||||||
|
DescriptionColumn,
|
||||||
|
LineItemsProgressColumn,
|
||||||
|
ProjectCodeColumn,
|
||||||
|
ResponsibleColumn,
|
||||||
|
StatusColumn,
|
||||||
|
TargetDateColumn,
|
||||||
|
TotalPriceColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,11 +39,9 @@ export function PurchaseOrderTable({ params }: { params?: any }) {
|
|||||||
title: t`Reference`,
|
title: t`Reference`,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: false
|
switchable: false
|
||||||
|
// TODO: Display extra information if order is overdue
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'supplier__name',
|
accessor: 'supplier__name',
|
||||||
title: t`Supplier`,
|
title: t`Supplier`,
|
||||||
@ -55,54 +62,13 @@ export function PurchaseOrderTable({ params }: { params?: any }) {
|
|||||||
accessor: 'supplier_reference',
|
accessor: 'supplier_reference',
|
||||||
title: t`Supplier Reference`
|
title: t`Supplier Reference`
|
||||||
},
|
},
|
||||||
{
|
LineItemsProgressColumn(),
|
||||||
accessor: 'project_code',
|
StatusColumn(ModelType.purchaseorder),
|
||||||
title: t`Project Code`
|
ProjectCodeColumn(),
|
||||||
|
CreationDateColumn(),
|
||||||
// TODO: Custom project code formatter
|
TargetDateColumn(),
|
||||||
},
|
TotalPriceColumn(),
|
||||||
{
|
ResponsibleColumn()
|
||||||
accessor: 'status',
|
|
||||||
title: t`Status`,
|
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
render: (record: any) =>
|
|
||||||
StatusRenderer({
|
|
||||||
status: record.status,
|
|
||||||
type: ModelType.purchaseorder
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'creation_date',
|
|
||||||
title: t`Created`
|
|
||||||
|
|
||||||
// TODO: Custom date formatter
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'target_date',
|
|
||||||
title: t`Target Date`
|
|
||||||
|
|
||||||
// TODO: Custom date formatter
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'line_items',
|
|
||||||
title: t`Line Items`,
|
|
||||||
sortable: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'total_price',
|
|
||||||
title: t`Total Price`,
|
|
||||||
sortable: true
|
|
||||||
|
|
||||||
// TODO: Custom money formatter
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'responsible',
|
|
||||||
title: t`Responsible`,
|
|
||||||
sortable: true
|
|
||||||
|
|
||||||
// TODO: custom 'owner' formatter
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import { useUserState } from '../../../states/UserState';
|
|||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { DescriptionColumn, LinkColumn } from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { RowDeleteAction, RowEditAction } from '../RowActions';
|
import { RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
import { TableHoverCard } from '../TableHoverCard';
|
import { TableHoverCard } from '../TableHoverCard';
|
||||||
@ -63,11 +64,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
|
|||||||
title: t`Supplier Part`,
|
title: t`Supplier Part`,
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`,
|
|
||||||
sortable: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'manufacturer',
|
accessor: 'manufacturer',
|
||||||
|
|
||||||
@ -128,13 +125,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
LinkColumn(),
|
||||||
accessor: 'link',
|
|
||||||
title: t`Link`,
|
|
||||||
sortable: false
|
|
||||||
|
|
||||||
// TODO: custom link renderer?
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'note',
|
accessor: 'note',
|
||||||
title: t`Notes`,
|
title: t`Notes`,
|
||||||
|
@ -6,7 +6,15 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { ModelType } from '../../render/ModelType';
|
import { ModelType } from '../../render/ModelType';
|
||||||
import { TableStatusRenderer } from '../../renderers/StatusRenderer';
|
import {
|
||||||
|
CreationDateColumn,
|
||||||
|
DescriptionColumn,
|
||||||
|
LineItemsProgressColumn,
|
||||||
|
ProjectCodeColumn,
|
||||||
|
ResponsibleColumn,
|
||||||
|
StatusColumn,
|
||||||
|
TargetDateColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
export function ReturnOrderTable({ params }: { params?: any }) {
|
export function ReturnOrderTable({ params }: { params?: any }) {
|
||||||
@ -26,10 +34,7 @@ export function ReturnOrderTable({ params }: { params?: any }) {
|
|||||||
accessor: 'reference',
|
accessor: 'reference',
|
||||||
title: t`Return Order`,
|
title: t`Return Order`,
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
// TODO: Display extra information if order is overdue
|
||||||
{
|
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: 'customer__name',
|
accessor: 'customer__name',
|
||||||
@ -51,24 +56,17 @@ export function ReturnOrderTable({ params }: { params?: any }) {
|
|||||||
accessor: 'customer_reference',
|
accessor: 'customer_reference',
|
||||||
title: t`Customer Reference`
|
title: t`Customer Reference`
|
||||||
},
|
},
|
||||||
|
DescriptionColumn(),
|
||||||
|
LineItemsProgressColumn(),
|
||||||
|
StatusColumn(ModelType.returnorder),
|
||||||
|
ProjectCodeColumn(),
|
||||||
|
CreationDateColumn(),
|
||||||
|
TargetDateColumn(),
|
||||||
|
ResponsibleColumn(),
|
||||||
{
|
{
|
||||||
accessor: 'project_code',
|
accessor: 'total_cost',
|
||||||
title: t`Project Code`
|
title: t`Total Cost`
|
||||||
|
|
||||||
// TODO: Custom formatter
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessor: 'status',
|
|
||||||
title: t`Status`,
|
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
render: TableStatusRenderer(ModelType.returnorder)
|
|
||||||
}
|
}
|
||||||
// TODO: Creation date
|
|
||||||
// TODO: Target date
|
|
||||||
// TODO: Line items
|
|
||||||
// TODO: Responsible
|
|
||||||
// TODO: Total cost
|
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -6,7 +6,16 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { ModelType } from '../../render/ModelType';
|
import { ModelType } from '../../render/ModelType';
|
||||||
import { TableStatusRenderer } from '../../renderers/StatusRenderer';
|
import {
|
||||||
|
CreationDateColumn,
|
||||||
|
DescriptionColumn,
|
||||||
|
LineItemsProgressColumn,
|
||||||
|
ProjectCodeColumn,
|
||||||
|
ShipmentDateColumn,
|
||||||
|
StatusColumn,
|
||||||
|
TargetDateColumn,
|
||||||
|
TotalPriceColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
export function SalesOrderTable({ params }: { params?: any }) {
|
export function SalesOrderTable({ params }: { params?: any }) {
|
||||||
@ -27,10 +36,7 @@ export function SalesOrderTable({ params }: { params?: any }) {
|
|||||||
title: t`Sales Order`,
|
title: t`Sales Order`,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: false
|
switchable: false
|
||||||
},
|
// TODO: Display extra information if order is overdue
|
||||||
{
|
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: 'customer__name',
|
accessor: 'customer__name',
|
||||||
@ -52,25 +58,14 @@ export function SalesOrderTable({ params }: { params?: any }) {
|
|||||||
accessor: 'customer_reference',
|
accessor: 'customer_reference',
|
||||||
title: t`Customer Reference`
|
title: t`Customer Reference`
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'project_code',
|
LineItemsProgressColumn(),
|
||||||
title: t`Project Code`
|
StatusColumn(ModelType.salesorder),
|
||||||
|
ProjectCodeColumn(),
|
||||||
// TODO: Custom formatter
|
CreationDateColumn(),
|
||||||
},
|
TargetDateColumn(),
|
||||||
{
|
ShipmentDateColumn(),
|
||||||
accessor: 'status',
|
TotalPriceColumn()
|
||||||
title: t`Status`,
|
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
render: TableStatusRenderer(ModelType.salesorder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Creation date
|
|
||||||
// TODO: Target date
|
|
||||||
// TODO: Shipment date
|
|
||||||
// TODO: Line items
|
|
||||||
// TODO: Total price
|
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { AddItemButton } from '../../buttons/AddItemButton';
|
import { AddItemButton } from '../../buttons/AddItemButton';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
|
|
||||||
@ -27,11 +28,7 @@ export function ProjectCodeTable() {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
title: t`Project Code`
|
title: t`Project Code`
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn()
|
||||||
accessor: 'description',
|
|
||||||
sortable: false,
|
|
||||||
title: t`Description`
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../images/Thumbnail';
|
import { Thumbnail } from '../../images/Thumbnail';
|
||||||
import { ModelType } from '../../render/ModelType';
|
import { ModelType } from '../../render/ModelType';
|
||||||
import { TableStatusRenderer } from '../../renderers/StatusRenderer';
|
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { StatusColumn } from '../ColumnRenderers';
|
||||||
import { TableFilter } from '../Filter';
|
import { TableFilter } from '../Filter';
|
||||||
import { RowAction } from '../RowActions';
|
import { RowAction } from '../RowActions';
|
||||||
import { TableHoverCard } from '../TableHoverCard';
|
import { TableHoverCard } from '../TableHoverCard';
|
||||||
@ -150,14 +150,7 @@ function stockItemTableColumns(): TableColumn[] {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
StatusColumn(ModelType.stockitem),
|
||||||
accessor: 'status',
|
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
filter: true,
|
|
||||||
title: t`Status`,
|
|
||||||
render: TableStatusRenderer(ModelType.stockitem)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'batch',
|
accessor: 'batch',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
@ -6,6 +6,7 @@ import { useTableRefresh } from '../../../hooks/TableRefresh';
|
|||||||
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { YesNoButton } from '../../items/YesNoButton';
|
import { YesNoButton } from '../../items/YesNoButton';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,10 +24,7 @@ export function StockLocationTable({ params = {} }: { params?: any }) {
|
|||||||
title: t`Name`,
|
title: t`Name`,
|
||||||
switchable: false
|
switchable: false
|
||||||
},
|
},
|
||||||
{
|
DescriptionColumn(),
|
||||||
accessor: 'description',
|
|
||||||
title: t`Description`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessor: 'pathstring',
|
accessor: 'pathstring',
|
||||||
title: t`Path`,
|
title: t`Path`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user