skyouc
5 天以前 273f2e5d3941b0e720e5eabd7dba9cfc042c3267
出库单生成波次功能开发
17个文件已修改
357 ■■■■■ 已修改文件
rsf-admin/.env 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderList.jsx 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WaveEdit.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WaveItemList.jsx 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/wave/WaveList.jsx 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Wave.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderLogSchedule.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/WaveService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/.env
@@ -1,3 +1,3 @@
VITE_BASE_IP=127.0.0.1
VITE_BASE_IP=192.168.4.50
# VITE_BASE_IP=47.76.147.249
VITE_BASE_PORT=8080
rsf-admin/src/i18n/en.js
@@ -837,6 +837,7 @@
                type: "type",
                exceStatus: "exceStatus",
                anfme: "anfme",
                groupQty: 'Group Qty',
                qty: "qty",
                orderNum: "orderNum",
            },
@@ -1146,6 +1147,8 @@
        selectSite: 'Select Site',
        top: "top",
        resort: "sort",
        start: 'Start',
        pause: 'Pause',
        subzone: 'subzone',
        bindmatnr: 'bind matnr',
        bindloc: 'bind loc',
@@ -1160,6 +1163,7 @@
        orderPrint: 'Orders Print',
        quality: "quality",
        complete: "complete",
        allComfirm: 'All Comfirm',
        verifyComfirm: 'Verify Comfirm',
        close: "close",
        asnCreate: "Create By Order",
