From 456f4f168f615b1d25fcc88f35efe1d7bf933302 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期四, 22 五月 2025 10:53:29 +0800
Subject: [PATCH] 库存出库生成任务 优化
---
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java | 116 +++++++++++++++++++
rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx | 8
rsf-admin/src/page/outWork/outBound/OutBoundList.jsx | 199 +++++++++++++++++++--------------
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java | 9 +
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocItem.java | 4
rsf-admin/src/i18n/zh.js | 2
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java | 4
rsf-admin/src/i18n/en.js | 2
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java | 4
9 files changed, 255 insertions(+), 93 deletions(-)
diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index b429a7a..84b91fa 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -1155,6 +1155,8 @@
error: {
stock: "Insufficient inventory to deliver 锛侊紒",
select_error_order: "Please Select Asn Orders",
+ out_stock_qty: "The outbound quantity cannot be greater than the inventory quantity",
+
}
}
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index c00e157..bde1a48 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -1152,6 +1152,8 @@
error: {
stock: "搴撳瓨涓嶈冻锛屾棤娉曟彁浜わ紒锛�",
select_error_order: "璇烽�夋嫨閫氱煡鍗�",
+ out_stock_qty: "鍑哄簱鏁伴噺涓嶈兘澶т簬搴撳瓨鏁伴噺",
+
}
}
diff --git a/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx b/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
index 45573d3..d3ea701 100644
--- a/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
+++ b/rsf-admin/src/page/outWork/outBound/OutBoundList.jsx
@@ -20,7 +20,8 @@
useCreateController,
useListContext,
useRefresh,
- Edit,
+ Edit,
+ useRedirect,
} from 'react-admin';
import {
Dialog,
@@ -59,13 +60,15 @@
import { Delete } from '@mui/icons-material';
import _, { set } from 'lodash';
import StaSelect from "./StaSelect";
+import { redirect } from "react-router";
+import { number } from "prop-types";
-const OutBoundList = () => {
+const OutBoundList = () => {
const [createDialog, setCreateDialog] = useState(false);
const [tabelData, setTableData] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
- const [sta,setSta] = useState("");
+ const [sta, setSta] = useState("");
const notify = useNotify();
const tableRef = useRef();
tableRef.current = useGridApiRef();
@@ -75,7 +78,7 @@
const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId));
setTableData(newTableData);
}
-
+
// 娣诲姞涓�涓鐞嗘柊鏁版嵁鐨勫嚱鏁帮紝璁剧疆outQty榛樿鍊�
const handleSetData = (newData) => {
// 涓烘柊娣诲姞鐨勬暟鎹缃畂utQty榛樿鍊间负anfme鐨勫��
@@ -86,109 +89,126 @@
setTableData([...tabelData, ...dataWithDefaultQty]);
};
-
-
+
+
return (
<>
- <Card sx={{ p: 2, mb: 2, mt:2}}>
- <Grid container spacing={2}>
- <Grid item xs={12}>
- <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
- <Typography variant="h6">
- {translate('table.field.outBound.stockWithdrawal')}
- </Typography>
- <Stack direction='row' spacing={2}>
- <Button
- variant="contained"
- color="primary"
- startIcon={<AddIcon />}
- onClick={() => setCreateDialog(true)}
- >
- {translate('table.field.outBound.withdrawal')}
- </Button>
- </Stack>
- </Box>
+ <Card sx={{ p: 2, mb: 2, mt: 2 }}>
+ <Grid container spacing={2}>
+ <Grid item xs={12}>
+ <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
+ <Typography variant="h6">
+ {translate('table.field.outBound.stockWithdrawal')}
+ </Typography>
+ <Stack direction='row' spacing={2}>
+ <Button
+ variant="contained"
+ color="primary"
+ startIcon={<AddIcon />}
+ onClick={() => setCreateDialog(true)}
+ >
+ {translate('table.field.outBound.withdrawal')}
+ </Button>
+ </Stack>
+ </Box>
+ </Grid>
</Grid>
- </Grid>
- </Card>
- <Card sx={{ p: 2, mb: 2}}>
- <Form>
- <Grid container spacing={2}>
- <Grid item xs={12}>
- <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
- <Typography variant="h6" >
- {translate('table.field.outBound.outSta')}
- </Typography>
- <Stack direction='row' spacing={2} minWidth={200}>
- <StaSelect
- source="sta"
- label={translate("table.field.outBound.outSta")}
- onChange={(e) => {
- setSta(e.target.value);
- console.log("绔欑偣宸查�夋嫨:", e.target.value);
- }}
- size="small"
- type="1"
- />
- </Stack>
- <Stack direction='row' spacing={2} minWidth={200}>
- <SubmitButton
- sta={sta}
- data={tabelData}
- />
- </Stack>
- </Box>
- </Grid>
- </Grid>
- </Form>
- </Card>
- <Card sx={{ mb: 2}}>
- <Box sx={{ }}>
- <ModalTable tabelData={tabelData} setTableData={setTableData} selectedRows={selectedRows} setSelectedRows={setSelectedRows} tableRef={tableRef}></ModalTable>
- </Box>
- </Card>
- <LocItemInfoModal
+ </Card>
+ <Card sx={{ p: 2, mb: 2 }}>
+ <Form>
+ <Grid container spacing={2}>
+ <Grid item xs={12}>
+ <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 1 }}>
+ <Typography variant="h6" >
+ {translate('table.field.outBound.outSta')}
+ </Typography>
+ <Stack direction='row' spacing={2} minWidth={200}>
+ <StaSelect
+ source="sta"
+ label={translate("table.field.outBound.outSta")}
+ onChange={(e) => {
+ setSta(e.target.value);
+ console.log("绔欑偣宸查�夋嫨:", e.target.value);
+ }}
+ size="small"
+ type="1"
+ />
+ </Stack>
+ <Stack direction='row' spacing={2} minWidth={200}>
+ <SubmitButton
+ sta={sta}
+ data={tabelData}
+ setTableData={setTableData}
+ />
+ </Stack>
+ </Box>
+ </Grid>
+ </Grid>
+ </Form>
+ </Card>
+ <Card sx={{ mb: 2 }}>
+ <Box sx={{}}>
+ <ModalTable tabelData={tabelData} setTableData={setTableData} selectedRows={selectedRows} setSelectedRows={setSelectedRows} tableRef={tableRef}></ModalTable>
+ </Box>
+ </Card>
+ <LocItemInfoModal
open={createDialog}
setOpen={setCreateDialog}
data={tabelData}
setData={handleSetData}
/>
-
+
</>
)
}
export default OutBoundList;
-const SubmitButton = (props) =>{
+const SubmitButton = (props) => {
const translate = useTranslate();
const notify = useNotify();
- const { sta, data } = props;
- const check = ()=>{
- if(sta === "" || sta === undefined || sta === null){
+ const redirect = useRedirect();
+ const refresh = useRefresh();
+ const { sta, data, setTableData } = props;
+ const check = () => {
+ if (sta === "" || sta === undefined || sta === null) {
notify("璇烽�夋嫨绔欑偣");
return;
}
- if(data.length === 0){
+ if (data.length === 0) {
notify("璇烽�夋嫨鐗╂枡");
return;
}
- http(sta,data);
+ http(sta, data);
+ }
+ const http = async (sta, items) => {
+ console.log(items);
- }
- const http = async (sta,data) => {
- console.log("鎻愪氦鏁版嵁",sta,data);
+ const filter = items.filter(item => (item.outQty + item.workQty) > item.anfme);
+ if (filter.length > 0) {
+ notify(translate('toolbar.request.error.out_stock_qty'))
+ return
+ }
+ const { data: { code, data, msg } } = await request.post(`/locItem/generate/task`, { siteNo: sta, items: items });
+ if (code === 200) {
+ notify(msg);
+ refresh()
+ setTableData([])
+ redirect("/task")
+ } else {
+ notify(msg);
+ }
}
return (
- <Button
- variant="contained"
- color="primary"
- onClick={check}
+ <ConfirmButton
+ variant="contained"
+ color="primary"
+ onConfirm={check}
+ label={"table.field.outBound.createTask"}
>
- {translate('table.field.outBound.createTask')}
- </Button>
+ </ConfirmButton>
)
-
+
}
const ModalTable = ({ tabelData, setTableData, selectedRows, setSelectedRows, tableRef }) => {
@@ -198,23 +218,32 @@
const [columns, setColumns] = useState([
{
field: 'outQty',
- headerName: translate('table.field.outBound.outQty')+"*",
+ headerName: translate('table.field.outBound.outQty') + "*",
width: 100,
- editable: true,
- headerClassName: "custom",
+ type: 'number',
+ editable: true,
+ headerClassName: "custom",
},
{
field: 'anfme',
headerName: translate('table.field.locItem.anfme'),
+ type: 'number',
width: 100,
editable: false,
- },
+ },
+ {
+ field: 'workQty',
+ headerName: translate('table.field.locItem.workQty'),
+ width: 100,
+ type: 'number',
+ editable: false,
+ },
{
field: 'matnrCode',
headerName: translate('table.field.locItem.matnrCode'),
width: 130,
editable: false,
- },
+ },
{
field: 'maktx',
headerName: translate('table.field.locItem.maktx'),
diff --git a/rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx b/rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx
index 69916c3..3f7d883 100644
--- a/rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx
+++ b/rsf-admin/src/page/outWork/outBound/locItemInfoModal.jsx
@@ -44,7 +44,7 @@
};
const reset = () => {
- setFormData({
+ setFormData({
})
}
@@ -129,7 +129,7 @@
onChange={handleChange}
size="small"
/>
- </Grid>
+ </Grid>
</Grid>
</Box>
<Box sx={{ mt: 2 }}>
@@ -172,9 +172,9 @@
{ field: 'maktx', headerName: translate('table.field.locItem.maktx'), width: 300 },
{ field: 'batch', headerName: translate('table.field.locItem.batch'), width: 100 },
{ field: 'anfme', headerName: translate('table.field.locItem.anfme'), width: 100 },
-
+ { field: 'workQty', headerName: translate('table.field.locItem.workQty'), width: 100 },
{ field: 'unit', headerName: translate('table.field.locItem.unit'), width: 100 },
-
+
])
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
index 703afe3..f6b67dc 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
@@ -81,8 +81,4 @@
return R.ok();
}
-
-
-
-
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java
index 65b395f..e06bb8b 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocItemController.java
@@ -78,6 +78,15 @@
}
@PreAuthorize("hasAuthority('manager:locItem:list')")
+ @PostMapping("/locItem/generate/task")
+ public R generateTask(@RequestBody Map<String, Object> map) {
+ if (Objects.isNull(map)) {
+ return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
+ }
+ return locItemService.generateTask(map);
+ }
+
+ @PreAuthorize("hasAuthority('manager:locItem:list')")
@PostMapping("/locItem/list")
public R list(@RequestBody Map<String, Object> map) {
return R.ok().add(locItemService.list());
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocItem.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocItem.java
index 754ed9c..3247606 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocItem.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocItem.java
@@ -94,6 +94,10 @@
@ApiModelProperty("椤圭洰鍙�")
private String projectCode;
+ @ApiModelProperty("鍑哄簱鏁伴噺")
+ @TableField(exist = false)
+ private Double outQty;
+
/**
* 鐗╂枡鍚嶇О
*/
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java
index ce85d82..108fd02 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocItemService.java
@@ -1,8 +1,12 @@
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.entity.LocItem;
+
+import java.util.Map;
public interface LocItemService extends IService<LocItem> {
+ R generateTask(Map<String, Object> map);
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
index 9cc069f..6bb75cf 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -1,12 +1,128 @@
package com.vincent.rsf.server.manager.service.impl;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+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.entity.Loc;
+import com.vincent.rsf.server.manager.entity.Task;
+import com.vincent.rsf.server.manager.entity.TaskItem;
+import com.vincent.rsf.server.manager.enums.*;
import com.vincent.rsf.server.manager.mapper.LocItemMapper;
import com.vincent.rsf.server.manager.entity.LocItem;
import com.vincent.rsf.server.manager.service.LocItemService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.vincent.rsf.server.manager.service.LocService;
+import com.vincent.rsf.server.manager.service.TaskItemService;
+import com.vincent.rsf.server.manager.service.TaskService;
+import com.vincent.rsf.server.system.constant.SerialRuleCode;
+import com.vincent.rsf.server.system.utils.SerialRuleUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
@Service("locItemService")
public class LocItemServiceImpl extends ServiceImpl<LocItemMapper, LocItem> implements LocItemService {
+ @Autowired
+ private LocService locService;
+ @Autowired
+ private TaskService taskService;
+ @Autowired
+ private TaskItemService taskItemService;
+ @Autowired
+ private LocItemService locItemService;
+
+
+ /**
+ * 搴撳瓨鍑哄簱鐢熸垚鍑哄簱浠诲姟
+ *
+ * @param map
+ * @return
+ */
+ @Override
+ public R generateTask(Map<String, Object> map) {
+ if (Objects.isNull(map.get("siteNo"))) {
+ throw new CoolException("绔欑偣涓嶈兘涓虹┖锛�");
+ }
+ if (Objects.isNull(map.get("items"))) {
+ throw new CoolException("鏄庣粏涓嶈兘涓虹┖锛�");
+ }
+ String siteNo = map.get("siteNo").toString();
+ List<LocItem> items = JSONArray.parseArray(JSONArray.toJSONString(map.get("items")), LocItem.class);
+ Map<Long, List<LocItem>> listMap = items.stream().collect(Collectors.groupingBy(LocItem::getLocId));
+ listMap.keySet().forEach(key -> {
+ Task task = new Task();
+ Loc loc = locService.getById(key);
+ if (Objects.isNull(loc)) {
+ throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樹俊鎭笉瀛樺湪锛侊紒");
+ }
+ String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
+ task.setOrgLoc(loc.getCode())
+ .setTaskCode(ruleCode)
+ .setTargSite(siteNo)
+ .setTaskStatus(TaskStsType.GENERATE_OUT.id)
+ .setBarcode(loc.getBarcode());
+
+ List<LocItem> locItems = this.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, key));
+ if (locItems.isEmpty()) {
+ throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樻槑缁嗕笉瀛樺湪锛侊紒");
+ }
+
+ Double orgQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
+ List<LocItem> locItemList = listMap.get(key);
+ Double outQty = locItemList.stream().mapToDouble(LocItem::getOutQty).sum();
+
+ if (orgQty.compareTo(outQty) > 0) {
+ //鎷f枡鍑哄簱
+ task.setTaskType(TaskType.TASK_TYPE_PICK_AGAIN_IN.type);
+ } else {
+ //鍏ㄦ澘鍑哄簱
+ task.setTaskType(TaskType.TASK_TYPE_OUT.type);
+ }
+ if (!taskService.save(task)) {
+ throw new CoolException("浠诲姟鍒涘缓澶辫触锛侊紒");
+ }
+ List<TaskItem> taskItems = new ArrayList<>();
+ listMap.get(key).forEach(item -> {
+ TaskItem taskItem = new TaskItem();
+ BeanUtils.copyProperties(item, taskItem);
+ taskItem.setTaskId(task.getId())
+ .setAnfme(item.getOutQty())
+ .setBatch(item.getBatch())
+ .setOrderType(OrderType.ORDER_OUT.type)
+ .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type));
+ taskItems.add(taskItem);
+
+ Double qty = Math.round((item.getWorkQty() + item.getOutQty()) * 10000) / 10000.0;
+ LocItem locItem = locItemService.getById(item.getId());
+ if (Objects.isNull(locItem)) {
+ throw new CoolException("搴撳瓨淇℃伅涓嶅瓨鍦紒");
+ }
+
+ if (locItem.getAnfme().compareTo(qty) < 0) {
+ Double minusQty = Math.round((locItem.getAnfme() - locItem.getWorkQty()) * 10000) / 10000.0;
+ item.setWorkQty(minusQty);
+ } else {
+ item.setWorkQty(qty);
+ }
+ if (! locItemService.updateById(item)) {
+ throw new CoolException("搴撳瓨淇℃伅淇敼澶辫触锛侊紒");
+ }
+ });
+
+ if (!taskItemService.saveBatch(taskItems)) {
+ throw new CoolException("浠诲姟鏄庣粏鐢熸垚澶辫触锛侊紒");
+ }
+ });
+
+ return R.ok("浠诲姟鐢熸垚瀹屾垚锛�!");
+ }
}
--
Gitblit v1.9.1