zjj
5 天以前 d8dd683271bffd641084193c6d8ef0b2cffa008d
Merge remote-tracking branch 'origin/devlop' into devlop
3个文件已添加
25个文件已修改
1056 ■■■■■ 已修改文件
rsf-admin/src/i18n/en.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/asnOrder/POItemModal.jsx 405 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/purchase/PurchaseList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/qlyInspect/QlyIsptItemResult.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/config/SysStockProperties.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/PurchaseController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Purchase.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/PurchaseTemplate.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/POExceStatus.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/AsnOrderService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/PurchaseService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderItemServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java 105 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/PurchaseItemServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/PurchaseServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/QlyIsptItemServiceImpl.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/FieldsController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/resources/application-dev.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js
@@ -1046,6 +1046,7 @@
        complete: "complete",
        close: "close",
        asnCreate: "Create By Order",
        poCreate: "Create By PO",
        createTask: "createTask",
        recover: "recover",
        createWave: "Create Wave",
rsf-admin/src/i18n/zh.js
@@ -486,7 +486,7 @@
            },
            qlyIsptItem: {
                ispectId: "主单ID",
                matnrCode: "物料编号",
                matnrCode: "物料编码",
                maktx: "物料名称",
                label: "标签",
                splrName: "供应商",
@@ -596,7 +596,7 @@
                spec: "规格",
                model: "型号",
                matnrCode: "物料编码",
                anfme: "计划数",
                anfme: "计划数量",
                stockUnit: "单位",
                isptResult: "质检结果",
                purQty: "采购量",
@@ -1079,6 +1079,7 @@
        complete: "完结",
        close: "关闭",
        asnCreate: "通过单据创建",
        poCreate: "通过PO单创建",
        orderPrint: '打印单据',
        createTask: "下发任务",
        createWave: "生成波次",
rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx
New file
@@ -0,0 +1,213 @@
import { Dialog, DialogActions, DialogContent, DialogTitle, Box } from "@mui/material";
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    Button,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    Toolbar,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    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 CheckCircleIcon from '@mui/icons-material/CheckCircle';
import POItemModal from "./POItemModal";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .status': {
        width: 90
    },
}));
const AsnCreateByPoModal = (props) => {
    const { open, setOpen, record } = props;
    const translate = useTranslate();
    const [params, setParams] = useState({});
    const [item, setItem] = useState({});
    const [poItemDialog, setPoItemDialog] = useState(false);
    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) => {
    //         if (event.target == undefined || event.target == null) { return }
    //         setFormValues(formValues => ({
    //             ...formValues,
    //             [event.target.name]: event.target.value
    //         }));
    //     };
    //     const handleSubmit = (event) => {
    //         setParams(formValues)
    //     };
    //     return (
    //         <Box sx={{ width: '100%', margin: 1, marginBottom: 8, "& .MuiDialogActions-root": { padding: 0 } }}>
    //             <Form>
    //                 <Grid container rowSpacing={2} columnSpacing={2} sx={{ padding: 2 }}>
    //                     <Stack>
    //                         <TextInput
    //                             source="condition"
    //                             label="common.action.search"
    //                             resettable
    //                             defaultValue={params?.condition}
    //                             onChange={handleChange} />
    //                     </Stack>
    //                 </Grid>
    //                 <DialogActions>
    //                     <Toolbar sx={{ width: '100%', justifyContent: 'end' }}  >
    //                         <SaveButton onClick={handleSubmit} label={"toolbar.query"} />
    //                     </Toolbar>
    //                 </DialogActions>
    //             </Form>
    //         </Box>
    //     );
    // };
    return (
        <Box>
            <Dialog
                open={open}
                onClose={handleClose}
                aria-labelledby="form-dialog-title"
                aria-hidden
                fullWidth
                disableRestoreFocus
                maxWidth="lg"
            >
                <DialogTitle id="form-dialog-title" sx={{
                    position: 'sticky',
                    top: 0,
                    backgroundColor: 'background.paper',
                    zIndex: 1000
                }}>
                    <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                        <DialogCloseButton onClose={handleClose} />
                    </Box>
                </DialogTitle>
                <Grid container rowSpacing={2} columnSpacing={2}>
                    <DialogContent>
                        <Grid item sx={24}>
                            <List
                                storeKey="selectPurchase"
                                resource="purchase/filters"
                                sx={{
                                    flexGrow: 1,
                                    marginTop: 8,
                                    height: 500,
                                    transition: (theme) =>
                                        theme.transitions.create(['all'], {
                                            duration: theme.transitions.duration.enteringScreen,
                                        }),
                                    marginRight: 0,
                                }}
                                // filters={<CustomFilter />}
                                queryOptions={{ meta: { ...params } }}
                                empty={false}
                                sort={{ field: "create_time", order: "desc" }}
                                actions={false}
                                perPage={DEFAULT_PAGE_SIZE}
                            >
                                <StyledDatagrid
                                    preferenceKey='selectPurchase'
                                    bulkActionButtons={
                                        <>
                                            <ConfirmSelectButton
                                                setOpen={setOpen}
                                                setPoItemDialog={setPoItemDialog}
                                                setItem={setItem}
                                                mutationMode="pessimistic" />
                                        </>
                                    }
                                    rowClick={false}
                                    expand={false}
                                    expandSingle={true}
                                    omit={['id', 'createTime', 'createBy', 'channel', 'platCode', 'memo', 'channel', 'startTime', 'workQty', 'endTime']}
                                >
                                    <NumberField source="id" />
                                    <TextField source="code" label="table.field.purchase.code" />
                                    <TextField source="type$" label="table.field.purchase.type" />
                                    <TextField source="wkType$" label="table.field.purchase.wkType" />
                                    <TextField source="source" label="table.field.purchase.source" />
                                    <NumberField source="anfme" label="table.field.purchase.anfme" />
                                    <NumberField source="qty" label="table.field.purchase.qty" />
                                    <TextField source="channel" label="table.field.purchase.channel" />
                                    <TextField source="platCode" label="table.field.purchase.platCode" />
                                    <DateField source="preArr" label="table.field.purchase.preArr" showTime />
                                    <DateField source="startTime" label="table.field.purchase.startTime" showTime />
                                    <DateField source="endTime" label="table.field.purchase.endTime" showTime />
                                    <TextField source="project" label="table.field.purchase.project" />
                                    <TextField source="memo" label="common.field.memo" sortable={false} />
                                </StyledDatagrid>
                            </List>
                        </Grid>
                    </DialogContent>
                </Grid>
            </Dialog >
            <POItemModal open={poItemDialog} setOpen={setPoItemDialog} record={item} />
        </Box>
    )
}
export default AsnCreateByPoModal;
const ConfirmSelectButton = ({ setOpen, setPoItemDialog, setItem }) => {
    const { selectedIds, onUnselectItems } = useListContext();
    const confirmSelect = async (event) => {
        setItem(selectedIds[0])
        onUnselectItems();
        setPoItemDialog(true)
        setOpen(false);
    }
    return (
        <Button label={"toolbar.confirm"} variant="contained" color="primary" size="medium" startIcon={<SaveIcon />} onClick={confirmSelect} />
    )
}
rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
@@ -58,7 +58,8 @@
import ImportButton from "../../components/ImportButton";
import PrintOutlinedIcon from '@mui/icons-material/PrintOutlined';
import OrderPrintPreview from "./OrderPrintPreview";
import CreateNewFolderOutlinedIcon from '@mui/icons-material/CreateNewFolderOutlined';
import AsnCreateByPoModal from "./AsnCreateByPoModal";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
  '& .css-1vooibu-MuiSvgIcon-root': {
    height: '.9em'
@@ -114,6 +115,7 @@
  const [createDialog, setCreateDialog] = useState(false);
  const [drawerVal, setDrawerVal] = useState(false);
  const [modalType, setmodalType] = useState(0);
  const [poCreate, setPoCreate] = useState(false);
  const [printOrder, setPrintOrder] = useState(false);
  const [select, setSelect] = useState({});
  const invoiceRef = useRef();
@@ -141,6 +143,7 @@
          <TopToolbar>
            <FilterButton />
            <MyCreateButton onClick={() => { setCreateDialog(true); setmodalType(0) }} />
            <CreateByPoButton setPoCreate={setPoCreate}/>
            <SelectColumnsButton preferenceKey='asnOrder' />
            <ImportButton value={'asnOrderItem'} />
            <MyExportButton />
@@ -186,8 +189,8 @@
            <MyButton setCreateDialog={setCreateDialog} setmodalType={setmodalType} />
            <InspectionButton />
            <CompleteButton />
            <ODeleteButton  />
            <PrintButton setPrintOrder={setPrintOrder} setSelect={setSelect}/>
            <ODeleteButton />
            <PrintButton setPrintOrder={setPrintOrder} setSelect={setSelect} />
            {/* <CloseButton /> */}
          </WrapperField>
        </StyledDatagrid>
@@ -198,10 +201,14 @@
        asnId={modalType}
        billReload={billReload}
      />
      <OrderPrintPreview
      <OrderPrintPreview
        open={printOrder}
        setOpen={setPrintOrder}
        record={select}
      />
      <AsnCreateByPoModal
        open={poCreate}
        setOpen={setPoCreate}
      />
      <PageDrawer
        title='AsnOrder Detail'
@@ -214,9 +221,24 @@
}
export default AsnOrderList;
//按PO单新建
const CreateByPoButton = ({setPoCreate}) => {
  const record = useRecordContext();
  const createEvent = (event) => {
    event.stopPropagation();
    setPoCreate(true)
  }
  return (
    <Button label={"toolbar.poCreate"} onClick={createEvent}>
      <CreateNewFolderOutlinedIcon />
    </Button>
  )
}
//打印按钮
const PrintButton = ({setPrintOrder, setSelect}) => {
const PrintButton = ({ setPrintOrder, setSelect }) => {
  const record = useRecordContext();
  const printOrder = (event) => {
    event.stopPropagation();
@@ -225,9 +247,9 @@
  }
  return (
      <Button label={"toolbar.print"} onClick={printOrder}>
          <PrintOutlinedIcon />
      </Button>
    <Button label={"toolbar.print"} onClick={printOrder}>
      <PrintOutlinedIcon />
    </Button>
  )
}
@@ -235,7 +257,7 @@
const ODeleteButton = () => {
  const record = useRecordContext();
  return (
    record.exceStatus === 0 ? <DeleteButton  mutationMode="pessimistic"/> : <></>
    record.exceStatus === 0 ? <DeleteButton mutationMode="pessimistic" /> : <></>
  )
}
@@ -251,15 +273,15 @@
  };
  return (
    record.exceStatus === 1 || record.exceStatus === 0 ?
    <Button
      color="primary"
      startIcon={<EditIcon />}
      onClick={(btn) => handleEditClick(btn)}
      sx={{ ml: 1 }}
      label={'ra.action.edit'}
    >
    </Button>
    : <></>
      <Button
        color="primary"
        startIcon={<EditIcon />}
        onClick={(btn) => handleEditClick(btn)}
        sx={{ ml: 1 }}
        label={'ra.action.edit'}
      >
      </Button>
      : <></>
  )
}
@@ -284,7 +306,7 @@
  }
  return (
      <ConfirmButton label={"toolbar.inspection"} color="secondary" startIcon={<ConstructionIcon />} onConfirm={inspection} />
    <ConfirmButton label={"toolbar.inspection"} color="secondary" startIcon={<ConstructionIcon />} onConfirm={inspection} />
  )
}
@@ -388,7 +410,7 @@
    // record.exceStatus === 1 && (record.anfme === record.qty ? <Button onClick={requestComplete} label={"toolbar.complete"} color="secondary">
    //   <TaskIcon />
    // </Button> : )
    record.exceStatus === 1 ? <ConfirmButton label={"toolbar.complete"} color="secondary"  startIcon={<TaskIcon />} onConfirm={requestComplete} /> : <></>
    record.exceStatus === 1 ? <ConfirmButton label={"toolbar.complete"} color="secondary" startIcon={<TaskIcon />} onConfirm={requestComplete} /> : <></>
  )
