skyouc
5 天以前 40d9cd510741a098bd52cbe22a5f9e5528f45abc
# 新增
1. 通过单据新增出库单功能
2. 新增生成出库单接口
8个文件已修改
306 ■■■■■ 已修改文件
rsf-admin/src/i18n/en.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/orders/outStock/OutOrderModal.jsx 146 ●●●●● 补丁 | 查看 | 原始文档 | 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/outStock/OutOrderModal.jsx
@@ -36,13 +36,16 @@
    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 } from "@mui/system";
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': {
@@ -95,6 +98,62 @@
            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
            open={open}
@@ -129,9 +188,8 @@
                                    }),
                                marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                            }}
                            storeKey='selectDelivery'
                            queryOptions={params}
                            filters={<CustomFilter />}
                            queryOptions={{ meta: { ...params } }}
                            empty={false}
                            sort={{ field: "create_time", order: "desc" }}
                            actions={(
@@ -143,7 +201,7 @@
                        >
                            <StyledDatagrid
                                preferenceKey='deliveryItem'
                                bulkActionButtons={() => <></>}
                                bulkActionButtons={<AddOutStockButton  setOpen={setOpen}/>}
                                rowClick={(id, resource, record) => false}
                                expand={false}
                                expandSingle={true}
@@ -173,63 +231,25 @@
export default OutOrderModal;
const CustomFilter = () => {
    const { filterValues, setFilters } = useListContext('deliveryItem');
    const [formValues, setFormValues] = useState(filterValues);
    const handleChange = (event) => {
        setFormValues(formValues => ({
            ...formValues,
            [event.target.name]: event.target.value
        }));
    };
    const handleSubmit = (event) => {
        console.log('---------->');
        console.log(formValues);
        event.preventDefault();
        setFilters(formValues, null, true);
    };
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 (
        <Form>
            <Grid container rowSpacing={2} columnSpacing={2} >
                <Stack>
                    <TextInput
                        source="matnrName"
                        label="table.field.deliveryItem.matnrName"
                        resettable
                        onChange={handleChange}
                        />
                </Stack>
                <Stack>
                    <TextInput
                        source="matnrCode"
                        label="table.field.deliveryItem.matnrCode"
                        resettable
                        onChange={handleChange} />
                </Stack>
                <Stack>
                    <TextInput
                        source="splrName"
                        label="table.field.deliveryItem.splrName"
                        resettable
                        onChange={handleChange} />
                </Stack>
                <Stack>
                    <TextInput
                        source="splrName"
                        label="table.field.deliveryItem.splrName"
                        resettable
                        onChange={handleChange} />
                </Stack>
            </Grid>
            <DialogActions>
                <Toolbar sx={{ width: '100%', justifyContent: 'end' }}  >
                    <SaveButton onClick={handleSubmit}/>
                    {/* <Button variant="contained" label="toolbar.confirm" startIcon={<SaveIcon />} onClick={handleSubmit} /> */}
                </Toolbar>
            </DialogActions>
        </Form>
    );
};
        <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();