2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 19:45:46 +00:00
Files
InvenTree/src/frontend/src/pages/part/PartStocktakeDetail.tsx
Oliver f132970ff3 [PUI] Stocktake (#7704)
* Adjust playwright test

* Add StocktakeReport table in the "admin" section

* Allow deletion of individual stocktake reports

* Add placeholder buttons

* Adds placeholder panel for stocktake data

* Implement <PartStocktakeTable />

* Add modal to generate a new report

* Generate stocktake report from part table

* Adjust table value

* panel display tweaks

* Improve query efficiency for supplier price breaks

* Refator part stocktake detail panel

* Fix role checks

* Cleanup code

* Fix "double loader" in <InvenTreeTable />

* API efficiency improvements

* Bump API version

* Tweak playwright test

* Update playwright test

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
2024-09-21 18:29:59 +10:00

201 lines
5.2 KiB
TypeScript

import { t } from '@lingui/macro';
import { LineChart } from '@mantine/charts';
import { Center, Loader, SimpleGrid } from '@mantine/core';
import { useCallback, useMemo, useState } from 'react';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import {
generateStocktakeReportFields,
partStocktakeFields
} from '../../forms/PartForms';
import {
useCreateApiFormModal,
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState';
import { TableColumn } from '../../tables/Column';
import { InvenTreeTable } from '../../tables/InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../../tables/RowActions';
export default function PartStocktakeDetail({ partId }: { partId: number }) {
const user = useUserState();
const table = useTable('part-stocktake');
const stocktakeFields = useMemo(() => partStocktakeFields(), []);
const [selectedStocktake, setSelectedStocktake] = useState<
number | undefined
>(undefined);
const editStocktakeEntry = useEditApiFormModal({
pk: selectedStocktake,
url: ApiEndpoints.part_stocktake_list,
title: t`Edit Stocktake Entry`,
fields: stocktakeFields,
table: table
});
const deleteStocktakeEntry = useDeleteApiFormModal({
pk: selectedStocktake,
url: ApiEndpoints.part_stocktake_list,
title: t`Delete Stocktake Entry`,
table: table
});
const generateReport = useCreateApiFormModal({
url: ApiEndpoints.part_stocktake_report_generate,
title: t`Generate Stocktake Report`,
fields: generateStocktakeReportFields(),
initialData: {
part: partId
},
successMessage: t`Stocktake report scheduled`
});
const tableColumns: TableColumn[] = useMemo(() => {
return [
{
accessor: 'quantity',
sortable: true,
switchable: false
},
{
accessor: 'item_count',
title: t`Stock Items`,
switchable: true,
sortable: true
},
{
accessor: 'cost',
title: t`Stock Value`,
render: (record: any) => {
return formatPriceRange(record.cost_min, record.cost_max, {
currency: record.cost_min_currency
});
}
},
{
accessor: 'date',
sortable: true
},
{
accessor: 'note'
}
];
}, []);
const tableActions = useMemo(() => {
return [
<AddItemButton
tooltip={t`New Stocktake Report`}
onClick={() => generateReport.open()}
hidden={!user.hasAddRole(UserRoles.stocktake)}
/>
];
}, [user]);
const rowActions = useCallback(
(record: any) => {
return [
RowEditAction({
hidden: !user.hasChangeRole(UserRoles.stocktake),
onClick: () => {
setSelectedStocktake(record.pk);
editStocktakeEntry.open();
}
}),
RowDeleteAction({
hidden: !user.hasDeleteRole(UserRoles.stocktake),
onClick: () => {
setSelectedStocktake(record.pk);
deleteStocktakeEntry.open();
}
})
];
},
[user]
);
const chartData = useMemo(() => {
let records =
table.records?.map((record: any) => {
return {
date: record.date,
quantity: record.quantity,
value_min: record.cost_min,
value_max: record.cost_max
};
}) ?? [];
// Sort records to ensure correct date order
records.sort((a, b) => {
return new Date(a.date) < new Date(b.date) ? -1 : 1;
});
return records;
}, [table.records]);
return (
<>
{generateReport.modal}
{editStocktakeEntry.modal}
{deleteStocktakeEntry.modal}
<SimpleGrid cols={2}>
<InvenTreeTable
url={apiUrl(ApiEndpoints.part_stocktake_list)}
tableState={table}
columns={tableColumns}
props={{
params: {
part: partId
},
rowActions: rowActions,
tableActions: tableActions
}}
/>
{table.isLoading ? (
<Center>
<Loader />
</Center>
) : (
<LineChart
data={chartData}
dataKey="date"
withLegend
withYAxis
withRightYAxis
yAxisLabel={t`Quantity`}
rightYAxisLabel={t`Stock Value`}
series={[
{
name: 'quantity',
label: t`Quantity`,
color: 'blue.6',
yAxisId: 'left'
},
{
name: 'value_min',
label: t`Min Value`,
color: 'teal.6',
yAxisId: 'right'
},
{
name: 'value_max',
label: t`Max Value`,
color: 'red.6',
yAxisId: 'right'
}
]}
/>
)}
</SimpleGrid>
</>
);
}