| 2025-12-25 | skyouc | ![]() |
| 2025-12-25 | skyouc | ![]() |
| 2025-12-25 | skyouc | ![]() |
| 2025-12-02 | skyouc | ![]() |
| 2025-12-03 | skyouc | ![]() |
| 2025-12-03 | skyouc | ![]() |
| 2025-12-04 | skyouc | ![]() |
| 2025-12-08 | skyouc | ![]() |
| 2025-12-08 | skyouc | ![]() |
| 2025-12-08 | skyouc | ![]() |
| 2025-11-11 | skyouc | ![]() |
| 2025-11-10 | skyouc | ![]() |
| 2025-11-06 | skyouc | ![]() |
| 2025-11-04 | skyouc | ![]() |
rsf-admin/src/i18n/en.js
@@ -217,7 +217,7 @@ locDeadReport: 'Locs Dead Report', stockStatistic: 'Stock Statistic', statisticCount: 'Statistic Count', preparation:"备料单", preparation: "备料单", }, table: { field: { @@ -1364,6 +1364,9 @@ selectWave: 'Select Wave Rule', }, placeholder: { warehouseAreasCode: "use for warehouse areas code prefix", }, request: { error: { stock: "Insufficient inventory to deliver !!", rsf-admin/src/i18n/zh.js
@@ -1402,6 +1402,9 @@ modiftySite: '修改库口', selectWave: '波次规则', }, placeholder: { warehouseAreasCode: "用于库位编码前缀占位符", }, request: { error: { stock: "库存不足,无法提交!!", rsf-admin/src/page/basicInfo/loc/LocItemList.jsx
@@ -8,37 +8,27 @@ SelectColumnsButton, EditButton, FilterButton, CreateButton, ExportButton, BulkDeleteButton, WrapperField, useRecordContext, useTranslate, useNotify, useListContext, FunctionField, TextField, NumberField, DateField, BooleanField, ReferenceField, TextInput, DateTimeInput, DateInput, SelectInput, NumberInput, ReferenceInput, ReferenceArrayInput, AutocompleteInput, DeleteButton, NumberInput, useRefresh, useGetRecordId, } from 'react-admin'; import { Box, Typography, Card, Stack } from '@mui/material'; import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material'; import { styled } from '@mui/material/styles'; import LocItemCreate from "./LocItemCreate"; import EmptyData from "../../components/EmptyData"; import MyCreateButton from "../../components/MyCreateButton"; import MyExportButton from '../../components/MyExportButton'; import request from '@/utils/request'; import PageDrawer from "../../components/PageDrawer"; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting'; @@ -119,42 +109,7 @@ )} perPage={DEFAULT_ITEM_PAGE_SIZE} > <StyledDatagrid preferenceKey='locItem' bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} rowClick={(id, resource, record) => false} expand={false} expandSingle={true} omit={['id', 'locId', 'orderId', 'orderItemId', 'matnrId', 'statusBool','trackCode', 'createTime', 'fieldsIndex','splrBatch', 'createBy', 'spec', 'model', 'memo']} > <NumberField source="id" /> <NumberField source="locId" label="table.field.locItem.locId" /> <NumberField source="orderId" label="table.field.locItem.orderId" /> <TextField source="type$" label="table.field.locItem.type" /> <NumberField source="orderItemId" label="table.field.locItem.orderItemId" /> <NumberField source="wkType$" label="table.field.locItem.wkType" /> <NumberField source="matnrId" label="table.field.locItem.matnrId" /> <TextField source="matnrCode" label="table.field.locItem.matnrCode" /> <TextField source="maktx" label="table.field.locItem.maktx" /> <TextField source="batch" label="table.field.locItem.batch" /> <TextField source="trackCode" label="table.field.locItem.trackCode" /> <NumberField source="anfme" label="table.field.locItem.anfme" /> <TextField source="unit" label="table.field.locItem.unit" /> <TextField source="splrBatch" label="table.field.locItem.splrBatch" /> <TextField source="spec" label="table.field.locItem.spec" /> <TextField source="model" label="table.field.locItem.model" /> <TextField source="fieldsIndex" label="table.field.locItem.fieldsIndex" /> <TextField source="updateBy$" label="common.field.updateBy" /> <DateField source="updateTime" label="common.field.updateTime" showTime /> <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} /> <WrapperField cellClassName="opt" label="common.field.opt"> <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} redirect={false}/> </WrapperField> </StyledDatagrid> <DynamicFields /> </List> <LocItemCreate open={createDialog} @@ -170,4 +125,81 @@ ) } export default LocItemList; const DynamicFields = (props) => { const translate = useTranslate(); const notify = useNotify(); const [columns, setColumns] = useState([]); const { isLoading } = useListContext(); const refresh = useRefresh(); useEffect(() => { getDynamicFields(); }, []); const getDynamicFields = async () => { const { data: { code, data, msg }, } = await request.get("/fields/enable/list"); if (code == 200) { const arr = [ <NumberField source="id" />, <NumberField source="locId" label="table.field.locItem.locId" />, <NumberField source="orderId" label="table.field.locItem.orderId" />, <TextField source="type$" label="table.field.locItem.type" />, <NumberField source="orderItemId" label="table.field.locItem.orderItemId" />, <NumberField source="wkType$" label="table.field.locItem.wkType" />, <NumberField source="matnrId" label="table.field.locItem.matnrId" />, <TextField source="matnrCode" label="table.field.locItem.matnrCode" />, <TextField source="maktx" label="table.field.locItem.maktx" />, <TextField source="batch" label="table.field.locItem.batch" />, <TextField source="trackCode" label="table.field.locItem.trackCode" />, <NumberField source="anfme" label="table.field.locItem.anfme" />, <TextField source="unit" label="table.field.locItem.unit" />, <TextField source="splrBatch" label="table.field.locItem.splrBatch" />, <TextField source="spec" label="table.field.locItem.spec" />, <TextField source="model" label="table.field.locItem.model" />, <TextField source="fieldsIndex" label="table.field.locItem.fieldsIndex" />, <BooleanField source="statusBool" label="common.field.status" sortable={false} />, ] const fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />) const lastArr = [ <TextField source="updateBy$" label="common.field.updateBy" />, <DateField source="updateTime" label="common.field.updateTime" showTime />, <TextField source="createBy$" label="common.field.createBy" />, <DateField source="createTime" label="common.field.createTime" showTime />, <TextField source="memo" label="common.field.memo" sortable={false} />, ] setColumns([...arr, ...fields, ...lastArr]); } else { notify(msg); } } return ( <Box sx={{ position: 'relative', minHeight: "60vh", }}> {isLoading && ( <LinearProgress sx={{ height: "2px", position: 'absolute', top: 0, left: 0, right: 0, }} /> )} {columns.length > 0 && <StyledDatagrid preferenceKey='locItem' bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} rowClick={(id, resource, record) => false} expand={false} expandSingle={true} omit={['id', 'locId', 'orderId', 'orderItemId', 'matnrId', 'statusBool', 'trackCode', 'createTime', 'fieldsIndex', 'splrBatch', 'createBy', 'spec', 'model', 'memo']} > {columns.map((column) => column)} </StyledDatagrid>} </Box> ) } rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
@@ -414,8 +414,6 @@ // </Button> : ) record.exceStatus === 1 ? <ConfirmButton label={"toolbar.complete"} color="secondary" startIcon={<TaskIcon />} onConfirm={requestComplete} /> : <></> ) } const CloseButton = () => { rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -55,6 +55,7 @@ import PublicIcon from '@mui/icons-material/Public'; import SelectMatnrModal from "./SelectMatnrModal"; import EditIcon from '@mui/icons-material/Edit'; import TaskIcon from '@mui/icons-material/Task'; import OutOrderPreview from "./OutOrderPreview"; import AddIcon from '@mui/icons-material/Add'; import OutStockPublic from "./OutStockPublic"; @@ -203,6 +204,7 @@ <MyButton setCreateDialog={setManualDialog} setmodalType={setmodalType} /> <EditButton label="toolbar.detail" icon={(<DetailsIcon />)}></EditButton> <CancelButton /> <CompleteButton /> <PublicButton setDrawerVal={setDrawerVal} drawerVal={drawerVal} setSelect={setSelect} /> </WrapperField> </StyledDatagrid> @@ -259,6 +261,29 @@ ); } //完成单据 const CompleteButton = () => { const record = useRecordContext(); const notify = useNotify(); const refresh = useRefresh(); const requestComplete = async () => { const { data: { code, data, msg } } = await request.get(`/outStock/complete/${record.id}`); if (code === 200) { notify(msg); refresh() } else { notify(msg); } } return ( // record.exceStatus === 1 && (record.anfme === record.qty ? <Button onClick={requestComplete} label={"toolbar.complete"} color="secondary"> // <TaskIcon /> // </Button> : ) record.exceStatus != 15 ? <ConfirmButton label={"toolbar.complete"} color="secondary" startIcon={<TaskIcon />} onConfirm={requestComplete} /> : <></> ) } const MyButton = ({ setCreateDialog, setmodalType }) => { const record = useRecordContext(); const handleEditClick = (btn) => { rsf-admin/src/page/statistics/stockManage/WarehouseStockList.jsx
@@ -53,19 +53,19 @@ cursor: 'auto' }, '& .MuiTableCell-root': { whiteSpace: 'nowrap', overflow: 'visible', textOverflow: 'unset' whiteSpace: 'nowrap', overflow: 'visible', textOverflow: 'unset' }, '& .opt': { width: 180, whiteSpace: 'normal', }, '& .column-maktx': { '& .column-maktx': { maxWidth: '15em', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', whiteSpace: 'nowrap', }, })); @@ -77,23 +77,11 @@ const translate = useTranslate(); const [createDialog, setCreateDialog] = useState(false); const [filters, setFilters] = useState([ <SearchInput source="condition" alwaysOn />, <NumberInput source="locId" label="table.field.locItem.locId" />, <TextInput source="locCode" label="table.field.locItem.locCode" />, <TextInput source="type" label="table.field.locItem.type" />, <AutocompleteInput choices={dict} optionText='label' optionValue="value" source="aggType" label="table.field.locItem.aggType" />, <NumberInput source="orderItemId" label="table.field.locItem.orderItemId" />, <NumberInput source="wkType" label="table.field.locItem.wkType" />, <NumberInput source="matnrId" label="table.field.locItem.matnrId" />, <TextInput source="matnrCode" label="table.field.warehouseStock.matnrCode" alwaysOn/>, <TextInput source="maktx" label="table.field.locItem.maktx" />, <TextInput source="unit" label="table.field.locItem.unit" />, <NumberInput source="anfme" label="table.field.locItem.anfme" />, <NumberInput source="workQty" label="table.field.locItem.workQty" />, <TextInput source="batch" label="table.field.locItem.batch" />, <TextInput source="spec" label="table.field.locItem.spec" />, <TextInput source="model" label="table.field.locItem.model" />, <TextInput source="fieldsIndex" label="table.field.locItem.fieldsIndex" />, <TextInput label="common.field.memo" source="memo" />,]); ]); const [select, setSelect] = useState({}); const [drawerVal, setDrawerVal] = useState(false); @@ -242,7 +230,7 @@ rowClick={false} expand={false} expandSingle={true} omit={['id', 'createTime', 'locId', 'spec', 'model', 'locCode', 'orderId', 'orderItemId', 'matnrId', 'splrBatch', 'createBy', 'memo', 'fieldsIndex','updateBy$']} omit={['id', 'createTime', 'locId', 'spec', 'model', 'locCode', 'orderId', 'orderItemId', 'matnrId', 'splrBatch', 'createBy', 'memo', 'fieldsIndex', 'updateBy$']} > {columns.map((column) => column)} </StyledDatagrid>} rsf-admin/src/page/system/menu/MenuList.jsx
@@ -199,7 +199,6 @@ onClick={() => column.id === 'name' && toggleNode(row.id)} sx={{ opacity: column.id === 'icon' ? 0.6 : (depth > 0 ? opacity : 1), color: depth > 0 ? `rgba(0, 0, 0, ${opacity})` : 'inherit', fontWeight: 400, // 使用字体大小或颜色来区分层级 fontSize: depth === 0 ? '0.95rem' : '0.9rem', @@ -267,6 +266,14 @@ const [editRecord, setEditRecord] = React.useState(null); const [openNodes, setOpenNodes] = React.useState({}); const [expandAll, setExpandAll] = React.useState(false); const notifyState = React.useRef({ last: '', at: 0 }); const pushNotify = React.useCallback((type, msg) => { const text = typeof msg === 'string' ? msg : (msg || ''); const now = Date.now(); if (notifyState.current.last === text && now - notifyState.current.at < 1500) return; notifyState.current = { last: text, at: now }; notify(text, { type, messageArgs: { _: text } }); }, [notify]); const http = async () => { const res = await request.post(RESOURCE + '/tree', { @@ -275,7 +282,8 @@ if (res?.data?.code === 200) { setTreeData(res.data.data); } else { notify(res.data.msg); const msg = translate('ra.notification.http_error', { _: res?.data?.msg || 'Request failed' }); pushNotify('warning', msg); } } @@ -305,10 +313,12 @@ { onSuccess: () => { handleRefresh(); notify('Department deleted successfully', { type: 'info', messageArgs: { _: 'Department deleted successfully' } }); const msg = translate('ra.message.delete_success', { _: 'Deleted successfully' }); pushNotify('success', msg); }, onError: (error) => { notify(`Error: ${error.message}`, { type: 'warning', messageArgs: { _: `Error: ${error.message}` } }); const msg = translate('ra.notification.http_error', { _: error?.message || 'Network error' }); pushNotify('error', msg); }, } ); @@ -320,6 +330,7 @@ const newExpandAll = !prevExpandAll; const newOpenNodes = {}; const updateOpenNodes = (nodes) => { if (!nodes) return; nodes.forEach(node => { newOpenNodes[node.id] = newExpandAll; if (node.children) { @@ -442,4 +453,4 @@ ); }; export default MenuList; export default MenuList; rsf-admin/src/page/warehouseAreas/WarehouseAreasCreate.jsx
@@ -103,11 +103,12 @@ source="code" validate={[required()]} parse={(v) => v} placeholder={translate("placeholder.warehouseAreasCode")} /> <AutocompleteInput choices={dicts} optionText="label" label="table.field.asnOrder.type" label="table.field.warehouseAreas.type" source="type" optionValue="value" parse={v => v} rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocController.java
@@ -127,10 +127,13 @@ public R update(@RequestBody Loc loc) { loc.setUpdateBy(getLoginUserId()); String join = StringUtils.join(loc.getTypeIds(), ","); loc.setType(join); if (Objects.isNull(loc.getTypeIds())) { throw new CoolException("库位类型不能为空!!"); if (!Objects.isNull(loc.getTypeIds())) { loc.setType(join); } if (Objects.isNull(loc.getTypeIds()) && !Objects.isNull(loc.getType())) { loc.setTypeIds(Arrays.asList(Long.valueOf(loc.getType()))); } if (!locService.updateById(loc)) { return R.error("Update Fail"); } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java
@@ -256,6 +256,17 @@ return outStockService.saveOutStock(params, getLoginUserId()); } @GetMapping("/outStock/complete/{id}") @ApiOperation("完成出库单") @PreAuthorize("hasAuthority('manager:outStock:update')") public R complete(@PathVariable Long id) { if (Objects.isNull(id)) { return R.error("参数不能为空!!"); } return outStockService.completeOutOrderById(id); } @ApiOperation("单据信息修改") @PostMapping("/outStock/items/update") @PreAuthorize("hasAuthority('manager:outStock:update')") rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseController.java
@@ -104,18 +104,17 @@ Warehouse warehouse1 = warehouseService.getById(warehouse.getId()); if (!warehouse.getName().equals(warehouse1.getName())) { List<Warehouse> areasList = warehouseService.list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getName, warehouse1.getName())); List<Warehouse> areasList = warehouseService.list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getName, warehouse.getName())); if (!areasList.isEmpty()) { throw new CoolException("仓库名已存在!!"); } } if (!warehouse.getCode().equals(warehouse1.getCode())) { List<Warehouse> areasList = warehouseService.list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getCode, warehouse1.getCode())); List<Warehouse> areasList = warehouseService.list(new LambdaQueryWrapper<Warehouse>().eq(Warehouse::getCode, warehouse.getCode())); if (!areasList.isEmpty()) { throw new CoolException("仓库编码已存在!!"); } } if (!warehouseService.updateById(warehouse)) { return R.error("Update Fail"); rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseStockController.java
@@ -59,17 +59,22 @@ } else { wrapper.groupBy("matnr_id"); } wrapper.eq(!Objects.isNull(param.get("matnrCode")), "matnr_code", param.get("matnrCode")); FieldsUtils.setFieldsFilters(wrapper, pageParam, ViewStockManage.class); IPage<ViewStockManage> pageResult = warehouseStockService.pageByStock(pageParam, wrapper); List<ViewStockManage> records = pageResult.getRecords(); for (ViewStockManage record : records) { records.forEach(record -> { if (!Objects.isNull(record.getFieldsIndex())) { Map<String, String> fields = FieldsUtils.getFields(record.getFieldsIndex()); record.setExtendFields(fields); } } }); pageResult.setRecords(records); return R.ok(pageResult); @@ -145,8 +150,17 @@ } else { wrapper.eq(ViewStockManage::getMatnrCode, stock.getMatnrCode()); } PageParam<ViewStockManage, BaseParam> result = warehouseStockService.page(pageParam, wrapper); List<ViewStockManage> records = result.getRecords(); records.forEach(record -> { if (!Objects.isNull(record.getFieldsIndex())) { Map<String, String> fields = FieldsUtils.getFields(record.getFieldsIndex()); record.setExtendFields(fields); } }); result.setRecords(records); return R.ok(warehouseStockService.page(pageParam, wrapper)); return R.ok(result); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java
@@ -32,4 +32,6 @@ R cancelOutOrderByItems(List<WkOrderItem> orderItems); R completeOutOrderById(Long id); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java
@@ -3,8 +3,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.server.manager.controller.params.GenerateTaskParams; import com.vincent.rsf.server.manager.entity.Task; import com.vincent.rsf.server.manager.entity.WaitPakin; import com.vincent.rsf.server.manager.entity.*; import java.util.List; @@ -29,4 +28,10 @@ Task operateComplete(Long id, Long loginUserId); void moveToDeep(Long loginUserId, String curLoc) throws Exception; void pubTaskToWcs(List<Task> tasks); R menualExceTask(List<Long> ids); void saveOutStockItem(List<TaskItem> taskItems, WkOrderItem orderItem, WaveItem waveItem, WkOrderItem diffItem, Long loginUserId) throws Exception; } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -65,7 +65,7 @@ @Override @Synchronized @Transactional(rollbackFor = Exception.class) public void generateTask(Short resouce, LocToTaskParams map, Long loginUserId) throws Exception { public synchronized void generateTask(Short resouce, LocToTaskParams map, Long loginUserId) throws Exception { if (Objects.isNull(map.getSiteNo())) { throw new CoolException("站点不能为空!"); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocServiceImpl.java
@@ -115,7 +115,7 @@ Integer chanl = 0; //默认第一巷道 for (int r = param.getStartRow(); r <= param.getEndRow(); r++) { try{ Shelves shelves = new Shelves(param.getEndRow() - param.getStartRow() + 1, param.getChannel(),param.getStartRow()); Shelves shelves = new Shelves(param.getEndRow() - param.getStartRow() + 1, param.getChannel(), param.getStartRow()); for (List<Integer> node : shelves.nodes){ if (node.contains(r)) { if (!Cools.isEmpty(param.getStartChannel()) && param.getStartChannel() > 0){ rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -728,4 +728,25 @@ return waveItems; } /** * @param id * @return * @author Ryan * @description 完成出库单 * @time 2025/4/25 10:07 */ @Override public R completeOutOrderById(Long id) { WkOrder order = this.getById(id); if (Objects.isNull(order)) { return R.error("出库单不存在!!"); } order.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val); if (!this.updateById(order)) { throw new CoolException("完成出库单失败!!"); } return R.ok("完成出库单成功!!"); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java
@@ -129,7 +129,7 @@ throw new CoolException("库位不存在!!"); } List<LocItem> list = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId())); if (!list.isEmpty()) { if (list.isEmpty()) { throw new CoolException("库位:" + loc.getCode() + ", 调整信息为空!!"); } locItemService.remove(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId())); rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -1,10 +1,21 @@ package com.vincent.rsf.server.manager.service.impl; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.cfg.CoercionAction; import com.fasterxml.jackson.databind.cfg.CoercionInputShape; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.DateUtils; import com.vincent.rsf.server.api.config.RemotesInfoProperties; import com.vincent.rsf.server.api.controller.erp.params.TaskInParam; import com.vincent.rsf.server.api.entity.CommonResponse; import com.vincent.rsf.server.api.entity.constant.RcsConstant; import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto; import com.vincent.rsf.server.api.entity.params.TaskItemParam; import com.vincent.rsf.server.api.entity.params.WcsTaskParams; import com.vincent.rsf.server.api.service.WcsService; import com.vincent.rsf.server.common.constant.Constants; import com.vincent.rsf.server.manager.controller.params.LocToTaskParams; @@ -18,8 +29,12 @@ import com.vincent.rsf.server.manager.service.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.vincent.rsf.server.manager.utils.LocManageUtil; import com.vincent.rsf.server.system.constant.GlobalConfigCode; import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.manager.enums.LocStsType; import com.vincent.rsf.server.system.entity.Config; import com.vincent.rsf.server.system.service.ConfigService; import com.vincent.rsf.server.system.service.impl.ConfigServiceImpl; import com.vincent.rsf.server.system.utils.SerialRuleUtils; import com.vincent.rsf.server.system.utils.SystemAuthUtils; import lombok.Synchronized; @@ -29,10 +44,16 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @Slf4j @@ -95,6 +116,12 @@ private CheckDiffItemService checkDiffItemService; @Autowired private BasContainerService basContainerService; @Autowired private ConfigService configService; @Autowired private RestTemplate restTemplate; @Autowired private RemotesInfoProperties.RcsApi rcsApi; @Override @Transactional(rollbackFor = Exception.class) @@ -309,6 +336,9 @@ waitPakins.forEach(pakin -> { BasContainer container = basContainerService.getOne(new LambdaUpdateWrapper<BasContainer>() .eq(BasContainer::getCode, pakin.getBarcode())); if (Objects.isNull(container)) { throw new CoolException("容器未维护入库,请维护后再操作!!"); } /**获取库位*/ String targetLoc = LocManageUtil.getTargetLoc(warehouseArea.getId(), container.getContainerType()); if (Cools.isEmpty(targetLoc)) { @@ -422,12 +452,12 @@ * @param tasks * @throws Exception */ @Synchronized @Override public void complateInTask(List<Task> tasks) throws Exception { Long loginUserId = SystemAuthUtils.getLoginUserId(); for (Task task : tasks) { try { public void complateInTask(List<Task> tasks) { AtomicBoolean success = new AtomicBoolean(false); if (success.compareAndSet(false, true)) { Long loginUserId = SystemAuthUtils.getLoginUserId(); for (Task task : tasks) { if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type)) { //1.入库 complateInstock(task, loginUserId); @@ -439,8 +469,6 @@ //移库 moveInStock(task, loginUserId); } } catch (Exception ex) { log.error(ex.getMessage(), ex); } } } @@ -675,7 +703,7 @@ * @param loginUserId */ @Transactional(rollbackFor = Exception.class) public void pickComplateInStock(Task task, Long loginUserId) throws Exception { public void pickComplateInStock(Task task, Long loginUserId) { if (Objects.isNull(task)) { return; } @@ -683,10 +711,9 @@ if (Objects.isNull(loc)) { throw new CoolException("库存不存在!!"); } if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_S.type)) { throw new CoolException("当前库位状态不处于S.入库预约,不可执行入库操作!"); } // if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_S.type)) { // throw new CoolException("当前库位状态不处于S.入库预约,不可执行入库操作!"); // } loc.setUseStatus(LocStsType.LOC_STS_TYPE_F.type) .setBarcode(task.getBarcode()) .setUpdateBy(loginUserId).setUpdateTime(new Date()); @@ -705,16 +732,17 @@ LocItem locItem = new LocItem(); LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>() .eq(LocItemWorking::getTaskId, taskItem.getTaskId()) .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch()) .eq(LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex()) .eq(StringUtils.isNotEmpty(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch()) .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId())); if (Objects.isNull(locWorking)) { throw new CoolException("数据错误,作业中库存数据丢失!!"); continue; } if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { locWorking.setAnfme(taskItem.getAnfme()); } BeanUtils.copyProperties(locWorking, locItem); locItem.setWorkQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date()); locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date()); items.add(locItem); } @@ -724,7 +752,7 @@ TaskItem taskItem = taskItems.stream().findFirst().get(); //保存入出库流水 saveStockItems(taskItems, task, null, null, taskItem.getWkType(), taskItem.getOrderType(), loginUserId); saveStockItems(taskItems, task, null, null, taskItem.getWkType(), OrderType.ORDER_IN.type, loginUserId); locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId())); @@ -788,7 +816,6 @@ } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) { List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getTaskId, Arrays.asList(ids))); if (!taskItems.isEmpty()) { taskItems.forEach(taskItem -> { if (!checkOrderItemService.update(new LambdaUpdateWrapper<WkOrderItem>() .eq(WkOrderItem::getId, taskItem.getOrderItemId()) @@ -868,7 +895,7 @@ if (Objects.isNull(waveItem)) { throw new CoolException("波次明细不存在!!"); } Double workQty = Math.round((waveItem.getWorkQty() - item.getAnfme()) * 10000) / 10000.0; Double workQty = Math.round((waveItem.getWorkQty() - item.getAnfme()) * 1000000) / 1000000.0; waveItem.setWorkQty(workQty).setExceStatus(WaveItemExceStatus.WAVE_ITEM_EXCE_STATUS_UN.val); if (!waveItemService.updateById(waveItem)) { throw new CoolException("波次明细更新失败!!"); @@ -892,7 +919,7 @@ if (Objects.isNull(wkOrder)) { throw new CoolException("数据错误:单据已不存在!!"); } Double workQty = Math.round((wkOrder.getWorkQty() - item.getAnfme()) * 10000) / 10000.0; Double workQty = Math.round((wkOrder.getWorkQty() - item.getAnfme()) * 1000000) / 1000000.0; wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val) .setWorkQty(workQty.compareTo(0.00) > 0 ? workQty : 0.00) @@ -907,7 +934,7 @@ throw new CoolException("数据错误:单据明细已不存在!!"); } Double workItmQty = Math.round((orderItem.getWorkQty() - item.getAnfme()) * 10000) / 10000.0; Double workItmQty = Math.round((orderItem.getWorkQty() - item.getAnfme()) * 1000000) / 1000000.0; orderItem.setWorkQty(workItmQty); if (!outStockItemService.updateById(orderItem)) { @@ -1017,37 +1044,37 @@ tempLocs.forEach(working -> { taskItems.forEach(taskItem -> { if (taskItem.getMatnrId().equals(working.getMatnrId())) { if (taskItem.getFieldsIndex().equals(working.getFieldsIndex())) { Double minQty = taskItem.getAnfme(); if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { minQty = Math.round((working.getAnfme() - taskItem.getAnfme()) * 10000) / 10000.0; minQty = Math.round((working.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0; } if (minQty.compareTo(0.0) > 0) { if (minQty.compareTo(0.0) >= 0) { taskItem.setAnfme(minQty); if (!taskItemService.updateById(taskItem)) { throw new CoolException("任务明细修改失败!!"); } } else { if (!taskItemService.removeById(taskItem)) { throw new CoolException("任务明细修改失败!!"); log.error("任务明细修改失败!!"); } } } }); }); List<Long> matnrIds = taskItems.stream().map(TaskItem::getMatnrId).collect(Collectors.toList()); List<String> matnrIds = taskItems.stream().map(TaskItem::getFieldsIndex).collect(Collectors.toList()); //删除与任务明细重复的库存信息,以任务明细为准 List<LocItemWorking> itemWorkings = tempLocs.stream() .filter(working -> !matnrIds.contains(working.getMatnrId())) .filter(working -> !matnrIds.contains(working.getFieldsIndex())) .collect(Collectors.toList()); itemWorkings.forEach(working -> { TaskItem taskItem = taskItems.stream().findFirst().get(); taskItem.setMatnrId(working.getMatnrId()) .setMaktx(working.getMaktx()) .setMatnrId(working.getMatnrId()) .setMatnrCode(working.getMatnrCode()) .setSpec(working.getSpec()) .setAnfme(working.getAnfme()) .setQty(0.0) .setBatch(working.getBatch()) .setFieldsIndex(working.getFieldsIndex()) .setUnit(working.getUnit()) @@ -1072,6 +1099,7 @@ LocItemWorking itemWorking = new LocItemWorking(); BeanUtils.copyProperties(taskItem, itemWorking); itemWorking.setTaskId(task.getId()) .setQty(0.0) .setLocId(loc1.getId()) .setLocCode(loc1.getCode()); workings.add(itemWorking); @@ -1159,11 +1187,11 @@ if (Objects.isNull(waveItem)) { throw new CoolException("波次明细不存在!!"); } try { saveOutStockItem(maps.get(key), null, waveItem, null, loginUserId); } catch (Exception e) { throw new CoolException(e.getMessage()); } // try { // saveOutStockItem(maps.get(key), null, waveItem, null, loginUserId); // } catch (Exception e) { // throw new CoolException(e.getMessage()); // } } else if (task.getResource().equals(TaskResouceType.TASK_RESOUCE_ORDER_TYPE.val)) { WkOrderItem orderItem = asnOrderItemService.getById(key); if (Objects.isNull(orderItem)) { @@ -1206,27 +1234,35 @@ throw new CoolException("库位状态修改失败!!"); } if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) { if (!this.update(new LambdaUpdateWrapper<Task>() .eq(Task::getId, task.getId()) .set(Task::getUpdateBy, loginUserId) .set(Task::getUpdateTime, new Date()) .set(Task::getTaskStatus, TaskStsType.WAVE_SEED.id))) { throw new CoolException("库存状态更新失败!!"); } } else { if (!this.update(new LambdaUpdateWrapper<Task>() .eq(Task::getId, task.getId()) .set(Task::getUpdateBy, loginUserId) .set(Task::getUpdateTime, new Date()) .set(Task::getTaskStatus, TaskStsType.UPDATED_OUT.id))) { throw new CoolException("库存状态更新失败!!"); } //全板出库,删除临时库存 if (!locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()))) { throw new CoolException("临时库存清除失败!!"); } if (!this.update(new LambdaUpdateWrapper<Task>() .eq(Task::getId, task.getId()) .set(Task::getUpdateBy, loginUserId) .set(Task::getUpdateTime, new Date()) .set(Task::getTaskStatus, TaskStsType.WAVE_SEED.id))) { throw new CoolException("库存状态更新失败!!"); } // if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) { // if (!this.update(new LambdaUpdateWrapper<Task>() // .eq(Task::getId, task.getId()) // .set(Task::getUpdateBy, loginUserId) // .set(Task::getUpdateTime, new Date()) // .set(Task::getTaskStatus, TaskStsType.WAVE_SEED.id))) { // throw new CoolException("库存状态更新失败!!"); // } // } else { // if (!this.update(new LambdaUpdateWrapper<Task>() // .eq(Task::getId, task.getId()) // .set(Task::getUpdateBy, loginUserId) // .set(Task::getUpdateTime, new Date()) // .set(Task::getTaskStatus, TaskStsType.WAVE_SEED.id))) { // throw new CoolException("库存状态更新失败!!"); // } //// //全板出库,删除临时库存 //// if (!locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()))) { //// throw new CoolException("临时库存清除失败!!"); //// } // } } @@ -1251,6 +1287,7 @@ * @description: 出库信息保存至库存明细表 * @version 1.0 */ @Override @Transactional(rollbackFor = Exception.class) public void saveOutStockItem(List<TaskItem> taskItems, WkOrderItem orderItem, WaveItem waveItem, WkOrderItem diffItem, Long loginUserId) throws Exception { Stock stock = new Stock(); @@ -1268,7 +1305,7 @@ stock.setSourceId(waveItem.getId()).setType(OrderType.ORDER_OUT.type); } else if (!Objects.isNull(orderItem) && StringUtils.isNotBlank(orderItem.getId() + "")) { WkOrder wkOrder = asnOrderService.getById(orderItem.getOrderId()); Double qty = Math.round((wkOrder.getQty() + sum) * 10000) / 10000.0; Double qty = Math.round((wkOrder.getQty() + sum) * 1000000) / 1000000.0; wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) .setQty(qty); if (!asnOrderService.updateById(wkOrder)) { @@ -1305,6 +1342,206 @@ } } /** * 手动下发执行任务 * @author Ryan * @date 2025/11/22 13:45 * @param ids * @return com.vincent.rsf.framework.common.R */ @Override @Transactional(rollbackFor = Exception.class) public R menualExceTask(List<Long> ids) { if (Objects.isNull(ids) || ids.isEmpty()) { return R.error("任务编码不能为空!!"); } List<Integer> integers = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id); List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>() .in(Task::getId, ids) .in(Task::getTaskStatus, integers) .orderByDesc(Task::getSort)); if (tasks.isEmpty()) { return R.error("任务已在执行中!!"); } Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.AUTO_RUN_CHECK_ORDERS)); if (!Objects.isNull(config) && !Objects.isNull(config.getVal())) { if (Boolean.parseBoolean(config.getVal())) { return R.error("自动生成任务已开启,无需手动下发!!"); } } taskService.pubTaskToWcs(tasks); return R.ok(); } /** * 下发任务至WCS * * @param tasks */ @Override @Transactional(rollbackFor = Exception.class) public void pubTaskToWcs(List<Task> tasks) { WcsTaskParams taskParams = new WcsTaskParams(); List<TaskItemParam> items = new ArrayList<>(); tasks.forEach(task -> { TaskItemParam itemParam = new TaskItemParam(); //任务类型,任务编码 itemParam.setTaskType(RcsTaskType.getTypeDesc(task.getTaskType())) .setSeqNum(task.getTaskCode()); //主参数 taskParams.setBatch(task.getBarcode()); BasStation station = null; if (!task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { station = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getTargSite())); if (Objects.isNull(station)) { throw new CoolException("站点不存在!!"); } } /**判断是否光电站点,非光店站点需管控站点状态*/ if (!Objects.isNull(station) && station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { if (task.getTaskType() <= TaskType.TASK_TYPE_CHECK_IN.type && !task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { station.setUseStatus(LocStsType.LOC_STS_TYPE_R.type); if (!basStationService.updateById(station)) { throw new CoolException("站点状态更新失败!!"); } } else if (task.getTaskType() >= TaskType.TASK_TYPE_OUT.type) { station.setUseStatus(LocStsType.LOC_STS_TYPE_S.type); if (!basStationService.updateById(station)) { throw new CoolException("站点状态更新失败!!"); } } } /**移库参数*/ if (task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { itemParam.setOriLoc(task.getOrgLoc()).setDestLoc(task.getTargLoc()); } else if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type)) { /**全板入库参数*/ itemParam.setDestLoc(task.getTargLoc()) .setOriSta(task.getOrgSite()); } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type)) { /**拣料/盘点入库参数*/ itemParam.setDestLoc(task.getTargLoc()) .setOriSta(task.getTargSite()); } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_OUT.type)) { /**出库参数*/ itemParam.setOriLoc(task.getOrgLoc()) .setDestSta(task.getTargSite()); } else { /**站点间移库参数*/ itemParam.setOriSta(task.getOrgSite()).setDestSta(task.getTargSite()); BasStation curSta = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getOrgSite())); if (Objects.isNull(curSta)) { throw new CoolException("站点不存在!!"); } if (curSta.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { if (!curSta.getUseStatus().equals(LocStsType.LOC_STS_TYPE_F.type)) { throw new CoolException("当前站点不是F.在库状态!!"); } } if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { if (!station.getUseStatus().equals(LocStsType.LOC_STS_TYPE_O.type)) { throw new CoolException("目标站点不是O.空闲状态!!"); } } } items.add(itemParam); }); taskParams.setTaskList(items); /**任务下发接口*/ String pubTakUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.pubTask; /**RCS基础配置链接*/ log.info("任务下发,请求地址: {}, 请求参数: {}", pubTakUrl, JSONObject.toJSONString(taskParams)); HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/json"); headers.add("api-version", "v2.0"); HttpEntity httpEntity = new HttpEntity(taskParams, headers); ResponseEntity<String> exchange = restTemplate.exchange(pubTakUrl, HttpMethod.POST, httpEntity, String.class); log.info("任务下发后,响应结果: {}", exchange); if (Objects.isNull(exchange.getBody())) { throw new CoolException("任务下发失败!!"); } else { try { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.coercionConfigDefaults() .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty); CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class); if (result.getCode() == 200) { tasks.forEach(task -> { if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type) || task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { BasStation curSta = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getOrgSite())); if (Objects.isNull(curSta)) { throw new CoolException("站点不存在!!"); } if (!taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()) .set(Task::getTaskStatus, TaskStsType.WCS_EXECUTE_IN.id))) { throw new CoolException("任务状态修改失败!!"); } /**排除移库功能*/ if (!task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { /**如果是普通站点,修改站点状态为出库预约*/ if (curSta.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { curSta.setUseStatus(LocStsType.LOC_STS_TYPE_R.type); if (!basStationService.updateById(curSta)) { throw new CoolException("站点预约失败!!"); } } } } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)) { BasStation curSta = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getTargSite())); if (Objects.isNull(curSta)) { throw new CoolException("站点不存在!!"); } if (!taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()) .set(Task::getTaskStatus, TaskStsType.WCS_EXECUTE_OUT.id))) { throw new CoolException("任务状态修改失败!!"); } /**如果是普通站点,修改站点状态为入库预约*/ if (curSta.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { curSta.setUseStatus(LocStsType.LOC_STS_TYPE_S.type); if (!basStationService.updateById(curSta)) { throw new CoolException("站点预约失败!!"); } } } }); } else { log.error(JSONObject.toJSONString(result)); // throw new CoolException("任务下发失败!!"); } } catch (JsonProcessingException e) { throw new CoolException(e.getMessage()); } } }/** /** * @author Ryan * @date 2025/5/20 @@ -1325,7 +1562,7 @@ * @version 1.0 */ @Transactional(rollbackFor = Exception.class) public void complateInstock(Task task, Long loginUserId) { public synchronized void complateInstock(Task task, Long loginUserId) { if (Objects.isNull(task)) { return; } @@ -1343,12 +1580,9 @@ if (taskItems.isEmpty()) { throw new CoolException("任务明细不存在!!"); } try { //更新库位明细 saveLocItem(taskItems, task.getId(), loginUserId); } catch (Exception e) { throw new CoolException("库位明细更新失败!!"); } //更新库位明细 saveLocItem(taskItems, task.getId(), loginUserId); /**对任务明细按组拖明细进行分组*/ Map<Long, List<TaskItem>> orderMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getSource)); @@ -1358,15 +1592,10 @@ throw new CoolException("数据错误:组拖数据不存在,请联系管理员!!"); } List<TaskItem> items = orderMap.get(key); try { //保存库存明细 saveStockItems(items, task, pakinItem.getId(), pakinItem.getAsnCode(), pakinItem.getWkType(), pakinItem.getType(), loginUserId); //移出收货区库存, 修改组托状态 removeReceiptStock(pakinItem, loginUserId); } catch (Exception e) { logger.error("<UNK>", e); throw new CoolException(e.getMessage()); } //保存入出库明细 saveStockItems(items, task, pakinItem.getId(), pakinItem.getAsnCode(), pakinItem.getWkType(), pakinItem.getType(), loginUserId); //移出收货区库存, 修改组托状态 removeReceiptStock(pakinItem, loginUserId); }); /**修改库位状态为F.在库*/ if (!locService.update(new LambdaUpdateWrapper<Loc>().set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_F.type).eq(Loc::getCode, task.getTargLoc()))) { @@ -1386,14 +1615,14 @@ * @time 2025/4/30 16:32 */ @Transactional(rollbackFor = Exception.class) public void removeReceiptStock(WaitPakinItem pakinItem, Long loginUserId) { public synchronized void removeReceiptStock(WaitPakinItem pakinItem, Long loginUserId) { WarehouseAreasItem itemServiceOne = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>() .eq(WarehouseAreasItem::getId, pakinItem.getSource())); if (Objects.isNull(itemServiceOne)) { throw new CoolException("数据错误:请查看请货区库存是否存在!!"); } Double workQty = Math.round((itemServiceOne.getWorkQty() - pakinItem.getAnfme()) * 10000) / 10000.0; Double qty = Math.round((itemServiceOne.getQty() + pakinItem.getAnfme()) * 10000) / 10000.0; Double workQty = Math.round((itemServiceOne.getWorkQty() - pakinItem.getAnfme()) * 1000000) / 1000000.0; Double qty = Math.round((itemServiceOne.getQty() + pakinItem.getAnfme()) * 1000000) / 1000000.0; itemServiceOne.setWorkQty(workQty).setQty(qty); if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>() @@ -1424,7 +1653,7 @@ * @time 2025/4/15 15:28 */ @Transactional(rollbackFor = Exception.class) public void saveLocItem(List<TaskItem> items, Long taskId, Long loginUserId) throws Exception { public synchronized void saveLocItem(List<TaskItem> items, Long taskId, Long loginUserId) { Task task = this.getById(taskId); if (Objects.isNull(task)) { throw new CoolException("任务不存在!!"); @@ -1440,8 +1669,8 @@ LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>() .eq(LocItem::getMatnrId, taskItem.getMatnrId()) .eq(LocItem::getLocId, loc.getId()) .eq(StringUtils.isNoneBlank(taskItem.getBatch()), LocItem::getBatch, taskItem.getBatch()) .eq(StringUtils.isNoneBlank(taskItem.getFieldsIndex()), LocItem::getFieldsIndex, taskItem.getFieldsIndex())); .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItem::getBatch, taskItem.getBatch()) .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItem::getFieldsIndex, taskItem.getFieldsIndex())); if (Objects.isNull(locItem)) { BeanUtils.copyProperties(taskItem, item); item.setLocCode(loc.getCode()) @@ -1450,16 +1679,20 @@ .setUpdateBy(loginUserId) .setWkType(taskItem.getWkType()) .setType(taskItem.getOrderType()); locItems.add(item); if (!locItemService.saveOrUpdate(item)) { throw new CoolException("库位明细更新失败!!"); } } else { locItem.setAnfme(Math.round((locItem.getAnfme() + taskItem.getAnfme()) * 10000) / 10000.0) .setUpdateTime(new Date()); locItems.add(locItem); logger.error("当前票号:" + locItem.getFieldsIndex() + " 已在库内,请检查后再操作!!"); // throw new CoolException("当前票号已在库内,请检查后再操作!!"); // locItem.setAnfme(Math.round((locItem.getAnfme() + taskItem.getAnfme()) * 1000000) / 1000000.0) // .setUpdateTime(new Date()); // if (!locItemService.saveOrUpdate(locItem)) { // throw new CoolException("库位明细更新失败!!"); // } } }); if (!locItemService.saveBatch(locItems)) { throw new CoolException("库位明细更新失败!!"); } } /** @@ -1470,7 +1703,7 @@ * @return */ @Transactional(rollbackFor = Exception.class) public void saveStockItems(List<TaskItem> items, Task task, Long id, String code, Short wkType, String type, Long loginUserId) { public synchronized void saveStockItems(List<TaskItem> items, Task task, Long id, String code, Short wkType, String type, Long loginUserId) { Stock stock = new Stock(); String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_STOCK_CODE, null); if (StringUtils.isBlank(ruleCode)) { rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
@@ -133,7 +133,9 @@ throw new CoolException("当前状态无法下发执行!!"); } List<WaveItem> items = waveItemService.list(new LambdaQueryWrapper<WaveItem>().eq(WaveItem::getWaveId, wave.getId())); List<WaveItem> items = waveItemService.list(new LambdaQueryWrapper<WaveItem>() .le(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) .eq(WaveItem::getWaveId, wave.getId())); if (items.isEmpty()) { throw new CoolException("波次明细不存在!!"); } @@ -203,14 +205,29 @@ throw new CoolException("下发执行异常,请稍候重试!"); } } if (!waveService.update(new LambdaUpdateWrapper<Wave>() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .set(Wave::getWorkQty, taskItems.stream().mapToDouble(TaskItem::getAnfme).sum()) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getMemo, null) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, wave.getId()))) { throw new CoolException("波次状态修改失败!!"); Double sum = taskItems.stream().mapToDouble(TaskItem::getAnfme).sum(); Double v = Math.round((wave.getWorkQty() + sum) * 1000000) / 1000000.0; if (wave.getAnfme().compareTo(v) == 0) { if (!waveService.update(new LambdaUpdateWrapper<Wave>() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .set(Wave::getWorkQty, v) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getMemo, null) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, wave.getId()))) { throw new CoolException("波次状态修改失败!!"); } } else { if (!waveService.update(new LambdaUpdateWrapper<Wave>() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) .set(Wave::getWorkQty, v) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getMemo, null) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, wave.getId()))) { throw new CoolException("波次状态修改失败!!"); } } } rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/LocManageUtil.java
@@ -8,15 +8,12 @@ import com.vincent.rsf.server.manager.controller.dto.OrderOutItemDto; import com.vincent.rsf.server.manager.controller.params.WaveToLocParams; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.enums.ContainerType; import com.vincent.rsf.server.manager.enums.TaskType; import com.vincent.rsf.server.manager.enums.WaveRuleType; import com.vincent.rsf.server.manager.service.*; import com.vincent.rsf.server.manager.enums.LocStsType; import io.swagger.models.auth.In; import org.apache.commons.lang3.StringUtils; import javax.swing.*; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -38,24 +35,24 @@ public static String getTargetLoc(Long areaId, Long containerType) { Long locType = null; if (!Objects.isNull(containerType)) { LocTypeService locService = SpringUtils.getBean(LocTypeService.class); if (containerType.equals(ContainerType.CONTAINER_TYPE_NORMAL.val)) { LocType low = locService.getOne(new LambdaQueryWrapper<LocType>() .eq(LocType::getCode, "L")); if (Objects.isNull(low)) { throw new CoolException("庫位類型不存在!!"); } locType = low.getId(); } else { LocType low = locService.getOne(new LambdaQueryWrapper<LocType>() .eq(LocType::getCode, "H")); if (Objects.isNull(low)) { throw new CoolException("庫位類型不存在!!"); } locType = low.getId(); } } // if (!Objects.isNull(containerType)) { // LocTypeService locService = SpringUtils.getBean(LocTypeService.class); // if (containerType.equals(ContainerType.CONTAINER_TYPE_NORMAL.val)) { // LocType low = locService.getOne(new LambdaQueryWrapper<LocType>() // .eq(LocType::getCode, "L")); // if (Objects.isNull(low)) { // throw new CoolException("庫位類型不存在!!"); // } // locType = low.getId(); // } else { // LocType low = locService.getOne(new LambdaQueryWrapper<LocType>() // .eq(LocType::getCode, "H")); // if (Objects.isNull(low)) { // throw new CoolException("庫位類型不存在!!"); // } // locType = low.getId(); // } // } //TODO 库位策略后续排期 LocService locService = SpringUtils.getBean(LocService.class); Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>() @@ -129,7 +126,12 @@ LambdaQueryWrapper<LocItem> locItemQueryWrapper = new LambdaQueryWrapper<>(); locItemQueryWrapper.eq(LocItem::getMatnrCode, matnrCode); locItemQueryWrapper.eq(StringUtils.isNotEmpty(splrBatch), LocItem::getBatch, splrBatch); locItemQueryWrapper.orderByAsc(LocItem::getCreateTime); //如果批次不为空,按批次先后出库 if (StringUtils.isNotBlank(splrBatch)) { locItemQueryWrapper.orderByAsc(LocItem::getBatch); } else { locItemQueryWrapper.orderByAsc(LocItem::getCreateTime); } String applySql = String.format( "EXISTS (SELECT 1 FROM man_loc ml " + "WHERE ml.use_status = '%s'" + @@ -156,6 +158,8 @@ DeviceSiteService deviceSiteService = SpringUtils.getBean(DeviceSiteService.class); List<OrderOutItemDto> list = new ArrayList<>(); //不让站点重复使用问题 List<BasStation> stations = new ArrayList<>(); Set<ExistDto> existDtos = new HashSet<>(); for (WaveToLocParams item : params) { BigDecimal issued = new BigDecimal(item.getAnfme().toString()) @@ -175,7 +179,6 @@ locItems = LocManageUtil.getFirstInFirstOutItemList(item.getMatnrCode(), item.getBatch(), item.getAnfme()); } } for (LocItem locItem : locItems) { Loc loc = locService.getById(locItem.getLocId()); List<LocItem> itemList = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, locItem.getLocCode())); @@ -184,8 +187,8 @@ if (existDtos.add(existDto)) { locItem.setOutQty(issued.doubleValue() >= locItem.getAnfme() ? locItem.getAnfme() : issued.doubleValue()); locItem.setBarcode(loc.getBarcode()) .setSourceId(item.getWaveId()) .setSource(item.getItemId()); .setSourceId(item.getWaveId())//波次ID .setSource(item.getItemId());//波次明细ID OrderOutItemDto orderOutItemDto = new OrderOutItemDto(); orderOutItemDto.setLocItem(locItem); @@ -203,12 +206,18 @@ maps.add(staListDto); } orderOutItemDto.setStaNos(maps); //默认获取第一站点 DeviceSite deviceSite = deviceSites.stream().findFirst().get(); //获取满足条件站点 Set<String> stationSet = deviceSites.stream().map(DeviceSite::getSite).collect(Collectors.toSet()); //已使用站点 Set<String> stas = stations.stream().map(BasStation::getStationName).collect(Collectors.toSet()); BasStationService basStationService = SpringUtils.getBean(BasStationService.class); BasStation basStation = basStationService.getOne(new LambdaQueryWrapper<BasStation>() .eq(BasStation::getUseStatus, LocStsType.LOC_STS_TYPE_O.type) .in(BasStation::getStationName, stationSet) .notIn(!stas.isEmpty(), BasStation::getStationName, stas) .last("LIMIT 1")); stations.add(basStation); if (Objects.isNull(basStation)) { throw new CoolException("站點不存在!!"); } @@ -217,7 +226,6 @@ orderOutItemDto.setSource(item.getItemId()) .setSourceId(item.getWaveId()); list.add(orderOutItemDto); issued = issued.subtract(new BigDecimal(locItem.getAnfme().toString()));