@@ -410,6 +432,6 @@
  }
  return (
    <ConfirmButton label={"toolbar.close"} color="error"  startIcon={<CloseIcon />} onConfirm={requestClose} />
    <ConfirmButton label={"toolbar.close"} color="error" startIcon={<CloseIcon />} onConfirm={requestClose} />
  )
}
rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx
@@ -123,7 +123,7 @@
    const setFinally = () => {
        const rows = tableRef.current.state.editRows;
        for (const key in rows) {
            const find = tabelData.find(item => item.matnrId === +key);
            const find = tabelData.find(item => item.id === +key);
            find.anfme = rows[key].anfme.value;
        }
        setTableData([...tabelData]);
@@ -201,7 +201,7 @@
    const handleDeleteItem = () => {
        const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.matnrId));
        const newTableData = _.filter(tabelData, (item) => !selectedRows.includes(item.id));
        setTableData(newTableData);
    }
@@ -370,7 +370,6 @@
                        value: selectedSupplier.id,
                    });
                }
            }
            }
@@ -591,16 +590,13 @@
        //     flex: 1,
        //     editable: true,
        // },
        {
            field: 'purUnit',
            headerName: translate('table.field.asnOrderItem.purUnit'),
            minWidth: 100,
            flex: 1,
            editable: false,
        },
        // {
        //     field: 'purUnit',
        //     headerName: translate('table.field.asnOrderItem.purUnit'),
        //     minWidth: 100,
        //     flex: 1,
        //     editable: false,
        // },
    ])
    const action = {
@@ -615,7 +611,6 @@
                </IconButton>
            </Tooltip>
        ),
    }
    let cdata = useRef([]);
