BOM pricing table fix (#7044)

* Allow click-through from BOM pricing table

* Allow sorting by price in BOM table

* Add "Total Price" column to BOM table

* Enable part table to be sorted by price range

* Enable click-through on VariantPricing table

* Update quantity columns for BOM tables

* Improve rendering for UsedInTable
This commit is contained in:
Oliver 2024-04-16 09:52:47 +10:00 committed by GitHub
parent 860ecc43e9
commit 9d2297da7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 74 additions and 18 deletions

View File

@ -1,5 +1,11 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { SegmentedControl, SimpleGrid, Stack } from '@mantine/core'; import {
Group,
SegmentedControl,
SimpleGrid,
Stack,
Text
} from '@mantine/core';
import { ReactNode, useMemo, useState } from 'react'; import { ReactNode, useMemo, useState } from 'react';
import { import {
Bar, Bar,
@ -17,6 +23,7 @@ import {
import { CHART_COLORS } from '../../../components/charts/colors'; import { CHART_COLORS } from '../../../components/charts/colors';
import { formatDecimal, formatPriceRange } from '../../../defaults/formatters'; import { formatDecimal, formatPriceRange } from '../../../defaults/formatters';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../../states/ApiState';
import { TableColumn } from '../../../tables/Column'; import { TableColumn } from '../../../tables/Column';
@ -110,7 +117,17 @@ export default function BomPricingPanel({
title: t`Quantity`, title: t`Quantity`,
sortable: true, sortable: true,
switchable: false, switchable: false,
render: (record: any) => formatDecimal(record.quantity) render: (record: any) => {
let quantity = formatDecimal(record.quantity);
let units = record.sub_part_detail?.units;
return (
<Group spacing="apart" grow>
<Text>{quantity}</Text>
{units && <Text size="xs">[{units}]</Text>}
</Group>
);
}
}, },
{ {
accessor: 'unit_price', accessor: 'unit_price',
@ -178,7 +195,9 @@ export default function BomPricingPanel({
sub_part_detail: true, sub_part_detail: true,
has_pricing: true has_pricing: true
}, },
enableSelection: false enableSelection: false,
modelType: ModelType.part,
modelField: 'sub_part'
}} }}
/> />
{bomPricingData.length > 0 ? ( {bomPricingData.length > 0 ? (

View File

@ -14,6 +14,7 @@ import {
import { CHART_COLORS } from '../../../components/charts/colors'; import { CHART_COLORS } from '../../../components/charts/colors';
import { formatCurrency } from '../../../defaults/formatters'; import { formatCurrency } from '../../../defaults/formatters';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../../states/ApiState';
import { TableColumn } from '../../../tables/Column'; import { TableColumn } from '../../../tables/Column';
@ -37,7 +38,7 @@ export default function VariantPricingPanel({
title: t`Variant Part`, title: t`Variant Part`,
sortable: true, sortable: true,
switchable: false, switchable: false,
render: (record: any) => PartColumn(record) render: (record: any) => PartColumn(record, true)
}, },
{ {
accessor: 'pricing_min', accessor: 'pricing_min',
@ -90,7 +91,8 @@ export default function VariantPricingPanel({
ancestor: part?.pk, ancestor: part?.pk,
has_pricing: true has_pricing: true
}, },
enablePagination: false enablePagination: true,
modelType: ModelType.part
}} }}
/> />
{variantPricingData.length > 0 ? ( {variantPricingData.length > 0 ? (

View File

@ -16,8 +16,13 @@ import { TableColumn } from './Column';
import { ProjectCodeHoverCard } from './TableHoverCard'; import { ProjectCodeHoverCard } from './TableHoverCard';
// Render a Part instance within a table // Render a Part instance within a table
export function PartColumn(part: any) { export function PartColumn(part: any, full_name?: boolean) {
return <Thumbnail src={part?.thumbnail ?? part.image} text={part.name} />; return (
<Thumbnail
src={part?.thumbnail ?? part.image}
text={full_name ? part.full_name : part.name}
/>
);
} }
export function BooleanColumn({ export function BooleanColumn({

View File

@ -1,5 +1,5 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Text } from '@mantine/core'; import { Group, Text } from '@mantine/core';
import { import {
IconArrowRight, IconArrowRight,
IconCircleCheck, IconCircleCheck,
@ -10,7 +10,7 @@ import { useNavigate } from 'react-router-dom';
import { YesNoButton } from '../../components/buttons/YesNoButton'; import { YesNoButton } from '../../components/buttons/YesNoButton';
import { Thumbnail } from '../../components/images/Thumbnail'; import { Thumbnail } from '../../components/images/Thumbnail';
import { formatPriceRange } from '../../defaults/formatters'; import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
@ -98,9 +98,19 @@ export function BomTable({
{ {
accessor: 'quantity', accessor: 'quantity',
switchable: false, switchable: false,
sortable: true sortable: true,
// TODO: Custom quantity renderer render: (record: any) => {
// TODO: see bom.js for existing implementation let quantity = formatDecimal(record.quantity);
let units = record.sub_part_detail?.units;
return (
<Group position="apart" grow>
<Text>{quantity}</Text>
{record.overage && <Text size="xs">+{record.overage}</Text>}
{units && <Text size="xs">{units}</Text>}
</Group>
);
}
}, },
{ {
accessor: 'substitutes', accessor: 'substitutes',
@ -131,12 +141,22 @@ export function BomTable({
}), }),
{ {
accessor: 'price_range', accessor: 'price_range',
title: t`Price Range`, title: t`Unit Price`,
ordering: 'pricing_max',
sortable: false, sortable: true,
switchable: true,
render: (record: any) => render: (record: any) =>
formatPriceRange(record.pricing_min, record.pricing_max) formatPriceRange(record.pricing_min, record.pricing_max)
}, },
{
accessor: 'total_price',
title: t`Total Price`,
ordering: 'pricing_max_total',
sortable: true,
switchable: true,
render: (record: any) =>
formatPriceRange(record.pricing_min_total, record.pricing_max_total)
},
{ {
accessor: 'available_stock', accessor: 'available_stock',
sortable: true, sortable: true,

View File

@ -1,7 +1,9 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Group, Text } from '@mantine/core';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { PartHoverCard } from '../../components/images/Thumbnail'; import { PartHoverCard } from '../../components/images/Thumbnail';
import { formatDecimal } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
@ -39,8 +41,15 @@ export function UsedInTable({
{ {
accessor: 'quantity', accessor: 'quantity',
render: (record: any) => { render: (record: any) => {
// TODO: render units if appropriate let quantity = formatDecimal(record.quantity);
return record.quantity; let units = record.sub_part_detail?.units;
return (
<Group position="apart" grow>
<Text>{quantity}</Text>
{units && <Text size="xs">{units}</Text>}
</Group>
);
} }
}, },
ReferenceColumn() ReferenceColumn()

View File

@ -158,7 +158,8 @@ function partTableColumns(): TableColumn[] {
{ {
accessor: 'price_range', accessor: 'price_range',
title: t`Price Range`, title: t`Price Range`,
sortable: false, sortable: true,
ordering: 'pricing_max',
render: (record: any) => render: (record: any) =>
formatPriceRange(record.pricing_min, record.pricing_max) formatPriceRange(record.pricing_min, record.pricing_max)
}, },