12个文件已修改
2个文件已添加
488 ■■■■ 已修改文件
rsf-admin/src/i18n/en.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderList.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/DeliveryItemController.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockItemController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js
@@ -79,6 +79,8 @@
                result: 'Contacts import complete. Imported %{success} success, with %{error} errors',
            },
            loadMore: 'Load More Data',
            updateSucc: 'Update Success',
            updateFaild: 'Update Failed',
            complete: 'Complete',
            deprecate: 'Deprecate',
            stockError: 'Empty',
rsf-admin/src/i18n/zh.js
@@ -81,6 +81,8 @@
                result: '导入完成。已导入 %{success} 成功, 和 %{error} 失败',
            },
            loadMore: '加载更多',
            updateSucc: '更新成功',
            updateFaild: '更新失败',
            complete: '完成',
            deprecate: '废弃',
            stockError: '没有库存',
@@ -673,7 +675,7 @@
                platOrderCode: '客单号',
                anfme: "计划出库数",
                stockUnit: "库存单位",
                workQty: '执行数',
                workQty: '已出数量',
                purQty: "下单数量",
                purUnit: "单位",
                qty: "完成数量",
rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -37,6 +37,7 @@
  Button,
  useRedirect,
  useUnselectAll,
  useRecordSelection,
} from 'react-admin';
import { Box, Typography, Card, Stack, Drawer } from '@mui/material';
import { styled } from '@mui/material/styles';
@@ -57,6 +58,7 @@
import AddTaskIcon from '@mui/icons-material/AddTask';
import PageEditDrawer from "../../components/PageEditDrawer";
import OutStockPublic from "./OutStockPublic";
import OutOrderPreview from "./OutOrderPreview";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
  '& .css-1vooibu-MuiSvgIcon-root': {
@@ -114,6 +116,7 @@
  const translate = useTranslate();
  const [createDialog, setCreateDialog] = useState(false);
  const [manualDialog, setManualDialog] = useState(false);
  const [preview, setPreview] = useState(false);
  const [drawerVal, setDrawerVal] = useState(false);
  const [modalType, setmodalType] = useState(0);
  const [select, setSelect] = useState(0);
@@ -191,13 +194,16 @@
      <OutOrderModal
        open={createDialog}
        setOpen={setCreateDialog}
        preview={preview}
        setPreview={setPreview}
      />
      <OutOrderPreview open={preview} setOpen={setPreview} />
      <PageEditDrawer
        title={"toolbar.publicWorking"}
        drawerVal={drawerVal}
        setDrawerVal={setDrawerVal}
      >
        <OutStockPublic record={select} open={drawerVal} setOpen={setDrawerVal}/>
        <OutStockPublic record={select} open={drawerVal} setOpen={setDrawerVal} />
      </PageEditDrawer>
    </Box >
  )