@@ -1170,6 +1174,8 @@
        createWave: "Create Wave",
        order: 'Orders',
        modiftySite: 'Modify SiteNo',
        selectWave: 'Select Wave Rule',
    },
    request: {
        error: {
rsf-admin/src/i18n/zh.js
@@ -867,6 +867,7 @@
                type: "单据类型",
                exceStatus: "状态",
                anfme: "数量",
                groupQty: '品类数',
                qty: "完成数量",
                orderNum: "单据数",
            },
@@ -1140,6 +1141,8 @@
        continue: '继续收货',
        batch: '批量操作',
        confirm: '确认',
        start: '开始下发',
        pause: '暂停',
        pick: '拣料',
        check: '盘点',
        bulkExport: "批量导出",
@@ -1163,6 +1166,7 @@
        batchLocType: "批量库位类型",
        batchPrint: "批量打印",
        verifyComfirm: '审核确认',
        allComfirm: '全部提交',
        quality: "质检",
        complete: "完结",
        close: "关闭",
@@ -1174,6 +1178,7 @@
        createWave: "生成波次",
        recover: "继续收货",
        modiftySite: '修改库口',
        selectWave: '波次规则',
    },
    request: {
        error: {
rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -39,26 +39,27 @@
  useUnselectAll,
  useRecordSelection,
} from 'react-admin';
import { Box, Typography, Card, Stack, Drawer } from '@mui/material';
import { styled } from '@mui/material/styles';
import MyCreateButton from "../../components/MyCreateButton";
import BillStatusField from '../../components/BillStatusField';
import ConfirmButton from '../../components/ConfirmButton';
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import EditIcon from '@mui/icons-material/Edit';
import request from '@/utils/request';
import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
import { Box, Typography, Card, Stack, Drawer } from '@mui/material';
import DictionarySelect from "../../components/DictionarySelect";
import BillStatusField from '../../components/BillStatusField';
import MyCreateButton from "../../components/MyCreateButton";
import PageEditDrawer from "../../components/PageEditDrawer";
import ConfirmButton from '../../components/ConfirmButton';
import ImportButton from "../../components/ImportButton";
import DetailsIcon from '@mui/icons-material/Details';
import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
import AddIcon from '@mui/icons-material/Add';
import OutOrderModal from "./OutOrderModal";
import AddTaskIcon from '@mui/icons-material/AddTask';
import PublicIcon from '@mui/icons-material/Public';
import SelectMatnrModal from "./SelectMatnrModal";
import AddTaskIcon from '@mui/icons-material/AddTask';
import PageEditDrawer from "../../components/PageEditDrawer";
import OutStockPublic from "./OutStockPublic";
import EditIcon from '@mui/icons-material/Edit';
import OutOrderPreview from "./OutOrderPreview";
import AddIcon from '@mui/icons-material/Add';
import OutStockPublic from "./OutStockPublic";
import OutOrderModal from "./OutOrderModal";
import request from '@/utils/request';
import OutStockWaveDialog from "./OutStockWaveDialog";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
  '& .css-1vooibu-MuiSvgIcon-root': {
@@ -109,19 +110,38 @@
    dictTypeCode="sys_asn_exce_status"
    alwaysOn
  />,
]
const OutOrderList = (props) => {
  const translate = useTranslate();
  const refresh = useRefresh();
  const [createDialog, setCreateDialog] = useState(false);
  const [manualDialog, setManualDialog] = useState(false);
  const [selectIds, setSelectIds] = useState([]);
  const [preview, setPreview] = useState(false);
  const [waveRule, setWaveRule] = useState(false);
  const [drawerVal, setDrawerVal] = useState(false);
  const [modalType, setmodalType] = useState(0);
  const [select, setSelect] = useState(0);
  const billReload = useRef();
  const dicts = JSON.parse(localStorage.getItem('sys_dicts'))?.filter(dict => (dict.dictTypeCode == 'sys_business_type')) || [];
  //获取波次规则
  const closeDialog = async (value) => {
    setWaveRule(false)
    refresh()
    console.log('=====>');
    console.log(value);
    console.log(selectIds);
    // const res = await request.post(`/outStock/generate/wave`, { ids: selectIds });
    // if (res?.data?.code === 200) {
    //   notify(res.data.msg);
    // } else {
    //   notify(res.data.msg);
    // }
  }
  return (
    <Box display="flex">
      <List
@@ -152,7 +172,7 @@
        <StyledDatagrid
          sx={{ width: '100%' }}
          preferenceKey='outStock'
          bulkActionButtons={<PublicTaskButton />}
          bulkActionButtons={<PublicTaskButton setWaveRule={setWaveRule} setSelectIds={setSelectIds} />}
          rowClick={false}
          expandSingle={true}
          omit={['id', 'createTime', 'createBy', 'memo', 'rleStatus$']}
@@ -194,9 +214,10 @@
      <OutOrderModal
        open={createDialog}
        setOpen={setCreateDialog}
        preview={preview}
        preview={preview}
        setPreview={setPreview}
      />
      <OutStockWaveDialog open={waveRule} setOpen={setWaveRule} onClose={closeDialog} />
      <OutOrderPreview open={preview} setOpen={setPreview} />
      <PageEditDrawer
        title={"toolbar.publicWorking"}
@@ -211,24 +232,16 @@
export default OutOrderList;
const PublicTaskButton = () => {
const PublicTaskButton = ({ setWaveRule, setSelectIds }) => {
  const record = useRecordContext();
  const { selectedIds, onUnselectItems } = useListContext();
  const notify = useNotify();
  const refresh = useRefresh();
  const redirect = useRedirect();
  const pubClick = async (event) => {
    event.stopPropagation();
  const pubClick = async () => {
    onUnselectItems();
    const res = await request.post(`/outStock/generate/wave`, { ids: selectedIds });
    if (res?.data?.code === 200) {
      notify(res.data.msg);
      redirect("/wave")
    } else {
      notify(res.data.msg);
    }
    refresh();
    setWaveRule(true);
    setSelectIds(selectedIds)
  }
  return (
@@ -236,7 +249,8 @@
      onClick={pubClick}
      label={"toolbar.createWave"}
      startIcon={<PublicIcon />}
    />);
    />
  );
}
const MyButton = ({ setCreateDialog, setmodalType }) => {
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
@@ -58,9 +58,11 @@
    '& .column-maktx': {
        width: 200
    },
    '& .RaBulkActionsToolbar-toolbar': {
        display: 'none'
    }
    mt: '60px'
    // '& .RaBulkActionsToolbar-toolbar': {
    //     display: 'none'
    // }
}));
@@ -88,19 +90,20 @@
    }, [selectedMatnr])
    const handleRowClick = (id, resource, record) => {
        setRowSelectedIds(prev =>
            prev.includes(id)
                ? prev.filter(item => item !== id)  // 取消选择
                : [...prev, id]                     // 添加选择
        );
    const ComfirmButton = () => {
        const { selectedIds, data } = useListContext();
        const handleRowClick = () => {
            const ids = data.filter(item => selectedIds.includes(item.id)).map(item => item.id);
            setRowSelectedIds(ids);
            const mas = data.filter(item => selectedIds.includes(item.id)).map(item => item.matnrCode);
            //设置库位信息筛选条件
            setSelectedMatnr(mas);
        }
        //设置库位信息筛选条件
        setSelectedMatnr(prev =>
            prev.includes(record?.matnrCode)
                ? prev.filter(item => item !== record?.matnrCode)  // 取消选择
                : [...prev, record?.matnrCode]                     // 添加选择
        );
        return (
            <Button label="toolbar.confirm" size="medium" onClick={handleRowClick} />
        )
    };
    const handleClickOpen = () => {
@@ -191,6 +194,7 @@
                                filter={{ asnId: record?.id, deleted: 0 }}
                                sort={{ field: "create_time", order: "desc" }}
                                actions={false}
                                pagination={false}
                                perPage={DEFAULT_ITEM_PAGE_SIZE}
                            >
                                <LinearProgress
@@ -199,9 +203,9 @@
                                <StyledDatagrid
                                    storeKey={"outStockPublic"}
                                    preferenceKey='outStockItem'
                                    bulkActionButtons={<></>}
                                    rowClick={handleRowClick}
                                    selectedIds={rowSelectedIds}
                                    bulkActionButtons={<>
                                        <ComfirmButton />
                                    </>}
                                    omit={['id', 'splrName', 'qty', 'poCode',]}
                                >
                                    <NumberField source="id" />
@@ -269,7 +273,8 @@
        { field: 'batch', headerName: '批次', width: 90 },
        { field: 'unit', headerName: '单位', width: 60 },
        { field: 'outQty', headerName: '出库数量', width: 110, },
        { field: 'anfme', headerName: '库存数量', width: 110,
        {
            field: 'anfme', headerName: '库存数量', width: 110,
            renderCell: (params) => (
                <OutStockAnfme value={params.value} />
            )
@@ -449,11 +454,10 @@
    }
    return (
        <ConfirmButton
            label="toolbar.confirm"
            label="toolbar.allComfirm"
            variant="contained"
            size="medium"
            onConfirm={submit}
            startIcon={<ConfirmationNumberOutlinedIcon />}
        />
    )
}
rsf-admin/src/page/orders/wave/WaveEdit.jsx
@@ -55,7 +55,7 @@
                <SimpleForm
                    shouldUnregister
                    warnWhenUnsavedChanges
                    toolbar={<FormToolbar />}
                    toolbar={false}
                    mode="onTouched"
                    defaultValues={{}}
                // validate={(values) => { }}
@@ -143,3 +143,5 @@
}
export default WaveEdit;
rsf-admin/src/page/orders/wave/WaveItemList.jsx
@@ -46,7 +46,8 @@
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import ContentCreate from '@mui/icons-material/Create';
import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined';
import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
@@ -72,10 +73,7 @@
    <TextInput source="matnrCode" label="table.field.waveItem.matnrCode" />,
    <TextInput source="batch" label="table.field.waveItem.batch" />,
    <TextInput source="splrBatch" label="table.field.waveItem.splrBatch" />,
    <TextInput source="orderCode" label="table.field.waveItem.orderCode" />,
    <NumberInput source="orderItemId" label="table.field.waveItem.orderItemId" />,
    <TextInput source="unit" label="table.field.waveItem.unit" />,
    <TextInput source="trackCode" label="table.field.waveItem.trackCode" />,
    <TextInput source="fieldsIndex" label="table.field.waveItem.fieldsIndex" />,
    <NumberInput source="anfme" label="table.field.waveItem.anfme" />,
    <NumberInput source="workQty" label="table.field.waveItem.workQty" />,
@@ -125,27 +123,29 @@
            >
                <StyledDatagrid
                    preferenceKey='waveItem'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    bulkActionButtons= {
                        <>
                            <BulkStartButton />
                            <BulkPauseButton />
                        </>
                    }
                    rowClick={(id, resource, record) => false}
                    expand={false}
                    expandSingle={false}
                    omit={['id', 'createTime', 'matnrId', 'waveId', 'batch', 'orderItemId', 'batch', 'fieldsIndex', 'createBy', 'memo']}
                    omit={['id', 'createTime', 'matnrId', 'waveId', 'batch', 'orderItemId', 'fieldsIndex', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
                    <NumberField source="waveId" label="table.field.waveItem.waveId" />
                    <TextField source="waveCode" label="table.field.waveItem.waveCode" />
                    <NumberField source="matnrId" label="table.field.waveItem.matnrId" />
                    <TextField source="maktx" label="table.field.waveItem.matnrName" />
                    <TextField source="matnrCode" label="table.field.waveItem.matnrCode" />
                    <TextField source="maktx" label="table.field.waveItem.matnrName" />
                    <TextField source="batch" label="table.field.waveItem.batch" />
                    <TextField source="splrBatch" label="table.field.waveItem.splrBatch" />
                    <TextField source="orderCode" label="table.field.waveItem.orderCode" />
                    <NumberField source="orderItemId" label="table.field.waveItem.orderItemId" />
                    <TextField source="unit" label="table.field.waveItem.unit" />
                    <TextField source="trackCode" label="table.field.waveItem.trackCode" />
                    <TextField source="fieldsIndex" label="table.field.waveItem.fieldsIndex" />
                    <NumberField source="anfme" label="table.field.waveItem.anfme" />
                    <TextField source="fieldsIndex" label="table.field.waveItem.fieldsIndex" />
                    <NumberField source="workQty" label="table.field.waveItem.workQty" />
                    <TextField source="unit" label="table.field.waveItem.unit" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy" />
@@ -182,8 +182,30 @@
    }
    return (
        <Button  label="ra.action.edit" onClick={editClick} startIcon={<ContentCreate />}/>
        <Button label="ra.action.edit" onClick={editClick} startIcon={<ContentCreate />} />
    )
}
const BulkStartButton = () => {
    const { data, selectedIds, onUnselectItems } = useListContext();
    const startClick = () => {
        onUnselectItems()
    }
    return (
        <Button label="toolbar.start" onClick={startClick} startIcon={<PlayArrowOutlinedIcon />} variant="outlined" />
    )
}
const BulkPauseButton = () => {
    const { data, selectedIds, onUnselectItems } = useListContext();
    const pauseClick = () => {
        onUnselectItems()
    }
    return (
        <Button label="toolbar.pause" onClick={pauseClick} startIcon={<PauseCircleOutlineIcon />} variant="outlined" />
    )
}
rsf-admin/src/page/orders/wave/WaveList.jsx
@@ -35,21 +35,15 @@
    useRedirect,
    Button,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import WaveCreate from "./WaveCreate";
import WavePanel from "./WavePanel";
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import request from '@/utils/request';
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import { Box, Typography, Card, Stack } from '@mui/material';
import ConfirmButton from "../../components/ConfirmButton";
import PageDrawer from "../../components/PageDrawer";
import PublicIcon from '@mui/icons-material/Public';
import ItemToTaskModal from "./ItemToTaskModal";
import ConfirmButton from "../../components/ConfirmButton";
import { styled } from '@mui/material/styles';
import request from '@/utils/request';
import WaveCreate from "./WaveCreate";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
@@ -143,6 +137,7 @@
                    <TextField source="type$" label="table.field.wave.type" sortable={false} />
                    <TextField source="exceStatus$" label="table.field.wave.exceStatus" sortable={false} />
                    <NumberField source="anfme" label="table.field.wave.anfme" />
                    <NumberField source="groupQty" label="table.field.wave.groupQty" />
                    <NumberField source="qty" label="table.field.wave.qty" />
                    <NumberField source="orderNum" label="table.field.wave.orderNum" />
                    <TextField source="updateBy$" label="common.field.updateBy" />
@@ -153,8 +148,7 @@
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <PublicTaskButton setSelectIds={setSelectIds} setDetailDialog={setDetailDialog} />
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                        <EditButton label="toolbar.detail" sx={{ padding: '1px', fontSize: '.75rem' }} />
                    </WrapperField>
                </StyledDatagrid>
            </List>
@@ -184,12 +178,12 @@
    const notify = useNotify();
    const refresh = useRefresh();
    const redirect = useRedirect();
    const pubClick = async (event) => {
        setSelectIds(record);
        setDetailDialog(true);
    }
    return (
        record?.exceStatus == 0 ? <ConfirmButton label={"toolbar.createTask"} startIcon={<PublicIcon /> } onConfirm={pubClick} size='small' /> : <></>
        record?.exceStatus == 0 ? <ConfirmButton label={"toolbar.createTask"} startIcon={<PublicIcon />} onConfirm={pubClick} size='small' /> : <></>
    );
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java
@@ -294,10 +294,14 @@
        if (Objects.isNull(params.get("outId"))) {
            return R.error("出库参数不能为空!!");
        }
        List<OutStockToTaskParams> taskParams = JSONArray.parseArray(JSONArray.toJSONString(params.get("items")), OutStockToTaskParams.class);
        return  outStockService.genOutStockTask(taskParams, getLoginUserId(), Long.parseLong(params.get("outId").toString()));
        List<OutStockToTaskParams> tasks = new ArrayList<>();
        for (OutStockToTaskParams taskParam : taskParams) {
            if (StringUtils.isNotBlank(taskParam.getLocCode())) {
                tasks.add(taskParam);
            }
        }
        return  outStockService.genOutStockTask(tasks, getLoginUserId(), Long.parseLong(params.get("outId").toString()));
    }
    /**
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
@@ -92,14 +92,12 @@
        if (Objects.isNull(ids)) {
            throw new CoolException("参数不能为空!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getSourceId, ids));
        if (taskItems.isEmpty()) {
        List<Long> list = Arrays.asList(ids);
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getSourceId, list));
        if (!taskItems.isEmpty()) {
            throw new CoolException("有未完成任务,不可执行删除操作!!");
        }
        if (!waveService.removeByIds(Arrays.asList(ids))) {
            return R.error("Delete Fail");
        }
        return R.ok("Delete Success").add(ids);
        return waveService.cancelWave(list);
    }
    @PreAuthorize("hasAuthority('manager:wave:list')")
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Wave.java
@@ -80,6 +80,9 @@
    @ApiModelProperty(value= "单据数量")
    private Integer orderNum;
    @ApiModelProperty("品类数量")
    private Integer groupQty;
    /**
     * 状态 1: 正常  0: 禁用  
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java
@@ -28,9 +28,11 @@
    OUT_STOCK_STATUS_TASK_EXCE("11", "待处理"),
    OUT_STOCK_STATUS_TASK_WAVE("11", "生成波次"),
    OUT_STOCK_STATUS_TASK_CREATE("13", "生成工作档"),
    OUT_STOCK_STATUS_TASK_WORKING("14", "作业中")
    OUT_STOCK_STATUS_TASK_WORKING("14", "作业中"),
    OUT_STOCK_STATUS_TASK_DONE("15", "已完成")
            ;
    ;
    AsnExceStatus(String val, String desc) {
        this.val = Short.parseShort(val);
        this.desc = desc;
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/AsnOrderLogSchedule.java
@@ -7,6 +7,7 @@
import com.vincent.rsf.server.manager.entity.AsnOrderItemLog;
import com.vincent.rsf.server.manager.entity.AsnOrderLog;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
import com.vincent.rsf.server.manager.enums.OrderType;
import com.vincent.rsf.server.manager.service.AsnOrderItemLogService;
import com.vincent.rsf.server.manager.service.AsnOrderItemService;
import com.vincent.rsf.server.manager.service.AsnOrderLogService;
@@ -19,7 +20,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -54,10 +54,45 @@
    @Scheduled(cron = "0 0/05 * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    public void moveOrderToLog() {
        List<AsnOrder> asnOrders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_TASK_DONE.val));
        List<AsnOrder> asnOrders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>()
                        .eq(AsnOrder::getType, OrderType.ORDER_IN.type)
                .eq(AsnOrder::getExceStatus, AsnExceStatus.ASN_EXCE_STATUS_TASK_DONE.val));
        if (asnOrders.isEmpty()) {
            return;
        }
        moveOrderToLog(asnOrders, OrderType.ORDER_IN.type);
    }
    /**
    * @author Ryan
    * @description 出库单完成后,状态修改
    * @param
    * @return
    * @time 2025/6/16 08:35
    */
    @Scheduled(cron = "0/30 * * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    public void outStockComplete() {
        List<AsnOrder> asnOrders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>()
                        .eq(AsnOrder::getType, OrderType.ORDER_OUT.type)
                .apply("anfme=work_qty")
        );
        if (asnOrders.isEmpty()) {
            return;
        }
        moveOrderToLog(asnOrders, OrderType.ORDER_OUT.type);
    }
    /**
     * @param
     * @param type
     * @return
     * @author Ryan
     * @description 添加历史单据
     * @time 2025/6/16 08:56
     */
    private void moveOrderToLog(List<AsnOrder> asnOrders, String type) {
        Set<Long> longSet = asnOrders.stream().map(AsnOrder::getId).collect(Collectors.toSet());
        List<AsnOrderItem> orderItems = asnOrderItemService.list(new LambdaQueryWrapper<AsnOrderItem>().in(AsnOrderItem::getAsnId, longSet));
        if (orderItems.isEmpty()) {
@@ -66,6 +101,10 @@
        for (AsnOrder order : asnOrders) {
            AsnOrderLog orderLog = new AsnOrderLog();
            if (type.equals(OrderType.ORDER_OUT.type)) {
                order.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_TASK_DONE.val);
                order.setQty(order.getWorkQty());
            }
            BeanUtils.copyProperties(order, orderLog);
            orderLog.setId(null);
            orderLog.setAsnId(order.getId());
@@ -86,7 +125,7 @@
            });
            if (!asnOrderItemLogService.saveBatch(logs)) {
                throw new CoolException("通知单明细历史档保存失败!!");
                throw new CoolException("单据明细历史档保存失败!!");
            }
        }