@@ -636,7 +631,17 @@
        } = await request.get("/fields/enable/list");
        if (code === 200) {
            const cols = data.map(el => ({
                field: el.fields,
                field:  el.fields,
                valueGetter: (value, row) => {
                    if (value != null && value != undefined) {
                        return value;
                    }
                    if (row.extendFields == null  ||row.extendFields[el.fields] == null) {
                        return ''
                    } else {
                        return `${row.extendFields[el.fields] == null ? '' : row.extendFields[el.fields]}`;
                    }
                },
                headerName: el.fieldsAlise,
                minWidth: 100,
                flex: 1,
@@ -648,17 +653,15 @@
        }
    }
    const handleDelete = (row) => {
        const newData = _.filter(cdata.current, (item) => item.matnrId !== row.matnrId);
        const newData = _.filter(cdata.current, (item) => item.id !== row.id);
        setTableData(newData);
    };
    const processRowUpdate = (newRow, oldRow) => {
        const rows = tabelData.map((r) =>
            r.matnrId === newRow.matnrId ? { ...newRow } : r
            r.id === newRow.id ? { ...newRow } : r
        )
        setTableData(rows)
        // setTableData((prevData) =>
@@ -673,6 +676,8 @@
    const handleSelectionChange = (ids) => {
        console.log(ids);
        setSelectedRows(ids)
    };
@@ -687,7 +692,7 @@
                rows={tabelData}
                columns={columns}
                disableRowSelectionOnClick
                getRowId={(row) => row.matnrId}
                getRowId={(row) => row.id}
                disableColumnFilter
                disableColumnSelector
                disableColumnSorting
rsf-admin/src/page/orders/asnOrder/POItemModal.jsx
New file
@@ -0,0 +1,405 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
    Select,
    MenuItem
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import StatusSelectInput from "../../components/StatusSelectInput";
import AsnWareModal from "./AsnWareModal";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _, { set } from 'lodash';
import { DataGrid, useGridApiRef, GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF, getGridDateOperators, useGridApiContext } from '@mui/x-data-grid';
import { LocalizationProvider, DatePicker, DateTimePicker } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import DictionarySelect from "../../components/DictionarySelect";
import DictSelect from "../../components/DictSelect";
import "./asnOrder.css";
import { 'zhCN' as locale } from 'date-fns/locale';
import { format, } from 'date-fns';
import { DemoContainer } from '@mui/x-date-pickers/internals/demo';
const POItemModal = (props) => {
    const { open, setOpen, billReload, record } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const refresh = useRefresh();
    const [disabled, setDisabled] = useState(false)
    const [createDialog, setCreateDialog] = useState(false);
    const tableRef = useRef();
    useEffect(() => {
        if (open && record !== 0) {
            requestGetBody()
        }
        setDisabled(false)
    }, [open])
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            refresh();
            setTableData([])
        }
    };
    const [tabelData, setTableData] = useState([]);
    const resetData = () => {
        setTableData([])
    }
    const setFinally = () => {
        const rows = tableRef.current.state.editRows;
        for (const key in rows) {
            const find = tabelData.find(item => item.id === +key);
            find.anfme = rows[key].anfme.value;
        }
        setTableData([...tabelData]);
    }
    const handleSubmit = async () => {
        setFinally()
        setDisabled(true)
        setOpen(false)
        const parmas = {
            "purchaseId": record,
            "items": tabelData,
        }
        console.log('--------->');
        console.log(parmas);
        // const res = await request.post(`/asnOrder/purchases/save`, parmas);
        // if (res?.data?.code === 200) {
        //     setOpen(false);
        //     refresh();
        //     resetData()
        // } else {
        //     notify(res.data.msg);
        // }
        setDisabled(false)
    };
    const requestGetBody = async () => {
        const res = await request.post(`/purchaseItem/page`, { purchaseId: record });
        if (res?.data?.code === 200) {
            setTableData(res.data.data.records)
        } else {
            notify(res.data.msg);
        }
    }
    const [selectedRows, setSelectedRows] = useState([]);
    return (
        <>
            <Dialog
                open={open}
                onClose={handleClose}
                aria-labelledby="form-dialog-title"
                aria-hidden
                fullWidth
                disableRestoreFocus
                maxWidth="xl"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
            >
                <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 sx={{ mt: 2 }}>
                    <Box sx={{ mt: 2 }}>
                        <AsnOrderModalTable tabelData={tabelData}
                            setTableData={setTableData}
                            record={record}
                            selectedRows={selectedRows}
                            setSelectedRows={setSelectedRows}
                            tableRef={tableRef} />
                    </Box>
                </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>
        </>
    )
}
export default POItemModal;
const SelectInputSplrNameEditCell = (params) => {
    const [formData, setFormData] = useState([{}])
    useEffect(() => {
        getOptions();
    }, []);
    const getOptions = async () => {
        const parmas = {
            "type": "supplier"
        }
        const {
            data: { code, data, msg },
        } = await request.post("companys/page", parmas);
        if (code === 200) {
            setFormData(data.records)
        } else {
            notify(msg);
        }
    }
    return (
        <Select
            value={params.value}
            onChange={(e) => {
                params.api.setEditCellValue({
                    id: params.id,
                    field: params.field,
                    value: e.target.value,
                })
                // 找到选中的供应商记录
                const selectedSupplier = formData.find(supplier => supplier.name === e.target.value);
                // 如果找到对应的供应商记录,同时更新splrCode字段
                if (selectedSupplier) {
                    params.api.setEditCellValue({
                        id: params.id,
                        field: 'splrCode',
                        value: selectedSupplier.id,
                    });
                }
            }
            }
            fullWidth
        >
            {formData.map(e => {
                return (
                    <MenuItem value={e.name} children={e.name} key={e.id} />
                );
            })}
        </Select>
    );
};
const AsnOrderModalTable = ({ tabelData, setTableData, record, selectedRows, setSelectedRows, tableRef }) => {
    const translate = useTranslate();
    const notify = useNotify();
    const [columns, setColumns] = useState([
        {
            field: 'matnrCode',
            headerName: translate('table.field.asnOrderItem.matnrCode'),
            width: 130,
            editable: false,
        },
        {
            field: 'matnrName',
            headerName: translate('table.field.asnOrderItem.maktx'),
            width: 250,
            editable: false,
        },
        {
            field: 'splrName',
            headerName: translate('table.field.asnOrderItem.splrName') + "*",
            minWidth: 150,
            flex: 1,
            editable: true,
            renderEditCell: (params) => (
                <SelectInputSplrNameEditCell {...params} />
            ),
            headerClassName: "custom",
        },
        {
            field: 'platItemId',
            headerName: translate('table.field.asnOrderItem.platItemId') + "*",
            minWidth: 100,
            flex: 1,
            editable: true,
            headerClassName: "custom",
        },
        {
            field: 'anfme',
            headerName: translate('table.field.asnOrderItem.anfme') + "*",
            type: 'number',
            minWidth: 100,
            flex: 1,
            editable: true,
            valueFormatter: (val) => val < 0 ? 0 : val,
            headerClassName: "custom",
        },
        {
            field: 'unit',
            headerName: translate('table.field.asnOrderItem.stockUnit'),
            minWidth: 100,
            flex: 1,
            editable: false,
        },
    ])
    const action = {
        field: 'action',
        headerName: '操作',
        width: 70,
        lockPosition: 'left',
        renderCell: (params) => (
            <Tooltip title="Delete">
                <IconButton onClick={() => handleDelete(params.row)}>
                    <Delete />
                </IconButton>
            </Tooltip>
        ),
    }
    let cdata = useRef([]);
    useEffect(() => {
        getDynamicFields();
    }, []);
    useEffect(() => {
        cdata.current = tabelData
    }, [tabelData]);
    const getDynamicFields = async () => {
        const {
            data: { code, data, msg },
        } = await request.get("/fields/enable/list");
        if (code === 200) {
            const cols = data.map(el => ({
                field: el.fields,
                valueGetter: (value, row) => {
                    if (value != null && value != undefined) {
                        return value;
                    }
                    if (row.extendFields == null || row.extendFields[el.fields] == null) {
                        return ''
                    } else {
                        return `${row.extendFields[el.fields] == null ? '' : row.extendFields[el.fields]}`;
                    }
                },
                headerName: el.fieldsAlise,
                minWidth: 100,
                flex: 1,
                editable: true
            }))
            setColumns([...columns, ...cols, action])
        } else {
            notify(msg);
        }
    }
    const handleDelete = (row) => {
        const newData = _.filter(cdata.current, (item) => item.id !== row.id);
        setTableData(newData);
    };
    const processRowUpdate = (newRow, oldRow) => {
        const rows = tabelData.map((r) =>
            r.id === newRow.id ? { ...newRow } : r
        )
        setTableData(rows)
        return newRow;
    };
    const handleSelectionChange = (ids) => {
        setSelectedRows(ids)
    };
    tableRef.current = useGridApiRef();
    return (
        <div style={{ height: 400, width: '100%' }}>
            <DataGrid
                apiRef={tableRef}
                rows={tabelData}
                columns={columns}
                disableRowSelectionOnClick
                getRowId={(row) => row.id}
                disableColumnFilter
                disableColumnSelector
                disableColumnSorting
                disableMultipleColumnsSorting
                processRowUpdate={processRowUpdate}
                initialState={{
                    pagination: {
                        paginationModel: {
                            pageSize: 25,
                        },
                    },
                }}
                pageSizeOptions={[10, 25, 50, 100]}
                editMode="row"
                checkboxSelection
                onRowSelectionModelChange={handleSelectionChange}
                selectionModel={selectedRows}
                sx={{
                    '& .MuiDataGrid-cell input': {
                        border: '1px solid #ccc'
                    },
                }}
            />
        </div>
    );
};
rsf-admin/src/page/orders/purchase/PurchaseList.jsx
@@ -126,19 +126,19 @@
          rowClick={'edit'}
          expand={false}
          expandSingle={true}
          omit={['id', 'createTime', 'createBy','channel', 'platCode', 'memo', 'preArr', 'channel','startTime','workQty', 'endTime']}
          omit={['id', 'createTime', 'createBy','channel', 'platCode', 'memo', 'channel','startTime','workQty', 'endTime']}
        >
          <NumberField source="id" />
          <TextField source="code" label="table.field.purchase.code" />
          <TextField source="type$" label="table.field.purchase.type" />
          <TextField source="wkType$" label="table.field.purchase.wkType" />
          <TextField source="source" label="table.field.purchase.source" />
          <DateField source="preArr" label="table.field.purchase.preArr" showTime />
          <NumberField source="anfme" label="table.field.purchase.anfme" />
          <NumberField source="qty" label="table.field.purchase.qty" />
          {/* <NumberField source="workQty" label="table.field.purchase.workQty" /> */}
          <TextField source="channel" label="table.field.purchase.channel" />
          <TextField source="platCode" label="table.field.purchase.platCode" />
          <DateField source="preArr" label="table.field.purchase.preArr" showTime />
          <DateField source="startTime" label="table.field.purchase.startTime" showTime />
          <DateField source="endTime" label="table.field.purchase.endTime" showTime />
          <TextField source="project" label="table.field.purchase.project" />
rsf-admin/src/page/orders/qlyInspect/QlyIsptItemResult.jsx
@@ -97,7 +97,7 @@
                <List
                    storeKey="IsptItem"
                    resource="qlyIsptItem/ispt/result"
                    filter={{ id: record?.id, type: '1' }}
                    filter={{ id: record?.id}}
                    empty={false}
                    filters={false}
                    sort={{ field: "create_time", order: "desc" }}
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx
@@ -64,8 +64,8 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <NumberInput source="areaId" label="table.field.warehouseAreasItem.areaId" />,
    <TextInput source="asnCode" label="table.field.warehouseAreasItem.asnCode" />,
    <TextInput source="areaName" label="table.field.warehouseAreasItem.areaName" />,
    <NumberInput source="matnrId" label="table.field.warehouseAreasItem.matnrId" />,
    <TextInput source="matnrName" label="table.field.warehouseAreasItem.matnrName" />,
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java
@@ -21,12 +21,14 @@
import com.vincent.rsf.server.manager.mapper.*;
import com.vincent.rsf.server.manager.service.*;
import com.vincent.rsf.server.system.constant.CodeRes;
import com.vincent.rsf.server.system.constant.GlobalConfigCode;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.controller.param.LoginParam;
import com.vincent.rsf.server.system.controller.result.LoginResult;
import com.vincent.rsf.server.system.entity.*;
import com.vincent.rsf.server.system.mapper.FieldsMapper;
import com.vincent.rsf.server.system.mapper.TenantMapper;
import com.vincent.rsf.server.system.service.ConfigService;
import com.vincent.rsf.server.system.service.FieldsItemService;
import com.vincent.rsf.server.system.service.UserLoginService;
import com.vincent.rsf.server.system.service.UserService;
@@ -40,6 +42,8 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@@ -120,6 +124,8 @@
    private LocAreaMapper locAreaMapper;
    @Autowired
    private DeviceSiteMapper deviceSiteMapper;
    @Autowired
    private ConfigService configService;
    /**
     * @return
@@ -230,11 +236,15 @@
        }
        //TODO /**收货数量累加,1. 会出超收情况 2. 会有收货不足情况*/
        Double rcptedQty = asnOrder.getQty() + receiptQty;
        asnOrder.setQty(rcptedQty).setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val);
        asnOrder.setQty(rcptedQty).setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val);
        if (!asnOrderMapper.updateById(asnOrder)) {
            throw new CoolException("已收货数量修改失败!!");
        }
        Config config = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.ALLOW_OVER_CHANGE));
        List<Map<String, Object>> receipts1 = (List<Map<String, Object>>) params.get("receipts");
        for (Map<String, Object> rcpt : receipts1) {
            if (null == rcpt || Objects.isNull(rcpt)) {
@@ -266,7 +276,27 @@
            if (Objects.isNull(dto.getReceiptQty()) || Double.compare(dto.getReceiptQty(), 0.0) == 0) {
                throw new CoolException("物料:" + dto.getMaktx() + "收货数量不能为零!!");
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            try {
                if (!Objects.isNull(dto.getProdTime())) {
                    sdf.parse(dto.getProdTime());
                }
            } catch (ParseException e) {
                throw new CoolException("请输入正确的时间格式!!");
            }
            Double itemRcptQty = dto.getReceiptQty() + orderItem.getQty();
            Boolean allowOver = false;
            if (!Objects.isNull(config)) {
                if (Boolean.parseBoolean(config.getVal())) {
                    allowOver = true;
                }
            }
            if (itemRcptQty.compareTo(orderItem.getAnfme()) > 0 && !allowOver) {
                throw new CoolException("收货数量不能大于计划数量!!");
            }
            orderItem.setQty(itemRcptQty)
//                    .setSplrBatch(dto.getSplrBatch())
                    .setUpdateBy(loginUserId)
@@ -342,13 +372,20 @@
                .setFieldsIndex(orderItem.getFieldsIndex())
                .setShipperId(matnr.getShipperId());
        //TODO 供应商标识未设置,标识由PO单供应商编码转换
        WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>()
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<WarehouseAreasItem>()
//                .eq(WarehouseAreasItem::getAsnItemId, item.getAsnItemId())
                .eq(WarehouseAreasItem::getMatnrCode, item.getMatnrCode())
                .eq(!Cools.isEmpty(item.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, item.getFieldsIndex())
                .eq(WarehouseAreasItem::getAsnCode, item.getAsnCode())
                .eq(!Cools.isEmpty(item.getIsptResult()), WarehouseAreasItem::getIsptResult, item.getIsptResult())
                .eq(StringUtils.isNotBlank(item.getSplrBatch()), WarehouseAreasItem::getSplrBatch, item.getSplrBatch()));
                .eq(StringUtils.isNotBlank(item.getSplrBatch()), WarehouseAreasItem::getSplrBatch, item.getSplrBatch());
        if (Objects.isNull(orderItem.getIsptResult())) {
            queryWrapper.isNull(WarehouseAreasItem::getIsptResult);
        } else {
            queryWrapper.eq(WarehouseAreasItem::getIsptResult, orderItem.getIsptResult());
        }
        WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(queryWrapper);
        if (!Objects.isNull(serviceOne)) {
            item.setId(serviceOne.getId());
rsf-server/src/main/java/com/vincent/rsf/server/common/config/SysStockProperties.java
@@ -15,8 +15,6 @@
@Configuration
@ConfigurationProperties(prefix = "stock")
public class SysStockProperties {
    /**
     * wms是否允许打印货物标签, 默认可打印
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderController.java
@@ -221,6 +221,22 @@
        return asnOrderService.saveOrderAndItems(params, getLoginUserId());
    }
    @PostMapping("/asnOrder/purchases/save")
    @ApiOperation("根据PO单新建收货单")
    @PreAuthorize("hasAuthority('manager:asnOrder:save')")
    public R orderCreateByPo(@RequestBody Map<String, Object> params) {
        if (Objects.isNull(params.get("ids"))) {
            return R.error("参数不能为空!!");
        }
        String json = params.get("ids").toString();
        List<Long> ids = JSONArray.parseArray(params.get("ids").toString(), Long.class);
        if (ids.isEmpty()) {
            return R.error("参数不能为空");
        }
        return asnOrderService.createByPo(ids);
    }
    @ApiOperation("单据信息修改")
    @PostMapping("/asnOrder/items/update")
    @PreAuthorize("hasAuthority('manager:asnOrder:update')")
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/PurchaseController.java
@@ -1,6 +1,7 @@
package com.vincent.rsf.server.manager.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
@@ -12,6 +13,7 @@
import com.vincent.rsf.server.manager.entity.AsnOrderItem;
import com.vincent.rsf.server.manager.entity.Purchase;
import com.vincent.rsf.server.manager.entity.PurchaseItem;
import com.vincent.rsf.server.manager.enums.POExceStatus;
import com.vincent.rsf.server.manager.service.AsnOrderItemService;
import com.vincent.rsf.server.manager.service.PurchaseItemService;
import com.vincent.rsf.server.manager.service.PurchaseService;
@@ -48,6 +50,17 @@
    }
    @PreAuthorize("hasAuthority('manager:purchase:list')")
    @PostMapping("/purchase/filters/page")
    public R filterPage(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<Purchase, BaseParam> pageParam = new PageParam<>(baseParam, Purchase.class);
        QueryWrapper<Purchase> wrapper = pageParam.buildWrapper(true);
        wrapper.ne("exce_status", POExceStatus.PO_EXCE_STATUS_ALL_DONE.val);
        return R.ok().add(purchaseService.page(pageParam, wrapper));
    }
    @PreAuthorize("hasAuthority('manager:purchase:list')")
    @PostMapping("/purchase/list")
    public R list(@RequestBody Map<String, Object> map) {
        return R.ok().add(purchaseService.list());
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Purchase.java
@@ -108,6 +108,9 @@
    @ApiModelProperty(value = "收货道口")
    private String channel;
    @ApiModelProperty("执行状态")
    private Short exceStatus;
    /**
     * erp单号
     */
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/excel/PurchaseTemplate.java
@@ -29,13 +29,13 @@
    @Excel(name = "单据类型")
    @ApiModelProperty(value= "单据类型")
    @ExcelComment(value = "type", example = "采购入库单")
    @ExcelComment(value = "type", example = "入库单")
    private String type;
    @Excel(name = "业务类型")
    @ApiModelProperty(value= "业务类型")
    @ExcelComment(value = "wkType", example = "外购收货")
    @ExcelComment(value = "wkType", example = "采购入库单")
    private String wkType;
    @Excel(name = "项目名称")
@@ -131,6 +131,7 @@
    @ExcelComment(value = "splrBatch", example = "20250401")
    private String splrBatch;
    @Excel(name = "预计送达时间")
    @ApiModelProperty("预计送达时间")
    @ExcelComment(value = "arrTime", example = "2025-05-21")
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/AsnExceStatus.java
@@ -9,7 +9,7 @@
 */
public enum AsnExceStatus {
    //质检状态
    //ASN执行状态状态
    ASN_EXCE_STATUS_UN_EXCE("0", "未执行"),
    ASN_EXCE_STATUS_EXCE_ING("1", "执行中"),
    ASN_EXCE_STATUS_RECEIPT_DONE("2", "收货完成"),
@@ -17,6 +17,12 @@
    ASN_EXCE_STATUS_TASK_CANCEL("4", "取消"),
    ASN_EXCE_STATUS_TASK_CLOSE("5", "已关闭"),
    //PO单执行状态
    PO_EXCE_STATUS_UN_EXCE("0", "未执行"),
    PO_EXCE_STATUS_EXCE_ING("1", "执行中"),
    PO_EXCE_STATUS_SECTION_DONE("3", "部分完成"),
    PO_EXCE_STATUS_ALL_DONE("3", "已完成"),
    OUT_STOCK_STATUS_TASK_INIT("11", "初始化"),
    OUT_STOCK_STATUS_TASK_EXCE("12", "待处理"),
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/POExceStatus.java
New file
@@ -0,0 +1,19 @@
package com.vincent.rsf.server.manager.enums;
public enum POExceStatus {
    PO_EXCE_STATUS_UN_EXCE("0", "未执行"),
    PO_EXCE_STATUS_EXCE_ING("1", "执行中"),
    PO_EXCE_STATUS_SECTION_DONE("3", "部分完成"),
    PO_EXCE_STATUS_ALL_DONE("3", "已完成"),
    ;
    POExceStatus(String val, String desc) {
        this.val = Short.parseShort(val);
        this.desc = desc;
    }
    public Short val;
    public String desc;
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java
@@ -11,6 +11,7 @@
import com.vincent.rsf.server.manager.controller.params.WarehouseAreaParam;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
import com.vincent.rsf.server.manager.enums.POExceStatus;
import com.vincent.rsf.server.manager.enums.PakinIOStatus;
import com.vincent.rsf.server.manager.enums.WarehouseAreasType;
import com.vincent.rsf.server.manager.service.*;
@@ -161,15 +162,22 @@
                .setMatnrId(matnr.getId())
                .setIsptResult(orderItem.getIsptResult())
                .setMaktx(matnr.getName())
                .setSplrBatch(orderItem.getSplrBatch())
                .setWeight(matnr.getWeight())
                .setFieldsIndex(orderItem.getFieldsIndex())
                .setShipperId(matnr.getShipperId());
        WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>()
                .eq(WarehouseAreasItem::getMatnrCode, item.getMatnrCode())
                .eq(!Cools.isEmpty(item.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, item.getFieldsIndex())
                .eq(WarehouseAreasItem::getAsnCode, item.getAsnCode())
                .eq(!Cools.isEmpty(item.getIsptResult()), WarehouseAreasItem::getIsptResult, item.getIsptResult())
                .eq(StringUtils.isNotBlank(item.getSplrBatch()), WarehouseAreasItem::getSplrBatch, item.getSplrBatch()));
        LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<WarehouseAreasItem>()
                .eq(WarehouseAreasItem::getMatnrCode, orderItem.getMatnrCode())
                .eq(!Cools.isEmpty(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex())
                .eq(WarehouseAreasItem::getAsnCode, orderItem.getAsnCode())
                .eq(StringUtils.isNotBlank(orderItem.getSplrBatch()), WarehouseAreasItem::getSplrBatch, orderItem.getSplrBatch());
        if (Objects.isNull(orderItem.getIsptResult())) {
            queryWrapper.isNull(WarehouseAreasItem::getIsptResult);
        } else {
            queryWrapper.eq(WarehouseAreasItem::getIsptResult, orderItem.getIsptResult());
        }
        WarehouseAreasItem serviceOne = warehouseAreasItemService.getOne(queryWrapper);
        if (!Objects.isNull(serviceOne)) {
            item.setId(serviceOne.getId());
            item.setAnfme(item.getAnfme() + serviceOne.getAnfme());
@@ -196,7 +204,7 @@
            return;
        }
        //获取未生成ASN单据
        List<Purchase> purchases = purchaseService.list(new LambdaQueryWrapper<Purchase>().eq(Purchase::getStatus, 0));
        List<Purchase> purchases = purchaseService.list(new LambdaQueryWrapper<Purchase>().eq(Purchase::getExceStatus, 0));
        //PO单为空,直接跳出当前任务
        if (purchases.isEmpty()) {
            return;
@@ -259,7 +267,8 @@
            }
            //任务执行完成,修改已完成数量和PO单执行状态
            purchase.setQty(purchase.getAnfme()).setStatus(1);
            purchase.setQty(purchase.getAnfme())
                    .setExceStatus(POExceStatus.PO_EXCE_STATUS_EXCE_ING.val);
            if (!purchaseService.saveOrUpdate(purchase)) {
                throw new CoolException("PO单执行完成后,保存失败!!");
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/AsnOrderService.java
@@ -25,4 +25,5 @@
    R closeOrder(Long id);
    R  createByPo(List<Long> ids);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/PurchaseService.java
@@ -1,8 +1,13 @@
package com.vincent.rsf.server.manager.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.vincent.rsf.server.api.entity.dto.PoItemsDto;
import com.vincent.rsf.server.manager.entity.Purchase;
import java.util.List;
import java.util.Set;
public interface PurchaseService extends IService<Purchase> {
    List<PoItemsDto> poList(Set<Long> asnIds);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderItemServiceImpl.java
@@ -248,8 +248,8 @@
//        }
        //保存扩展字段
        try {
            StringBuffer sb = new StringBuffer();
            if (Objects.isNull(asnOrderItem.getFieldsIndex()) || StringUtils.isBlank(asnOrderItem.getFieldsIndex())) {
                StringBuffer sb = new StringBuffer();
                if (!Objects.isNull(asnOrderItem.getExtendFields()) && !asnOrderItem.getExtendFields().isEmpty()) {
                    Map<String, String> fields = asnOrderItem.getExtendFields();
                    asnOrderItem.getExtendFields().keySet().forEach(key -> {
@@ -260,10 +260,10 @@
                //获取16位uuid
                String uuid16 = Cools.md5Chinese(sb.toString());
                asnOrderItem.setFieldsIndex(uuid16);
                if (FieldsUtils.saveFields(params, uuid16)) {
                    asnOrderItem.setFieldsIndex(uuid16);
                }
                params.put("index", uuid16);
            }
            //保存或更新动态字段值
            FieldsUtils.updateFieldsValue(params);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
@@ -8,19 +8,14 @@
import com.vincent.rsf.server.api.entity.dto.PoItemsDto;
import com.vincent.rsf.server.api.service.ReceiveMsgService;
import com.vincent.rsf.server.api.service.ReportMsgService;
import com.vincent.rsf.server.common.utils.DateUtils;
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.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.enums.POExceStatus;
import com.vincent.rsf.server.manager.mapper.AsnOrderMapper;
import com.vincent.rsf.server.manager.entity.AsnOrder;
import com.vincent.rsf.server.manager.mapper.PurchaseMapper;
import com.vincent.rsf.server.manager.service.AsnOrderItemLogService;
import com.vincent.rsf.server.manager.service.AsnOrderItemService;
import com.vincent.rsf.server.manager.service.AsnOrderLogService;
import com.vincent.rsf.server.manager.service.AsnOrderService;
import com.vincent.rsf.server.manager.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.mapper.SerialRuleMapper;
@@ -49,8 +44,7 @@
    private ReceiveMsgService receiveMsgService;
    @Autowired
    private ReportMsgService reportMsgService;
    @Resource
    private PurchaseMapper purchaseMapper;
    @Autowired
    private AsnOrderItemService asnOrderItemService;
    @Autowired
@@ -59,6 +53,12 @@
    private AsnOrderItemLogService asnOrderItemLogService;
    @Resource
    private SerialRuleMapper serialRuleMapper;
    @Autowired
    private MatnrService matnrService;
    @Autowired
    private PurchaseService purchaseService;
    @Autowired
    private PurchaseItemService purchaseItemService;
    @Override
    public boolean notifyInspect(List<AsnOrder> orders) {
@@ -69,7 +69,7 @@
        if (asnIds.isEmpty()) {
            throw new CoolException("ASN单据不能为空!!");
        }
        List<PoItemsDto> items = purchaseMapper.poList(asnIds);
        List<PoItemsDto> items = purchaseService.poList(asnIds);
        if (items.isEmpty()) {
            throw new CoolException("物料所属采购单据不存在!!");
        }
@@ -247,6 +247,87 @@
    }
    /**
     * @author Ryan
     * @date 2025/5/13
     * @description: 根据PO单创建ASN单
     * @version 1.0
     */
    @Override
    public R createByPo(List<Long> ids) {
        //获取未生成ASN单据
        List<Purchase> purchases = purchaseService.list(new LambdaQueryWrapper<Purchase>().in(Purchase::getId, ids));
        //生成ASN单据
        purchases.forEach(purchase -> {
            if (!Objects.isNull(purchase.getStartTime())) {
                //判断起始时间是否大于当前时间
                if (DateUtils.compareDate(new Date(), purchase.getStartTime())) {
                    return;
                }
            }
            List<PurchaseItem> items = purchaseItemService.list(new LambdaQueryWrapper<PurchaseItem>().eq(PurchaseItem::getPurchaseId, purchase.getId()));
            if (items.isEmpty()) {
                throw new CoolException("子列表数据为空,请查询PO单是否正确录入!!");
            }
            AsnOrder order = new AsnOrder();
            //根据编码规则生成ASN单号
            String code = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_ASN_ORDER, purchase);
            order.setAnfme(purchase.getAnfme())
                    .setCode(code)
                    .setArrTime(purchase.getPreArr())
                    .setQty(purchase.getQty())
                    .setPoId(purchase.getId())
                    .setPoCode(purchase.getCode());
            if (!this.save(order)) {
                throw new CoolException("ASN单据保存失败!!");
            }
            List<AsnOrderItem> orderItems = new ArrayList<>();
            items.forEach(item -> {
                AsnOrderItem orderItem = new AsnOrderItem();
                Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getCode, item.getMatnrCode()));
                if (Objects.isNull(matnr)) {
                    throw new CoolException("数据错误:当前物料不存在!!");
                }
                String trackCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_LABEL_CODE, item);
                if (StringUtils.isBlank(trackCode)) {
                    throw new CoolException("单据跟踪码生成失败:请检查「sys_asn_mantr_label」是否配置完成!!");
                }
//                String barcode = code + matnr.getCode();
                orderItem.setAnfme(item.getAnfme())
                        .setAsnId(order.getId())
                        .setQty(item.getAnfme())
                        .setSplrName(item.getSplrName())
                        .setAsnCode(code)
                        .setSplrBatch(item.getSplrBatch())
                        .setSplrCode(item.getSplrCode())
                        .setPoDetlId(item.getId())
                        .setPlatItemId(item.getPlatItemId())
                        .setTrackCode(trackCode)
                        .setPoCode(purchase.getCode())
                        .setPurQty(item.getAnfme())
                        .setPurUnit(item.getUnit())
                        .setMatnrCode(matnr.getCode())
                        .setMaktx(matnr.getName())
                        .setMatnrId(matnr.getId());
                orderItems.add(orderItem);
            });
            if (!asnOrderItemService.saveBatch(orderItems)) {
                throw new CoolException(("Asn单据明细保存失败!!"));
            }
            //任务执行完成,修改已完成数量和PO单执行状态
            purchase.setQty(purchase.getAnfme())
                    .setExceStatus(POExceStatus.PO_EXCE_STATUS_EXCE_ING.val);
            if (!purchaseService.saveOrUpdate(purchase)) {
                throw new CoolException("PO单执行完成后,保存失败!!");
            }
        });
        return null;
    }
    /**
     * @param
     * @return
     * @author Ryan
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/PurchaseItemServiceImpl.java
@@ -96,25 +96,25 @@
                if (StringUtils.isBlank(purchaseTemplate.getMatnrCode())) {
                    throw new CoolException(purchaseTemplate.getPoCode() + ":物料编码不能为空!!");
                }
                Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getCode, template.getMatnrCode()));
                Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getCode, purchaseTemplate.getMatnrCode()));
                if (Objects.isNull(matnr)) {
                    throw new CoolException(template.getMatnrCode() + "物料不存在!!");
                    throw new CoolException(purchaseTemplate.getMatnrCode() + "物料不存在!!");
                }
                item.setMatnrName(matnr.getName())
                        .setMatnrCode(matnr.getCode())
                        .setPlatItemId(template.getPlatItemId())
                        .setAnfme(template.getAnfme())
                        .setPlatItemId(purchaseTemplate.getPlatItemId())
                        .setAnfme(purchaseTemplate.getAnfme())
                        .setPurchaseId(purchase.getId())
                        .setUnit(matnr.getUnit())
                        .setNromQty(matnr.getNromNum())
                        .setSplrBatch(template.getSplrBatch())
                        .setSplrBatch(purchaseTemplate.getSplrBatch())
                        .setCreateBy(loginUserId)
                        .setUpdateBy(loginUserId);
                if (StringUtils.isNotBlank(purchaseTemplate.getSplrCode())) {
                    Companys companys = companysService.getOne(new LambdaQueryWrapper<Companys>()
                            .eq(Companys::getType, CompanysType.COMPANYS_TYPE_SUPPLIER.val)
                            .eq(Companys::getCode, template.getSplrCode()));
                            .eq(Companys::getCode, purchaseTemplate.getSplrCode()));
                    if (!Objects.isNull(companys)) {
                        item.setSplrCode(companys.getCode()).setSplrName(companys.getName());
                    } else {
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/PurchaseServiceImpl.java
@@ -1,12 +1,20 @@
package com.vincent.rsf.server.manager.service.impl;
import com.vincent.rsf.server.api.entity.dto.PoItemsDto;
import com.vincent.rsf.server.manager.mapper.PurchaseMapper;
import com.vincent.rsf.server.manager.entity.Purchase;
import com.vincent.rsf.server.manager.service.PurchaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
@Service("purchaseService")
public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, Purchase> implements PurchaseService {
    @Override
    public List<PoItemsDto> poList(Set<Long> asnIds) {
        return this.baseMapper.poList(asnIds);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/QlyIsptItemServiceImpl.java
@@ -16,6 +16,7 @@
import com.vincent.rsf.server.manager.service.QlyInspectService;
import com.vincent.rsf.server.manager.service.QlyIsptItemService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -122,10 +123,9 @@
                    throw new CoolException("收货区库存信息更新失败!!");
                }
                //新建质检单,质检结果不会有质检结果
                if (Objects.isNull(orderItem.getIsptResult())) {
                    operateReceipt(item, orderItem);
                } else {
                }
            }
        }
@@ -141,7 +141,6 @@
                    .eq(QlyInspect::getId, isptItem.stream().findFirst().get().getIspectId()));
        }
//        qlyIsptItemService.pageByIsptResult(null, new QueryWrapper<QlyIsptItem>())
        return true;
    }
@@ -158,37 +157,51 @@
        if (sum.compareTo(orderItem.getAnfme()) >= 0) {
            //完成质检,做更新操作
            if (safeQty.compareTo(0.0) > 0) {
                orderItem.setIsptQty(safeQty);
                orderItem.setIsptQty(safeQty).setAnfme(safeQty);
                orderItem.setIsptResult(QlyIsptResult.QLY_ISPT_RESULT_EXCELLENT.val);
                if (!warehouseAreasItemService.updateById(orderItem)) {
                    throw new CoolException("收货区库存明细更新失败!!");
                }
            }
            WarehouseAreasItem areasItem = new WarehouseAreasItem();
            BeanUtils.copyProperties(orderItem, areasItem);
            if (disQty.compareTo(0.0) > 0) {
                orderItem.setIsptQty(disQty)
                areasItem.setIsptQty(disQty)
                        .setAnfme(disQty)
                        .setId(null)
                        .setIsptResult(QlyIsptResult.QLY_ISPT_RESULT_DEFECT.val);
                if (!warehouseAreasItemService.saveOrUpdate(orderItem)) {
                if (!warehouseAreasItemService.saveOrUpdate(areasItem)) {
                    throw new CoolException("收货区库存明细更新失败!!");
                }
            }
        } else {
            orderItem.setAnfme(orderItem.getAnfme() - sum);
            if (!warehouseAreasItemService.updateById(orderItem)) {
                throw new CoolException("收货区库存明细更新失败!!");
            }
            WarehouseAreasItem areasItem = new WarehouseAreasItem();
            BeanUtils.copyProperties(orderItem, areasItem);
            //未完成做添加操作
            if (safeQty.compareTo(0.0) > 0) {
                orderItem.setIsptQty(safeQty)
                areasItem.setIsptQty(safeQty)
                        .setAnfme(safeQty)
                        .setId(null)
                        .setIsptResult(QlyIsptResult.QLY_ISPT_RESULT_EXCELLENT.val);
                if (!warehouseAreasItemService.saveOrUpdate(orderItem)) {
                if (!warehouseAreasItemService.saveOrUpdate(areasItem)) {
                    throw new CoolException("收货区库存明细更新失败!!");
                }
            }
            WarehouseAreasItem items = new WarehouseAreasItem();
            BeanUtils.copyProperties(orderItem, items);
            if (disQty.compareTo(0.0) > 0) {
                orderItem.setIsptQty(disQty)
                items.setIsptQty(disQty)
                        .setAnfme(disQty)
                        .setId(null)
                        .setIsptResult(QlyIsptResult.QLY_ISPT_RESULT_DEFECT.val);
                if (!warehouseAreasItemService.saveOrUpdate(orderItem)) {
                if (!warehouseAreasItemService.saveOrUpdate(items)) {
                    throw new CoolException("收货区库存明细更新失败!!");
                }
            }
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/GlobalConfigCode.java
@@ -8,10 +8,11 @@
 */
public class GlobalConfigCode {
    public final static String EXECUTION = "Execution";
    /**直接组托*/
    public final static String DIRECT_WAIT_PAKIN = "DirectWaitPakin";
    /**收货时是否允许超收*/
    public final static String ALLOW_OVER_CHANGE = "AllowOverchange";
}
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/FieldsController.java
@@ -46,7 +46,7 @@
    @GetMapping("/fields/enable/list")
    @ApiOperation("获取已开启扩展字段")
    public R getEnableList() {
        return R.ok(fieldsService.list(new LambdaQueryWrapper<Fields>().eq(Fields::getFlagEnable, 1).eq(Fields::getStatus, 1)));
        return R.ok(fieldsService.list(new LambdaQueryWrapper<Fields>().eq(Fields::getFlagEnable, 1)));
    }
    @PreAuthorize("hasAuthority('system:fields:list')")
rsf-server/src/main/resources/application-dev.yml
@@ -89,7 +89,7 @@
  #是否允许打印货物标签, 默认允许打印,也可由供应商提供标签
  flagPrinter: false
  #是否自动生成ASN单(默认:是),为『否』则开启PO单手动生成ASN单功能
  flagAutoAsn: true
  flagAutoAsn: false
  #质检功能 是否校验上架(默认:是),是否校验收货(默认:否)
  inspect:
    #判断是后检验合格后,才允许上架