@@ -257,7 +263,6 @@
  const record = useRecordContext();
  const notify = useNotify();
  const refresh = useRefresh();
  const createByOrder = async (event) => {
    event.stopPropagation();
    setCreateDialog(true);
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
@@ -46,6 +46,8 @@
import request from '@/utils/request';
import SaveIcon from '@mui/icons-material/Save';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import EditableTextField from "../../components/EditableTextField";
import OutOrderPreview from "./OutOrderPreview";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -90,9 +92,11 @@
]
const OutOrderModal = (props) => {
    const { open, setOpen, record } = props;
    const { open, setOpen, preview, setPreview, record } = props;
    const translate = useTranslate();
    const [params, setParams] = useState({});
    const [select, setSelect] = useState([]);
    const [drawerVal, setDrawerVal] = useState(false);
    const refresh = useRefresh();
@@ -221,11 +225,11 @@
                                />
                                <StyledDatagrid
                                    preferenceKey='deliveryItem'
                                    bulkActionButtons={<AddOutStockButton setOpen={setOpen} />}
                                    bulkActionButtons={<AddOutStockButton setOpen={setOpen} setPreview={setPreview} setSelect={setSelect} />}
                                    rowClick={(id, resource, record) => false}
                                    expand={false}
                                    expandSingle={true}
                                    omit={['id', 'createTime', 'createBy', 'memo', 'workQty', 'startTime', 'endTime', 'updateBy', 'createTime']}
                                    omit={['id', 'createTime', 'createBy', 'memo', 'startTime', 'endTime', 'updateBy', 'createTime']}
                                >
                                    <NumberField source="id" />
                                    <TextField source="deliveryCode" label="table.field.deliveryItem.deliveryCode" />
@@ -233,6 +237,7 @@
                                    <TextField source="maktx" label="table.field.deliveryItem.matnrName" />
                                    <TextField source="unit" label="table.field.deliveryItem.unit" />
                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" />
                                    <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                                    <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                                    <TextField source="updateBy$" label="common.field.updateBy" />
@@ -247,6 +252,9 @@
                    </Grid>
                </DialogContent>
            </Grid>
            <Grid>
                <OutOrderPreview open={preview} setOpen={setPreview} selectedIds={select} />
            </Grid>
        </Dialog >
    )
}
@@ -254,20 +262,15 @@
export default OutOrderModal;
const AddOutStockButton = (props) => {
    const { setOpen } = props;
    const { setOpen, setPreview, setSelect } = props;
    const { selectedIds, onUnselectItems } = useListContext();
    const notify = useNotify();
    const refresh = useRefresh();
    const confirm = async (event) => {
        const res = await request.post(`/outStock/generate/orders`, { ids: selectedIds });
        if (res?.data?.code === 200) {
            notify(res.data.msg);
        } else {
            notify(res.data.msg);
        }
        refresh();
        setPreview(true)
        setSelect(selectedIds);
        onUnselectItems();
        setOpen(false);
        // refresh();
    }
    return (
rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx
New file
@@ -0,0 +1,139 @@
import { Dialog, DialogActions, DialogContent, DialogTitle, Box, LinearProgress, Grid, } from "@mui/material";
import React, { useState, useRef, useEffect, useMemo, memo } from "react";
import {
    Toolbar,
    Button,
    useTranslate,
    useNotify,
    useRefresh,
    useGetList,
} from 'react-admin';
import request from '@/utils/request';
import { styled } from '@mui/material/styles';
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import { DataGrid, useGridApiContext, GridActionsCellItem, useGridApiRef } from '@mui/x-data-grid';
import DialogCloseButton from "../../components/DialogCloseButton";
const OutOrderPreview = (props) => {
    const { open, setOpen, record, selectedIds } = props;
    const translate = useTranslate();
    const gridRef = useGridApiRef();
    const [rows, setRows] = useState([]);
    const notify = useNotify();
    const refresh = useRefresh();
    const handleClose = async (event, reason) => {
        if (reason !== "backdropClick") {
            // const res = await request.get(`/outStock/items/cancel/` + selectedIds);
            setOpen(false);
        }
    };
    if (!selectedIds) { return }
    const { data, isLoading, error } = useGetList('/deliveryItem/edit', {
        pagination: { page: 1, perPage: 1000 },
        filter: { deleted: 0, ids: selectedIds }
    });
    return (
        <Dialog
            open={open}
            onClose={handleClose}
            aria-labelledby="form-dialog-title"
            aria-hidden
            fullWidth
            maxWidth="lg"
        >
            <DialogTitle id="form-dialog-title" sx={{
                position: 'sticky',
                top: 0,
                backgroundColor: 'background.paper',
                zIndex: 1000
            }}>
                {translate('create.title')}
                <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                    <DialogCloseButton onClose={handleClose} />
                </Box>
            </DialogTitle>
            <DialogContent>
                <Grid container xl={12}>
                    <Grid item xl={12}>
                        <Box display="flex" sx={{ height: 400, width: '100%', '& .RaConfigurable-root': { width: '100%' } }}>
                            <LinearProgress sx={{ height: "2px", position: 'absolute', top: 0, left: 0, right: 0, }} />
                            <OrderPreview rows={data} gridRef={gridRef} />
                        </Box >
                    </Grid>
                </Grid>
                <Toolbar sx={{ justifyContent: 'end' }}>
                    <ConfirmButton label="toolbar.confirm" variant="contained" size="large" gridRef={gridRef} setOpen={setOpen} />
                </Toolbar>
            </DialogContent>
        </Dialog>
    )
}
export default OutOrderPreview;
const ConfirmButton = ({ gridRef, setOpen }) => {
    const refresh = useRefresh();
    const notify = useNotify();
    const confirm = async () => {
        const items = gridRef.current?.getSortedRows();
        const { data: { code, msg } } = await request.post(`/outStock/generate/orders`, { ids: items });
        if (code === 200) {
            notify(msg);
            refresh()
            setOpen(false)
        } else {
            notify(msg);
        }
    }
    return (
        <Button label="toolbar.confirm" variant="contained" size="large" onClick={confirm} />
    )
}
const OrderPreview = ({ rows, gridRef }) => {
    gridRef.current = useGridApiRef();
    const columns = [
        { field: 'matnrCode', headerName: '物料编码', width: 110 },
        { field: 'maktx', headerName: '物料名称', width: 190 },
        {
            field: 'anfme', headerName: '出库数量', width: 110, type: 'number', editable: true,
            valueGetter: (value, row) => {
                return row.anfme - row.workQty - row.qty;
            },
        },
        {
            field: 'workQty', headerName: '剩余数量', width: 110, type: 'number',
            valueGetter: (value, row) => {
                return row.anfme - row.workQty - row.qty;
            },
        },
        { field: 'unit', headerName: '单位', width: 110 },
        { field: 'splrBatch', headerName: '批次', width: 110 },
        { field: 'splrName', headerName: '供应商', width: 110 },
        { field: 'updateTime', headerName: '更新时间', width: 110 },
        { field: 'updateBy$', headerName: '更新人员', width: 110 },
    ]
    return (
        <DataGrid
            storeKey={"outOrderItemPreview"}
            rows={rows}
            columns={columns}
            apiRef={gridRef}
            disableRowSelectionOnClick
            hideFooterPagination={true}  // 隐藏分页控件
            hideFooter={true}
            onRowSelectionModelChange={(ids) => {
                setSelectedIds(ids)
            }}
        />
    )
}
rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
@@ -69,14 +69,39 @@
    const notify = useNotify();
    const gridRef = useGridApiRef();
    const [rows, setRows] = useState([]);
    const [fetchRows, setFetchRows] = useState([]);
    const translate = useTranslate();
    const [rowSelectedIds, setRowSelectedIds] = useState([]);
    const [selectedMatnr, setSelectedMatnr] = useState([]);
    const [selectedIds, setSelectedIds] = useState([]);
    const [formData, setFormData] = useState({
        orderId: record?.id,
        waveId: DEFAULT_TYPE
    });
    const [formData, setFormData] = useState({ orderId: record?.id, waveId: DEFAULT_TYPE });
    const [dialog, setDialog] = useState(false);
    const [selectedValue, setSelectedValue] = useState({});
    useEffect(() => {
        if (selectedMatnr.length < 1) {
            setRows(fetchRows)
        } else {
            const mas = fetchRows.filter(item => selectedMatnr.includes(item.matnrCode));
            setRows(mas)
        }
    }, [selectedMatnr])
    const handleRowClick = (id, resource, record) => {
        setRowSelectedIds(prev =>
            prev.includes(id)
                ? prev.filter(item => item !== id)  // 取消选择
                : [...prev, id]                     // 添加选择
        );
        //设置库位信息筛选条件
        setSelectedMatnr(prev =>
            prev.includes(record?.matnrCode)
                ? prev.filter(item => item !== record?.matnrCode)  // 取消选择
                : [...prev, record?.matnrCode]                     // 添加选择
        );
    };
    const handleClickOpen = () => {
        setDialog(true);
@@ -85,13 +110,23 @@
    const handleClose = (value) => {
        setDialog(false);
        setSelectedValue(value);
        const newRows = rows.map(item => {
            return selectedIds.includes(item?.id) ? {
                ...item,
                siteNo: value?.site
            } : item
        })
        setRows(newRows);
        if (selectedIds.length == 0) {
            const newRows = rows.map(item => {
                return {
                    ...item,
                    siteNo: value?.site
                }
            })
            setRows(newRows);
        } else {
            const newRows = rows.map(item => {
                return selectedIds.includes(item?.id) ? {
                    ...item,
                    siteNo: value?.site
                } : item
            })
            setRows(newRows);
        }
    };
    useEffect(() => {
@@ -107,6 +142,7 @@
        const { data: { code, data, msg } } = await request.post('/outStock/order/getOutTaskItems', { ...formData });
        if (code === 200) {
            setRows(data)
            setFetchRows(data)
        } else {
            notify(msg);
        }
@@ -161,10 +197,12 @@
                                    sx={{ height: "2px", position: 'absolute', top: 0, left: 0, right: 0, }}
                                />
                                <StyledDatagrid
                                    storeKey={"outStockPublic"}
                                    preferenceKey='outStockItem'
                                    bulkActionButtons={<></>}
                                    rowClick={false}
                                    omit={['id', 'splrName', 'qty', 'poCode', 'workQty']}
                                    rowClick={handleRowClick}
                                    selectedIds={rowSelectedIds}
                                    omit={['id', 'splrName', 'qty', 'poCode',]}
                                >
                                    <NumberField source="id" />
                                    <TextField source="asnCode" label="table.field.outStockItem.asnCode" />
@@ -181,8 +219,8 @@
                        </Card>
                    </Grid>
                    <Grid item xl={6.3} gap={2}>
                        <Card>
                            <Box sx={{ height: 500, width: '100%' }}>
                        <Card sx={{ minHeight: 1050, height: 'calc(100% - 10px)', width: '100%' }}>
                            <Box>
                                <PreviewTable
                                    rows={rows}
                                    gridRef={gridRef}
@@ -223,7 +261,6 @@
        }
    }, [selectedIds])
    const baseColumns = [
        // { field: 'id', headerName: 'ID', width: 40 },
        { field: 'locCode', headerName: '库位', width: 110 },
@@ -232,8 +269,7 @@
        { 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} />
            )
@@ -379,6 +415,7 @@
    return (
        <DataGrid
            storeKey={"locItemPreview"}
            rows={rows}
            columns={columns}
            slots={{ toolbar: CustomToolBar }}
@@ -393,7 +430,6 @@
        />
    )
}
//提交按钮
rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx
New file
@@ -0,0 +1,54 @@
import { Box, Card, Grid, List, LinearProgress, Select, MenuItem, ListItemText, ListItemAvatar, Avatar, ListItemButton, Dialog, DialogTitle, ListItem } from "@mui/material";
import React, { useState, useRef, useEffect, useMemo } from "react";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting';
import { Delete, Edit, Add } from '@mui/icons-material';
import request from '@/utils/request';
import { useTranslate } from "react-admin";
const OutStockSiteDialog = (props) => {
    const translate = useTranslate();
    const { onClose, selectedValue, open } = props;
    const [siteNos, setSiteNos] = useState([]);
    const handleClose = () => {
        onClose(selectedValue);
    }
    const handleListItemClick = (value) => {
        onClose(value);
    }
    useEffect(() => {
        getSiteNos()
    }, [open])
    const getSiteNos = async () => {
        const { data: { code, data, msg } } = await request.get('/outStock/tasks/sites');
        if (code === 200) {
            setSiteNos(data);
        } else {
            notify(msg);
        }
    }
    return (
        <Dialog
            onClose={handleClose}
            open={open}
        >
            <DialogTitle>{translate("toolbar.modiftySite")}</DialogTitle>
            <List sx={{ pt: 0 }}>
                {siteNos.map((site) => (
                    <ListItem disableGutters key={site?.id}>
                        <ListItemButton onClick={() => handleListItemClick(site)}>
                            <ListItemText primary={site.site} />
                        </ListItemButton>
                    </ListItem>
                ))}
            </List>
        </Dialog>
    );
}
export default OutStockSiteDialog;
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/DeliveryItemController.java
@@ -60,6 +60,29 @@
        return R.ok().add(deliveryItemService.page(pageParam, wrapper));
    }
    @PreAuthorize("hasAuthority('manager:deliveryItem:list')")
    @ApiOperation("分页获取列表")
    @PostMapping("/deliveryItem/edit/page")
    public R byPoIdspage(@RequestBody Map<String, Object> map) {
        List<Long> poDetlIds = new ArrayList<>();
        if (!Objects.isNull(map.get("ids"))) {
            poDetlIds = JSONArray.parseArray(JSONArray.toJSONString(map.get("ids")), Long.class);
            map.remove("ids");
        }
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<DeliveryItem, BaseParam> pageParam = new PageParam<>(baseParam, DeliveryItem.class);
        QueryWrapper<DeliveryItem> queryWrapper = pageParam.buildWrapper(true);
        if (!poDetlIds.isEmpty()) {
            queryWrapper.in("id", poDetlIds);
        } else {
            return R.ok();
        }
        return R.ok().add(deliveryItemService.page(pageParam, queryWrapper));
    }
    @PreAuthorize("hasAuthority('manager:deliveryItem:list')")
    @PostMapping("/deliveryItem/list")
    public R list(@RequestBody Map<String, Object> map) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java