@@ -97,4 +136,6 @@
            throw new CoolException("原单据删除失败!!");
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/WaveService.java
@@ -28,4 +28,13 @@
     * @time 2025/4/27 11:08
     */
    List<WaveItem> mergeWavePreview(Long waveId);
    /**
    * @author Ryan
    * @description 取消波次,修改订单信息
    * @param
    * @return
    * @time 2025/6/17 10:03
    */
    R cancelWave(List<Long> ids);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -279,13 +279,13 @@
        if (Objects.isNull(ids) || ids.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        List<AsnOrder> orders = this.list(new LambdaQueryWrapper<AsnOrder>()
                .in(AsnOrder::getId, ids)
                .eq(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val));
        List<AsnOrder> orders = this.list(new LambdaQueryWrapper<AsnOrder>().in(AsnOrder::getId, ids));
        if (orders.isEmpty()) {
            throw new CoolException("当前单据状态不能执行波次生成操作!!");
        }
        double sum = orders.stream().mapToDouble(AsnOrder::getAnfme).sum();
        Double sum = orders.stream().mapToDouble(AsnOrder::getAnfme).sum();
        Double workQty = orders.stream().mapToDouble(AsnOrder::getWorkQty).sum();
        Double anfme = Math.round((sum - workQty) * 10000) / 10000.0;
        Wave wave = new Wave();
        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_WAVE_TYPE, null);
        if (Objects.isNull(ruleCode) || StringUtils.isBlank(ruleCode)) {
@@ -295,7 +295,7 @@
                .setType(Short.parseShort("1"))
                .setCode(ruleCode)
                .setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_INIT.val)
                .setAnfme(sum);
                .setAnfme(anfme);
        if (!waveService.save(wave)) {
            throw new CoolException("波次保存失败!!");
        }
