mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
[PUI] Platform fixes (#8324)
* Add "IPN" column to build order allocated stock table * Allow sorting and searching by IPN * Handle allocations where allocated but required == 0 * Add "no info available" message to part scheduling * Adjust PartSchedulingTable * Icon fix * Add "latest serial number" information to PartDetail page * Cleanup code for serial-number placeholder in forms * Logic fix for displaying non-unity pack quantity * Fix description field on SupplierPart page * Fix duplicate table column
This commit is contained in:
parent
e219b7c914
commit
ddea9fa4b9
@ -737,10 +737,12 @@ class BuildItemList(DataExportViewMixin, BulkDeleteMixin, ListCreateAPI):
|
|||||||
'quantity',
|
'quantity',
|
||||||
'location',
|
'location',
|
||||||
'reference',
|
'reference',
|
||||||
|
'IPN',
|
||||||
]
|
]
|
||||||
|
|
||||||
ordering_field_aliases = {
|
ordering_field_aliases = {
|
||||||
'part': 'stock_item__part__name',
|
'part': 'stock_item__part__name',
|
||||||
|
'IPN': 'stock_item__part__IPN',
|
||||||
'sku': 'stock_item__supplier_part__SKU',
|
'sku': 'stock_item__supplier_part__SKU',
|
||||||
'location': 'stock_item__location__name',
|
'location': 'stock_item__location__name',
|
||||||
'reference': 'build_line__bom_item__reference',
|
'reference': 'build_line__bom_item__reference',
|
||||||
@ -749,6 +751,7 @@ class BuildItemList(DataExportViewMixin, BulkDeleteMixin, ListCreateAPI):
|
|||||||
search_fields = [
|
search_fields = [
|
||||||
'stock_item__supplier_part__SKU',
|
'stock_item__supplier_part__SKU',
|
||||||
'stock_item__part__name',
|
'stock_item__part__name',
|
||||||
|
'stock_item__part__IPN',
|
||||||
'build_line__bom_item__reference',
|
'build_line__bom_item__reference',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -315,6 +315,10 @@ function TableAnchorValue(props: Readonly<FieldProps>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ProgressBarValue(props: Readonly<FieldProps>) {
|
function ProgressBarValue(props: Readonly<FieldProps>) {
|
||||||
|
if (props.field_data.total <= 0) {
|
||||||
|
return <Text size="sm">{props.field_data.progress}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
value={props.field_data.progress}
|
value={props.field_data.progress}
|
||||||
|
@ -40,6 +40,7 @@ import {
|
|||||||
useBatchCodeGenerator,
|
useBatchCodeGenerator,
|
||||||
useSerialNumberGenerator
|
useSerialNumberGenerator
|
||||||
} from '../hooks/UseGenerator';
|
} from '../hooks/UseGenerator';
|
||||||
|
import { useInstance } from '../hooks/UseInstance';
|
||||||
import { useSerialNumberPlaceholder } from '../hooks/UsePlaceholder';
|
import { useSerialNumberPlaceholder } from '../hooks/UsePlaceholder';
|
||||||
import { apiUrl } from '../states/ApiState';
|
import { apiUrl } from '../states/ApiState';
|
||||||
import { useGlobalSettingsState } from '../states/SettingsState';
|
import { useGlobalSettingsState } from '../states/SettingsState';
|
||||||
@ -48,65 +49,66 @@ import { useGlobalSettingsState } from '../states/SettingsState';
|
|||||||
* Construct a set of fields for creating / editing a StockItem instance
|
* Construct a set of fields for creating / editing a StockItem instance
|
||||||
*/
|
*/
|
||||||
export function useStockFields({
|
export function useStockFields({
|
||||||
item_detail,
|
|
||||||
part_detail,
|
|
||||||
partId,
|
partId,
|
||||||
|
stockItem,
|
||||||
create = false
|
create = false
|
||||||
}: {
|
}: {
|
||||||
partId?: number;
|
partId?: number;
|
||||||
item_detail?: any;
|
stockItem?: any;
|
||||||
part_detail?: any;
|
|
||||||
create: boolean;
|
create: boolean;
|
||||||
}): ApiFormFieldSet {
|
}): ApiFormFieldSet {
|
||||||
const globalSettings = useGlobalSettingsState();
|
const globalSettings = useGlobalSettingsState();
|
||||||
|
|
||||||
const [part, setPart] = useState<number | null>(null);
|
// Keep track of the "part" instance
|
||||||
|
const [partInstance, setPartInstance] = useState<any>({});
|
||||||
|
|
||||||
const [supplierPart, setSupplierPart] = useState<number | null>(null);
|
const [supplierPart, setSupplierPart] = useState<number | null>(null);
|
||||||
|
|
||||||
const [batchCode, setBatchCode] = useState<string>('');
|
const [nextBatchCode, setNextBatchCode] = useState<string>('');
|
||||||
const [serialNumbers, setSerialNumbers] = useState<string>('');
|
const [nextSerialNumber, setNextSerialNumber] = useState<string>('');
|
||||||
|
|
||||||
const [trackable, setTrackable] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const batchGenerator = useBatchCodeGenerator((value: any) => {
|
const batchGenerator = useBatchCodeGenerator((value: any) => {
|
||||||
if (!batchCode) {
|
if (value) {
|
||||||
setBatchCode(value);
|
setNextBatchCode(`Next batch code` + `: ${value}`);
|
||||||
|
} else {
|
||||||
|
setNextBatchCode('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const serialGenerator = useSerialNumberGenerator((value: any) => {
|
const serialGenerator = useSerialNumberGenerator((value: any) => {
|
||||||
if (!serialNumbers && create && trackable) {
|
if (value) {
|
||||||
setSerialNumbers(value);
|
setNextSerialNumber(t`Next serial number` + `: ${value}`);
|
||||||
|
} else {
|
||||||
|
setNextSerialNumber('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (partInstance?.pk) {
|
||||||
|
// Update the generators whenever the part ID changes
|
||||||
|
batchGenerator.update({ part: partInstance.pk });
|
||||||
|
serialGenerator.update({ part: partInstance.pk });
|
||||||
|
}
|
||||||
|
}, [partInstance.pk]);
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const fields: ApiFormFieldSet = {
|
const fields: ApiFormFieldSet = {
|
||||||
part: {
|
part: {
|
||||||
value: partId,
|
value: partInstance.pk,
|
||||||
disabled: !create,
|
disabled: !create,
|
||||||
filters: {
|
filters: {
|
||||||
active: create ? true : undefined
|
active: create ? true : undefined
|
||||||
},
|
},
|
||||||
onValueChange: (value, record) => {
|
onValueChange: (value, record) => {
|
||||||
setPart(value);
|
// Update the tracked part instance
|
||||||
// TODO: implement remaining functionality from old stock.py
|
setPartInstance(record);
|
||||||
|
|
||||||
setTrackable(record.trackable ?? false);
|
|
||||||
|
|
||||||
batchGenerator.update({ part: value });
|
|
||||||
serialGenerator.update({ part: value });
|
|
||||||
|
|
||||||
if (!record.trackable) {
|
|
||||||
setSerialNumbers('');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the 'supplier_part' field if the part is changed
|
// Clear the 'supplier_part' field if the part is changed
|
||||||
setSupplierPart(null);
|
setSupplierPart(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
supplier_part: {
|
supplier_part: {
|
||||||
hidden: part_detail?.purchaseable == false,
|
hidden: partInstance?.purchaseable == false,
|
||||||
value: supplierPart,
|
value: supplierPart,
|
||||||
onValueChange: (value) => {
|
onValueChange: (value) => {
|
||||||
setSupplierPart(value);
|
setSupplierPart(value);
|
||||||
@ -114,7 +116,7 @@ export function useStockFields({
|
|||||||
filters: {
|
filters: {
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
supplier_detail: true,
|
supplier_detail: true,
|
||||||
...(part ? { part } : {})
|
part: partId
|
||||||
},
|
},
|
||||||
adjustFilters: (adjust: ApiFormAdjustFilterType) => {
|
adjustFilters: (adjust: ApiFormAdjustFilterType) => {
|
||||||
if (adjust.data.part) {
|
if (adjust.data.part) {
|
||||||
@ -148,22 +150,20 @@ export function useStockFields({
|
|||||||
serial_numbers: {
|
serial_numbers: {
|
||||||
field_type: 'string',
|
field_type: 'string',
|
||||||
label: t`Serial Numbers`,
|
label: t`Serial Numbers`,
|
||||||
|
disabled: partInstance?.trackable == false,
|
||||||
description: t`Enter serial numbers for new stock (or leave blank)`,
|
description: t`Enter serial numbers for new stock (or leave blank)`,
|
||||||
required: false,
|
required: false,
|
||||||
disabled: !trackable,
|
|
||||||
hidden: !create,
|
hidden: !create,
|
||||||
value: serialNumbers,
|
placeholder: nextSerialNumber
|
||||||
onValueChange: (value) => setSerialNumbers(value)
|
|
||||||
},
|
},
|
||||||
serial: {
|
serial: {
|
||||||
hidden:
|
hidden:
|
||||||
create ||
|
create ||
|
||||||
part_detail?.trackable == false ||
|
partInstance.trackable == false ||
|
||||||
(!item_detail?.quantity != undefined && item_detail?.quantity != 1)
|
(!stockItem?.quantity != undefined && stockItem?.quantity != 1)
|
||||||
},
|
},
|
||||||
batch: {
|
batch: {
|
||||||
value: batchCode,
|
placeholder: nextBatchCode
|
||||||
onValueChange: (value) => setBatchCode(value)
|
|
||||||
},
|
},
|
||||||
status_custom_key: {
|
status_custom_key: {
|
||||||
label: t`Stock Status`
|
label: t`Stock Status`
|
||||||
@ -195,16 +195,14 @@ export function useStockFields({
|
|||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}, [
|
}, [
|
||||||
item_detail,
|
stockItem,
|
||||||
part_detail,
|
partInstance,
|
||||||
part,
|
partId,
|
||||||
globalSettings,
|
globalSettings,
|
||||||
supplierPart,
|
supplierPart,
|
||||||
batchCode,
|
nextSerialNumber,
|
||||||
serialNumbers,
|
nextBatchCode,
|
||||||
trackable,
|
create
|
||||||
create,
|
|
||||||
partId
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,13 @@ export function useInstance<T = any>({
|
|||||||
const [requestStatus, setRequestStatus] = useState<number>(0);
|
const [requestStatus, setRequestStatus] = useState<number>(0);
|
||||||
|
|
||||||
const instanceQuery = useQuery<T>({
|
const instanceQuery = useQuery<T>({
|
||||||
queryKey: ['instance', endpoint, pk, params, pathParams],
|
queryKey: [
|
||||||
|
'instance',
|
||||||
|
endpoint,
|
||||||
|
pk,
|
||||||
|
JSON.stringify(params),
|
||||||
|
JSON.stringify(pathParams)
|
||||||
|
],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (hasPrimaryKey) {
|
if (hasPrimaryKey) {
|
||||||
if (
|
if (
|
||||||
|
@ -96,9 +96,10 @@ export default function SupplierPartDetail() {
|
|||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'part_detail.description',
|
name: 'part_detail.description',
|
||||||
label: t`Description`,
|
label: t`Part Description`,
|
||||||
copy: true,
|
copy: true,
|
||||||
icon: 'info'
|
icon: 'info',
|
||||||
|
hidden: !data.part_detail?.description
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'link',
|
type: 'link',
|
||||||
@ -133,6 +134,13 @@ export default function SupplierPartDetail() {
|
|||||||
copy: true,
|
copy: true,
|
||||||
icon: 'reference'
|
icon: 'reference'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'description',
|
||||||
|
label: t`Description`,
|
||||||
|
copy: true,
|
||||||
|
hidden: !data.description
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'link',
|
type: 'link',
|
||||||
name: 'manufacturer',
|
name: 'manufacturer',
|
||||||
|
@ -118,6 +118,14 @@ export default function PartDetail() {
|
|||||||
const globalSettings = useGlobalSettingsState();
|
const globalSettings = useGlobalSettingsState();
|
||||||
const userSettings = useUserSettingsState();
|
const userSettings = useUserSettingsState();
|
||||||
|
|
||||||
|
const { instance: serials } = useInstance({
|
||||||
|
endpoint: ApiEndpoints.part_serial_numbers,
|
||||||
|
pk: id,
|
||||||
|
hasPrimaryKey: true,
|
||||||
|
refetchOnMount: false,
|
||||||
|
defaultValue: {}
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
instance: part,
|
instance: part,
|
||||||
refreshInstance,
|
refreshInstance,
|
||||||
@ -132,15 +140,22 @@ export default function PartDetail() {
|
|||||||
refetchOnMount: true
|
refetchOnMount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
part.required =
|
|
||||||
(part?.required_for_build_orders ?? 0) +
|
|
||||||
(part?.required_for_sales_orders ?? 0);
|
|
||||||
|
|
||||||
const detailsPanel = useMemo(() => {
|
const detailsPanel = useMemo(() => {
|
||||||
if (instanceQuery.isFetching) {
|
if (instanceQuery.isFetching) {
|
||||||
return <Skeleton />;
|
return <Skeleton />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data = { ...part };
|
||||||
|
|
||||||
|
data.required =
|
||||||
|
(data?.required_for_build_orders ?? 0) +
|
||||||
|
(data?.required_for_sales_orders ?? 0);
|
||||||
|
|
||||||
|
// Provide latest serial number info
|
||||||
|
if (!!serials.latest) {
|
||||||
|
data.latest_serial_number = serials.latest;
|
||||||
|
}
|
||||||
|
|
||||||
// Construct the details tables
|
// Construct the details tables
|
||||||
let tl: DetailsField[] = [
|
let tl: DetailsField[] = [
|
||||||
{
|
{
|
||||||
@ -277,7 +292,10 @@ export default function PartDetail() {
|
|||||||
total: part.required_for_build_orders,
|
total: part.required_for_build_orders,
|
||||||
progress: part.allocated_to_build_orders,
|
progress: part.allocated_to_build_orders,
|
||||||
label: t`Allocated to Build Orders`,
|
label: t`Allocated to Build Orders`,
|
||||||
hidden: !part.component || part.required_for_build_orders <= 0
|
hidden:
|
||||||
|
!part.component ||
|
||||||
|
(part.required_for_build_orders <= 0 &&
|
||||||
|
part.allocated_to_build_orders <= 0)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'progressbar',
|
type: 'progressbar',
|
||||||
@ -285,7 +303,10 @@ export default function PartDetail() {
|
|||||||
total: part.required_for_sales_orders,
|
total: part.required_for_sales_orders,
|
||||||
progress: part.allocated_to_sales_orders,
|
progress: part.allocated_to_sales_orders,
|
||||||
label: t`Allocated to Sales Orders`,
|
label: t`Allocated to Sales Orders`,
|
||||||
hidden: !part.salable || part.required_for_sales_orders <= 0
|
hidden:
|
||||||
|
!part.salable ||
|
||||||
|
(part.required_for_sales_orders <= 0 &&
|
||||||
|
part.allocated_to_sales_orders <= 0)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -349,6 +370,7 @@ export default function PartDetail() {
|
|||||||
{
|
{
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
name: 'salable',
|
name: 'salable',
|
||||||
|
icon: 'saleable',
|
||||||
label: t`Saleable Part`
|
label: t`Saleable Part`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -434,6 +456,14 @@ export default function PartDetail() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
br.push({
|
||||||
|
type: 'string',
|
||||||
|
name: 'latest_serial_number',
|
||||||
|
label: t`Latest Serial Number`,
|
||||||
|
hidden: !part.trackable || !data.latest_serial_number,
|
||||||
|
icon: 'serial'
|
||||||
|
});
|
||||||
|
|
||||||
// Add in stocktake information
|
// Add in stocktake information
|
||||||
if (id && part.last_stocktake) {
|
if (id && part.last_stocktake) {
|
||||||
br.push({
|
br.push({
|
||||||
@ -526,17 +556,17 @@ export default function PartDetail() {
|
|||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={8}>
|
<Grid.Col span={8}>
|
||||||
<DetailsTable fields={tl} item={part} />
|
<DetailsTable fields={tl} item={data} />
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
<DetailsTable fields={tr} item={part} />
|
<DetailsTable fields={tr} item={data} />
|
||||||
<DetailsTable fields={bl} item={part} />
|
<DetailsTable fields={bl} item={data} />
|
||||||
<DetailsTable fields={br} item={part} />
|
<DetailsTable fields={br} item={data} />
|
||||||
</ItemDetailsGrid>
|
</ItemDetailsGrid>
|
||||||
) : (
|
) : (
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
);
|
);
|
||||||
}, [globalSettings, part, instanceQuery]);
|
}, [globalSettings, part, serials, instanceQuery]);
|
||||||
|
|
||||||
// Part data panels (recalculate when part data changes)
|
// Part data panels (recalculate when part data changes)
|
||||||
const partPanels: PanelType[] = useMemo(() => {
|
const partPanels: PanelType[] = useMemo(() => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { ChartTooltipProps, LineChart } from '@mantine/charts';
|
import { ChartTooltipProps, LineChart } from '@mantine/charts';
|
||||||
import {
|
import {
|
||||||
Anchor,
|
Alert,
|
||||||
Center,
|
Center,
|
||||||
Divider,
|
Divider,
|
||||||
Loader,
|
Loader,
|
||||||
@ -65,23 +65,7 @@ export default function PartSchedulingDetail({ part }: { part: any }) {
|
|||||||
{
|
{
|
||||||
accessor: 'label',
|
accessor: 'label',
|
||||||
switchable: false,
|
switchable: false,
|
||||||
title: t`Order`,
|
title: t`Order`
|
||||||
render: (record: any) => {
|
|
||||||
const url = getDetailUrl(record.model, record.model_id);
|
|
||||||
|
|
||||||
if (url) {
|
|
||||||
return (
|
|
||||||
<Anchor
|
|
||||||
href="#"
|
|
||||||
onClick={(event: any) => navigateToLink(url, navigate, event)}
|
|
||||||
>
|
|
||||||
{record.label}
|
|
||||||
</Anchor>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return record.label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
DescriptionColumn({
|
DescriptionColumn({
|
||||||
accessor: 'title',
|
accessor: 'title',
|
||||||
@ -245,15 +229,32 @@ export default function PartSchedulingDetail({ part }: { part: any }) {
|
|||||||
return [min_date.valueOf(), max_date.valueOf()];
|
return [min_date.valueOf(), max_date.valueOf()];
|
||||||
}, [chartData]);
|
}, [chartData]);
|
||||||
|
|
||||||
|
const hasSchedulingInfo: boolean = useMemo(
|
||||||
|
() => table.recordCount > 0,
|
||||||
|
[table.recordCount]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{!table.isLoading && !hasSchedulingInfo && (
|
||||||
|
<Alert color="blue" title={t`No information available`}>
|
||||||
|
<Text>{t`There is no scheduling information available for the selected part`}</Text>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
<SimpleGrid cols={2}>
|
<SimpleGrid cols={2}>
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={apiUrl(ApiEndpoints.part_scheduling, part.pk)}
|
url={apiUrl(ApiEndpoints.part_scheduling, part.pk)}
|
||||||
tableState={table}
|
tableState={table}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
enableSearch: false
|
enableSearch: false,
|
||||||
|
onRowClick: (record: any, index: number, event: any) => {
|
||||||
|
const url = getDetailUrl(record.model, record.model_id);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
navigateToLink(url, navigate, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{table.isLoading ? (
|
{table.isLoading ? (
|
||||||
|
@ -525,7 +525,7 @@ export default function StockDetail() {
|
|||||||
|
|
||||||
const editStockItemFields = useStockFields({
|
const editStockItemFields = useStockFields({
|
||||||
create: false,
|
create: false,
|
||||||
part_detail: stockitem.part_detail
|
partId: stockitem.part
|
||||||
});
|
});
|
||||||
|
|
||||||
const editStockItem = useEditApiFormModal({
|
const editStockItem = useEditApiFormModal({
|
||||||
|
@ -97,6 +97,14 @@ export default function BuildAllocatedStockTable({
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
render: (record: any) => PartColumn({ part: record.part_detail })
|
render: (record: any) => PartColumn({ part: record.part_detail })
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessor: 'part_detail.IPN',
|
||||||
|
ordering: 'IPN',
|
||||||
|
hidden: !showPartInfo,
|
||||||
|
title: t`IPN`,
|
||||||
|
sortable: true,
|
||||||
|
switchable: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
hidden: !showPartInfo,
|
hidden: !showPartInfo,
|
||||||
accessor: 'bom_reference',
|
accessor: 'bom_reference',
|
||||||
|
@ -218,8 +218,8 @@ export default function BuildOutputTable({
|
|||||||
|
|
||||||
const editStockItemFields = useStockFields({
|
const editStockItemFields = useStockFields({
|
||||||
create: false,
|
create: false,
|
||||||
item_detail: selectedOutputs[0],
|
partId: partId,
|
||||||
part_detail: selectedOutputs[0]?.part_detail
|
stockItem: selectedOutputs[0]
|
||||||
});
|
});
|
||||||
|
|
||||||
const editBuildOutput = useEditApiFormModal({
|
const editBuildOutput = useEditApiFormModal({
|
||||||
|
@ -95,10 +95,6 @@ export default function PartPurchaseOrdersTable({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DateColumn({
|
|
||||||
accessor: 'order_detail.complete_date',
|
|
||||||
title: t`Order Completed Date`
|
|
||||||
}),
|
|
||||||
DateColumn({
|
DateColumn({
|
||||||
accessor: 'target_date',
|
accessor: 'target_date',
|
||||||
title: t`Target Date`
|
title: t`Target Date`
|
||||||
|
@ -149,7 +149,10 @@ export function PurchaseOrderLineItemTable({
|
|||||||
let part = record?.part_detail ?? supplier_part?.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 != undefined &&
|
||||||
|
supplier_part.pack_quantity_native != 1
|
||||||
|
) {
|
||||||
let total = record.quantity * supplier_part.pack_quantity_native;
|
let total = record.quantity * supplier_part.pack_quantity_native;
|
||||||
|
|
||||||
extra.push(
|
extra.push(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user