From f695b59337121fb6c93251e73bdfb3fc8e847cc8 Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期五, 25 七月 2025 17:07:09 +0800 Subject: [PATCH] 调拔单功能优化 --- rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java | 3 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java | 32 + rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java | 25 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java | 6 rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java | 3 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java | 6 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java | 31 + rsf-admin/src/page/orders/transfer/TransferCreate.jsx | 451 ++++++++++---- rsf-admin/src/page/orders/transfer/TransferList.jsx | 52 - /dev/null | 203 ------- rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java | 24 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java | 91 +++ rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java | 36 rsf-admin/src/page/orders/transfer/ManualCreate.jsx | 469 ++++++++++++++++ rsf-admin/src/i18n/zh.js | 1 rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx | 300 ++++++++++ rsf-admin/src/i18n/en.js | 1 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java | 2 18 files changed, 1,351 insertions(+), 385 deletions(-) diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js index bd7b5ab..8551425 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -1270,6 +1270,7 @@ quality: "quality", complete: "complete", allComfirm: 'All Comfirm', + createTransfer: 'Create Transfer Order', verifyComfirm: 'Verify Comfirm', close: "close", asnCreate: "Create By Order", diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index fdcbf80..4b086a3 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -1282,6 +1282,7 @@ quality: "璐ㄦ", complete: "瀹岀粨", close: "鍏抽棴", + createTransfer: '鍒涘缓璋冩嫈鍗�', asnCreate: "閫氳繃鍗曟嵁鍒涘缓", poCreate: "閫氳繃PO鍗曞垱寤�", orderPrint: '鎵撳嵃鍗曟嵁', diff --git a/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx b/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx new file mode 100644 index 0000000..ef7023d --- /dev/null +++ b/rsf-admin/src/page/orders/transfer/CreateBySelectMats.jsx @@ -0,0 +1,300 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + Edit, + SimpleForm, + FormDataConsumer, + useTranslate, + TextInput, + NumberInput, + BooleanInput, + DateInput, + SelectInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + SaveButton, + Toolbar, + Labeled, + NumberField, + useNotify, + useRefresh, + required, + useRecordContext, + DeleteButton, +} from 'react-admin'; +import { Stack, Grid, Box, Typography, Dialog, DialogTitle, DialogContent, TextField, Button, DialogActions } from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton.jsx"; +import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting'; +import StatusSelectInput from "../../components/StatusSelectInput"; +import CustomerTopToolBar from "../../components/EditTopToolBar"; +import TreeSelectInput from "@/page/components/TreeSelectInput"; +import EditBaseAside from "../../components/EditBaseAside"; +import MemoInput from "../../components/MemoInput"; +import SaveIcon from '@mui/icons-material/Save'; +import { DataGrid } from '@mui/x-data-grid'; +import * as Common from '@/utils/common'; +import request from '@/utils/request'; + + +const CreateBySelectMats = (props) => { + const { open, setOpen, data, setData } = props; + + const [page, setPage] = useState(0); + const [rowCount, setRowCount] = useState(0); + const [formData, setFormData] = useState({}); + const [tableData, setTableData] = useState([]); + const [dyFields, setDyFields] = useState([]); + const [pageSize, setPageSize] = useState(25); + const [selectedRows, setSelectedRows] = useState([]); + + const translate = useTranslate(); + const notify = useNotify(); + const refresh = useRefresh(); + + + + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData(() => ({ + [name]: value + })); + }; + + const reset = () => { + setFormData({ + name: '', + code: '', + groupId: 0 + }) + } + + const handleSubmit = () => { + const hasarr = data.map(el => +el.matnrId) + const selectedData = selectedRows.filter(item => !hasarr.includes(item)).map(id => (tableData.find(row => row.id === id))); + const value = selectedData.map((el => { + const dynamicFields = dyFields.reduce((acc, item) => { + acc[item.fields] = el['extendFields']?.[item.fields] || ''; + return acc; + }, {}); + return { + matnrId: el.id, + maktx: el.name, + matnrCode: el.code, + stockUnit: el.stockUnit || '', + purUnit: el.purchaseUnit || '', + ...dynamicFields + } + })) + setData([...data, ...value]); + setOpen(false); + reset(); + }; + + const getData = async () => { + const res = await request.post(`/matnr/page`, { + ...formData, + current: page, + pageSize: pageSize, + orderBy: "create_time desc" + }); + if (res?.data?.code === 200) { + const {data} = res.data; + setTableData(data?.records); + setRowCount(data?.total) + + console.log(rowCount); + console.log(data); + + + } else { + notify(res.data.msg); + } + }; + + useEffect(() => { + getData(); + }, [open]); + + const handleSearch = () => { + getData() + }; + + return ( + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + fullWidth + disableRestoreFocus + maxWidth="lg" + > + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }}> + {translate("common.action.newAddMats")} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Grid container spacing={2}> + <Grid item md={3}> + <TextField + label={translate('table.field.matnr.name')} + name="name" + value={formData.name} + onChange={handleChange} + size="small" + /> + </Grid> + <Grid item md={3}> + <TextField + label={translate('table.field.matnr.code')} + name="code" + value={formData.code} + onChange={handleChange} + size="small" + /> + </Grid> + <Grid item md={3}> + <TreeSelectInput + label="table.field.matnr.groupId" + value={formData.groupId} + resource={'matnrGroup'} + source="groupId" + name="groupId" + onChange={handleChange} + /> + </Grid> + <Grid item md={2} sx={{ margin: 'auto' }}> + <Button variant="contained" onClick={handleSearch}>{translate('toolbar.query')}</Button> + </Grid> + </Grid> + </Box> + + <Box sx={{ mt: 2, height: 400, width: '100%' }}> + <SelectMatsTableView + tableData={tableData} + setTableData={setTableData} + page={page} + rowCount={rowCount} + pageSize={pageSize} + setPage={setPage} + setPageSize={setPageSize} + dyFields={dyFields} + setDyFields={setDyFields} + selectedRows={selectedRows} + setSelectedRows={setSelectedRows} + /> + </Box> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Box sx={{ width: '100%', display: 'flex', justifyContent: 'flex-end' }}> + <Button onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}> + {translate('toolbar.confirm')} + </Button> + </Box> + </DialogActions> + </Dialog> + ); +} + +export default CreateBySelectMats; + + +const SelectMatsTableView = ({ tableData, page, pageSize,setPage, setPageSize, rowCount, setTableData, selectedRows, setSelectedRows, dyFields, setDyFields }) => { + const translate = useTranslate(); + + const notify = useNotify(); + const [extendColumns, setExtendColumns] = useState([]); + + const [columns, setColumns] = useState([ + { field: 'name', headerName: translate('table.field.matnr.name'), width: 300 }, + { field: 'code', headerName: translate('table.field.matnr.code'), width: 200 }, + { field: 'groupId$', headerName: translate('table.field.matnr.groupId'), width: 100 }, + { field: 'spec', headerName: translate('table.field.matnr.spec'), width: 100 }, + { field: 'model', headerName: translate('table.field.matnr.model'), width: 100 }, + { field: 'weight', headerName: translate('table.field.matnr.weight'), width: 100 }, + { field: 'describle', headerName: translate('table.field.matnr.describle'), width: 100 }, + { field: 'nromNum', headerName: translate('table.field.matnr.nromNum'), width: 100 }, + { field: 'unit', headerName: translate('table.field.matnr.unit'), width: 100 }, + { field: 'purchaseUnit', headerName: translate('table.field.matnr.purUnit'), width: 100 }, + { field: 'stockUnit', headerName: translate('table.field.matnr.stockUnit'), width: 100 }, + { field: 'stockLeval$', headerName: translate('table.field.matnr.stockLevel'), width: 100, sortable: false }, + ]) + + const handleSelectionChange = (ids) => { + setSelectedRows(ids) + }; + + useEffect(() => { + if (extendColumns == undefined || extendColumns.length < 1) { + getDynamicFields(); + } + }, []); + + const getDynamicFields = async () => { + const { + data: { code, data, msg }, + } = await request.get("/fields/enable/list"); + if (code === 200) { + const cols = data.map(el => ({ + field: el.fields, + headerName: el.fieldsAlise, + minWidth: 100, + flex: 1, + editable: el.unique, + valueGetter: (value, row) => { + return row.extendFields?.[el.fields] || ''; + }, + })) + setExtendColumns(cols); + setDyFields(data) + setColumns([...columns, ...cols]) + } else { + notify(msg); + } + } + + return ( + <div style={{ height: 400, width: '100%' }}> + <DataGrid + size="small" + rows={tableData} + page={page} + pageSize={pageSize} + columns={columns} + pagination + checkboxSelection + rowCount={rowCount} + onRowSelectionModelChange={handleSelectionChange} + onPageChange={(newPage) => setPage(newPage)} + onPageSizeChange={(newPageSize) => setPageSize(newPageSize)} + selectionModel={selectedRows} + paginationMode="server" + disableColumnMenu={true} + initialState={{ + pagination: { + paginationModel: { + pageSize: 25, + }, + }, + }} + pageSizeOptions={[15, 25, 50, 100]} + disableColumnSorting + disableMultipleColumnsSorting + /> + </div> + ); +}; diff --git a/rsf-admin/src/page/orders/transfer/ManualCreate.jsx b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx new file mode 100644 index 0000000..5251ed0 --- /dev/null +++ b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx @@ -0,0 +1,469 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { + CreateBase, + useTranslate, + TextInput, + NumberInput, + BooleanInput, + DateInput, + SaveButton, + SelectInput, + ReferenceInput, + ReferenceArrayInput, + AutocompleteInput, + Toolbar, + required, + useDataProvider, + useNotify, + Form, + useCreateController, +} from 'react-admin'; +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + TextField, + IconButton, + MenuItem, + Tooltip, + Select, + Button, + Stack, + Grid, + Box, +} from '@mui/material'; +import DialogCloseButton from "../../components/DialogCloseButton.jsx"; +import ConfirmationNumberIcon from '@mui/icons-material/ConfirmationNumber'; +import CreateBySelectMats from "./CreateBySelectMats.jsx"; +import { DataGrid, useGridApiRef } from '@mui/x-data-grid'; +import { Add, Edit, Delete } from '@mui/icons-material'; +import ConfirmButton from "../../components/ConfirmButton"; +import DictSelect from "../../components/DictSelect"; +import { minHeight, padding } from "@mui/system"; +import SaveIcon from '@mui/icons-material/Save'; +import request from '@/utils/request'; + +const ManualCreate = (props) => { + const { open, setOpen, orderId } = props; + const tableRef = useRef(); + const notify = useNotify(); + const translate = useTranslate(); + const [tabelData, setTableData] = useState([]); + const [disabled, setDisabled] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [createDialog, setCreateDialog] = useState(false); + const [formData, setFormData] = useState({}); + const handleClose = (event, reason) => { + if (reason !== "backdropClick") { + setOpen(false); + } + }; + + const handleSubmit = async () => { + setFinally() + setDisabled(true) + + if (asnId === 0) { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/outStock/items/save`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + resetData() + } else { + notify(res.data.msg); + } + } else { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/outStock/items/update`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + resetData() + } else { + notify(res.data.msg); + } + } + setDisabled(false) + + }; + + const handleSuccess = async (data) => { + setOpen(false); + notify('common.response.success'); + }; + + const handleDeleteItem = () => { + const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId)); + setTableData(newTableData); + } + + const handleError = async (error) => { + notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); + }; + + return ( + <> + <Box sx={{ padding: 1 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form defaultValues={formData}> + <Grid container spacing={2}> + <Grid item md={2}> + <DictSelect + label={translate("table.field.transfer.type")} + value={formData.wkType} + variant="filled" + group='2' + onChange={(e) => handleChange(e.target.value, 'wkType')} + dictTypeCode="sys_business_type" + required + /> + </Grid> + <Grid item md={2}> + <ReferenceInput reference="warehouseAreas" source="name"> + <AutocompleteInput optionText="name" label="table.field.transfer.orgAreaName" /> + </ReferenceInput> + </Grid> + <Grid item md={2}> + <ReferenceInput reference="warehouseAreas" source="name"> + <AutocompleteInput optionText="name" label="table.field.transfer.orgAreaName" /> + </ReferenceInput> + </Grid> + </Grid> + </Form> + </Box> + <Box sx={{ mt: 2 }}> + <Stack direction="row" spacing={2} sx={{ justifyContent: "flex-end" }}> + <Button variant="contained" onClick={() => setCreateDialog(true)} > + {translate('common.action.newAddMats')} + </Button> + <ConfirmButton label={"toolbar.delete"} variant="outlined" color="error" onConfirm={handleDeleteItem} /> + </Stack> + </Box> + <Box sx={{ mt: 2 }}> + <TransferTableView + tabelData={tabelData} + setTableData={setTableData} + asnId={orderId} + selectedRows={selectedRows} + setSelectedRows={setSelectedRows} + tableRef={tableRef}> + </TransferTableView> + </Box> + <Toolbar sx={{ width: '100%', justifyContent: 'flex-end', bgcolor: 'white' }} > + <Button disabled={disabled} onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}> + {translate('toolbar.confirm')} + </Button> + </Toolbar> + <CreateBySelectMats + open={createDialog} + setOpen={setCreateDialog} + data={tabelData} + setData={setTableData} + /> + </Box> + </> + ) +} + +const SelectInputSplrNameEditCell = (params) => { + const [formData, setFormData] = useState([{}]) + useEffect(() => { + getOptions(); + }, []); + const getOptions = async () => { + const parmas = { + "type": "supplier" + } + const { + data: { code, data, msg }, + } = await request.post("companys/page", parmas); + if (code === 200) { + setFormData(data.records) + } else { + notify(msg); + } + } + + return ( + <Select + value={params.value} + onChange={(e) => { + params.api.setEditCellValue({ + id: params.id, + field: params.field, + value: e.target.value, + }) + // 鎵惧埌閫変腑鐨勪緵搴斿晢璁板綍 + const selectedSupplier = formData.find(supplier => supplier.name === e.target.value); + + // 濡傛灉鎵惧埌瀵瑰簲鐨勪緵搴斿晢璁板綍锛屽悓鏃舵洿鏂皊plrCode瀛楁 + if (selectedSupplier) { + params.api.setEditCellValue({ + id: params.id, + field: 'splrCode', + value: selectedSupplier.id, + }); + } + }} + fullWidth + > + {formData.map(e => { + return ( + <MenuItem value={e.name} children={e.name} key={e.id} /> + ); + + })} + + </Select> + ); +}; + +const SelectInputSplrCodeEditCell = (params) => { + const [formData, setFormData] = useState([{}]) + useEffect(() => { + getOptions(); + }, []); + const getOptions = async () => { + const parmas = { + "type": "supplier" + } + const { + data: { code, data, msg }, + } = await request.post("companys/page", parmas); + if (code === 200) { + setFormData(data.records) + } else { + notify(msg); + } + } + + return ( + <Select + value={params.value} + onChange={(e) => { + params.api.setEditCellValue({ + id: params.id, + field: params.field, + value: e.target.value, + }) + const selectedSupplier = formData.find(supplier => supplier.id === e.target.value); + + // 濡傛灉鎵惧埌瀵瑰簲鐨勪緵搴斿晢璁板綍锛屽悓鏃舵洿鏂皊plrCode瀛楁 + if (selectedSupplier) { + params.api.setEditCellValue({ + id: params.id, + field: 'splrName', + value: selectedSupplier.name, + }); + } + }} + fullWidth + + > + {formData.map(e => { + return ( + <MenuItem value={e.id} children={e.name} key={e.id} /> + ); + + })} + + </Select> + ); +}; + + + +const TransferTableView = ({ tabelData, setTableData, orderId, selectedRows, setSelectedRows, tableRef }) => { + const translate = useTranslate(); + const notify = useNotify(); + const [extendColumns, setExtendColumns] = useState([]); + const [columns, setColumns] = useState([ + { + field: 'maktx', + headerName: translate('table.field.outStockItem.maktx'), + width: 250, + editable: false, + }, + { + field: 'matnrCode', + headerName: translate('table.field.outStockItem.matnrCode'), + width: 130, + editable: false, + }, + { + field: 'anfme', + headerName: translate('table.field.outStockItem.anfme') + "*", + type: 'number', + minWidth: 100, + flex: 1, + editable: true, + valueFormatter: (val) => val < 0 ? 0 : val, + headerClassName: "custom", + }, + { + field: 'splrCode', + headerName: translate('table.field.outStockItem.splrCode') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrCodeEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrName', + headerName: translate('table.field.outStockItem.splrName') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrNameEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrBatch', + headerName: translate('table.field.outStockItem.splrBatch'), + minWidth: 100, + flex: 1, + editable: true, + }, + { + field: 'poCode', + headerName: translate('table.field.outStockItem.poDetlCode'), + minWidth: 100, + flex: 1, + editable: true, + }, + { + field: 'stockUnit', + headerName: translate('table.field.outStockItem.stockUnit'), + minWidth: 100, + flex: 1, + editable: true, + }, + ]) + + const action = { + field: 'action', + headerName: '鎿嶄綔', + width: 70, + lockPosition: 'left', + renderCell: (params) => ( + <Tooltip title="Delete"> + <IconButton onClick={() => handleDelete(params.row)}> + <Delete /> + </IconButton> + </Tooltip> + ), + } + + let cdata = useRef([]); + + useEffect(() => { + if (extendColumns == undefined || extendColumns.length < 1) { + getDynamicFields(); + } + }, []); + + useEffect(() => { + cdata.current = tabelData + }, [tabelData]); + + + const getDynamicFields = async () => { + const { + data: { code, data, msg }, + } = await request.get("/fields/enable/list"); + if (code === 200) { + const cols = data.map(el => ({ + field: el.fields, + headerName: el.fieldsAlise, + minWidth: 100, + flex: 1, + editable: false + })) + setColumns([...columns, ...cols, action]) + setExtendColumns(cols); + } else { + notify(msg); + } + } + + + const handleDelete = (row) => { + const newData = _.filter(cdata.current, (item) => item.matnrId !== row.matnrId); + setTableData(newData); + }; + + + const processRowUpdate = (newRow, oldRow) => { + const rows = tabelData.map((r) => + r.matnrId === newRow.matnrId ? { ...newRow } : r + ) + setTableData(rows) + return newRow; + }; + + const handleSelectionChange = (ids) => { + setSelectedRows(ids) + }; + + tableRef.current = useGridApiRef(); + + return ( + <Box> + <DataGrid + apiRef={tableRef} + rows={tabelData} + columns={columns} + disableRowSelectionOnClick + getRowId={(row) => row.matnrId ? row.matnrId : row.id} + disableColumnFilter + disableColumnSelector + disableColumnSorting + disableMultipleColumnsSorting + processRowUpdate={processRowUpdate} + initialState={{ + pagination: { + paginationModel: { + pageSize: 25, + }, + }, + }} + pageSizeOptions={[15, 25, 50, 100]} + editMode="row" + checkboxSelection + onRowSelectionModelChange={handleSelectionChange} + selectionModel={selectedRows} + sx={{ + height: 610, + '& .MuiDataGrid-cell input': { + border: '1px solid #ccc' + }, + }} + /> + {/* <Box sx={{ + padding: 2, + position: 'absolute', + right: 1 + }}> + <Button variant="contained" onClick={() => handleSubmit()} startIcon={<SaveIcon/>} > + {translate('toolbar.confirm')} + </Button> + </Box> */} + </Box> + ); +}; + + +export default ManualCreate; diff --git a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx index 19a4edf..a6a754e 100644 --- a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx +++ b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx @@ -23,19 +23,30 @@ DialogActions, DialogContent, DialogTitle, + TextField, + Button, Stack, Grid, Box, } from '@mui/material'; import DialogCloseButton from "../../components/DialogCloseButton.jsx"; -import StatusSelectInput from "../../components/StatusSelectInput.jsx"; -import MemoInput from "../../components/MemoInput.jsx"; +import CreateBySelectMats from "./CreateBySelectMats.jsx"; +import { DataGrid, useGridApiRef } from '@mui/x-data-grid'; +import ConfirmButton from "../../components/ConfirmButton"; +import DictSelect from "../../components/DictSelect"; +import SaveIcon from '@mui/icons-material/Save'; +import request from '@/utils/request'; const TransferCreate = (props) => { - const { open, setOpen } = props; - - const translate = useTranslate(); + const { open, setOpen, orderId } = props; + const tableRef = useRef(); const notify = useNotify(); + const translate = useTranslate(); + const [tabelData, setTableData] = useState([]); + const [disabled, setDisabled] = useState(false) + const [selectedRows, setSelectedRows] = useState([]); + const [createDialog, setCreateDialog] = useState(false); + const [formData, setFormData] = useState({}); const handleClose = (event, reason) => { if (reason !== "backdropClick") { @@ -43,10 +54,50 @@ } }; + const handleSubmit = async () => { + setFinally() + setDisabled(true) + + if (asnId === 0) { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/outStock/items/save`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + resetData() + } else { + notify(res.data.msg); + } + } else { + const parmas = { + "orders": formData, + "items": tabelData, + } + const res = await request.post(`/outStock/items/update`, parmas); + if (res?.data?.code === 200) { + setOpen(false); + refresh(); + resetData() + } else { + notify(res.data.msg); + } + } + setDisabled(false) + + }; + const handleSuccess = async (data) => { setOpen(false); notify('common.response.success'); }; + + const handleDeleteItem = () => { + const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId)); + setTableData(newTableData); + } const handleError = async (error) => { notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } }); @@ -54,146 +105,280 @@ return ( <> - <CreateBase - record={{}} - transform={(data) => { - return data; - }} - mutationOptions={{ onSuccess: handleSuccess, onError: handleError }} + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="form-dialog-title" + aria-hidden + fullWidth + disableRestoreFocus + maxWidth="xl" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' > - <Dialog - open={open} - onClose={handleClose} - aria-labelledby="form-dialog-title" - fullWidth - disableRestoreFocus - maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' - > - <Form> - <DialogTitle id="form-dialog-title" sx={{ - position: 'sticky', - top: 0, - backgroundColor: 'background.paper', - zIndex: 1000 - }} - > - {translate('create.title')} - <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> - <DialogCloseButton onClose={handleClose} /> - </Box> - </DialogTitle> - <DialogContent sx={{ mt: 2 }}> - <Grid container rowSpacing={2} columnSpacing={2}> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.transfer.code" - source="code" - parse={v => v} - autoFocus + <DialogTitle id="form-dialog-title" sx={{ + position: 'sticky', + top: 0, + backgroundColor: 'background.paper', + zIndex: 1000 + }}> + {translate('create.title')} + <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> + <DialogCloseButton onClose={handleClose} /> + </Box> + </DialogTitle> + <DialogContent sx={{ mt: 2 }}> + <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}> + <Form defaultValues={formData}> + <Grid container spacing={2}> + <Grid item md={2}> + <DictSelect + label={translate("table.field.outStock.wkType")} + value={formData.wkType} + variant="filled" + group='2' + onChange={(e) => handleChange(e.target.value, 'wkType')} + dictTypeCode="sys_business_type" + required /> </Grid> - <Grid item xs={6} display="flex" gap={1}> - <NumberInput - label="table.field.transfer.type" - source="type" + <Grid item md={2}> + <TextField + label={translate("table.field.outStock.poCode")} + value={formData.poCode} + variant="filled" + size='small' + onChange={(e) => handleChange(e.target.value, 'poCode')} /> </Grid> - <Grid item xs={6} display="flex" gap={1}> - <SelectInput - label="table.field.transfer.source" - source="source" - choices={[ - { id: 1, name: 'ERP绯荤粺' }, - { id: 2, name: 'WMS绯荤粺鐢熸垚' }, - { id: 3, name: 'EXCEL瀵煎叆 ' }, - { id: 4, name: 'QMS绯荤粺' }, - ]} + <Grid item md={2}> + <TextField + label={translate("table.field.outStock.logisNo")} + value={formData.logisNo} + variant="filled" + size='small' + onChange={(e) => handleChange(e.target.value, 'logisNo')} /> </Grid> - <Grid item xs={6} display="flex" gap={1}> - <SelectInput - label="table.field.transfer.exceStatus" - source="exceStatus" - choices={[ - { id: 0, name: '鏈墽琛�' }, - { id: 1, name: '鎵ц涓�' }, - { id: 2, name: '鎵ц瀹屾垚' }, - ]} + <Grid item md={2}> + <DateInput + source="arrTime" + label="table.field.outStock.arrTime" + size='small' + variant="filled" + value={formData.arrTime} + onChange={(e) => handleChange(e.target.value, 'arrTime')} /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <NumberInput - label="table.field.transfer.orgWareId" - source="orgWareId" - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.transfer.orgWareName" - source="orgWareName" - parse={v => v} - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <NumberInput - label="table.field.transfer.tarWareId" - source="tarWareId" - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.transfer.tarWareName" - source="tarWareName" - parse={v => v} - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <NumberInput - label="table.field.transfer.orgAreaId" - source="orgAreaId" - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.transfer.orgAreaName" - source="orgAreaName" - parse={v => v} - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <NumberInput - label="table.field.transfer.tarAreaId" - source="tarAreaId" - /> - </Grid> - <Grid item xs={6} display="flex" gap={1}> - <TextInput - label="table.field.transfer.tarAreaName" - source="tarAreaName" - parse={v => v} - /> - </Grid> - - <Grid item xs={6} display="flex" gap={1}> - <StatusSelectInput /> - </Grid> - <Grid item xs={12} display="flex" gap={1}> - <Stack direction="column" spacing={1} width={'100%'}> - <MemoInput /> - </Stack> </Grid> </Grid> - </DialogContent> - <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> - <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }} > - <SaveButton /> - </Toolbar> - </DialogActions> - </Form> - </Dialog> - </CreateBase> + </Form> + </Box> + + <Box sx={{ mt: 2 }}> + <Stack direction="row" spacing={2}> + <Button variant="contained" onClick={() => setCreateDialog(true)} > + {translate('common.action.newAddMats')} + </Button> + <ConfirmButton label={"toolbar.delete"} variant="outlined" color="error" onConfirm={handleDeleteItem} /> + </Stack> + </Box> + <Box sx={{ mt: 2 }}> + <TransferTableView + tabelData={tabelData} + setTableData={setTableData} + asnId={orderId} + selectedRows={selectedRows} + setSelectedRows={setSelectedRows} + tableRef={tableRef}> + </TransferTableView> + </Box> + </DialogContent> + <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}> + <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }} > + <Button disabled={disabled} onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}> + {translate('toolbar.confirm')} + </Button> + </Toolbar> + </DialogActions> + </Dialog> + <CreateBySelectMats + open={createDialog} + setOpen={setCreateDialog} + data={tabelData} + setData={setTableData} + /> </> ) } +const TransferTableView = ({ tabelData, setTableData, orderId, selectedRows, setSelectedRows, tableRef }) => { + const translate = useTranslate(); + const notify = useNotify(); + + const [columns, setColumns] = useState([ + { + field: 'maktx', + headerName: translate('table.field.outStockItem.maktx'), + width: 250, + editable: false, + }, + { + field: 'matnrCode', + headerName: translate('table.field.outStockItem.matnrCode'), + width: 130, + editable: false, + }, + { + field: 'anfme', + headerName: translate('table.field.outStockItem.anfme') + "*", + type: 'number', + minWidth: 100, + flex: 1, + editable: true, + valueFormatter: (val) => val < 0 ? 0 : val, + headerClassName: "custom", + }, + { + field: 'splrCode', + headerName: translate('table.field.outStockItem.splrCode') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrCodeEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrName', + headerName: translate('table.field.outStockItem.splrName') + "*", + minWidth: 100, + flex: 1, + editable: true, + renderEditCell: (params) => ( + <SelectInputSplrNameEditCell {...params} /> + ), + headerClassName: "custom", + }, + { + field: 'splrBatch', + headerName: translate('table.field.outStockItem.splrBatch'), + minWidth: 100, + flex: 1, + editable: true, + }, + { + field: 'poCode', + headerName: translate('table.field.outStockItem.poDetlCode'), + minWidth: 100, + flex: 1, + editable: true, + }, + { + field: 'stockUnit', + headerName: translate('table.field.outStockItem.stockUnit'), + minWidth: 100, + flex: 1, + editable: true, + }, + ]) + + const action = { + field: 'action', + headerName: '鎿嶄綔', + width: 70, + lockPosition: 'left', + renderCell: (params) => ( + <Tooltip title="Delete"> + <IconButton onClick={() => handleDelete(params.row)}> + <Delete /> + </IconButton> + </Tooltip> + ), + + } + + let cdata = useRef([]); + + useEffect(() => { + getDynamicFields(); + }, []); + + useEffect(() => { + cdata.current = tabelData + }, [tabelData]); + + + const getDynamicFields = async () => { + const { + data: { code, data, msg }, + } = await request.get("/fields/enable/list"); + if (code === 200) { + const cols = data.map(el => ({ + field: el.fields, + headerName: el.fieldsAlise, + minWidth: 100, + flex: 1, + editable: false + })) + setColumns([...columns, ...cols, action]) + } else { + notify(msg); + } + } + + + const handleDelete = (row) => { + const newData = _.filter(cdata.current, (item) => item.matnrId !== row.matnrId); + setTableData(newData); + }; + + + const processRowUpdate = (newRow, oldRow) => { + const rows = tabelData.map((r) => + r.matnrId === newRow.matnrId ? { ...newRow } : r + ) + setTableData(rows) + return newRow; + }; + + const handleSelectionChange = (ids) => { + setSelectedRows(ids) + }; + + tableRef.current = useGridApiRef(); + + return ( + <div style={{ height: 400, width: '100%' }}> + <DataGrid + apiRef={tableRef} + rows={tabelData} + columns={columns} + disableRowSelectionOnClick + getRowId={(row) => row.matnrId ? row.matnrId : row.id} + disableColumnFilter + disableColumnSelector + disableColumnSorting + disableMultipleColumnsSorting + processRowUpdate={processRowUpdate} + initialState={{ + pagination: { + paginationModel: { + pageSize: 25, + }, + }, + }} + pageSizeOptions={[15, 25, 50, 100]} + editMode="row" + checkboxSelection + onRowSelectionModelChange={handleSelectionChange} + selectionModel={selectedRows} + sx={{ + '& .MuiDataGrid-cell input': { + border: '1px solid #ccc' + }, + }} + /> + </div> + ); +}; + export default TransferCreate; diff --git a/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx b/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx deleted file mode 100644 index 3bde7c2..0000000 --- a/rsf-admin/src/page/orders/transfer/TransferItemEdit.jsx +++ /dev/null @@ -1,203 +0,0 @@ -import React, { useState, useRef, useEffect, useMemo } from "react"; -import { - Edit, - SimpleForm, - FormDataConsumer, - useTranslate, - TextInput, - NumberInput, - BooleanInput, - DateInput, - SelectInput, - ReferenceInput, - ReferenceArrayInput, - AutocompleteInput, - SaveButton, - Toolbar, - Labeled, - NumberField, - required, - useRecordContext, - DeleteButton, -} from 'react-admin'; -import { useWatch, useFormContext } from "react-hook-form"; -import { Stack, Grid, Box, Typography } from '@mui/material'; -import * as Common from '@/utils/common'; -import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting'; -import EditBaseAside from "../../components/EditBaseAside"; -import CustomerTopToolBar from "../../components/EditTopToolBar"; -import MemoInput from "../../components/MemoInput"; -import StatusSelectInput from "../../components/StatusSelectInput"; - -const FormToolbar = () => { - const { getValues } = useFormContext(); - - return ( - <Toolbar sx={{ justifyContent: 'space-between' }}> - <SaveButton /> - <DeleteButton mutationMode="optimistic" /> - </Toolbar> - ) -} - -const TransferItemEdit = () => { - const translate = useTranslate(); - - return ( - <Edit - redirect="list" - mutationMode={EDIT_MODE} - actions={<CustomerTopToolBar />} - aside={<EditBaseAside />} - > - <SimpleForm - shouldUnregister - warnWhenUnsavedChanges - toolbar={<FormToolbar />} - mode="onTouched" - defaultValues={{}} - // validate={(values) => { }} - > - <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}> - <Grid item xs={12} md={8}> - <Typography variant="h6" gutterBottom> - {translate('common.edit.title.main')} - </Typography> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.transferId" - source="transferId" - autoFocus - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.transferCode" - source="transferCode" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.matnrId" - source="matnrId" - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.maktx" - source="maktx" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.matnrCode" - source="matnrCode" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.unit" - source="unit" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.anfme" - source="anfme" - /> - </Stack> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.qty" - source="qty" - /> - </Stack> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.workQty" - source="workQty" - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.batch" - source="batch" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <NumberInput - label="table.field.transferItem.splrId" - source="splrId" - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.spec" - source="spec" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.model" - source="model" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.fieldsIndex" - source="fieldsIndex" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.platItemId" - source="platItemId" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.platOrderCode" - source="platOrderCode" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.platWorkCode" - source="platWorkCode" - parse={v => v} - /> - </Stack> - <Stack direction='row' gap={2}> - <TextInput - label="table.field.transferItem.projectCode" - source="projectCode" - parse={v => v} - /> - </Stack> - - </Grid> - <Grid item xs={12} md={4}> - <Typography variant="h6" gutterBottom> - {translate('common.edit.title.common')} - </Typography> - <StatusSelectInput /> - <Box mt="2em" /> - <MemoInput /> - </Grid> - </Grid> - </SimpleForm> - </Edit > - ) -} - -export default TransferItemEdit; diff --git a/rsf-admin/src/page/orders/transfer/TransferList.jsx b/rsf-admin/src/page/orders/transfer/TransferList.jsx index 790702b..3e6b4fa 100644 --- a/rsf-admin/src/page/orders/transfer/TransferList.jsx +++ b/rsf-admin/src/page/orders/transfer/TransferList.jsx @@ -33,16 +33,19 @@ DeleteButton, } from 'react-admin'; import { Box, Typography, Card, Stack } from '@mui/material'; -import { styled } from '@mui/material/styles'; -import TransferCreate from "./TransferCreate.jsx"; -import TransferPanel from "./TransferPanel.jsx"; -import EmptyData from "../../components/EmptyData.jsx"; +import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting.js'; + import MyCreateButton from "../../components/MyCreateButton.jsx"; import MyExportButton from '../../components/MyExportButton.jsx'; +import PageEditDrawer from "../../components/PageEditDrawer"; import PageDrawer from "../../components/PageDrawer.jsx"; +import EmptyData from "../../components/EmptyData.jsx"; import MyField from "../../components/MyField.jsx"; -import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting.js'; +import TransferCreate from "./TransferCreate.jsx"; +import { styled } from '@mui/material/styles'; +import TransferPanel from "./TransferPanel.jsx"; import * as Common from '@/utils/common.js'; +import ManualCreate from "./ManualCreate.jsx"; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -62,22 +65,21 @@ <SearchInput source="condition" alwaysOn />, <DateInput label='common.time.after' source="timeStart" alwaysOn />, <DateInput label='common.time.before' source="timeEnd" alwaysOn />, - <TextInput source="code" label="table.field.transfer.code" />, <NumberInput source="type" label="table.field.transfer.type" />, <SelectInput source="source" label="table.field.transfer.source" choices={[ { id: 1, name: 'ERP绯荤粺' }, - { id: 2, name: 'WMS绯荤粺鐢熸垚' }, - { id: 3, name: 'EXCEL瀵煎叆 ' }, - { id: 4, name: 'QMS绯荤粺' }, + { id: 2, name: 'WMS绯荤粺鐢熸垚' }, + { id: 3, name: 'EXCEL瀵煎叆 ' }, + { id: 4, name: 'QMS绯荤粺' }, ]} />, <SelectInput source="exceStatus" label="table.field.transfer.exceStatus" choices={[ { id: 0, name: '鏈墽琛�' }, - { id: 1, name: '鎵ц涓�' }, - { id: 2, name: '鎵ц瀹屾垚' }, + { id: 1, name: '鎵ц涓�' }, + { id: 2, name: '鎵ц瀹屾垚' }, ]} />, <NumberInput source="orgWareId" label="table.field.transfer.orgWareId" />, @@ -88,7 +90,6 @@ <TextInput source="orgAreaName" label="table.field.transfer.orgAreaName" />, <NumberInput source="tarAreaId" label="table.field.transfer.tarAreaId" />, <TextInput source="tarAreaName" label="table.field.transfer.tarAreaName" />, - <TextInput label="common.field.memo" source="memo" />, <SelectInput label="common.field.status" @@ -103,7 +104,6 @@ const TransferList = () => { const translate = useTranslate(); - const [createDialog, setCreateDialog] = useState(false); const [drawerVal, setDrawerVal] = useState(false); @@ -138,7 +138,7 @@ rowClick={(id, resource, record) => false} expand={() => <TransferPanel />} expandSingle={true} - omit={['id', 'createTime', 'createBy', 'memo']} + omit={['id', 'createTime', 'createBy$', 'memo']} > <NumberField source="id" /> <TextField source="code" label="table.field.transfer.code" /> @@ -153,14 +153,9 @@ <TextField source="orgAreaName" label="table.field.transfer.orgAreaName" /> <NumberField source="tarAreaId" label="table.field.transfer.tarAreaId" /> <TextField source="tarAreaName" label="table.field.transfer.tarAreaName" /> - - <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}> - <TextField source="nickname" /> - </ReferenceField> + <TextField source="updateBy$" label="common.field.updateBy" /> <DateField source="updateTime" label="common.field.updateTime" showTime /> - <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}> - <TextField source="nickname" /> - </ReferenceField> + <TextField source="createBy$" label="common.field.createBy" /> <DateField source="createTime" label="common.field.createTime" showTime /> <BooleanField source="statusBool" label="common.field.status" sortable={false} /> <TextField source="memo" label="common.field.memo" sortable={false} /> @@ -170,16 +165,13 @@ </WrapperField> </StyledDatagrid> </List> - <TransferCreate - open={createDialog} - setOpen={setCreateDialog} - /> - <PageDrawer - title='Transfer Detail' - drawerVal={drawerVal} - setDrawerVal={setDrawerVal} + <PageEditDrawer + title={"toolbar.createTransfer"} + drawerVal={createDialog} + setDrawerVal={setCreateDialog} > - </PageDrawer> + <ManualCreate /> + </PageEditDrawer> </Box> ) } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java index cf5f8c2..9767a12 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TransferController.java @@ -9,10 +9,14 @@ import com.vincent.rsf.server.common.domain.BaseParam; import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; +import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams; +import com.vincent.rsf.server.manager.controller.params.TransferItemParams; import com.vincent.rsf.server.manager.entity.Transfer; import com.vincent.rsf.server.manager.entity.excel.CheckOrderTemplate; import com.vincent.rsf.server.manager.service.TransferService; +import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.controller.BaseController; +import com.vincent.rsf.server.system.utils.SerialRuleUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -63,6 +67,12 @@ transfer.setCreateTime(new Date()); transfer.setUpdateBy(getLoginUserId()); transfer.setUpdateTime(new Date()); + + if (Objects.isNull(transfer.getCode())) { + String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TRANSFER_ORDER_CODE, transfer); + transfer.setCode(ruleCode); + } + if (!transferService.save(transfer)) { return R.error("Save Fail"); } @@ -105,6 +115,28 @@ return R.ok().add(vos); } + @PostMapping("/transfer/items/save") + @ApiOperation("淇濆瓨涓诲崟鍙婃槑缁�") + @PreAuthorize("hasAuthority('manager:transfer:save')") + public R saveOutStock(@RequestBody TransferItemParams params) throws Exception { + if (Objects.isNull(params)) { + return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒"); + } + return transferService.saveTransfer(params, getLoginUserId()); + } + + @ApiOperation("鍗曟嵁淇℃伅淇敼") + @PostMapping("/transfer/items/update") + @PreAuthorize("hasAuthority('manager:outStock:update')") + public R orderAndrItemUpdate(@RequestBody TransferItemParams params) throws Exception { + if (Objects.isNull(params)) { + return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒"); + } + return transferService.updateTransfer(params, getLoginUserId()); + } + + + /** * @author Ryan * @description 涓嬭浇妯℃澘 diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java new file mode 100644 index 0000000..0a06795 --- /dev/null +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/TransferItemParams.java @@ -0,0 +1,24 @@ +package com.vincent.rsf.server.manager.controller.params; + +import com.vincent.rsf.server.manager.entity.Transfer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@Accessors(chain = true) +@ApiModel(value = "TransferItemParams", description = "璋冩嫈鍗曞弬鏁�") +public class TransferItemParams implements Serializable { + + @ApiModelProperty("璋冩嫈鍗�") + private Transfer transfer; + + @ApiModelProperty("璋冩嫈鍗曟槑缁�") + private List<Map<String, Object>> items; + +} diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java index 154ab5b..1d64745 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Transfer.java @@ -3,6 +3,13 @@ import com.baomidou.mybatisplus.annotation.TableLogic; import java.text.SimpleDateFormat; import java.util.Date; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.vincent.rsf.server.manager.enums.OrderType; +import com.vincent.rsf.server.system.constant.DictTypeCode; +import com.vincent.rsf.server.system.entity.DictData; +import com.vincent.rsf.server.system.service.DictDataService; +import lombok.experimental.Accessors; import org.springframework.format.annotation.DateTimeFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -20,8 +27,10 @@ import com.vincent.rsf.server.system.entity.User; import java.io.Serializable; import java.util.Date; +import java.util.Objects; @Data +@Accessors(chain = true) @TableName("man_transfer") public class Transfer implements Serializable { @@ -56,7 +65,7 @@ * 鎵ц鐘舵��: 0: 鏈墽琛� 1: 鎵ц涓� 2: 鎵ц瀹屾垚 */ @ApiModelProperty(value= "鎵ц鐘舵��: 0: 鏈墽琛� 1: 鎵ц涓� 2: 鎵ц瀹屾垚 ") - private Integer exceStatus; + private Short exceStatus; /** * 婧愪粨搴揑D @@ -159,7 +168,7 @@ public Transfer() {} - public Transfer(String code,Integer type,Integer source,Integer exceStatus,Long orgWareId,String orgWareName,Long tarWareId,String tarWareName,Long orgAreaId,String orgAreaName,Long tarAreaId,String tarAreaName,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) { + public Transfer(String code,Integer type,Integer source,Short exceStatus,Long orgWareId,String orgWareName,Long tarWareId,String tarWareName,Long orgAreaId,String orgAreaName,Long tarAreaId,String tarAreaName,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) { this.code = code; this.type = type; this.source = source; @@ -221,20 +230,21 @@ } } - public String getExceStatus$(){ - if (null == this.exceStatus){ return null; } - switch (this.exceStatus){ - case 0: - return "鏈墽琛�"; - case 1: - return "鎵ц涓�"; - case 2: - return "鎵ц瀹屾垚"; - default: - return String.valueOf(this.exceStatus); + public String getExceStatus$() { + if (Cools.isEmpty(this.exceStatus)){ + return ""; } + DictDataService dictDataService = SpringUtils.getBean(DictDataService.class); + DictData dictData = dictDataService.getOne(new LambdaQueryWrapper<DictData>() + .eq(DictData::getDictTypeCode, DictTypeCode.SYS_ORDER_SOURCE) + .eq(DictData::getValue, this.exceStatus)); + if (Objects.isNull(dictData)) { + return null; + } + return dictData.getLabel(); } + public String getStatus$(){ if (null == this.status){ return null; } switch (this.status){ diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java index 6fb3726..f9381c9 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderSourceType.java @@ -16,10 +16,37 @@ ; OrderSourceType(String val, String desc) { - this.val = Short.parseShort(val); + this.val = Integer.parseInt(val); this.desc = desc; } - public Short val; + public Integer val; public String desc; + + + public static Integer getSourceVal(String desc) { + if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_ERP.desc)) { + return OrderSourceType.ORDER_SOURCE_TYPE_ERP.val; + } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.desc)) { + return OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val; + } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.desc)) { + return OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.val; + } else if (desc.equals(OrderSourceType.ORDER_SOURCE_TYPE_QMS.desc)) { + return OrderSourceType.ORDER_SOURCE_TYPE_QMS.val; + } + return null; + } + + public static String getSourceDesc(Integer val) { + if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_ERP.val)) { + return OrderSourceType.ORDER_SOURCE_TYPE_ERP.desc; + } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val)) { + return OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.desc; + } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.val)) { + return OrderSourceType.ORDER_SOURCE_TYPE_EXCEL.desc; + } else if (val.equals(OrderSourceType.ORDER_SOURCE_TYPE_QMS.val)) { + return OrderSourceType.ORDER_SOURCE_TYPE_QMS.desc; + } + return null; + } } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java index 583ebdf..15a0a35 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderType.java @@ -12,7 +12,7 @@ ORDER_OUT("out", "鍑哄簱鍗�"), ORDER_IN("in", "鍏ュ簱鍗�"), ORDER_CHECK("check", "鐩樼偣鍗�"); - ; + OrderType(String type, String desc) { this.type = type; diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java new file mode 100644 index 0000000..c23e0f3 --- /dev/null +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TransferType.java @@ -0,0 +1,25 @@ +package com.vincent.rsf.server.manager.enums; + +/** + * @author Ryan + * @date 2025/7/25 + * @description: 璋冩嫈绫诲瀷 + * @version 1.0 + */ +public enum TransferType { + + //璋冩嫈绫诲瀷 + TRANSFER_TYPE_WAREHOUSE("1" ,"璺ㄤ粨璋冩嫈"), + TRANSFER_TYPE_AREAS("2", "璺ㄥ尯璋冩嫈"), + TRANSFER_TYPE_LOCAL("0", "鏈湴璋冩嫈"); + + private Integer val; + + private String desc; + + TransferType(String val, String desc) { + this.val = Integer.parseInt(val); + this.desc = desc; + } + +} diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java index 47d4f27..640cd5f 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TransferService.java @@ -1,8 +1,14 @@ package com.vincent.rsf.server.manager.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.vincent.rsf.framework.common.R; +import com.vincent.rsf.server.manager.controller.params.TransferItemParams; import com.vincent.rsf.server.manager.entity.Transfer; public interface TransferService extends IService<Transfer> { + R saveTransfer(TransferItemParams params, Long loginUserId); + + R updateTransfer(TransferItemParams params, Long loginUserId); } + diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java index d0eb7ca..bcf2413 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrServiceImpl.java @@ -115,15 +115,15 @@ if (null != group){ pageParam.getWhere().getMap().remove("groupId"); if(!group.getCode().equals("01")){ - List<MatnrGroup> matnrGroups = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>().eq(MatnrGroup::getParentId, Long.parseLong(groupId.toString())).select(MatnrGroup::getId)); + List<MatnrGroup> matnrGroups = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>() + .eq(MatnrGroup::getParentId, Long.parseLong(groupId.toString())) + .select(MatnrGroup::getId)); if (!matnrGroups.isEmpty()) { longs = matnrGroups.stream().map(MatnrGroup::getId).collect(Collectors.toList()); } longs.add(group.getId()); } - - } } QueryWrapper<Matnr> queryWrapper = pageParam.buildWrapper(true); diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java index b4b3026..fa85fe3 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TransferServiceImpl.java @@ -1,12 +1,103 @@ package com.vincent.rsf.server.manager.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.vincent.rsf.framework.common.R; +import com.vincent.rsf.framework.exception.CoolException; +import com.vincent.rsf.server.manager.controller.params.TransferItemParams; +import com.vincent.rsf.server.manager.entity.WkOrder; +import com.vincent.rsf.server.manager.entity.WkOrderItem; +import com.vincent.rsf.server.manager.enums.AsnExceStatus; +import com.vincent.rsf.server.manager.enums.CheckExceStatus; +import com.vincent.rsf.server.manager.enums.OrderSourceType; +import com.vincent.rsf.server.manager.enums.OrderType; import com.vincent.rsf.server.manager.mapper.TransferMapper; import com.vincent.rsf.server.manager.entity.Transfer; import com.vincent.rsf.server.manager.service.TransferService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.vincent.rsf.server.system.constant.SerialRuleCode; +import com.vincent.rsf.server.system.utils.SerialRuleUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; @Service("transferService") public class TransferServiceImpl extends ServiceImpl<TransferMapper, Transfer> implements TransferService { + /** + * @author Ryan + * @date 2025/7/25 + * @description: 淇濆瓨璋冩嫈鍗曞強鏄庣粏 + * @version 1.0 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R saveTransfer(TransferItemParams params, Long loginUserId) { + if (Objects.isNull(params.getTransfer())) { + throw new CoolException("涓诲崟淇℃伅涓嶈兘涓虹┖"); + } + Transfer transfer = params.getTransfer(); + if (StringUtils.isBlank(transfer.getType() + "")) { + throw new CoolException("涓氬姟绫诲瀷涓嶈兘涓虹┖锛侊紒"); + } + + String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TRANSFER_ORDER_CODE, transfer); + if (StringUtils.isBlank(ruleCode)) { + throw new CoolException("缂栫爜瑙勫垯閿欒锛氳妫�鏌ャ�孲YS_TRANSFER_ORDER_CODE銆嶆槸鍚﹁缃纭紒锛�"); + } + transfer.setCode(ruleCode) + .setExceStatus(CheckExceStatus.CHECK_ORDER_STATUS_UN_EXCE.val) + .setSource(OrderSourceType.ORDER_SOURCE_TYPE_SYSTEM.val) + .setUpdateBy(loginUserId) + .setCreateBy(loginUserId); + if (!this.save(transfer)) { + throw new CoolException("涓诲崟淇濆瓨澶辫触锛侊紒"); + } + if (params.getItems().isEmpty()) { + throw new CoolException("鏀惰揣閫氱煡鍗曟槑缁嗕笉鑳戒负绌猴紒锛�"); + } + params.setTransfer(transfer); + try { + svaeOrUpdateOrderItem(params, loginUserId); + } catch (Exception e) { + throw new CoolException(e.getMessage()); + } + return R.ok(); + } + + + private void svaeOrUpdateOrderItem(TransferItemParams params, Long loginUserId) { +// Transfer orders = params.getTransfer(); +// params.getItems().forEach(item -> { +// item.put("orderId", orders.getId()); +// item.put("orderCode", orders.getCode()); +// item.put("poCode", orders.getPoCode()); +// item.put("createBy", loginUserId); +// item.put("updateBy", loginUserId); +// if (!asnOrderItemService.fieldsSave(item, loginUserId)) { +// throw new CoolException("鏄庣粏淇濆瓨澶辫触锛侊紒"); +// } +// }); +// List<WkOrderItem> orderItems = checkOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>() +// .eq(WkOrderItem::getOrderId, params.getOrders().getId())); +// Double sum = orderItems.stream().mapToDouble(WkOrderItem::getAnfme).sum(); +// orders.setAnfme(sum); +// if (!this.updateById(orders)) { +// throw new CoolException("璁″垝鏀惰揣鏁伴噺淇敼澶辫触锛侊紒"); +// } + } + + + /** + * @author Ryan + * @date 2025/7/25 + * @description: 璋冩嫈鍗曞強鏄庣粏淇敼 + * @version 1.0 + */ + @Override + public R updateTransfer(TransferItemParams params, Long loginUserId) { + return null; + } } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java index 40e8b46..43d2e0e 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/DictTypeCode.java @@ -91,4 +91,7 @@ public final static String SYS_CHECK_DIFF_REASON = "sys_check_diff_reason"; /**鐩樼偣绫诲瀷*/ public final static String SYS_CHECK_TYPE = "sys_check_type"; + + /**鍗曟嵁鏉ユ簮*/ + public final static String SYS_ORDER_SOURCE = "sys_order_source"; } diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java index c0e28de..6361b89 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java @@ -88,5 +88,8 @@ /**鐩樼偣鍗曞彿*/ public final static String SYS_CHECK_RULE_CODE = "sys_check_rule_code"; + /**璋冩嫈鍗曠紪鐮佽鍒�*/ + public final static String SYS_TRANSFER_ORDER_CODE = "sys_transfer_order_code"; + } -- Gitblit v1.9.1