huminmin
2026-07-10 2ee9e158e3129070f6b1fd953da1540f05d4f2b0
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -7,10 +7,16 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.service.ApprovalTemplateService;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.TypeEnums;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
@@ -78,6 +84,8 @@
    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
    private final ApprovalTemplateService approvalTemplateService;
    private final ApprovalInstanceService approvalInstanceService;
    private final StockUtils stockUtils;
    private final StockInRecordService stockInRecordService;
    private final StockInventoryService stockInventoryService;
@@ -277,9 +285,13 @@
        productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName());
        productionProductMain.setProductionOperationTaskId(taskId);
        productionProductMain.setStatus(0);
        productionProductMain.setReportType(dto.getReportType() == null ? 0 : dto.getReportType());
        productionProductMain.setAuditStatus(dto.getAuditStatus() == null ? 0 : dto.getAuditStatus());
        productionProductMain.setAuditRemark(dto.getAuditRemark());
        productionProductMain.setWorkHour(dto.getWorkHour());
        productionProductMainMapper.insert(productionProductMain);
        syncOperationParamInputValue(dto, routingOperation.getId(), productionProductMain.getId());
        createReportApprovalInstance(productionProductMain);
        List<ProductStructureDto> productStructureDtos = resolveInputStructures(
                productionOrder.getId(), routingOperation, productModel.getId());
