import { t } from '@lingui/macro'; import { Group, Stack, Text } from '@mantine/core'; import { ReactNode, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTableRefresh } from '../../../hooks/TableRefresh'; import { ApiPaths, apiUrl } from '../../../states/ApiState'; import { Thumbnail } from '../../images/Thumbnail'; import { ModelType } from '../../render/ModelType'; import { TableStatusRenderer } from '../../renderers/StatusRenderer'; import { TableColumn } from '../Column'; import { TableFilter } from '../Filter'; import { RowAction } from '../RowActions'; import { TableHoverCard } from '../TableHoverCard'; import { InvenTreeTable } from './../InvenTreeTable'; /** * Construct a list of columns for the stock item table */ function stockItemTableColumns(): TableColumn[] { return [ { accessor: 'part', sortable: true, title: t`Part`, render: function (record: any) { let part = record.part_detail ?? {}; return ( {part?.full_name} ); } }, { accessor: 'part_detail.description', sortable: false, switchable: true, title: t`Description` }, { accessor: 'quantity', sortable: true, title: t`Stock`, render: (record) => { // TODO: Push this out into a custom renderer let quantity = record?.quantity ?? 0; let allocated = record?.allocated ?? 0; let available = quantity - allocated; let text = quantity; let part = record?.part_detail ?? {}; let extra: ReactNode[] = []; let color = undefined; if (record.serial && quantity == 1) { text = `# ${record.serial}`; } if (record.is_building) { color = 'blue'; extra.push( {t`This stock item is in production`} ); } if (record.sales_order) { extra.push( {t`This stock item has been assigned to a sales order`} ); } if (record.customer) { extra.push( {t`This stock item has been assigned to a customer`} ); } if (record.belongs_to) { extra.push( {t`This stock item is installed in another stock item`} ); } if (record.consumed_by) { extra.push( {t`This stock item has been consumed by a build order`} ); } if (record.expired) { extra.push({t`This stock item has expired`}); } else if (record.stale) { extra.push({t`This stock item is stale`}); } if (allocated > 0) { if (allocated >= quantity) { color = 'orange'; extra.push( {t`This stock item is fully allocated`} ); } else { extra.push( {t`This stock item is partially allocated`} ); } } if (available != quantity) { if (available > 0) { extra.push( {t`Available` + `: ${available}`} ); } else { extra.push( {t`No stock available`} ); } } if (quantity <= 0) { color = 'red'; extra.push( {t`This stock item has been depleted`} ); } return ( {text} {part.units && ( [{part.units}] )} } title={t`Stock Information`} extra={extra.length > 0 && {extra}} /> ); } }, { accessor: 'status', sortable: true, switchable: true, filter: true, title: t`Status`, render: TableStatusRenderer(ModelType.stockitem) }, { accessor: 'batch', sortable: true, switchable: true, title: t`Batch` }, { accessor: 'location', sortable: true, switchable: true, title: t`Location`, render: function (record: any) { // TODO: Custom renderer for location // TODO: Note, if not "In stock" we don't want to display the actual location here return record?.location_detail?.pathstring ?? record.location ?? '-'; } } // TODO: stocktake column // TODO: expiry date // TODO: last updated // TODO: purchase order // TODO: Supplier part // TODO: purchase price // TODO: stock value // TODO: packaging // TODO: notes ]; } /** * Construct a list of available filters for the stock item table */ function stockItemTableFilters(): TableFilter[] { return [ { name: 'test_filter', label: t`Test Filter`, description: t`This is a test filter`, type: 'choice', choiceFunction: () => [ { value: '1', label: 'One' }, { value: '2', label: 'Two' }, { value: '3', label: 'Three' } ] } ]; } /* * Load a table of stock items */ export function StockItemTable({ params = {} }: { params?: any }) { let tableColumns = useMemo(() => stockItemTableColumns(), []); let tableFilters = useMemo(() => stockItemTableFilters(), []); const { tableKey, refreshTable } = useTableRefresh('stockitem'); function stockItemRowActions(record: any): RowAction[] { let actions: RowAction[] = []; // TODO: Custom row actions for stock table return actions; } const navigate = useNavigate(); return ( navigate(`/stock/item/${record.pk}`), params: { ...params, part_detail: true, location_detail: true, supplier_part_detail: true } }} /> ); }