huminmin
10 小时以前 bdb10f17dd56fdb8dd8e3dca897c5cfb5e40a75d
src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
@@ -4,12 +4,16 @@
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ai.assistant.Assistant;
import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
import com.ruoyi.approve.pojo.ApprovalInstance;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.basic.service.ICustomerService;
import com.ruoyi.basic.service.ISupplierService;
import com.ruoyi.common.enums.ReviewStatusEnum;
import com.ruoyi.mock.dto.DataGenerateRequest;
import com.ruoyi.mock.prompt.MockDataPrompt;
import com.ruoyi.mock.service.DataGenerateService;
@@ -20,25 +24,34 @@
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.production.service.ProductionPlanService;
import com.ruoyi.purchase.dto.PurchaseLedgerDto;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.purchase.service.IPurchaseLedgerService;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardBinding;
import com.ruoyi.quality.service.IQualityInspectService;
import com.ruoyi.quality.service.IQualityTestStandardService;
import com.ruoyi.quality.service.QualityTestStandardBindingService;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerService;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
@Slf4j
@@ -59,6 +72,12 @@
    private final ProductionPlanService productionPlanService;
    private final ProductionOrderService productionOrderService;
    private final StockInventoryService stockInventoryService;
    // 采购完整流程需要的service
    private final ApprovalInstanceService approvalInstanceService;
    private final ApprovalInstanceMapper approvalInstanceMapper;
    private final IQualityInspectService qualityInspectService;
    private final StockInRecordService stockInRecordService;
    @Override
    public DataGenerateResult generate(DataGenerateRequest request) {
@@ -132,7 +151,8 @@
                totalGenerated += s.getSuccessCount();
            }
            if (grouped.containsKey("purchaseLedger")) {
                ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId);
                ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId,
                        request.getAdditionalInfo(), request.getDateEnd());
                summaries.add(s);
                totalGenerated += s.getSuccessCount();
            }
@@ -208,7 +228,23 @@
                c.setContactPerson(item.getString("contactPerson"));
                c.setContactPhone(item.getString("contactPhone"));
                c.setCompanyAddress(item.getString("companyAddress"));
                c.setCompanyPhone(item.getString("companyPhone"));
                c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber"));
                c.setMaintainer(item.getString("maintainer"));
                if (item.containsKey("maintenanceTime")) {
                    c.setMaintenanceTime(java.sql.Date.valueOf(item.getString("maintenanceTime")));
                } else {
                    c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis()));
                }
                if (item.containsKey("bankAccount")) {
                    c.setBankAccount(item.getString("bankAccount"));
                }
                if (item.containsKey("basicBankAccount")) {
                    c.setBasicBankAccount(item.getString("basicBankAccount"));
                }
                if (item.containsKey("bankCode")) {
                    c.setBankCode(item.getString("bankCode"));
                }
                customerService.insertCustomer(c);
                if (c.getId() != null) {
                    nameToId.put(c.getCustomerName(), c.getId());
@@ -232,6 +268,7 @@
                s.setContactUserName(item.getString("contactUserName"));
                s.setContactUserPhone(item.getString("contactUserPhone"));
                s.setCompanyAddress(item.getString("companyAddress"));
                s.setCompanyPhone(item.getString("companyPhone"));
                s.setTaxpayerIdentificationNum(item.getString("taxpayerIdentificationNum"));
                s.setBankAccountName(item.getString("bankAccountName"));
                s.setBankAccountNum(item.getString("bankAccountNum"));
@@ -286,6 +323,10 @@
                dto.setSalesman(item.getString("salesman"));
                dto.setPaymentMethod(item.getString("paymentMethod"));
                dto.setType(item.getInteger("type"));
                // 录入人:优先使用AI提供的数据,否则用当前登录用户
                if (item.containsKey("entryPerson")) {
                    dto.setEntryPerson(item.getString("entryPerson"));
                }
                if (item.containsKey("entryDate")) {
                    dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
                }
@@ -309,6 +350,17 @@
                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
                        slp.setUnit(pd.getString("unit"));
                        slp.setType(pd.getInteger("type"));
                        if (pd.containsKey("taxExclusiveTotalPrice")) {
                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
                            // 不含税总价 = 含税总价 / (1 + 税率/100)
                            slp.setTaxExclusiveTotalPrice(
                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
                                    2, RoundingMode.HALF_UP));
                        } else {
                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
                        }
                        products.add(slp);
                    }
                    dto.setProductData(products);