@@ -8,8 +8,10 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.manager.controller.params.OrderOutTaskParam;
import com.vincent.rsf.server.manager.controller.params.OutStockToTaskParams;
import com.vincent.rsf.server.manager.entity.DeliveryItem;
import com.vincent.rsf.server.manager.entity.excel.OutStockTemplate;
import com.vincent.rsf.server.manager.enums.OrderType;
import com.vincent.rsf.server.manager.enums.OrderWorkType;
@@ -43,7 +45,6 @@
@RestController
@Api(tags = "出库单据")
public class OutStockController extends BaseController {
    Logger logger = LoggerFactory.getLogger(OutStockController.class);
    @Autowired
@@ -54,6 +55,17 @@
    @PreAuthorize("hasAuthority('manager:outStock:list')")
    @PostMapping("/outStock/page")
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<AsnOrder, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrder.class);
        QueryWrapper<AsnOrder> queryWrapper = pageParam.buildWrapper(true);
        List<String> list = Arrays.asList(OrderType.ORDER_OUT.type);
        queryWrapper.in("type", list);
        return R.ok().add(outStockService.page(pageParam, queryWrapper));
    }
    @PreAuthorize("hasAuthority('manager:outStock:list')")
    @PostMapping("/outStock/dialog/page")
    public R dialogPage(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<AsnOrder, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrder.class);
        QueryWrapper<AsnOrder> queryWrapper = pageParam.buildWrapper(true);