@@ -378,8 +390,10 @@
            if (ObjectUtils.isNull(productionOrder.getStartTime())) {
                productionOrder.setStartTime(LocalDateTime.now());
            }
            // 订单状态由最后一道工序的合格产出推动,避免中间工序提前完工。
            productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
            // 仅待开始状态才推进到进行中,避免非末道工序报工时覆盖已完成状态。
            if (ProductOrderStatusEnum.WAIT.getCode().equals(productionOrder.getStatus())) {
                productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
            }
            if (isLastOperation) {
                productionOrder.setCompleteQuantity(defaultDecimal(productionOrder.getCompleteQuantity()).add(productQty));
                if (productionOrder.getQuantity() != null
@@ -404,7 +418,6 @@
            productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
            productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
            productionAccount.setSchedulingDate(LocalDateTime.now());
            productionAccountMapper.insert(productionAccount);
        }
        if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
            stockUtils.addUnStockWithBatchNo(
@@ -415,6 +428,120 @@
                    qualifiedBatchNo);
        }
        return true;
    }
    private void createReportApprovalInstance(ProductionProductMain productionProductMain) {
        if (productionProductMain == null || productionProductMain.getId() == null) {
            return;
        }
        ApprovalTemplateVo templateVo = approvalTemplateService.getEnabledTemplateByBusinessType(
                TypeEnums.PRODUCTION_REPORT_APPROVAL.getCode()
        );
        if (templateVo == null) {
            throw new ServiceException("请先配置报工审批模板");
        }
        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
        approvalInstanceDto.setTemplateId(templateVo.getId());
        approvalInstanceDto.setTemplateName(templateVo.getTemplateName());
        approvalInstanceDto.setBusinessId(productionProductMain.getId());
        approvalInstanceDto.setBusinessType(TypeEnums.PRODUCTION_REPORT_APPROVAL.getCode());
        approvalInstanceDto.setTitle(productionProductMain.getProductNo());
        approvalInstanceDto.setApplicantId(productionProductMain.getUserId());
        approvalInstanceDto.setApplicantName(productionProductMain.getUserName());
        approvalInstanceDto.setApplyTime(LocalDateTime.now());
        approvalInstanceDto.setStatus("PENDING");
        approvalInstanceDto.setFormConfig(JSON.toJSONString(buildReportApprovalFormConfig(productionProductMain)));
        approvalInstanceService.add(approvalInstanceDto);
    }
    private Map<String, Object> buildReportApprovalFormConfig(ProductionProductMain productionProductMain) {
        Map<String, Object> formConfig = new LinkedHashMap<>();
        formConfig.put("summaryPlaceholder", "报工审批");
        formConfig.put("approvalType", "production_report");
        List<Map<String, Object>> fields = new ArrayList<>();
        fields.add(buildReportField("productNo", "报工单号", "text", productionProductMain.getProductNo()));
        fields.add(buildReportField("userName", "报工人员", "text", productionProductMain.getUserName()));
        fields.add(buildReportField("workOrderNo", "工单编号", "text", resolveWorkOrderNo(productionProductMain.getProductionOperationTaskId())));
        fields.add(buildReportField("reportType", "报工结果", "select", resolveReportTypeLabel(productionProductMain.getReportType())));
        fields.add(buildReportField("workHour", "工时", "number", productionProductMain.getWorkHour()));
        fields.add(buildReportField("auditStatus", "审核状态", "select", resolveAuditStatusLabel(productionProductMain.getAuditStatus())));
        fields.add(buildReportField("auditRemark", "审核意见", "textarea", productionProductMain.getAuditRemark()));
        formConfig.put("fields", fields);
        Map<String, Object> formPayload = new LinkedHashMap<>();
        formPayload.put("productNo", productionProductMain.getProductNo());
        formPayload.put("userName", productionProductMain.getUserName());
        formPayload.put("workOrderNo", resolveWorkOrderNo(productionProductMain.getProductionOperationTaskId()));
        formPayload.put("reportType", resolveReportTypeLabel(productionProductMain.getReportType()));
        formPayload.put("workHour", productionProductMain.getWorkHour());
        formPayload.put("auditStatus", resolveAuditStatusLabel(productionProductMain.getAuditStatus()));
        formPayload.put("auditRemark", productionProductMain.getAuditRemark());
        formConfig.put("formPayload", formPayload);
        return formConfig;
    }
    private Map<String, Object> buildReportField(String key, String label, String type, Object defaultValue) {
        Map<String, Object> field = new LinkedHashMap<>();
        field.put("key", key);
        field.put("label", label);
        field.put("type", type);
        field.put("required", Boolean.FALSE);
        field.put("defaultValue", defaultValue);
        return field;
    }
    private String resolveWorkOrderNo(Long productionOperationTaskId) {
        if (productionOperationTaskId == null) {
            return null;
        }
        ProductionOperationTask task = productionOperationTaskMapper.selectById(productionOperationTaskId);
        if (task != null && task.getWorkOrderNo() != null) {
            return task.getWorkOrderNo();
        }
        if (task == null || task.getProductionOrderRoutingOperationId() == null) {
            return null;
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(task.getProductionOrderRoutingOperationId());
        if (routingOperation == null || routingOperation.getProductionOrderId() == null) {
            return null;
        }
        ProductionOrder productionOrder = productionOrderMapper.selectById(routingOperation.getProductionOrderId());
        return productionOrder == null ? null : productionOrder.getNpsNo();
    }
    private String resolveReportTypeLabel(Integer reportType) {
        if (reportType == null) {
            return "—";
        }
        switch (reportType) {
            case 0:
                return "合格";
            case 1:
                return "轻微返工";
            case 2:
                return "严重返工";
            case 3:
                return "报废";
            default:
                return "—";
        }
    }
    private String resolveAuditStatusLabel(Integer auditStatus) {
        if (auditStatus == null) {
            return "待审核";
        }
        switch (auditStatus) {
            case 0:
                return "待审核";
            case 1:
                return "审核通过";
            case 2:
                return "审核不通过";
            default:
                return "—";
        }
    }
    private String resolveLatestStockInBatchNo(Long recordId,
@@ -679,6 +806,86 @@
        return dto.getProductionOperationTaskId();
    }
    private boolean isCountingWageReport(ProductionProductMain productionProductMain) {
        return productionProductMain != null
                && productionProductMain.getAuditStatus() != null
                && productionProductMain.getAuditStatus() == 1
                && productionProductMain.getReportType() != null
                && productionProductMain.getReportType() == 0;
    }
    private boolean isExcludedFromWage(ProductionProductMain productionProductMain) {
        return productionProductMain != null
                && productionProductMain.getReportType() != null
                && productionProductMain.getReportType() != 0;
    }
    @Override
    public Boolean auditProductMain(ProductionProductMainDto productionProductMainDto) {
        if (productionProductMainDto == null || productionProductMainDto.getId() == null) {
            throw new ServiceException("参数错误");
        }
        ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productionProductMainDto.getId());
        if (productionProductMain == null) {
            throw new ServiceException("报工不存在");
        }
        Integer auditStatus = productionProductMainDto.getAuditStatus();
        if (auditStatus == null) {
            throw new ServiceException("审核状态不能为空");
        }
        productionProductMain.setAuditStatus(auditStatus);
        productionProductMain.setAuditRemark(productionProductMainDto.getAuditRemark());
        productionProductMainMapper.updateById(productionProductMain);
        productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                .eq(ProductionAccount::getProductionProductMainId, productionProductMain.getId()));
        if (auditStatus == 1 && !isExcludedFromWage(productionProductMain)) {
            rebuildProductionAccount(productionProductMain);
        }
        return true;
    }
    private void rebuildProductionAccount(ProductionProductMain productionProductMain) {
        if (productionProductMain == null || productionProductMain.getId() == null) {
            return;
        }
        ProductionProductOutput output = productionProductOutputMapper.selectOne(
                Wrappers.<ProductionProductOutput>lambdaQuery()
                        .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId())
                        .last("limit 1"));
        if (output == null) {
            return;
        }
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
        if (productionOperationTask == null) {
            return;
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getProductionOrderRoutingOperationId());
        if (routingOperation == null) {
            return;
        }
        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
        if (productionOrder == null) {
            return;
        }
        TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
        TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
        SysUser user = userMapper.selectUserById(productionProductMain.getUserId());
        BigDecimal productQty = defaultDecimal(output.getQuantity());
        if (productQty.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        ProductionAccount productionAccount = new ProductionAccount();
        productionAccount.setProductionProductMainId(productionProductMain.getId());
        productionAccount.setSchedulingUserId(user == null ? productionProductMain.getUserId() : user.getUserId());
        productionAccount.setSchedulingUserName(user == null ? productionProductMain.getUserName() : user.getNickName());
        productionAccount.setFinishedNum(productQty);
        productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
        productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
        productionAccount.setSchedulingDate(LocalDateTime.now());
        productionAccountMapper.insert(productionAccount);
    }
    @Override
    public ArrayList<Long> listMain(List<Long> idList) {
        // 查询主表ID集合