4496b9019ba423dd1c51c719bcc0a5938d90fff9..40d9cd510741a098bd52cbe22a5f9e5528f45abc
4 天以前 skyouc
# 新增 1. 通过单据新增出库单功能 2. 新增生成出库单接口
40d9cd 对比 | 目录
4 天以前 skyouc
通过单据创建DO单优化
f0e887 对比 | 目录
12个文件已修改
424 ■■■■■ 已修改文件
rsf-admin/src/i18n/en.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryCreate.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryItemEdit.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/delivery/DeliveryItemList.jsx 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderList.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx 196 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java 104 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js
@@ -51,6 +51,7 @@
            before: 'Time Before'
        },
        action: {
            search: 'Search',
            reset: 'Reset',
            expand: 'Expand',
            expandAll: 'Expand All',
@@ -919,6 +920,7 @@
        batch: 'batch',
        confirm: 'confirm',
        cancel: "cancel",
        query: "Query",
        bulkExport: "Bulk Export",
        continue: 'Continue Receipt',
        confirmSelect: 'Confirm Select',
rsf-admin/src/i18n/zh.js
@@ -51,6 +51,7 @@
            before: '结束时间'
        },
        action: {
            search: '搜索',
            reset: '重置',
            expand: '展开',
            expandAll: '全部展开',
@@ -970,6 +971,7 @@
        selectSite: '选择站点',
        confirmSelect: '确认选择',
        cancel: "取消",
        query: "查询",
        top: "置顶",
        resort: "排序",
        subzone: '绑定分区',
rsf-admin/src/page/orders/delivery/DeliveryCreate.jsx
@@ -99,6 +99,8 @@
                                        source="type"
                                        optionValue="value"
                                        parse={v => v}
                                        validate={required()}
                                    />
                                    <AutocompleteInput
                                        choices={business}
@@ -106,6 +108,7 @@
                                        label="table.field.asnOrder.wkType"
                                        source="wkType"
                                        optionValue="value"
                                        validate={required()}
                                        parse={v => v}
                                    />
                                    <TextInput
rsf-admin/src/page/orders/delivery/DeliveryItemEdit.jsx
@@ -100,17 +100,19 @@
                                    <Typography variant="h6" gutterBottom>
                                        {translate('common.edit.title.main')}
                                    </Typography>
                                    <Stack direction='row' gap={2}>
                                    <Stack direction='row' gap={2} sx={{ display: 'none' }}>
                                        <NumberInput
                                            label="table.field.deliveryItem.deliveryId"
                                            source="deliveryId"
                                            autoFocus
                                            readOnly
                                        />
                                        <TextInput
                                            label="table.field.deliveryItem.platItemId"
                                            source="platItemId"
                                            parse={v => v}
                                        />
                                    </Stack>
                                    <Stack direction='row' gap={2}>
                                        <TextInput
                                            label="table.field.deliveryItem.matnrCode"
                                            source="matnrCode"
@@ -121,14 +123,13 @@
                                            source="matnrName"
                                            parse={v => v}
                                        />
                                    </Stack>
                                    <Stack direction='row' gap={2}>
                                        <TextInput
                                            label="table.field.deliveryItem.fieldsIndex"
                                            source="fieldsIndex"
                                            parse={v => v}
                                        />
                                    </Stack>
                                    <Stack direction='row' gap={2}>
                                        <TextInput
                                            label="table.field.deliveryItem.unit"
                                            source="unit"
@@ -142,11 +143,6 @@
                                        <NumberInput
                                            label="table.field.deliveryItem.qty"
                                            source="qty"
                                            validate={required()}
                                        />
                                        <NumberInput
                                            label="table.field.deliveryItem.nromQty"
                                            source="nromQty"
                                            validate={required()}
                                        />
                                    </Stack>
rsf-admin/src/page/orders/delivery/DeliveryItemList.jsx
@@ -33,17 +33,14 @@
    DeleteButton,
    useGetOne,
    useGetRecordId,
    SimpleForm,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import DeliveryItemCreate from "./DeliveryItemCreate";
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 { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting';
import DeliveryItemEdit from "./DeliveryItemEdit";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
@@ -53,33 +50,21 @@
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
        width: 150
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
    <NumberInput source="deliveryId" label="table.field.deliveryItem.deliveryId" />,
    <DateInput label='common.time.after' source="timeStart" />,
    <DateInput label='common.time.before' source="timeEnd" />,
    <TextInput source="platItemId" label="table.field.deliveryItem.platItemId" />,
    <TextInput source="matnrCode" label="table.field.deliveryItem.matnrCode" />,
    <TextInput source="matnrName" label="table.field.deliveryItem.matnrName" />,
    <TextInput source="fieldsIndex" label="table.field.deliveryItem.fieldsIndex" />,
    <TextInput source="unit" label="table.field.deliveryItem.unit" />,
    <NumberInput source="anfme" label="table.field.deliveryItem.anfme" />,
    <NumberInput source="qty" label="table.field.deliveryItem.qty" />,
    <NumberInput source="nromQty" label="table.field.deliveryItem.nromQty" />,
    <NumberInput source="printQty" label="table.field.deliveryItem.printQty" />,
    <TextInput source="splrName" label="table.field.deliveryItem.splrName" />,
    <TextInput source="splrCode" label="table.field.deliveryItem.splrCode" />,
    <TextInput source="splrBatch" label="table.field.deliveryItem.splrBatch" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
@@ -115,17 +100,17 @@
                title={"menu.deliveryItem"}
                empty={false}
                filters={filters}
                filter={{deliveryId: doId}}
                filter={{ deliveryId: doId }}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <SelectColumnsButton preferenceKey='deliveryItem' />
                        <MyExportButton />
                        {/* <MyExportButton /> */}
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
                perPage={DEFAULT_ITEM_PAGE_SIZE}
            >
                <StyledDatagrid
                    preferenceKey='deliveryItem'
@@ -136,7 +121,7 @@
                    }}
                    expand={false}
                    expandSingle={true}
                    omit={['id', 'createTime','deliveryId','fieldsIndex','qty', 'printQty', 'nromQty', 'createBy', 'memo']}
                    omit={['id', 'createTime', 'deliveryId', 'fieldsIndex', 'qty', 'printQty', 'nromQty', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
                    <NumberField source="deliveryId" label="table.field.deliveryItem.deliveryId" />
@@ -152,9 +137,9 @@
                    <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                    <TextField source="splrCode" label="table.field.deliveryItem.splrCode" />
                    <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                    <TextField source="updateBy$" label="common.field.updateBy"  />
                    <TextField source="updateBy$" label="common.field.updateBy" />
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <TextField source="createBy$" label="common.field.createBy"  />
                    <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} />
@@ -163,7 +148,7 @@
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <DeliveryItemEdit
            <DeliveryItemEdit
                open={editDialog}
                setOpen={setEditDialog}
                record={select}
rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -121,7 +121,6 @@
    <Box display="flex">
      <List
        resource="outStock"
        storeKey='outStock'
        sx={{
          flexGrow: 1,
          transition: (theme) =>
@@ -138,7 +137,7 @@
        actions={(
          <TopToolbar>
            <FilterButton />
            <CreateByOrderButton setCreateDialog={setCreateDialog}/>
            <CreateByOrderButton setCreateDialog={setCreateDialog} />
            <MyCreateButton onClick={() => { setManualDialog(true) }} />
            <SelectColumnsButton preferenceKey='outStock' />
            <ImportButton value={'asnOrderItem'} />
@@ -183,7 +182,10 @@
          </WrapperField>
        </StyledDatagrid>
      </List>
      <OutOrderCreate open={manualDialog} setOpen={setManualDialog} />
      <OutOrderCreate
        open={manualDialog}
        setOpen={setManualDialog}
      />
      <OutOrderModal
        open={createDialog}
        setOpen={setCreateDialog}
@@ -219,7 +221,7 @@
  )
}
const CreateByOrderButton = ({setCreateDialog}) => {
const CreateByOrderButton = ({ setCreateDialog }) => {
  const record = useRecordContext();
  const notify = useNotify();
  const refresh = useRefresh();
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
@@ -33,10 +33,20 @@
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
    Form,
    SaveButton,
    useRefresh,
    useGetList,
} from 'react-admin';
import DialogCloseButton from "../../components/DialogCloseButton";
import { styled } from '@mui/material/styles';
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import { Grid, Stack, width } from "@mui/system";
import request from '@/utils/request';
import SaveIcon from '@mui/icons-material/Save';
import debounce from "lodash/debounce";
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
@@ -79,12 +89,70 @@
const OutOrderModal = (props) => {
    const { open, setOpen, record } = props;
    const translate = useTranslate();
    const [params, setParams] = useState({});
    const [drawerVal, setDrawerVal] = useState(false);
    const refresh = useRefresh();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const CustomFilter = () => {
        const { filterValues, setFilters, refetch } = useListContext('deliveryItem');
        const [formValues, setFormValues] = useState(filterValues);
        const handleChange = (event) => {
            setFormValues(formValues => ({
                ...formValues,
                [event.target.name]: event.target.value
            }));
        };
        const handleSubmit = (event) => {
            setParams(formValues)
        };
        return (
            <Form>
                <Grid container rowSpacing={2} columnSpacing={2} >
                    <Stack>
                        <TextInput
                            source="condition"
                            label="common.action.search"
                            resettable
                            defaultValue={params?.condition}
                            onChange={handleChange} />
                    </Stack>
                    <Stack>
                        <TextInput
                            source="matnrName"
                            label="table.field.deliveryItem.matnrName"
                            defaultValue={params?.matnrName}
                            onChange={handleChange}
                        />
                    </Stack>
                    <Stack>
                        <TextInput
                            source="matnrCode"
                            label="table.field.deliveryItem.matnrCode"
                            defaultValue={params?.matnrCode}
                            onChange={handleChange} />
                    </Stack>
                    <Stack>
                        <TextInput
                            source="splrName"
                            label="table.field.deliveryItem.splrName"
                            defaultValue={params?.splrName}
                            onChange={handleChange} />
                    </Stack>
                </Grid>
                <DialogActions>
                    <Toolbar sx={{ width: '100%', justifyContent: 'end' }}  >
                        <SaveButton onClick={handleSubmit} label={"toolbar.query"} />
                    </Toolbar>
                </DialogActions>
            </Form>
        );
    };
    return (
        <Dialog
@@ -107,61 +175,81 @@
                    <DialogCloseButton onClose={handleClose} />
                </Box>
            </DialogTitle>
            <DialogContent>
                <List
                    resource="deliveryItem"
                    storeKey='selectDelivery'
                    sx={{
                        flexGrow: 1,
                        transition: (theme) =>
                            theme.transitions.create(['all'], {
                                duration: theme.transitions.duration.enteringScreen,
                            }),
                        marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    }}
                    title={"menu.delivery"}
                    empty={false}
                    sort={{ field: "create_time", order: "desc" }}
                    actions={(
                        <TopToolbar>
                            <></>
                        </TopToolbar>
                    )}
                    perPage={DEFAULT_PAGE_SIZE}
                >
                    <StyledDatagrid
                        preferenceKey='deliveryItem'
                        bulkActionButtons={() => <></>}
                        rowClick={(id, resource, record) => false}
                        expand={false}
                        expandSingle={true}
                        omit={['id', 'createTime', 'createBy', 'memo', 'workQty', 'startTime', 'endTime', 'updateBy', 'createTime']}
                    >
                        <NumberField source="id" />
                        <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                        <TextField source="matnrName" label="table.field.deliveryItem.matnrName" />
                        <TextField source="unit" label="table.field.deliveryItem.unit" />
                        <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                        <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                        <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                        <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} />
                    </StyledDatagrid>
                </List>
            </DialogContent>
            <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                {/* <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                    <Button disabled={disabled} onClick={handleSubmit} variant="contained" startIcon={<SaveIcon />}>
                        {translate('toolbar.confirm')}
                    </Button>
                </Toolbar> */}
            </DialogActions>
        </Dialog>
            <Grid container rowSpacing={2} columnSpacing={2}>
                <DialogContent>
                    <Grid item sx={24}>
                        <List
                            resource="deliveryItem"
                            sx={{
                                flexGrow: 1,
                                transition: (theme) =>
                                    theme.transitions.create(['all'], {
                                        duration: theme.transitions.duration.enteringScreen,
                                    }),
                                marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                            }}
                            filters={<CustomFilter />}
                            queryOptions={{ meta: { ...params } }}
                            empty={false}
                            sort={{ field: "create_time", order: "desc" }}
                            actions={(
                                <TopToolbar>
                                    <></>
                                </TopToolbar>
                            )}
                            perPage={DEFAULT_PAGE_SIZE}
                        >
                            <StyledDatagrid
                                preferenceKey='deliveryItem'
                                bulkActionButtons={<AddOutStockButton  setOpen={setOpen}/>}
                                rowClick={(id, resource, record) => false}
                                expand={false}
                                expandSingle={true}
                                omit={['id', 'createTime', 'createBy', 'memo', 'workQty', 'startTime', 'endTime', 'updateBy', 'createTime']}
                            >
                                <NumberField source="id" />
                                <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                                <TextField source="matnrName" label="table.field.deliveryItem.matnrName" />
                                <TextField source="unit" label="table.field.deliveryItem.unit" />
                                <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
                                <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                                <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                                <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} />
                            </StyledDatagrid>
                        </List>
                    </Grid>
                </DialogContent>
            </Grid>
        </Dialog >
    )
}
export default OutOrderModal;
const AddOutStockButton = (props) => {
    const { setOpen } = props;
    const { selectedIds, onUnselectItems } = useListContext();
    const notify = useNotify();
    const confirm = async (event) => {
        console.log(selectedIds);
        const res = await request.post(`/outStock/generate/orders`, {ids: selectedIds});
        if (res?.data?.code === 200) {
            notify(res.data.msg);
        } else {
            notify(res.data.msg);
        }
        onUnselectItems();
        setOpen(false);
    }
    return (
        <Button label={"toolbar.confirmSelect"} onClick={confirm}>
            <CheckCircleIcon />
        </Button>
    )
}
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java
@@ -71,7 +71,7 @@
    }
    public QueryWrapper<T> buildWrapper(boolean like, List<String> fields) {
        return this.buildWrapper(like, null,"create_time", fields);
        return this.buildWrapper(like, null, "create_time", fields);
    }
    @SuppressWarnings("all")
@@ -133,26 +133,26 @@
        if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) {
            List<String> columns = new ArrayList<>();
            for (Field field : Cools.getAllFields(cls)){
            for (Field field : Cools.getAllFields(cls)) {
                if (Modifier.isFinal(field.getModifiers())
                        || Modifier.isStatic(field.getModifiers())
                        || Modifier.isTransient(field.getModifiers())){
                        || Modifier.isTransient(field.getModifiers())) {
                    continue;
                }
                if (field.isAnnotationPresent(TableField.class)){
                if (field.isAnnotationPresent(TableField.class)) {
                    TableField annotation = field.getAnnotation(TableField.class);
                    if (!annotation.exist()) {
                        continue;
                    }
                }
                String column =  Utils.toSymbolCase(field.getName(), '_');
                String column = Utils.toSymbolCase(field.getName(), '_');
                columns.add(column);
            }
            if (!columns.isEmpty()) {
                queryWrapper.and(wrapper -> {
                    for (int i=0;i<columns.size();i++){
                    for (int i = 0; i < columns.size(); i++) {
                        String column = columns.get(i);
                        String condition = where.getCondition();
                        if (i == 0) {
@@ -168,7 +168,7 @@
    }
    @SuppressWarnings("all")
    public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer,String timeField, List<String> fields) {
    public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer, String timeField, List<String> fields) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        Map<String, Object> map = where.getMap();
        for (String key : map.keySet()) {
@@ -192,9 +192,9 @@
                    key = Utils.toSymbolCase(key, '_');
                }
                if (like && !fields.contains(key)) {
                    queryWrapper.like("`" +  key + "`", val);
                    queryWrapper.like("`" + key + "`", val);
                } else {
                    queryWrapper.eq("`" +  key + "`", val);
                    queryWrapper.eq("`" + key + "`", val);
                }
            }
        }
@@ -223,21 +223,21 @@
        if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) {
            List<String> columns = new ArrayList<>();
            for (Field field : Cools.getAllFields(cls)){
            for (Field field : Cools.getAllFields(cls)) {
                if (Modifier.isFinal(field.getModifiers())
                        || Modifier.isStatic(field.getModifiers())
                        || Modifier.isTransient(field.getModifiers())){
                        || Modifier.isTransient(field.getModifiers())) {
                    continue;
                }
                if (field.isAnnotationPresent(TableField.class)){
                if (field.isAnnotationPresent(TableField.class)) {
                    TableField annotation = field.getAnnotation(TableField.class);
                    if (!annotation.exist()) {
                        continue;
                    }
                }
                String column =  Utils.toSymbolCase(field.getName(), '_');
                String column = Utils.toSymbolCase(field.getName(), '_');
                columns.add(column);
            }
//            if (!columns.isEmpty()) {
@@ -254,7 +254,7 @@
//            }
            if (!columns.isEmpty()) {
                queryWrapper.and(wrapper -> {
                    for (int i=0;i<columns.size();i++){
                    for (int i = 0; i < columns.size(); i++) {
                        String column = columns.get(i);
                        String condition = where.getCondition();
                        if (i == 0) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java
@@ -190,4 +190,18 @@
        }
        ExcelUtil.build(ExcelUtil.create(orderTemplates, AsnOrderTemplate.class), response);
    }
    @PreAuthorize("hasAuthority('manager:outStock:update')")
    @ApiOperation("通过DO单生成出库单")
    @PostMapping("/outStock/generate/orders")
    public R genOutStock(@RequestBody Map<String, Object> params) {
        if (Objects.isNull(params.get("ids"))) {
            return R.error("参数不能为空!!");
        }
        List<Long> ids = (List<Long>) params.get("ids");
        return outStockService.genOutStock(ids);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java
@@ -12,4 +12,6 @@
public interface OutStockService extends IService<AsnOrder> {
    R cancelOutOrder(String id);
    R genOutStock(List<Long> ids);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -11,10 +11,7 @@
import com.vincent.rsf.server.api.service.ReportMsgService;
import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams;
import com.vincent.rsf.server.manager.controller.params.BatchUpdateParam;
import com.vincent.rsf.server.manager.entity.AsnOrder;
import com.vincent.rsf.server.manager.entity.AsnOrderItem;
import com.vincent.rsf.server.manager.entity.AsnOrderItemLog;
import com.vincent.rsf.server.manager.entity.AsnOrderLog;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
import com.vincent.rsf.server.manager.mapper.AsnOrderMapper;
import com.vincent.rsf.server.manager.mapper.PurchaseMapper;
@@ -22,6 +19,7 @@
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.mapper.SerialRuleMapper;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -42,29 +40,31 @@
public class OutStockServiceImpl extends ServiceImpl<AsnOrderMapper, AsnOrder> implements OutStockService {
    @Autowired
    private ReceiveMsgService receiveMsgService;
    @Autowired
    private ReportMsgService reportMsgService;
    @Resource
    private PurchaseMapper purchaseMapper;
    @Autowired
    private AsnOrderItemService asnOrderItemService;
    @Autowired
    private AsnOrderLogService asnOrderLogService;
    @Autowired
    private AsnOrderItemLogService asnOrderItemLogService;
    @Resource
    private SerialRuleMapper serialRuleMapper;
    @Autowired
    private DeliveryItemService deliveryItemService;
    @Autowired
    private DeliveryService deliveryService;
    @Autowired
    private MatnrService matnrService;
    /**
     * @author Ryan
     * @description 更新或保存明细
     * @param
     * @return
     * @author Ryan
     * @description 更新或保存明细
     * @time 2025/4/7 13:28
     */
    @Transactional(rollbackFor = Exception.class)
    private void svaeOrUpdateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) throws Exception{
    private void svaeOrUpdateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) throws Exception {
        AsnOrder orders = params.getOrders();
        params.getItems().forEach(item -> {
@@ -88,14 +88,14 @@
    /**
     * @author Ryan
     * @description 删除原主单及明细,加入历史档
     * @param
     * @return
     * @author Ryan
     * @description 删除原主单及明细,加入历史档
     * @time 2025/3/19 19:53
     */
    @Transactional(rollbackFor = Exception.class)
    private void operateOrderLogs(AsnOrder asrder) throws Exception{
    private void operateOrderLogs(AsnOrder asrder) throws Exception {
        if (Objects.isNull(asrder) || Objects.isNull(asrder.getId())) {
            throw new CoolException("参数不能为空!!");
        }
@@ -148,10 +148,10 @@
    }
    /**
     * @author Ryan
     * @description 取消出库单据
     * @param
     * @return
     * @author Ryan
     * @description 取消出库单据
     * @time 2025/4/22 10:40
     */
    @Override
@@ -174,4 +174,68 @@
        }
        return R.ok("操作成功");
    }
    /**
     * @param
     * @return
     * @author Ryan
     * @description 通过DO单生成出库单
     * @time 2025/4/23 16:24
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R genOutStock(List<Long> ids) {
        if (Objects.isNull(ids) || ids.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        List<DeliveryItem> items = deliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>().in(DeliveryItem::getId, ids));
        if (items.isEmpty()) {
            throw new CoolException("单据不存在!!");
        }
        Map<Long, List<DeliveryItem>> listMap = items.stream().collect(Collectors.groupingBy(DeliveryItem::getDeliveryId));
        listMap.keySet().forEach(key -> {
            //TODO 判断单据是否已经存在,如存在则累加修改子表,不存在才新建
            Delivery delivery = deliveryService.getById(key);
            if (Objects.isNull(delivery)) {
                throw new CoolException("单据不存在!!");
            }
            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)) {
                throw new CoolException("编码规则错误:请检查 「SYS_OUT_STOCK_CODE」编码是否设置成功");
            }
            order.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val)
                    .setCode(ruleCode)
                    .setPoId(delivery.getId())
                    .setId(null)
                    .setPoCode(delivery.getCode());
            if (!this.save(order)) {
                throw new CoolException("主单保存失败!!");
            }
            List<AsnOrderItem> orderItems = new ArrayList<>();
            listMap.get(key).forEach(item -> {
                AsnOrderItem orderItem = new AsnOrderItem();
                BeanUtils.copyProperties(item, orderItem);
                orderItem.setId(null)
                        .setPoCode(order.getPoCode())
                        .setAsnId(order.getId())
                        .setAsnCode(order.getCode())
                        .setPlatItemId(item.getPlatItemId())
                        .setPoDetlId(item.getId());
                orderItems.add(orderItem);
            });
            double sum = orderItems.stream().mapToDouble(AsnOrderItem::getAnfme).sum();
            //修改计划数量
            order.setAnfme(sum);
            if (!this.saveOrUpdate(order)) {
                throw new CoolException("主单数量修改失败!!");
            }
            if (!asnOrderItemService.saveBatch(orderItems)) {
                throw new CoolException("明细保存失败!!");
            }
        });
        return R.ok();
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java
@@ -9,6 +9,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * Created by vincent on 1/30/2024
@@ -42,6 +43,13 @@
    }
    public <T extends BaseParam> T buildParam(Map<String, Object> map, Class<T> clz) {
        if (!Objects.isNull(map.get("meta"))) {
            Map<String, Object> meta = (Map<String, Object>) map.get("meta");
            meta.keySet().forEach(key -> {
                map.put(key, meta.get(key));
            });
            map.remove("meta");
        }
        T t  = null;
        try {
            t = clz.getDeclaredConstructor().newInstance();