@@ -323,7 +375,11 @@
        return summary("sales", "销售台账", items.size(), success, fail);
    }
    private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId) {
    private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId,
                                                 String additionalInfo, String dateEnd) {
        // 是否需要质检,从补充信息判断,默认不需要
        boolean needQualityInspect = additionalInfo != null
                && (additionalInfo.contains("质检") || additionalInfo.contains("需要检验"));
        int success = 0, fail = 0;
        for (JSONObject item : items) {
            try {
@@ -337,8 +393,12 @@
                dto.setProjectName(item.getString("projectName"));
                dto.setContractAmount(item.getBigDecimal("contractAmount"));
                dto.setPaymentMethod(item.getString("paymentMethod"));
                String entryDateStr = item.getString("entryDate");
                LocalDate entryDate = null;
                if (item.containsKey("entryDate")) {
                    dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
                    entryDate = LocalDate.parse(entryDateStr);
                    dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
                }
                if (item.containsKey("executionDate")) {
                    dto.setExecutionDate(java.sql.Date.valueOf(item.getString("executionDate")));
@@ -357,11 +417,32 @@
                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
                        slp.setUnit(pd.getString("unit"));
                        slp.setType(2);
                        // 是否质检:从补充信息判断,默认不需要
                        slp.setIsChecked(needQualityInspect);
                        if (pd.containsKey("taxExclusiveTotalPrice")) {
                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
                            slp.setTaxExclusiveTotalPrice(
                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
                                    2, RoundingMode.HALF_UP));
                        } else {
                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
                        }
                        products.add(slp);
                    }
                    dto.setProductData(products);
                }
                purchaseLedgerService.addOrEditPurchase(dto);
                // 通过合同号找到刚创建的采购台账
                PurchaseLedger savedLedger = purchaseLedgerService.getOne(
                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<PurchaseLedger>()
                                .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber())
                                .last("limit 1"));
                if (savedLedger != null) {
                    // 走完整流程:审核通过 → 质检(可选) → 入库 + 入库审核通过
                    processPurchaseFullFlow(savedLedger, needQualityInspect, entryDate, dateEnd);
                }
                success++;
            } catch (Exception e) {
                log.warn("创建采购台账失败: {}", e.getMessage());
@@ -371,6 +452,108 @@
        return summary("purchase", "采购台账", items.size(), success, fail);
    }
    /**
     * 采购完整流程: 审核通过 → 质检(可选) → 入库审核通过
     */
    private void processPurchaseFullFlow(PurchaseLedger purchaseLedger, boolean needQualityInspect,
                                          LocalDate entryDate, String dateEnd) {
        try {
            // 1. 审批自动通过
            ApprovalInstance approvalInstance = approvalInstanceMapper.selectOne(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
                            .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
                            .eq(ApprovalInstance::getBusinessType, 5L)
                            .eq(ApprovalInstance::getDeleted, 0)
                            .orderByDesc(ApprovalInstance::getId)
                            .last("limit 1"));
            if (approvalInstance != null) {
                // 结算审批开始时间:基于录入日期,随机推0-3天
                LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
                LocalDate approveDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
                // 使用autoApprove完成审批
                approvalInstanceService.autoApprove(approvalInstance.getId());
                log.info("采购台账[{}]审批通过, 审批日期: {}", purchaseLedger.getPurchaseContractNumber(), approveDate);
            }
            // 2. 质检流程(如果需要质检)
            if (needQualityInspect) {
                processQualityInspect(purchaseLedger, entryDate, dateEnd);
            }
            // 3. 入库审批通过
            processStockInApprove(purchaseLedger, dateEnd);
        } catch (Exception e) {
            log.warn("采购完整流程处理失败[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
        }
    }
    /**
     * 质检: 找到采购关联的质检单,自动提交为合格
     */
    private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate entryDate, String dateEnd) {
        try {
            List<QualityInspect> inspectList = qualityInspectService.list(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()));
            for (QualityInspect qi : inspectList) {
                if (qi.getInspectState() == null || qi.getInspectState() == 0) {
                    qualityInspectService.autoSubmit(qi.getId());
                    log.info("采购台账[{}]质检单[{}]自动提交合格", purchaseLedger.getPurchaseContractNumber(), qi.getId());
                }
            }
        } catch (Exception e) {
            log.warn("质检流程处理失败[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
        }
    }
    /**
     * 入库审核: 找到入库记录并审批通过
     */
    private void processStockInApprove(PurchaseLedger purchaseLedger, String dateEnd) {
        try {
            List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
                                    String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode())));
            // 如果按PURCHASE_STOCK_IN找不到,尝试CUSTOMIZATION_UNSTOCK_OUT(质检合格入库)
            if (stockRecords.isEmpty()) {
                stockRecords = stockInRecordService.list(
                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
                                        String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode())));
            }
            // 也尝试按质检单ID查找(质检单的recordId是质检单ID)
            for (QualityInspect qi : qualityInspectService.list(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()))) {
                List<com.ruoyi.stock.pojo.StockInRecord> qiRecords = stockInRecordService.list(
                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, qi.getId()));
                stockRecords.addAll(qiRecords);
            }
            // 去重
            stockRecords = stockRecords.stream()
                    .collect(Collectors.toMap(com.ruoyi.stock.pojo.StockInRecord::getId, r -> r, (a, b) -> a))
                    .values().stream().collect(Collectors.toList());
            if (!stockRecords.isEmpty()) {
                List<Long> recordIds = stockRecords.stream()
                        .filter(r -> r.getApprovalStatus() == null || r.getApprovalStatus() == 0)
                        .map(com.ruoyi.stock.pojo.StockInRecord::getId)
                        .collect(Collectors.toList());
                if (!recordIds.isEmpty()) {
                    stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
                    log.info("采购台账[{}]入库审批通过, 入库记录数: {}", purchaseLedger.getPurchaseContractNumber(), recordIds.size());
                }
            }
        } catch (Exception e) {
            log.warn("入库审批失败[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
        }
    }
    private ModuleSummary createProductionPlans(List<JSONObject> items) {
        int success = 0, fail = 0;
        for (JSONObject item : items) {