rsf-admin/.env
@@ -1,3 +1,3 @@ VITE_BASE_IP=192.168.4.50 VITE_BASE_IP=192.168.4.16 # VITE_BASE_IP=47.76.147.249 VITE_BASE_PORT=8080 rsf-admin/src/i18n/en.js
@@ -1171,6 +1171,7 @@ poCreate: "Create By PO", createTask: "createTask", publicWorking: 'Public Working', continuePub: 'Continue Public', recover: "recover", createWave: "Create Wave", order: 'Orders', rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx
@@ -158,7 +158,7 @@ </ReferenceField>, <DateField source="createTime" label="common.field.createTime" showTime /> <TextField source="memo" label="common.field.memo" sortable={false} /> </StyledDatagrid>Ï </StyledDatagrid> </List> <OutOrderItemCreate open={createDialog} rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -115,6 +115,7 @@ const OutOrderList = (props) => { const translate = useTranslate(); const refresh = useRefresh(); const notify = useNotify(); const [createDialog, setCreateDialog] = useState(false); const [manualDialog, setManualDialog] = useState(false); rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx
@@ -135,7 +135,6 @@ if (res?.data?.code === 200) { setOpen(false); refresh(); billReload?.current() resetData() } else { notify(res.data.msg); @@ -149,7 +148,6 @@ if (res?.data?.code === 200) { setOpen(false); refresh(); billReload?.current() resetData() } else { notify(res.data.msg); rsf-admin/src/page/orders/wave/WaveItemList.jsx
@@ -33,6 +33,7 @@ DeleteButton, useGetRecordId, Button, useRefresh, } from 'react-admin'; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline'; @@ -151,6 +152,7 @@ <TextField source="memo" label="common.field.memo" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt"> <BulkPauseButton /> <ContinueButton /> </WrapperField> </StyledDatagrid> </List> @@ -191,6 +193,7 @@ const { data, selectedIds, onUnselectItems } = useListContext(); const waveId = useGetRecordId(); const notify = useNotify(); const refresh = useRefresh() const startClick = async () => { onUnselectItems(); const { data: { code, data, msg } } = await request.post('/wave/selects/task', { wave: waveId, waveItem: selectedIds }); @@ -200,6 +203,7 @@ } else { notify(msg); } refresh() } return ( <Button label="toolbar.publicWorking" onClick={startClick} startIcon={<PlayArrowOutlinedIcon />} variant="outlined" /> @@ -208,11 +212,34 @@ const BulkPauseButton = () => { const { data, selectedIds, onUnselectItems } = useListContext(); const notify = useNotify() const record = useRecordContext(); const pauseClick = () => { onUnselectItems(); const pauseClick = async () => { const { data: { code, data, msg } } = await request.post('/waveItem/pause/pub', { wave: waveId, waveItem: selectedIds }); if (code === 200) { notify(msg); } else { notify(msg); } } return ( record?.exceStatus == 2 ? <Button label="toolbar.pause" onClick={pauseClick} startIcon={<PauseCircleOutlineIcon />} /> : <></> record?.exceStatus == 1 ? <Button label="toolbar.pause" onClick={pauseClick} startIcon={<PauseCircleOutlineIcon />} /> : <></> ) } const ContinueButton = () => { const { data, selectedIds, onUnselectItems } = useListContext(); const notify = useNotify() const record = useRecordContext(); const continueClick = async () => { const { data: { code, data, msg } } = await request.post('/waveItem/continue/pub', { wave: waveId, waveItem: selectedIds }); if (code === 200) { notify(msg); } else { notify(msg); } } return ( record?.exceStatus == 4 ? <Button label="toolbar.continuePub" onClick={continueClick} startIcon={<PauseCircleOutlineIcon />} /> : <></> ) } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/mcp/McpController.java
@@ -84,13 +84,13 @@ } param.setType(Constants.TASK_TYPE_OUT_STOCK); try { locItemService.generateTask(TaskResouceType.TASK_RESOUCE_STOCK_TYPE.val, param, getLoginUserId()); } catch (Exception e) { throw new RuntimeException(e); } // try { // locItemService.generateTask(TaskResouceType.TASK_RESOUCE_STOCK_TYPE.val, param, getLoginUserId()); // } catch (Exception e) { // throw new RuntimeException(e); // } return R.ok("任务生成成功"); return R.ok(param); } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaOutStockController.java
New file @@ -0,0 +1,54 @@ package com.vincent.rsf.server.api.controller.pda; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.server.api.entity.dto.ContainerWaveDto; import com.vincent.rsf.server.api.service.PdaOutStockService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; @Api(tags = "PDA出库操作接口") @RequestMapping("/pda") @RestController public class PdaOutStockController { @Autowired private PdaOutStockService pdaOutStockService; @PreAuthorize("hasAuthority('manager:task:list')") @GetMapping("/outStockTaskItem/{barcode}") @ApiOperation("快速拣货查询") public R getOutStockTaskItem(@PathVariable String barcode) { return pdaOutStockService.getOutStockTaskItem(barcode); } @PreAuthorize("hasAuthority('manager:task:list')") @PostMapping("/getWaveList") @ApiOperation("查询波次列表") public R getWaveListItem(@RequestBody Map<String, String> map) { return pdaOutStockService.getWaveListItem(map.get("barcode")); } @PreAuthorize("hasAuthority('manager:task:list')") @PostMapping("/getContainerWaveList") @ApiOperation("根据容器码查询波次及出库单") public R getContainerWaveList(@RequestBody Map<String, String> map) { return pdaOutStockService.getContainerWaveList(map); } @PreAuthorize("hasAuthority('manager:task:list')") @PostMapping("/saveWavePick") @ApiOperation("根据容器码查询波次及出库单") public R saveWavePick(@RequestBody List<ContainerWaveDto> containerWaveDtos) { return pdaOutStockService.saveWavePick(containerWaveDtos); } } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/pdaOutStockController.java
File was deleted rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/ContainerWaveDto.java
New file @@ -0,0 +1,19 @@ package com.vincent.rsf.server.api.entity.dto; import com.vincent.rsf.server.manager.entity.AsnOrderItem; import com.vincent.rsf.server.manager.entity.TaskItem; import io.swagger.annotations.ApiModel; import lombok.Data; import lombok.experimental.Accessors; import java.util.List; @Data @Accessors(chain = true) @ApiModel(value = "ContainerWaveDto", description = "PDA波次拣货") public class ContainerWaveDto { private TaskItem taskItem; private List<AsnOrderItem> asnOrderItems; } rsf-server/src/main/java/com/vincent/rsf/server/api/service/PdaOutStockService.java
@@ -1,9 +1,17 @@ package com.vincent.rsf.server.api.service; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.server.api.entity.dto.ContainerWaveDto; import java.util.List; import java.util.Map; public interface PdaOutStockService { R getOutStockTaskItem(String barcode); R getWaveListItem(String barcode); R getContainerWaveList(Map<String, String> map); R saveWavePick(List<ContainerWaveDto> containerWaveDtos); } rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -1,19 +1,21 @@ package com.vincent.rsf.server.api.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.api.entity.dto.ContainerWaveDto; import com.vincent.rsf.server.api.service.PdaOutStockService; import com.vincent.rsf.server.manager.entity.AsnOrder; import com.vincent.rsf.server.manager.entity.Task; import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.service.AsnOrderService; import com.vincent.rsf.server.manager.service.OutStockService; import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.TaskService; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.enums.TaskStsType; import com.vincent.rsf.server.manager.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -25,6 +27,12 @@ private TaskService taskService; @Resource private TaskItemService taskItemService; @Autowired private WaveService waveService; @Autowired private AsnOrderService asnOrderService; @Autowired private AsnOrderItemService asnOrderItemService; @Override public R getOutStockTaskItem(String barcode) { @@ -42,4 +50,95 @@ return R.ok(taskItems); } @Override public R getWaveListItem(String barcode) { LambdaQueryWrapper<Wave> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(!Cools.isEmpty(barcode),Wave::getCode,barcode); List<Wave> waveList = waveService.list(lambdaQueryWrapper); return R.ok(waveList); } @Override public R getContainerWaveList(Map<String, String> map) { String barcode = map.get("barcode"); if (Cools.isEmpty(barcode) ){ throw new CoolException("参数有误"); } Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, barcode)); if (null == task){ throw new CoolException("未找到容器号对应任务"); } if (task.getTaskStatus().equals(TaskStsType.COMPLETE_OUT.id)){ throw new CoolException("当前状态为不可拣货状态"); } ArrayList<ContainerWaveDto> containerWaveDtos = new ArrayList<>(); List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId())); for (TaskItem taskItem : taskItems) { ContainerWaveDto containerWaveDto = new ContainerWaveDto(); containerWaveDto.setTaskItem(taskItem); Wave wave = waveService.getById(taskItem.getSourceId()); if (null == wave){ throw new CoolException("未找到容器号对应波次"); } ArrayList<AsnOrderItem> list = new ArrayList<>(); List<AsnOrder> asnOrderList = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getWaveId, wave.getId())); for (AsnOrder asnOrder : asnOrderList) { AsnOrderItem orderItem = asnOrderItemService.getOne(new LambdaQueryWrapper<AsnOrderItem>() .eq(AsnOrderItem::getAsnId, asnOrder.getId()) .eq(AsnOrderItem::getMatnrCode, taskItem.getMatnrCode()) .eq(AsnOrderItem::getSplrBatch, taskItem.getBatch()) ); if (null != orderItem){ list.add(orderItem); } } containerWaveDto.setAsnOrderItems(list); containerWaveDtos.add(containerWaveDto); } return R.ok(containerWaveDtos); } @Override @Transactional(rollbackFor = Exception.class) public R saveWavePick(List<ContainerWaveDto> containerWaveDtos) { if (null == containerWaveDtos || containerWaveDtos.size() <= 0){ return R.error("参数错误"); } Task task = taskService.getById(containerWaveDtos.get(0).getTaskItem().getTaskId()); if (null == task){ return R.error("未找到托盘对应的任务"); } for (ContainerWaveDto containerWaveDto : containerWaveDtos) { //做一次校验,判断前端所有出库数量是否超过本托出库数量 double sum = containerWaveDto.getAsnOrderItems().stream().mapToDouble(AsnOrderItem::getDemandQty).sum(); BigDecimal total = new BigDecimal(String.valueOf(sum)); BigDecimal anfme = new BigDecimal(containerWaveDto.getTaskItem().getAnfme().toString()); if (!anfme.equals(total)){ throw new CoolException("播种数量不等于容器出库数量,请检查"); } for (AsnOrderItem orderItem : containerWaveDto.getAsnOrderItems()) { BigDecimal num = new BigDecimal(orderItem.getWorkQty().toString()).subtract(new BigDecimal(orderItem.getQty().toString())); BigDecimal orderDemandQty = new BigDecimal(orderItem.getDemandQty().toString()); if (num.compareTo(orderDemandQty) < 0){ throw new CoolException("播种数量大于单据出库数量,请检查"); } orderItem.setQty(new BigDecimal(orderItem.getQty().toString()).add(orderDemandQty).doubleValue()); if (!asnOrderItemService.updateById(orderItem)){ throw new CoolException("单据明细更新失败"); } } } task.setTaskStatus(TaskStsType.COMPLETE_OUT.id); if (!taskService.updateById(task)){ throw new CoolException("任务状态更新失败"); } return R.ok(); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
@@ -154,4 +154,7 @@ return R.ok().add(pageResult); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveItemController.java
@@ -1,6 +1,7 @@ package com.vincent.rsf.server.manager.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.R; @@ -10,8 +11,10 @@ import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.server.manager.entity.WaveItem; import com.vincent.rsf.server.manager.enums.WaveItemExceStatus; import com.vincent.rsf.server.manager.service.WaveItemService; import com.vincent.rsf.server.system.controller.BaseController; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -107,4 +110,25 @@ ExcelUtil.build(ExcelUtil.create(waveItemService.list(), WaveItem.class), response); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("暂停下发任务") @PostMapping("/waveItem/pause/pub") public R pausePublicTask(@PathVariable Long id) { waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .eq(WaveItem::getId, id) .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_ITEM_EXCE_PAUSE.val)); return R.ok(); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("继续下发任务") @PostMapping("/waveItem/continue/pub") public R continuePublicTask(@PathVariable Long id) { waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .eq(WaveItem::getId, id) .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_ITEM_EXCE_STATUS_UN.val)); return R.ok(); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/AsnOrderItem.java
@@ -276,6 +276,9 @@ */ @ApiModelProperty(value= "备注") private String memo; @TableField(exist = false) private Double demandQty = 0.0; // public AsnOrderItem() {} rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/WaveItemExceStatus.java
@@ -14,6 +14,7 @@ WAVE_ITEM_EXCE_STATUS_UN("0", "未执行"), WAVE_EXCE_STATUS_ING("1", "执行中"), WAVE_EXCE_STATUS_SEED("2", "已下发"), WAVE_ITEM_EXCE_PAUSE("4", "暂停"), WAVE_EXCE_STATUS_DONE("3", "下发完成"), ; rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/WaveSchedules.java
New file @@ -0,0 +1,84 @@ package com.vincent.rsf.server.manager.schedules; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.constant.Constants; import com.vincent.rsf.server.manager.entity.Wave; import com.vincent.rsf.server.manager.entity.WaveItem; import com.vincent.rsf.server.manager.enums.WaveExceStatus; import com.vincent.rsf.server.manager.enums.WaveItemExceStatus; import com.vincent.rsf.server.manager.service.WaveItemService; import com.vincent.rsf.server.manager.service.WaveService; import com.vincent.rsf.server.system.constant.GlobalConfigCode; import com.vincent.rsf.server.system.entity.Config; import com.vincent.rsf.server.system.service.ConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; /** * @author Ryan * @description 波次定时任务 * @param * @return * @time 2025/6/23 13:49 */ @Component public class WaveSchedules { @Autowired private WaveService waveService; @Autowired private WaveItemService waveItemService; @Autowired private ConfigService configService; /** * @author Ryan * @description 自动下发波次任务 * @param * @return * @time 2025/6/23 13:52 */ @Scheduled(cron = "0/15 * * * * ?") public void autoGenerateTask() { Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.WAVE_AUTO_EXCE_TASK)); if (Objects.isNull(config) || !Boolean.parseBoolean(config.getVal())) { return; } List<Wave> list = waveService.list(new LambdaQueryWrapper<Wave>() .select(Wave::getId) .eq(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_INIT.val)); if (list.isEmpty()) { return; } List<Long> longs = list.stream().map(Wave::getId).collect(Collectors.toList()); List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>() .in(WaveItem::getId, longs) .eq(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_ITEM_EXCE_STATUS_UN.val) ); if (waveItems.isEmpty()) { return; } Map<Long, List<WaveItem>> listMap = waveItems.stream().collect(Collectors.groupingBy(WaveItem::getWaveId)); listMap.keySet().forEach(waveId -> { Map<String, Object> params = new HashMap<>(); params.put("wave", waveId); params.put("waveItems", waveItems); waveService.waveToTask(params, waveId); }); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -81,13 +81,12 @@ listMap.keySet().forEach(key -> { Task task = new Task(); Loc loc = locService.getById(key); logger.info("库位:>{}<UNK>", loc.getCode()); logger.info("库位:>{}", loc.getCode()); if (Objects.isNull(loc)) { throw new CoolException("数据错误:所选库存信息不存在!!"); } if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_F.type)) { throw new CoolException("库位:" + loc.getCode() + ",不处于F.在库状态,不可执行R.出库预约操作!!"); throw new CoolException("库位:" + loc.getCode() + ",不处于F.在库状态,不可执行R.出库预约操作!!"); } loc.setUseStatus(LocStsType.LOC_STS_TYPE_R.type); @@ -202,15 +201,15 @@ .setUpdateTime(new Date()) .setOrderType(OrderType.ORDER_OUT.type) .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type)); if (map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)) { if (map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)) { taskItem.setWkType(Short.parseShort(order.getWkType())) .setSourceCode(order.getCode()) .setSourceId(order.getId()); } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK) || map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)) { taskItem.setSource(item.getId()) .setSourceId(item.getLocId()) .setSourceCode(item.getLocCode()); } } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK) || map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)) { taskItem.setSource(item.getId()) .setSourceId(item.getLocId()) .setSourceCode(item.getLocCode()); } taskItems.add(taskItem); Double qty = Math.round((item.getWorkQty() + item.getOutQty()) * 10000) / 10000.0; @@ -274,7 +273,7 @@ if (Objects.isNull(map.getTarLoc()) || StringUtils.isBlank(map.getTarLoc())) { //目标库位为空,自动获取新库位 DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>() .eq(DeviceSite::getType, TaskType.TASK_TYPE_LOC_MOVE.type) .eq(DeviceSite::getType, TaskType.TASK_TYPE_LOC_MOVE.type) .eq(DeviceSite::getChannel, orgLoc.getChannel()), false); if (Objects.isNull(deviceSite)) { throw new CoolException("站点信息不存在!!"); rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -790,7 +790,7 @@ List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId())); if (!taskItems.isEmpty()) { for (TaskItem item : taskItems) { if (item.getOrderType().equals(OrderType.ORDER_OUT.type)) { if (!Objects.isNull(item.getOrderType()) && item.getOrderType().equals(OrderType.ORDER_OUT.type)) { Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc())); if (Objects.isNull(loc)) { throw new CoolException("数据错误:库位信息不存在!!"); rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
@@ -116,6 +116,13 @@ if (items.isEmpty()) { throw new CoolException("波次明细不存在!!"); } if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val) .in(WaveItem::getId, waveItems))) { throw new CoolException("下发执行异常,请稍候重试!"); } /**生成出库任务*/ try { generateOutTask(items, loginUserId, waves); @@ -123,7 +130,7 @@ log.error("UNK", e); throw new CoolException(e.getMessage()); } return null; return R.ok(); } /** rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java
@@ -16,5 +16,7 @@ public final static String ALLOW_OVER_CHANGE = "AllowOverchange"; /**订单是否上报平台*/ public final static String ORDER_INOF_REPORT_PLAT = "OrderInofReportPlat"; /**波次自动下发任务*/ public final static String WAVE_AUTO_EXCE_TASK = "WaveAutoExce"; }