FPSMS-frontend
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 

231 righe
8.4 KiB

  1. "use client";
  2. import {
  3. Box,
  4. Button,
  5. CircularProgress,
  6. Paper,
  7. Stack,
  8. Table,
  9. TableBody,
  10. TableCell,
  11. TableContainer,
  12. TableHead,
  13. TableRow,
  14. TextField,
  15. Typography,
  16. TablePagination,
  17. } from "@mui/material";
  18. import { useCallback, useMemo } from "react";
  19. import { useTranslation } from "react-i18next";
  20. interface CombinedLotTableProps {
  21. combinedLotData: any[];
  22. combinedDataLoading: boolean;
  23. pickQtyData: Record<string, number>;
  24. paginationController: {
  25. pageNum: number;
  26. pageSize: number;
  27. };
  28. onPickQtyChange: (lotKey: string, value: number | string) => void;
  29. onSubmitPickQty: (lot: any) => void;
  30. onRejectLot: (lot: any) => void;
  31. onPageChange: (event: unknown, newPage: number) => void;
  32. onPageSizeChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  33. }
  34. // Simple helper function to check if item is completed
  35. const isItemCompleted = (lot: any) => {
  36. const actualPickQty = Number(lot.actualPickQty) || 0;
  37. const requiredQty = Number(lot.requiredQty) || 0;
  38. return lot.stockOutLineStatus === 'completed' ||
  39. (actualPickQty > 0 && requiredQty > 0 && actualPickQty >= requiredQty);
  40. };
  41. const isItemRejected = (lot: any) => {
  42. return lot.stockOutLineStatus === 'rejected';
  43. };
  44. const CombinedLotTable: React.FC<CombinedLotTableProps> = ({
  45. combinedLotData,
  46. combinedDataLoading,
  47. pickQtyData,
  48. paginationController,
  49. onPickQtyChange,
  50. onSubmitPickQty,
  51. onRejectLot,
  52. onPageChange,
  53. onPageSizeChange,
  54. }) => {
  55. const { t } = useTranslation("pickOrder");
  56. // Paginated data
  57. const paginatedLotData = useMemo(() => {
  58. const startIndex = paginationController.pageNum * paginationController.pageSize;
  59. const endIndex = startIndex + paginationController.pageSize;
  60. return combinedLotData.slice(startIndex, endIndex);
  61. }, [combinedLotData, paginationController]);
  62. if (combinedDataLoading) {
  63. return (
  64. <Box display="flex" justifyContent="center" alignItems="center" minHeight="200px">
  65. <CircularProgress size={40} />
  66. </Box>
  67. );
  68. }
  69. return (
  70. <>
  71. <TableContainer component={Paper}>
  72. <Table>
  73. <TableHead>
  74. <TableRow>
  75. <TableCell>{t("Pick Order Code")}</TableCell>
  76. <TableCell>{t("Item Code")}</TableCell>
  77. <TableCell>{t("Item Name")}</TableCell>
  78. <TableCell>{t("Lot No")}</TableCell>
  79. {/* <TableCell>{t("Expiry Date")}</TableCell> */}
  80. <TableCell>{t("Location")}</TableCell>
  81. <TableCell align="right">{t("Current Stock")}</TableCell>
  82. <TableCell align="right">{t("Lot Required Pick Qty")}</TableCell>
  83. <TableCell align="right">{t("Qty Already Picked")}</TableCell>
  84. <TableCell align="right">{t("Lot Actual Pick Qty")}</TableCell>
  85. <TableCell>{t("Stock Unit")}</TableCell>
  86. <TableCell align="center">{t("Submit")}</TableCell>
  87. <TableCell align="center">{t("Reject")}</TableCell>
  88. </TableRow>
  89. </TableHead>
  90. <TableBody>
  91. {paginatedLotData.length === 0 ? (
  92. <TableRow>
  93. <TableCell colSpan={13} align="center">
  94. <Typography variant="body2" color="text.secondary">
  95. {t("No data available")}
  96. </Typography>
  97. </TableCell>
  98. </TableRow>
  99. ) : (
  100. paginatedLotData.map((lot: any) => {
  101. const lotKey = `${lot.pickOrderLineId}-${lot.lotId}`;
  102. const currentPickQty = pickQtyData[lotKey] ?? '';
  103. const isCompleted = isItemCompleted(lot);
  104. const isRejected = isItemRejected(lot);
  105. // Green text color for completed items
  106. const textColor = isCompleted ? 'success.main' : isRejected ? 'error.main' : 'inherit';
  107. return (
  108. <TableRow
  109. key={lotKey}
  110. sx={{
  111. '&:hover': {
  112. backgroundColor: 'action.hover',
  113. },
  114. }}
  115. >
  116. <TableCell sx={{ color: textColor }}>{lot.pickOrderCode}</TableCell>
  117. <TableCell sx={{ color: textColor }}>{lot.itemCode}</TableCell>
  118. <TableCell sx={{ color: textColor }}>{lot.itemName}</TableCell>
  119. <TableCell sx={{ color: textColor }}>{lot.lotNo}</TableCell>
  120. {/* <TableCell sx={{ color: textColor }}>
  121. {lot.expiryDate ? dayjs(lot.expiryDate).format(OUTPUT_DATE_FORMAT) : 'N/A'}
  122. </TableCell>
  123. */}
  124. <TableCell sx={{ color: textColor }}>{lot.location}</TableCell>
  125. <TableCell align="right" sx={{ color: textColor }}>{lot.availableQty}</TableCell>
  126. <TableCell align="right" sx={{ color: textColor }}>{lot.requiredQty}</TableCell>
  127. <TableCell align="right" sx={{ color: textColor }}>{lot.actualPickQty || 0}</TableCell>
  128. <TableCell align="right">
  129. <TextField
  130. type="number"
  131. value={currentPickQty}
  132. onChange={(e) => {
  133. onPickQtyChange(lotKey, e.target.value);
  134. }}
  135. onFocus={(e) => {
  136. e.target.select();
  137. }}
  138. inputProps={{
  139. min: 0,
  140. max: lot.availableQty,
  141. step: 0.01
  142. }}
  143. disabled={
  144. isCompleted ||
  145. isRejected ||
  146. lot.lotAvailability === 'expired' ||
  147. lot.lotAvailability === 'status_unavailable'
  148. }
  149. sx={{
  150. width: '80px',
  151. '& .MuiInputBase-input': {
  152. textAlign: 'right',
  153. }
  154. }}
  155. />
  156. </TableCell>
  157. <TableCell sx={{ color: textColor }}>{lot.stockUnit}</TableCell>
  158. <TableCell align="center">
  159. <Button
  160. variant="contained"
  161. size="small"
  162. disabled={isCompleted || isRejected || !currentPickQty || currentPickQty <= 0}
  163. onClick={() => onSubmitPickQty(lot)}
  164. sx={{
  165. backgroundColor: isCompleted ? 'success.main' : 'primary.main',
  166. color: 'white',
  167. '&:disabled': {
  168. backgroundColor: 'grey.300',
  169. color: 'grey.500',
  170. },
  171. }}
  172. >
  173. {isCompleted ? t("Completed") : t("Submit")}
  174. </Button>
  175. </TableCell>
  176. <TableCell align="center">
  177. <Button
  178. variant="outlined"
  179. size="small"
  180. color="error"
  181. disabled={isCompleted || isRejected}
  182. onClick={() => onRejectLot(lot)}
  183. sx={{
  184. '&:disabled': {
  185. borderColor: 'grey.300',
  186. color: 'grey.500',
  187. },
  188. }}
  189. >
  190. {t("Reject")}
  191. </Button>
  192. </TableCell>
  193. </TableRow>
  194. );
  195. })
  196. )}
  197. </TableBody>
  198. </Table>
  199. </TableContainer>
  200. <TablePagination
  201. component="div"
  202. count={combinedLotData.length}
  203. page={paginationController.pageNum}
  204. rowsPerPage={paginationController.pageSize}
  205. onPageChange={onPageChange}
  206. onRowsPerPageChange={onPageSizeChange}
  207. rowsPerPageOptions={[10, 25, 50]}
  208. labelRowsPerPage={t("Rows per page")}
  209. labelDisplayedRows={({ from, to, count }) =>
  210. `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}`
  211. }
  212. />
  213. </>
  214. );
  215. };
  216. export default CombinedLotTable;