@@ -155,6 +167,21 @@
        return outStockService.cancelOutOrder(id);
    }
    @PreAuthorize("hasAuthority('manager:outStock:update')")
    @ApiOperation("删除已生成明细")
    @GetMapping("/outStock/items/cancel/{ids}")
    public R cancel(@PathVariable Long[] ids) {
        List<Long> list = Arrays.asList(ids);
        if (list.isEmpty()) {
            return R.error("参数不能为空!!");
        }
        List<AsnOrderItem> orderItems = outStockItemService.list(new LambdaQueryWrapper<AsnOrderItem>().in(AsnOrderItem::getId, list));
        if (orderItems.isEmpty()) {
            throw new CoolException("单据明细不存在!!");
        }
        return outStockService.cancelOutOrderByItems(orderItems);
    }
    @PreAuthorize("hasAuthority('manager:outStock:list')")
    @PostMapping("/outStock/export")
@@ -205,8 +232,8 @@
        if (Objects.isNull(params.get("ids"))) {
            return R.error("参数不能为空!!");
        }
        List<Long> ids = (List<Long>) params.get("ids");
        return outStockService.genOutStock(ids, getLoginUserId());
        List<DeliveryItem> items = JSON.parseArray(JSONObject.toJSONString(params.get("ids")), DeliveryItem.class);
        return outStockService.genOutStock(items, getLoginUserId());
    }
    @PreAuthorize("hasAuthority('manager:outStock:update')")
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockItemController.java
@@ -4,6 +4,7 @@
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
@@ -48,7 +49,8 @@
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<AsnOrderItem, BaseParam> pageParam = new PageParam<>(baseParam, AsnOrderItem.class);
        return R.ok().add(outStockItemService.listByAsnId(pageParam, pageParam.buildWrapper(true)));
        QueryWrapper<AsnOrderItem> queryWrapper = pageParam.buildWrapper(true);
        return R.ok().add(outStockItemService.listByAsnId(pageParam, queryWrapper));
    }
    @PreAuthorize("hasAuthority('manager:outStockItem:list')")