@@ -306,13 +306,13 @@
        if (orderItems.isEmpty()) {
            throw new CoolException("单据不存在!!");
        }
        //合并物料,生成波次明细
        List<WaveItem> waveItems = mergeWave(orderItems, wave);
        if (!waveItemService.saveBatch(waveItems)) {
            throw new CoolException("波次明细保存失败!!");
        }
        double sum1 = waveItems.stream().mapToDouble(WaveItem::getAnfme).sum();
        wave.setAnfme(sum1);
        wave.setAnfme(sum1).setGroupQty(waveItems.size());
        if (!waveService.saveOrUpdate(wave)) {
            throw new CoolException("主单修改失败!!");
        }
@@ -325,14 +325,17 @@
            throw new CoolException("出库单执行数量修改失败!!");
        }
        double sum2 = orderItems.stream().mapToDouble(AsnOrderItem::getWorkQty).sum();
        if (!this.update(new LambdaUpdateWrapper<AsnOrder>()
                .set(AsnOrder::getWaveId, wave.getId())
                .set(AsnOrder::getWorkQty, sum2)
                .set(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WAVE.val)
                .in(AsnOrder::getId, ids))) {
            throw new CoolException("执行状态修改修改失败!!");
        for (AsnOrder order : orders) {
            Double wkQty = Math.round((order.getWorkQty() + order.getAnfme()) * 10000) / 10000.0;
            if (!this.update(new LambdaUpdateWrapper<AsnOrder>()
                    .set(AsnOrder::getWaveId, wave.getId())
                    .set(AsnOrder::getWorkQty, wkQty)
                    .set(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WAVE.val)
                    .in(AsnOrder::getId, ids))) {
                throw new CoolException("执行状态修改修改失败!!");
            }
        }
        return R.ok("操作完成!!");
    }
