mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	[PUI] Allocation Tables (#7836)
* Skeleton panel and placeholder tables * Implement build order allocation table * Refactor and repurpose existing table * Add allocations table to stock item page * Skeleton for <SalesOrderAllocationTable /> * Implement sales order allocation table(s)
This commit is contained in:
		@@ -141,6 +141,7 @@ export enum ApiEndpoints {
 | 
				
			|||||||
  sales_order_ship = 'order/so/:id/ship/',
 | 
					  sales_order_ship = 'order/so/:id/ship/',
 | 
				
			||||||
  sales_order_complete = 'order/so/:id/complete/',
 | 
					  sales_order_complete = 'order/so/:id/complete/',
 | 
				
			||||||
  sales_order_line_list = 'order/so-line/',
 | 
					  sales_order_line_list = 'order/so-line/',
 | 
				
			||||||
 | 
					  sales_order_allocation_list = 'order/so-allocation/',
 | 
				
			||||||
  sales_order_shipment_list = 'order/so/shipment/',
 | 
					  sales_order_shipment_list = 'order/so/shipment/',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return_order_list = 'order/ro/',
 | 
					  return_order_list = 'order/ro/',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -283,7 +283,7 @@ export default function BuildDetail() {
 | 
				
			|||||||
        label: t`Allocated Stock`,
 | 
					        label: t`Allocated Stock`,
 | 
				
			||||||
        icon: <IconList />,
 | 
					        icon: <IconList />,
 | 
				
			||||||
        content: build.pk ? (
 | 
					        content: build.pk ? (
 | 
				
			||||||
          <BuildAllocatedStockTable buildId={build.pk} />
 | 
					          <BuildAllocatedStockTable buildId={build.pk} showPartInfo allowEdit />
 | 
				
			||||||
        ) : (
 | 
					        ) : (
 | 
				
			||||||
          <Skeleton />
 | 
					          <Skeleton />
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,13 @@
 | 
				
			|||||||
import { t } from '@lingui/macro';
 | 
					import { t } from '@lingui/macro';
 | 
				
			||||||
import { Alert, Grid, Skeleton, Space, Stack, Text } from '@mantine/core';
 | 
					import {
 | 
				
			||||||
 | 
					  Accordion,
 | 
				
			||||||
 | 
					  Alert,
 | 
				
			||||||
 | 
					  Grid,
 | 
				
			||||||
 | 
					  Skeleton,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Stack,
 | 
				
			||||||
 | 
					  Text
 | 
				
			||||||
 | 
					} from '@mantine/core';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  IconBookmarks,
 | 
					  IconBookmarks,
 | 
				
			||||||
  IconBuilding,
 | 
					  IconBuilding,
 | 
				
			||||||
@@ -48,6 +56,7 @@ import {
 | 
				
			|||||||
  ViewBarcodeAction
 | 
					  ViewBarcodeAction
 | 
				
			||||||
} from '../../components/items/ActionDropdown';
 | 
					} from '../../components/items/ActionDropdown';
 | 
				
			||||||
import { PlaceholderPanel } from '../../components/items/Placeholder';
 | 
					import { PlaceholderPanel } from '../../components/items/Placeholder';
 | 
				
			||||||
 | 
					import { StylishText } from '../../components/items/StylishText';
 | 
				
			||||||
import InstanceDetail from '../../components/nav/InstanceDetail';
 | 
					import InstanceDetail from '../../components/nav/InstanceDetail';
 | 
				
			||||||
import NavigationTree from '../../components/nav/NavigationTree';
 | 
					import NavigationTree from '../../components/nav/NavigationTree';
 | 
				
			||||||
import { PageDetail } from '../../components/nav/PageDetail';
 | 
					import { PageDetail } from '../../components/nav/PageDetail';
 | 
				
			||||||
@@ -76,6 +85,7 @@ import { useGlobalSettingsState } from '../../states/SettingsState';
 | 
				
			|||||||
import { useUserState } from '../../states/UserState';
 | 
					import { useUserState } from '../../states/UserState';
 | 
				
			||||||
import { BomTable } from '../../tables/bom/BomTable';
 | 
					import { BomTable } from '../../tables/bom/BomTable';
 | 
				
			||||||
import { UsedInTable } from '../../tables/bom/UsedInTable';
 | 
					import { UsedInTable } from '../../tables/bom/UsedInTable';
 | 
				
			||||||
 | 
					import BuildAllocatedStockTable from '../../tables/build/BuildAllocatedStockTable';
 | 
				
			||||||
import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
 | 
					import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
 | 
				
			||||||
import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
					import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
				
			||||||
import { PartParameterTable } from '../../tables/part/PartParameterTable';
 | 
					import { PartParameterTable } from '../../tables/part/PartParameterTable';
 | 
				
			||||||
@@ -84,6 +94,7 @@ import { PartVariantTable } from '../../tables/part/PartVariantTable';
 | 
				
			|||||||
import { RelatedPartTable } from '../../tables/part/RelatedPartTable';
 | 
					import { RelatedPartTable } from '../../tables/part/RelatedPartTable';
 | 
				
			||||||
import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
 | 
					import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
 | 
				
			||||||
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
 | 
					import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
 | 
				
			||||||
 | 
					import SalesOrderAllocationTable from '../../tables/sales/SalesOrderAllocationTable';
 | 
				
			||||||
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
 | 
					import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
 | 
				
			||||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
 | 
					import { StockItemTable } from '../../tables/stock/StockItemTable';
 | 
				
			||||||
import { TestStatisticsTable } from '../../tables/stock/TestStatisticsTable';
 | 
					import { TestStatisticsTable } from '../../tables/stock/TestStatisticsTable';
 | 
				
			||||||
@@ -539,7 +550,43 @@ export default function PartDetail() {
 | 
				
			|||||||
        label: t`Allocations`,
 | 
					        label: t`Allocations`,
 | 
				
			||||||
        icon: <IconBookmarks />,
 | 
					        icon: <IconBookmarks />,
 | 
				
			||||||
        hidden: !part.component && !part.salable,
 | 
					        hidden: !part.component && !part.salable,
 | 
				
			||||||
        content: <PlaceholderPanel />
 | 
					        content: (
 | 
				
			||||||
 | 
					          <Accordion
 | 
				
			||||||
 | 
					            multiple={true}
 | 
				
			||||||
 | 
					            defaultValue={['buildallocations', 'salesallocations']}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {part.component && (
 | 
				
			||||||
 | 
					              <Accordion.Item value="buildallocations" key="buildallocations">
 | 
				
			||||||
 | 
					                <Accordion.Control>
 | 
				
			||||||
 | 
					                  <StylishText size="lg">{t`Build Order Allocations`}</StylishText>
 | 
				
			||||||
 | 
					                </Accordion.Control>
 | 
				
			||||||
 | 
					                <Accordion.Panel>
 | 
				
			||||||
 | 
					                  <BuildAllocatedStockTable
 | 
				
			||||||
 | 
					                    partId={part.pk}
 | 
				
			||||||
 | 
					                    modelField="build"
 | 
				
			||||||
 | 
					                    modelTarget={ModelType.build}
 | 
				
			||||||
 | 
					                    showBuildInfo
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Accordion.Panel>
 | 
				
			||||||
 | 
					              </Accordion.Item>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					            {part.salable && (
 | 
				
			||||||
 | 
					              <Accordion.Item value="salesallocations" key="salesallocations">
 | 
				
			||||||
 | 
					                <Accordion.Control>
 | 
				
			||||||
 | 
					                  <StylishText size="lg">{t`Sales Order Allocations`}</StylishText>
 | 
				
			||||||
 | 
					                </Accordion.Control>
 | 
				
			||||||
 | 
					                <Accordion.Panel>
 | 
				
			||||||
 | 
					                  <SalesOrderAllocationTable
 | 
				
			||||||
 | 
					                    partId={part.pk}
 | 
				
			||||||
 | 
					                    modelField="order"
 | 
				
			||||||
 | 
					                    modelTarget={ModelType.salesorder}
 | 
				
			||||||
 | 
					                    showOrderInfo
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Accordion.Panel>
 | 
				
			||||||
 | 
					              </Accordion.Item>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </Accordion>
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name: 'bom',
 | 
					        name: 'bom',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
import { t } from '@lingui/macro';
 | 
					import { t } from '@lingui/macro';
 | 
				
			||||||
import { Grid, Skeleton, Stack } from '@mantine/core';
 | 
					import { Grid, Skeleton, Stack } from '@mantine/core';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  IconBook,
 | 
				
			||||||
 | 
					  IconBookmark,
 | 
				
			||||||
  IconDots,
 | 
					  IconDots,
 | 
				
			||||||
  IconInfoCircle,
 | 
					  IconInfoCircle,
 | 
				
			||||||
  IconList,
 | 
					  IconList,
 | 
				
			||||||
@@ -49,6 +51,7 @@ import { apiUrl } from '../../states/ApiState';
 | 
				
			|||||||
import { useUserState } from '../../states/UserState';
 | 
					import { useUserState } from '../../states/UserState';
 | 
				
			||||||
import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
 | 
					import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
 | 
				
			||||||
import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
					import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
				
			||||||
 | 
					import SalesOrderAllocationTable from '../../tables/sales/SalesOrderAllocationTable';
 | 
				
			||||||
import SalesOrderLineItemTable from '../../tables/sales/SalesOrderLineItemTable';
 | 
					import SalesOrderLineItemTable from '../../tables/sales/SalesOrderLineItemTable';
 | 
				
			||||||
import SalesOrderShipmentTable from '../../tables/sales/SalesOrderShipmentTable';
 | 
					import SalesOrderShipmentTable from '../../tables/sales/SalesOrderShipmentTable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,6 +275,20 @@ export default function SalesOrderDetail() {
 | 
				
			|||||||
        icon: <IconTruckDelivery />,
 | 
					        icon: <IconTruckDelivery />,
 | 
				
			||||||
        content: <SalesOrderShipmentTable orderId={order.pk} />
 | 
					        content: <SalesOrderShipmentTable orderId={order.pk} />
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        name: 'allocations',
 | 
				
			||||||
 | 
					        label: t`Allocated Stock`,
 | 
				
			||||||
 | 
					        icon: <IconBookmark />,
 | 
				
			||||||
 | 
					        content: (
 | 
				
			||||||
 | 
					          <SalesOrderAllocationTable
 | 
				
			||||||
 | 
					            orderId={order.pk}
 | 
				
			||||||
 | 
					            showPartInfo
 | 
				
			||||||
 | 
					            allowEdit
 | 
				
			||||||
 | 
					            modelField="item"
 | 
				
			||||||
 | 
					            modelTarget={ModelType.stockitem}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name: 'build-orders',
 | 
					        name: 'build-orders',
 | 
				
			||||||
        label: t`Build Orders`,
 | 
					        label: t`Build Orders`,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import { t } from '@lingui/macro';
 | 
					import { t } from '@lingui/macro';
 | 
				
			||||||
import { Grid, Skeleton, Stack } from '@mantine/core';
 | 
					import { Accordion, Grid, Skeleton, Stack } from '@mantine/core';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  IconBookmark,
 | 
					  IconBookmark,
 | 
				
			||||||
  IconBoxPadding,
 | 
					  IconBoxPadding,
 | 
				
			||||||
@@ -33,6 +33,7 @@ import {
 | 
				
			|||||||
  ViewBarcodeAction
 | 
					  ViewBarcodeAction
 | 
				
			||||||
} from '../../components/items/ActionDropdown';
 | 
					} from '../../components/items/ActionDropdown';
 | 
				
			||||||
import { PlaceholderPanel } from '../../components/items/Placeholder';
 | 
					import { PlaceholderPanel } from '../../components/items/Placeholder';
 | 
				
			||||||
 | 
					import { StylishText } from '../../components/items/StylishText';
 | 
				
			||||||
import InstanceDetail from '../../components/nav/InstanceDetail';
 | 
					import InstanceDetail from '../../components/nav/InstanceDetail';
 | 
				
			||||||
import NavigationTree from '../../components/nav/NavigationTree';
 | 
					import NavigationTree from '../../components/nav/NavigationTree';
 | 
				
			||||||
import { PageDetail } from '../../components/nav/PageDetail';
 | 
					import { PageDetail } from '../../components/nav/PageDetail';
 | 
				
			||||||
@@ -58,7 +59,9 @@ import {
 | 
				
			|||||||
} from '../../hooks/UseForm';
 | 
					} from '../../hooks/UseForm';
 | 
				
			||||||
import { useInstance } from '../../hooks/UseInstance';
 | 
					import { useInstance } from '../../hooks/UseInstance';
 | 
				
			||||||
import { useUserState } from '../../states/UserState';
 | 
					import { useUserState } from '../../states/UserState';
 | 
				
			||||||
 | 
					import BuildAllocatedStockTable from '../../tables/build/BuildAllocatedStockTable';
 | 
				
			||||||
import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
					import { AttachmentTable } from '../../tables/general/AttachmentTable';
 | 
				
			||||||
 | 
					import SalesOrderAllocationTable from '../../tables/sales/SalesOrderAllocationTable';
 | 
				
			||||||
import InstalledItemsTable from '../../tables/stock/InstalledItemsTable';
 | 
					import InstalledItemsTable from '../../tables/stock/InstalledItemsTable';
 | 
				
			||||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
 | 
					import { StockItemTable } from '../../tables/stock/StockItemTable';
 | 
				
			||||||
import StockItemTestResultTable from '../../tables/stock/StockItemTestResultTable';
 | 
					import StockItemTestResultTable from '../../tables/stock/StockItemTestResultTable';
 | 
				
			||||||
@@ -268,6 +271,19 @@ export default function StockDetail() {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }, [stockitem, instanceQuery]);
 | 
					  }, [stockitem, instanceQuery]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showBuildAllocations = useMemo(() => {
 | 
				
			||||||
 | 
					    // Determine if "build allocations" should be shown for this stock item
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      stockitem?.part_detail?.component && // Must be a "component"
 | 
				
			||||||
 | 
					      !stockitem?.sales_order && // Must not be assigned to a sales order
 | 
				
			||||||
 | 
					      !stockitem?.belongs_to
 | 
				
			||||||
 | 
					    ); // Must not be installed into another item
 | 
				
			||||||
 | 
					  }, [stockitem]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showSalesAlloctions = useMemo(() => {
 | 
				
			||||||
 | 
					    return stockitem?.part_detail?.salable;
 | 
				
			||||||
 | 
					  }, [stockitem]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const stockPanels: PanelType[] = useMemo(() => {
 | 
					  const stockPanels: PanelType[] = useMemo(() => {
 | 
				
			||||||
    return [
 | 
					    return [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@@ -290,10 +306,44 @@ export default function StockDetail() {
 | 
				
			|||||||
        name: 'allocations',
 | 
					        name: 'allocations',
 | 
				
			||||||
        label: t`Allocations`,
 | 
					        label: t`Allocations`,
 | 
				
			||||||
        icon: <IconBookmark />,
 | 
					        icon: <IconBookmark />,
 | 
				
			||||||
        hidden:
 | 
					        hidden: !showSalesAlloctions && !showBuildAllocations,
 | 
				
			||||||
          !stockitem?.part_detail?.salable &&
 | 
					        content: (
 | 
				
			||||||
          !stockitem?.part_detail?.component,
 | 
					          <Accordion
 | 
				
			||||||
        content: <PlaceholderPanel />
 | 
					            multiple={true}
 | 
				
			||||||
 | 
					            defaultValue={['buildallocations', 'salesallocations']}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {showBuildAllocations && (
 | 
				
			||||||
 | 
					              <Accordion.Item value="buildallocations" key="buildallocations">
 | 
				
			||||||
 | 
					                <Accordion.Control>
 | 
				
			||||||
 | 
					                  <StylishText size="lg">{t`Build Order Allocations`}</StylishText>
 | 
				
			||||||
 | 
					                </Accordion.Control>
 | 
				
			||||||
 | 
					                <Accordion.Panel>
 | 
				
			||||||
 | 
					                  <BuildAllocatedStockTable
 | 
				
			||||||
 | 
					                    stockId={stockitem.pk}
 | 
				
			||||||
 | 
					                    modelField="build"
 | 
				
			||||||
 | 
					                    modelTarget={ModelType.build}
 | 
				
			||||||
 | 
					                    showBuildInfo
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Accordion.Panel>
 | 
				
			||||||
 | 
					              </Accordion.Item>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					            {showSalesAlloctions && (
 | 
				
			||||||
 | 
					              <Accordion.Item value="salesallocations" key="salesallocations">
 | 
				
			||||||
 | 
					                <Accordion.Control>
 | 
				
			||||||
 | 
					                  <StylishText size="lg">{t`Sales Order Allocations`}</StylishText>
 | 
				
			||||||
 | 
					                </Accordion.Control>
 | 
				
			||||||
 | 
					                <Accordion.Panel>
 | 
				
			||||||
 | 
					                  <SalesOrderAllocationTable
 | 
				
			||||||
 | 
					                    stockId={stockitem.pk}
 | 
				
			||||||
 | 
					                    modelField="order"
 | 
				
			||||||
 | 
					                    modelTarget={ModelType.salesorder}
 | 
				
			||||||
 | 
					                    showOrderInfo
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                </Accordion.Panel>
 | 
				
			||||||
 | 
					              </Accordion.Item>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </Accordion>
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        name: 'testdata',
 | 
					        name: 'testdata',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,17 +164,20 @@ export function StatusColumn({
 | 
				
			|||||||
  model,
 | 
					  model,
 | 
				
			||||||
  sortable,
 | 
					  sortable,
 | 
				
			||||||
  accessor,
 | 
					  accessor,
 | 
				
			||||||
  title
 | 
					  title,
 | 
				
			||||||
 | 
					  hidden
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  model: ModelType;
 | 
					  model: ModelType;
 | 
				
			||||||
  sortable?: boolean;
 | 
					  sortable?: boolean;
 | 
				
			||||||
  accessor?: string;
 | 
					  accessor?: string;
 | 
				
			||||||
 | 
					  hidden?: boolean;
 | 
				
			||||||
  title?: string;
 | 
					  title?: string;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    accessor: accessor ?? 'status',
 | 
					    accessor: accessor ?? 'status',
 | 
				
			||||||
    sortable: sortable ?? true,
 | 
					    sortable: sortable ?? true,
 | 
				
			||||||
    title: title,
 | 
					    title: title,
 | 
				
			||||||
 | 
					    hidden: hidden,
 | 
				
			||||||
    render: TableStatusRenderer(model, accessor ?? 'status')
 | 
					    render: TableStatusRenderer(model, accessor ?? 'status')
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -251,7 +251,16 @@ export function InvenTreeTable<T = any>({
 | 
				
			|||||||
    if (props.enableColumnSwitching == false) {
 | 
					    if (props.enableColumnSwitching == false) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      return columns.some((col: TableColumn) => col.switchable ?? true);
 | 
					      return columns.some((col: TableColumn) => {
 | 
				
			||||||
 | 
					        if (col.hidden == true) {
 | 
				
			||||||
 | 
					          // Not a switchable column - is hidden
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					        } else if (col.switchable == false) {
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [columns, props.enableColumnSwitching]);
 | 
					  }, [columns, props.enableColumnSwitching]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -264,7 +273,9 @@ export function InvenTreeTable<T = any>({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Update column visibility when hiddenColumns change
 | 
					  // Update column visibility when hiddenColumns change
 | 
				
			||||||
  const dataColumns: any = useMemo(() => {
 | 
					  const dataColumns: any = useMemo(() => {
 | 
				
			||||||
    let cols = columns.map((col) => {
 | 
					    let cols = columns
 | 
				
			||||||
 | 
					      .filter((col) => col?.hidden != true)
 | 
				
			||||||
 | 
					      .map((col) => {
 | 
				
			||||||
        let hidden: boolean = col.hidden ?? false;
 | 
					        let hidden: boolean = col.hidden ?? false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (col.switchable ?? true) {
 | 
					        if (col.switchable ?? true) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,12 @@ import { useTable } from '../../hooks/UseTable';
 | 
				
			|||||||
import { apiUrl } from '../../states/ApiState';
 | 
					import { apiUrl } from '../../states/ApiState';
 | 
				
			||||||
import { useUserState } from '../../states/UserState';
 | 
					import { useUserState } from '../../states/UserState';
 | 
				
			||||||
import { TableColumn } from '../Column';
 | 
					import { TableColumn } from '../Column';
 | 
				
			||||||
import { LocationColumn, PartColumn } from '../ColumnRenderers';
 | 
					import {
 | 
				
			||||||
 | 
					  LocationColumn,
 | 
				
			||||||
 | 
					  PartColumn,
 | 
				
			||||||
 | 
					  ReferenceColumn,
 | 
				
			||||||
 | 
					  StatusColumn
 | 
				
			||||||
 | 
					} from '../ColumnRenderers';
 | 
				
			||||||
import { TableFilter } from '../Filter';
 | 
					import { TableFilter } from '../Filter';
 | 
				
			||||||
import { InvenTreeTable } from '../InvenTreeTable';
 | 
					import { InvenTreeTable } from '../InvenTreeTable';
 | 
				
			||||||
import { RowDeleteAction, RowEditAction } from '../RowActions';
 | 
					import { RowDeleteAction, RowEditAction } from '../RowActions';
 | 
				
			||||||
@@ -21,12 +26,26 @@ import { RowDeleteAction, RowEditAction } from '../RowActions';
 | 
				
			|||||||
 * Render a table of allocated stock for a build.
 | 
					 * Render a table of allocated stock for a build.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default function BuildAllocatedStockTable({
 | 
					export default function BuildAllocatedStockTable({
 | 
				
			||||||
  buildId
 | 
					  buildId,
 | 
				
			||||||
 | 
					  stockId,
 | 
				
			||||||
 | 
					  partId,
 | 
				
			||||||
 | 
					  showBuildInfo,
 | 
				
			||||||
 | 
					  showPartInfo,
 | 
				
			||||||
 | 
					  allowEdit,
 | 
				
			||||||
 | 
					  modelTarget,
 | 
				
			||||||
 | 
					  modelField
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  buildId: number;
 | 
					  buildId?: number;
 | 
				
			||||||
 | 
					  stockId?: number;
 | 
				
			||||||
 | 
					  partId?: number;
 | 
				
			||||||
 | 
					  showPartInfo?: boolean;
 | 
				
			||||||
 | 
					  showBuildInfo?: boolean;
 | 
				
			||||||
 | 
					  allowEdit?: boolean;
 | 
				
			||||||
 | 
					  modelTarget?: ModelType;
 | 
				
			||||||
 | 
					  modelField?: string;
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const user = useUserState();
 | 
					  const user = useUserState();
 | 
				
			||||||
  const table = useTable('build-allocated-stock');
 | 
					  const table = useTable('buildallocatedstock');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const tableFilters: TableFilter[] = useMemo(() => {
 | 
					  const tableFilters: TableFilter[] = useMemo(() => {
 | 
				
			||||||
    return [
 | 
					    return [
 | 
				
			||||||
@@ -40,14 +59,33 @@ export default function BuildAllocatedStockTable({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const tableColumns: TableColumn[] = useMemo(() => {
 | 
					  const tableColumns: TableColumn[] = useMemo(() => {
 | 
				
			||||||
    return [
 | 
					    return [
 | 
				
			||||||
 | 
					      ReferenceColumn({
 | 
				
			||||||
 | 
					        accessor: 'build_detail.reference',
 | 
				
			||||||
 | 
					        title: t`Build Order`,
 | 
				
			||||||
 | 
					        switchable: false,
 | 
				
			||||||
 | 
					        hidden: showBuildInfo != true
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'build_detail.title',
 | 
				
			||||||
 | 
					        title: t`Description`,
 | 
				
			||||||
 | 
					        hidden: showBuildInfo != true
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      StatusColumn({
 | 
				
			||||||
 | 
					        accessor: 'build_detail.status',
 | 
				
			||||||
 | 
					        model: ModelType.build,
 | 
				
			||||||
 | 
					        title: t`Order Status`,
 | 
				
			||||||
 | 
					        hidden: showBuildInfo != true
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        accessor: 'part',
 | 
					        accessor: 'part',
 | 
				
			||||||
 | 
					        hidden: !showPartInfo,
 | 
				
			||||||
        title: t`Part`,
 | 
					        title: t`Part`,
 | 
				
			||||||
        sortable: true,
 | 
					        sortable: true,
 | 
				
			||||||
        switchable: false,
 | 
					        switchable: false,
 | 
				
			||||||
        render: (record: any) => PartColumn(record.part_detail)
 | 
					        render: (record: any) => PartColumn(record.part_detail)
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 | 
					        hidden: !showPartInfo,
 | 
				
			||||||
        accessor: 'bom_reference',
 | 
					        accessor: 'bom_reference',
 | 
				
			||||||
        title: t`Reference`,
 | 
					        title: t`Reference`,
 | 
				
			||||||
        sortable: true,
 | 
					        sortable: true,
 | 
				
			||||||
@@ -149,18 +187,21 @@ export default function BuildAllocatedStockTable({
 | 
				
			|||||||
        props={{
 | 
					        props={{
 | 
				
			||||||
          params: {
 | 
					          params: {
 | 
				
			||||||
            build: buildId,
 | 
					            build: buildId,
 | 
				
			||||||
            part_detail: true,
 | 
					            part: partId,
 | 
				
			||||||
 | 
					            stock_item: stockId,
 | 
				
			||||||
 | 
					            build_detail: showBuildInfo ?? false,
 | 
				
			||||||
 | 
					            part_detail: showPartInfo ?? false,
 | 
				
			||||||
            location_detail: true,
 | 
					            location_detail: true,
 | 
				
			||||||
            stock_detail: true,
 | 
					            stock_detail: true,
 | 
				
			||||||
            supplier_detail: true
 | 
					            supplier_detail: true
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          enableBulkDelete: user.hasDeleteRole(UserRoles.build),
 | 
					          enableBulkDelete: allowEdit && user.hasDeleteRole(UserRoles.build),
 | 
				
			||||||
          enableDownload: true,
 | 
					          enableDownload: true,
 | 
				
			||||||
          enableSelection: true,
 | 
					          enableSelection: allowEdit && user.hasDeleteRole(UserRoles.build),
 | 
				
			||||||
          rowActions: rowActions,
 | 
					          rowActions: rowActions,
 | 
				
			||||||
          tableFilters: tableFilters,
 | 
					          tableFilters: tableFilters,
 | 
				
			||||||
          modelField: 'stock_item',
 | 
					          modelField: modelField ?? 'stock_item',
 | 
				
			||||||
          modelType: ModelType.stockitem
 | 
					          modelType: modelTarget ?? ModelType.stockitem
 | 
				
			||||||
        }}
 | 
					        }}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										135
									
								
								src/frontend/src/tables/sales/SalesOrderAllocationTable.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/frontend/src/tables/sales/SalesOrderAllocationTable.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					import { t } from '@lingui/macro';
 | 
				
			||||||
 | 
					import { useCallback, useMemo } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ApiEndpoints } from '../../enums/ApiEndpoints';
 | 
				
			||||||
 | 
					import { ModelType } from '../../enums/ModelType';
 | 
				
			||||||
 | 
					import { useTable } from '../../hooks/UseTable';
 | 
				
			||||||
 | 
					import { apiUrl } from '../../states/ApiState';
 | 
				
			||||||
 | 
					import { useUserState } from '../../states/UserState';
 | 
				
			||||||
 | 
					import { TableColumn } from '../Column';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  LocationColumn,
 | 
				
			||||||
 | 
					  PartColumn,
 | 
				
			||||||
 | 
					  ReferenceColumn,
 | 
				
			||||||
 | 
					  StatusColumn
 | 
				
			||||||
 | 
					} from '../ColumnRenderers';
 | 
				
			||||||
 | 
					import { TableFilter } from '../Filter';
 | 
				
			||||||
 | 
					import { InvenTreeTable } from '../InvenTreeTable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function SalesOrderAllocationTable({
 | 
				
			||||||
 | 
					  partId,
 | 
				
			||||||
 | 
					  stockId,
 | 
				
			||||||
 | 
					  orderId,
 | 
				
			||||||
 | 
					  showPartInfo,
 | 
				
			||||||
 | 
					  showOrderInfo,
 | 
				
			||||||
 | 
					  allowEdit,
 | 
				
			||||||
 | 
					  modelTarget,
 | 
				
			||||||
 | 
					  modelField
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  partId?: number;
 | 
				
			||||||
 | 
					  stockId?: number;
 | 
				
			||||||
 | 
					  orderId?: number;
 | 
				
			||||||
 | 
					  showPartInfo?: boolean;
 | 
				
			||||||
 | 
					  showOrderInfo?: boolean;
 | 
				
			||||||
 | 
					  allowEdit?: boolean;
 | 
				
			||||||
 | 
					  modelTarget?: ModelType;
 | 
				
			||||||
 | 
					  modelField?: string;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const user = useUserState();
 | 
				
			||||||
 | 
					  const table = useTable('salesorderallocations');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const tableFilters: TableFilter[] = useMemo(() => {
 | 
				
			||||||
 | 
					    return [];
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const tableColumns: TableColumn[] = useMemo(() => {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      ReferenceColumn({
 | 
				
			||||||
 | 
					        accessor: 'order_detail.reference',
 | 
				
			||||||
 | 
					        title: t`Sales Order`,
 | 
				
			||||||
 | 
					        switchable: false,
 | 
				
			||||||
 | 
					        hidden: showOrderInfo != true
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'order_detail.description',
 | 
				
			||||||
 | 
					        title: t`Description`,
 | 
				
			||||||
 | 
					        hidden: showOrderInfo != true
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      StatusColumn({
 | 
				
			||||||
 | 
					        accessor: 'order_detail.status',
 | 
				
			||||||
 | 
					        model: ModelType.salesorder,
 | 
				
			||||||
 | 
					        title: t`Order Status`,
 | 
				
			||||||
 | 
					        hidden: showOrderInfo != true
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'part',
 | 
				
			||||||
 | 
					        hidden: showPartInfo != true,
 | 
				
			||||||
 | 
					        title: t`Part`,
 | 
				
			||||||
 | 
					        sortable: true,
 | 
				
			||||||
 | 
					        switchable: false,
 | 
				
			||||||
 | 
					        render: (record: any) => PartColumn(record.part_detail)
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'quantity',
 | 
				
			||||||
 | 
					        title: t`Allocated Quantity`,
 | 
				
			||||||
 | 
					        sortable: true
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'serial',
 | 
				
			||||||
 | 
					        title: t`Serial Number`,
 | 
				
			||||||
 | 
					        sortable: false,
 | 
				
			||||||
 | 
					        switchable: true,
 | 
				
			||||||
 | 
					        render: (record: any) => record?.item_detail?.serial
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'batch',
 | 
				
			||||||
 | 
					        title: t`Batch Code`,
 | 
				
			||||||
 | 
					        sortable: false,
 | 
				
			||||||
 | 
					        switchable: true,
 | 
				
			||||||
 | 
					        render: (record: any) => record?.item_detail?.batch
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        accessor: 'available',
 | 
				
			||||||
 | 
					        title: t`Available Quantity`,
 | 
				
			||||||
 | 
					        render: (record: any) => record?.item_detail?.quantity
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      LocationColumn({
 | 
				
			||||||
 | 
					        accessor: 'location_detail',
 | 
				
			||||||
 | 
					        switchable: true,
 | 
				
			||||||
 | 
					        sortable: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const rowActions = useCallback(
 | 
				
			||||||
 | 
					    (record: any) => {
 | 
				
			||||||
 | 
					      return [];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    [user]
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <InvenTreeTable
 | 
				
			||||||
 | 
					        url={apiUrl(ApiEndpoints.sales_order_allocation_list)}
 | 
				
			||||||
 | 
					        tableState={table}
 | 
				
			||||||
 | 
					        columns={tableColumns}
 | 
				
			||||||
 | 
					        props={{
 | 
				
			||||||
 | 
					          params: {
 | 
				
			||||||
 | 
					            part_detail: showPartInfo ?? false,
 | 
				
			||||||
 | 
					            order_detail: showOrderInfo ?? false,
 | 
				
			||||||
 | 
					            item_detail: true,
 | 
				
			||||||
 | 
					            location_detail: true,
 | 
				
			||||||
 | 
					            part: partId,
 | 
				
			||||||
 | 
					            order: orderId,
 | 
				
			||||||
 | 
					            stock_item: stockId
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          rowActions: rowActions,
 | 
				
			||||||
 | 
					          tableFilters: tableFilters,
 | 
				
			||||||
 | 
					          modelField: modelField ?? 'order',
 | 
				
			||||||
 | 
					          modelType: modelTarget ?? ModelType.salesorder
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user