@@ -106,6 +108,7 @@
        return R.ok("Update Success").add(asnOrderItem);
    }
    @PreAuthorize("hasAuthority('manager:outStockItem:remove')")
    @OperationLog("Delete 出库单明细")
    @PostMapping("/outStockItem/remove/{ids}")
@@ -130,6 +133,7 @@
        return R.ok().add(vos);
    }
    @PreAuthorize("hasAuthority('manager:outStockItem:list')")
    @PostMapping("/outStockItem/export")
    @ApiOperation("导出出库单明细")
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java
@@ -6,6 +6,8 @@
import com.vincent.rsf.server.manager.controller.params.OrderOutTaskParam;
import com.vincent.rsf.server.manager.controller.params.OutStockToTaskParams;
import com.vincent.rsf.server.manager.entity.AsnOrder;
import com.vincent.rsf.server.manager.entity.AsnOrderItem;
import com.vincent.rsf.server.manager.entity.DeliveryItem;
import java.util.List;
@@ -13,7 +15,7 @@
    R cancelOutOrder(String id);
    R genOutStock(List<Long> ids, Long loginUserId);
    R genOutStock(List<DeliveryItem> ids, Long loginUserId);
    R generateWaves(List<Long> ids);
@@ -26,4 +28,6 @@
    R genOutStockTask(List<OutStockToTaskParams> params, Long loginUserId, Long outId);
    R getSiteNos();
    R cancelOutOrderByItems(List<AsnOrderItem> orderItems);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -115,18 +115,11 @@
            }
            Double orgQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
            Double workQty = locItems.stream().mapToDouble(LocItem::getWorkQty).sum();
            List<LocItem> locItemList = listMap.get(key);
            Double outQty = locItemList.stream().mapToDouble(LocItem::getOutQty).sum();