@@ -442,12 +445,14 @@
            throw new CoolException("参数不能为空!!");
        }
        //优先生成浅库位任务
        List<OutStockToTaskParams> Items = params.stream().sorted(Comparator.comparing(OutStockToTaskParams::getLocCode).thenComparing(item -> {
        List<OutStockToTaskParams> Items = params.stream()
                .sorted(Comparator.comparing(OutStockToTaskParams::getLocCode)
                        .thenComparing(item -> {
            return LocUtils.isShallowLoc(item.getLocCode()) ? 1 : 0;
        }).reversed()).collect(Collectors.toList());
        for (OutStockToTaskParams param : Items) {
            if (Objects.isNull(param)) {
            if (Objects.isNull(param) || StringUtils.isBlank(param.getLocCode())) {
                continue;
            }
            Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, param.getLocCode()).eq(Loc::getBarcode, param.getBarcode()));
@@ -697,12 +702,11 @@
    private List<WaveItem> mergeWave(List<AsnOrderItem> orderItems, Wave wave) {
        List<WaveItem> items = new ArrayList<>();
        orderItems.forEach(order -> {
            Double anfme = Math.round((order.getAnfme() - order.getWorkQty()) * 10000) / 10000.0;
            WaveItem item = new WaveItem();
            BeanUtils.copyProperties(order, item);
            item.setOrderItemId(order.getId())
                    .setId(null)
                    .setOrderCode(order.getAsnCode())
                    .setOrderId(order.getAsnId())
                item.setId(null)
                    .setAnfme(anfme)
                    .setMatnrId(order.getMatnrId())
                    .setMaktx(order.getMaktx())
                    .setWaveId(wave.getId())
@@ -735,7 +739,7 @@
                        p1.getUpdateBy(),
                        p1.getMemo()
                ),
                WaveItem::getSplrBatch, WaveItem::getMatnrCode, WaveItem::getFieldsIndex
                WaveItem::getSplrBatch, WaveItem::getMatnrId, WaveItem::getFieldsIndex
        );
        return waveItems;
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -1047,7 +1047,6 @@
                    if (Objects.isNull(orderItem)) {
                        throw new CoolException("单据明细不存在!!");
                    }
                    try {
                        saveOutStockItem(maps.get(key), orderItem, null, loginUserId);
                    } catch (Exception e) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
@@ -43,6 +43,8 @@
    private LocItemService locItemService;
    @Autowired
    private LocService locService;
    @Autowired
    private OutStockService outStockService;
    /**
     * @param
@@ -239,6 +241,20 @@
    }
    /**
    * @author Ryan
    * @description 取消波次
    * @param
    * @return
    * @time 2025/6/17 10:04
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R cancelWave(List<Long> ids) {
        return null;
    }
    /**
     * @param
     * @param waveItems
     * @return