FPSMS-frontend
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

PickTable.tsx 8.9 KiB

pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
pirms 2 mēnešiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import { JoDetail, JoDetailPickLine } from "@/app/api/jo";
  2. import { decimalFormatter } from "@/app/utils/formatUtil";
  3. import { GridColDef, GridRenderCellParams, GridValidRowModel } from "@mui/x-data-grid";
  4. import { isEmpty, pick, upperFirst } from "lodash";
  5. import { useCallback, useMemo } from "react";
  6. import { useFormContext } from "react-hook-form";
  7. import { useTranslation } from "react-i18next";
  8. import StyledDataGrid from "../StyledDataGrid/StyledDataGrid";
  9. import { Box, Grid, Icon, IconButton, Stack, Typography } from "@mui/material";
  10. import PendingOutlinedIcon from '@mui/icons-material/PendingOutlined';
  11. import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined';
  12. import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined';
  13. import { fetchInventories } from "@/app/api/inventory/actions";
  14. import { InventoryResult } from "@/app/api/inventory";
  15. import { useEffect, useState } from "react";
  16. import DoDisturbAltRoundedIcon from '@mui/icons-material/DoDisturbAltRounded';
  17. type JoDetailPickLineWithCalculations = JoDetailPickLine & {
  18. stockAvailable: number;
  19. isStockSufficient: boolean;
  20. };
  21. type Props = {
  22. };
  23. const PickTable: React.FC<Props> = ({
  24. }) => {
  25. const { t } = useTranslation("jo")
  26. const {
  27. watch
  28. } = useFormContext<JoDetail>()
  29. const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]);
  30. const pickLines = watch("pickLines");
  31. useEffect(() => {
  32. const fetchInventoryData = async () => {
  33. try {
  34. const inventoryResponse = await fetchInventories({
  35. code: "",
  36. name: "",
  37. type: "",
  38. pageNum: 0,
  39. pageSize: 1000
  40. });
  41. setInventoryData(inventoryResponse.records);
  42. } catch (error) {
  43. console.error("Error fetching inventory data:", error);
  44. }
  45. };
  46. fetchInventoryData();
  47. }, [pickLines]);
  48. const getStockAvailable = (pickLine: JoDetailPickLine) => {
  49. const inventory = inventoryData.find(inventory =>
  50. inventory.itemCode === pickLine.code || inventory.itemName === pickLine.name
  51. );
  52. if (inventory) {
  53. return inventory.availableQty || (inventory.onHandQty - inventory.onHoldQty - inventory.unavailableQty);
  54. }
  55. return 0;
  56. };
  57. const isStockSufficient = (pickLine: JoDetailPickLine) => {
  58. const stockAvailable = getStockAvailable(pickLine);
  59. return stockAvailable >= pickLine.reqQty;
  60. };
  61. const sufficientStockIcon = useMemo(() => {
  62. return <CheckCircleOutlineOutlinedIcon fontSize={"large"} color="success" />
  63. }, []);
  64. const insufficientStockIcon = useMemo(() => {
  65. return <DoDisturbAltRoundedIcon fontSize={"large"} color="error" />
  66. }, []);
  67. const rowsWithCalculatedFields = useMemo(() => {
  68. return pickLines.map((pickLine, index) => ({
  69. ...pickLine,
  70. id: pickLine.id || index,
  71. sequence: index + 1,
  72. stockAvailable: getStockAvailable(pickLine),
  73. isStockSufficient: isStockSufficient(pickLine),
  74. }));
  75. }, [pickLines, inventoryData]);
  76. const notPickedStatusColumn = useMemo(() => {
  77. return (<HelpOutlineOutlinedIcon fontSize={"large"} color={"error"} />)
  78. }, [])
  79. const scanStatusColumn = useCallback((status: boolean) => {
  80. return status ?
  81. <CheckCircleOutlineOutlinedIcon fontSize={"large"} sx={{ ml: "5px" }} color="success" />
  82. : <PendingOutlinedIcon fontSize={"large"} sx={{ ml: "5px" }} color="warning" />
  83. }, [])
  84. const columns = useMemo<GridColDef[]>(() => [
  85. {
  86. field: "sequence",
  87. headerName: t("Sequence"),
  88. flex: 0.2,
  89. align: "left",
  90. headerAlign: "left",
  91. type: "number",
  92. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  93. return params.value;
  94. },
  95. },
  96. {
  97. field: "code",
  98. headerName: t("Item Code"),
  99. flex: 0.6,
  100. },
  101. {
  102. field: "name",
  103. headerName: t("Item Name"),
  104. flex: 1,
  105. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  106. return `${params.value} (${params.row.uom})`;
  107. },
  108. },
  109. /*{
  110. field: "scanStatus",
  111. headerName: t("Scan Status"),
  112. flex: 0.4,
  113. align: "right",
  114. headerAlign: "right",
  115. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  116. if (params.row.pickedLotNo === null || params.row.pickedLotNo === undefined) {
  117. return notPickedStatusColumn
  118. }
  119. const scanStatus = params.row.pickedLotNo.map((pln) => params.row.status === "completed" ? true : Boolean(pln.isScanned))
  120. return isEmpty(scanStatus) ? notPickedStatusColumn : <Stack key={`${params.id}-scan`} direction={"column"}>{scanStatus.map((status) => scanStatusColumn(status))}</Stack>
  121. },
  122. },
  123. {
  124. field: "lotNo",
  125. headerName: t("Lot No."),
  126. flex: 1,
  127. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  128. if (params.row.pickedLotNo === null || params.row.pickedLotNo === undefined) {
  129. return t("Pending for pick")
  130. }
  131. const lotNos = params.row.pickedLotNo.map((pln) => pln.lotNo)
  132. return isEmpty(lotNos) ? t("Pending for pick") : lotNos.map((lotNo) => (<>{lotNo}<br /></>))
  133. },
  134. },
  135. {
  136. field: "pickedQty",
  137. headerName: t("Picked Qty"),
  138. flex: 0.7,
  139. align: "right",
  140. headerAlign: "right",
  141. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  142. if (params.row.pickedLotNo === null || params.row.pickedLotNo === undefined) {
  143. return t("Pending for pick")
  144. }
  145. const qtys = params.row.pickedLotNo.map((pln) => pln.qty)
  146. return isEmpty(qtys) ? t("Pending for pick") : qtys.map((qty) => <>{qty}<br /></>)
  147. },
  148. },*/
  149. {
  150. field: "reqQty",
  151. headerName: t("Req. Qty"),
  152. flex: 0.7,
  153. align: "right",
  154. headerAlign: "right",
  155. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  156. return `${decimalFormatter.format(params.value)} (${params.row.shortUom})`;
  157. },
  158. },
  159. {
  160. field: "stockAvailable",
  161. headerName: t("Stock Available"),
  162. flex: 0.7,
  163. align: "right",
  164. headerAlign: "right",
  165. type: "number",
  166. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  167. return `${decimalFormatter.format(params.value)} (${params.row.shortUom})`;
  168. },
  169. },
  170. {
  171. field: "stockStatus",
  172. headerName: t("Stock Status"),
  173. flex: 0.5,
  174. align: "right",
  175. headerAlign: "right",
  176. type: "boolean",
  177. renderCell: (params: GridRenderCellParams<JoDetailPickLineWithCalculations>) => {
  178. return params.row.isStockSufficient ? sufficientStockIcon : insufficientStockIcon;
  179. },
  180. }
  181. /*{
  182. field: "status",
  183. headerName: t("Status"),
  184. flex: 1,
  185. align: "right",
  186. headerAlign: "right",
  187. renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
  188. const status = Boolean(params.row.pickedLotNo?.every((lotNo) => Boolean(lotNo.isScanned))) || params.row.status === "completed"
  189. return (
  190. <>
  191. {params.row.pickedLotNo?.every((lotNo) => Boolean(lotNo.isScanned)) ? t("Scanned") : t(upperFirst(params.value))}
  192. {scanStatusColumn(status)}
  193. </>
  194. )
  195. },
  196. },*/
  197. ], [t, inventoryData])
  198. return (
  199. <>
  200. <StyledDataGrid
  201. sx={{
  202. "--DataGrid-overlayHeight": "100px",
  203. ".MuiDataGrid-row .MuiDataGrid-cell.hasError": {
  204. border: "1px solid",
  205. borderColor: "error.main",
  206. },
  207. ".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": {
  208. border: "1px solid",
  209. borderColor: "warning.main",
  210. },
  211. }}
  212. disableColumnMenu
  213. rows={rowsWithCalculatedFields}
  214. columns={columns}
  215. getRowHeight={() => 'auto'}
  216. />
  217. </>
  218. )
  219. }
  220. export default PickTable;