//            Task serviceOne = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, loc.getBarcode()));
//            if (!Objects.isNull(serviceOne)) {
//                throw new CoolException("托盘任务执行中,不能重复创建!");
//            }
            if (map.getType().equals(Constants.TASK_TYPE_OUT_STOCK) || map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)) {
                Double useQty = Math.round((outQty + workQty) * 10000) / 10000.0;
                if (orgQty.compareTo(useQty) > 0) {
                if (orgQty.compareTo(outQty) > 0) {
                    //拣料出库
                    DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                            .eq(DeviceSite::getSite, siteNo)
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -171,13 +171,9 @@
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R genOutStock(List<Long> ids, Long loginUserId) {
        if (Objects.isNull(ids) || ids.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        List<DeliveryItem> items = deliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>().in(DeliveryItem::getId, ids));
    public R genOutStock(List<DeliveryItem> items, Long loginUserId) {
        if (items.isEmpty()) {
            throw new CoolException("单据不存在!!");
            throw new CoolException("参数不能为空!!");
        }
        Map<Long, List<DeliveryItem>> listMap = items.stream().collect(Collectors.groupingBy(DeliveryItem::getDeliveryId));
        listMap.keySet().forEach(key -> {
@@ -188,7 +184,7 @@
            AsnOrder order = new AsnOrder();
            BeanUtils.copyProperties(delivery, order);
            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_OUT_STOCK_CODE, order);
            if (Objects.isNull(ruleCode) || StringUtils.isBlank(ruleCode)) {
            if (StringUtils.isBlank(ruleCode)) {
                throw new CoolException("编码规则错误:请检查 「SYS_OUT_STOCK_CODE」编码是否设置成功");
            }
            order.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val)
@@ -205,15 +201,23 @@
            }
            List<AsnOrderItem> orderItems = new ArrayList<>();
            listMap.get(key).forEach(item -> {
                DeliveryItem deliveryItem = deliveryItemService.getById(item.getId());
                AsnOrderItem orderItem = new AsnOrderItem();
                Double anfme = Math.round((item.getAnfme() - item.getWorkQty() - item.getQty()) * 10000) / 10000.0;
                if (item.getAnfme().compareTo(0.0) <= 0) {
                    throw new CoolException("出库数量不能小于或等于零!!");
                }
                Double anfme = Math.round((deliveryItem.getAnfme() - item.getAnfme()) * 10000) / 10000.0;
                if (anfme.compareTo(0.0) < 0) {
                    throw new CoolException("出库数量不足!!");
                }
                BeanUtils.copyProperties(item, orderItem);
                orderItem.setId(null)
                        .setPoCode(order.getPoCode())
                        .setMaktx(item.getMaktx())
                        .setMatnrCode(item.getMatnrCode())
                        .setFieldsIndex(item.getFieldsIndex())
                        .setAnfme(anfme)
                        .setAnfme(item.getAnfme())
                        .setWorkQty(0.0)
                        .setAsnId(order.getId())
                        .setAsnCode(order.getCode())
@@ -257,7 +261,6 @@
                    .eq(Delivery::getId, key))) {
                throw new CoolException("主单修改失败!!");
            }
        });
        return R.ok();
    }
@@ -446,7 +449,7 @@
            if (Objects.isNull(param)) {
                continue;
            }
            Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, param.getBarcode()));
            Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, param.getLocCode()).eq(Loc::getBarcode, param.getBarcode()));
            if (!Objects.isNull(loc)) {
                List<LocItem> locItems = new ArrayList<>();
                LocItem locItem = locItemService.getById(param.getId());
@@ -512,6 +515,7 @@
    /**
     * 获取出库站点
     *
     * @return
     */
    @Override
@@ -522,6 +526,47 @@
                TaskType.TASK_TYPE_PICK_AGAIN_OUT.type);
        List<DeviceSite> sites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>().in(DeviceSite::getType, list).groupBy(DeviceSite::getSite));
        return R.ok(sites);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R cancelOutOrderByItems(List<AsnOrderItem> orderItems) {
        Map<Long, List<AsnOrderItem>> listMap = orderItems.stream().collect(Collectors.groupingBy(AsnOrderItem::getAsnId));
        for (Long key : listMap.keySet()) {
            AsnOrder order = this.getById(key);
            if (Objects.isNull(order)) {
                throw new CoolException("单据不存在!!");
            }
            List<AsnOrderItem> items = listMap.get(key);
            if (!items.isEmpty()) {
                for (AsnOrderItem orderItem : items) {
                    DeliveryItem deliveryItem = deliveryItemService.getById(orderItem.getPoDetlId());
                    Double workQty = Math.round((deliveryItem.getWorkQty() - orderItem.getAnfme()) * 10000) / 10000.0;
                    deliveryItem.setWorkQty(workQty.compareTo(0.0) >= 0 ? workQty : 0);
                    if (!deliveryItemService.updateById(deliveryItem)) {
                        throw new CoolException("DO单明细更新失败!!");
                    }
                    Delivery delivery = deliveryService.getOne(new LambdaQueryWrapper<Delivery>().eq(Delivery::getCode, orderItem.getPoCode()));
                    if (!Objects.isNull(delivery)) {
                        Double wkQty = Math.round((delivery.getWorkQty() - delivery.getAnfme()) * 10000) / 10000.0;
                        delivery.setWorkQty(wkQty.compareTo(0.0) >= 0 ? wkQty : 0).setExceStatus(POExceStatus.PO_EXCE_STATUS_UN_EXCE.val);
                        if (!deliveryService.updateById(delivery)) {
                            throw new CoolException("DO单据修改失败!!");
                        }
                    }
                }
            }
            if (!this.remove(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getId, key))) {
                throw new CoolException("主单删除失败!!");
            }
            if (!outStockItemService.remove(new LambdaQueryWrapper<AsnOrderItem>()
                    .eq(AsnOrderItem::getAsnId, key))) {
                throw new CoolException("单据明细删除失败!!");
            }
        }
        return R.ok("操作成功");
    }
@@ -538,9 +583,7 @@
        );
        locItemQueryWrapper.apply(applySql);
        List<LocItem> locItems = locItemService.list(locItemQueryWrapper);
        locItems.sort(Comparator
                .comparing((LocItem item) -> !LocUtils.isShallowLoc(item.getLocCode()))
        );
        locItems.sort(Comparator.comparing((LocItem item) -> !LocUtils.isShallowLoc(item.getLocCode())));
        return locItems;
    }
@@ -575,13 +618,30 @@
                continue;
            }
            List<LocItem> locItems = null;
            if (WaveRuleType.Efficiency_First.type.equals(waveRule.getType())) {
                locItems = getEfficiencyFirstItemList(asnOrderItem);
            } else if (WaveRuleType.First_In_First_Out.type.equals(waveRule.getType())) {
                locItems = getFirstInFirstOutItemList(asnOrderItem);
            } else {
                locItems = getFirstInFirstOutItemList(asnOrderItem);
            List<LocItem> items = locItemService.list(new LambdaQueryWrapper<LocItem>()
                    .eq(StringUtils.isNotBlank(asnOrderItem.getSplrBatch()), LocItem::getBatch, asnOrderItem.getSplrBatch())
                    .eq(StringUtils.isNotBlank(asnOrderItem.getFieldsIndex()), LocItem::getFieldsIndex, asnOrderItem.getFieldsIndex())
                    .eq(StringUtils.isNotBlank(asnOrderItem.getPlatOrderCode()), LocItem::getPlatOrderCode, asnOrderItem.getPlatOrderCode())
                    .eq(LocItem::getAnfme, asnOrderItem.getAnfme())
                    .eq(LocItem::getMatnrId, asnOrderItem.getMatnrId()));
            if (!items.isEmpty()) {
                for (LocItem item : items) {
                    if (LocUtils.isShallowLoc(item.getLocCode())) {
                        locItems.add(item);
                    }
                }
            }
            if (Objects.isNull(locItems) || locItems.isEmpty()) {
                if (WaveRuleType.Efficiency_First.type.equals(waveRule.getType())) {
                    locItems = getEfficiencyFirstItemList(asnOrderItem);
                } else if (WaveRuleType.First_In_First_Out.type.equals(waveRule.getType())) {
                    locItems = getFirstInFirstOutItemList(asnOrderItem);
                } else {
                    locItems = getFirstInFirstOutItemList(asnOrderItem);
                }
            }
            for (LocItem locItem : locItems) {
                Loc loc = locService.getById(locItem.getLocId());
                List<LocItem> itemList = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, locItem.getLocCode()));
rsf-server/src/main/resources/application.yml
@@ -25,7 +25,7 @@
  #  global-config:
  #    field-strategy: 0
  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
    cache-enabled: true
    call-setters-on-nulls: true