package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 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.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.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DictUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.dto.*; import com.ruoyi.production.mapper.ProductionProductReportDailyMapper; import com.ruoyi.production.pojo.ProductionProductReportDaily; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.quality.mapper.*; import com.ruoyi.quality.pojo.*; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.production.mapper.ProductionProductMainMapper; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service @AllArgsConstructor @Transactional(rollbackFor = Exception.class) public class ProductionProductMainServiceImpl extends ServiceImpl implements ProductionProductMainService { private ProductionProductMainMapper productionProductMainMapper; private ProductionProductReportDailyMapper productionProductReportDailyMapper; private ProductWorkOrderMapper productWorkOrderMapper; private ProductProcessRouteItemMapper productProcessRouteItemMapper; private SysUserMapper userMapper; private ProductionProductOutputMapper productionProductOutputMapper; private ProductModelMapper productModelMapper; private ProductMapper productMapper; private ProductProcessMapper productProcessMapper; private QualityInspectMapper qualityInspectMapper; private QualityUnqualifiedMapper qualityUnqualifiedMapper; private QualityInspectParamMapper qualityInspectParamMapper; private QualityTestStandardParamMapper qualityTestStandardParamMapper; private QualityTestStandardMapper qualityTestStandardMapper; private ProductionProductInputMapper productionProductInputMapper; private ProductOrderMapper productOrderMapper; private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper; private StockUtils stockUtils; @Override public IPage listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) { if (productionProductMainDto == null) { productionProductMainDto = new ProductionProductMainDto(); } // productionProductMainDto.setUserId(SecurityUtils.getUserId()); IPage result = productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto); fillHourDefaults(result.getRecords()); return result; } @Override public IPage listPageProductionProductMainDetailDto(Page page, ProductionProductMainDto productionProductMainDto) { if (productionProductMainDto == null) { productionProductMainDto = new ProductionProductMainDto(); } IPage result = productionProductMainMapper.listPageProductionProductMainDetailDto(page, productionProductMainDto); fillHourDefaults(result.getRecords()); return result; } @Override public List listSummaryExportData(ProductionProductMainDto productionProductMainDto) { return listPageProductionProductMainDto(new Page<>(1, -1), productionProductMainDto) .getRecords() .stream() .map(item -> { ProductionProductMainSummaryExportDto exportDto = new ProductionProductMainSummaryExportDto(); exportDto.setProcess(item.getProcess()); exportDto.setWorkOrderNo(item.getWorkOrderNo()); exportDto.setSalesContractNo(item.getSalesContractNo()); exportDto.setProductOrderNpsNo(item.getProductOrderNpsNo()); exportDto.setProductName(item.getProductName()); exportDto.setProductModelName(item.getProductModelName()); exportDto.setUnit(item.getUnit()); exportDto.setProjectTotalHours(item.getProjectTotalHours()); exportDto.setProcessStandardHours(item.getProcessStandardHours()); exportDto.setActualReportHours(item.getActualReportHours()); exportDto.setDailyPersonHours(item.getDailyPersonHours()); exportDto.setOutputTotalQuantity(item.getOutputTotalQuantity()); exportDto.setScrapTotalQuantity(item.getScrapTotalQuantity()); return exportDto; }) .collect(Collectors.toList()); } @Override public List listDetailExportData(ProductionProductMainDto productionProductMainDto) { return listPageProductionProductMainDetailDto(new Page<>(1, -1), productionProductMainDto) .getRecords() .stream() .map(item -> { ProductionProductMainDetailExportDto exportDto = new ProductionProductMainDetailExportDto(); exportDto.setProductNo(item.getProductNo()); exportDto.setNickName(item.getNickName()); exportDto.setProcess(item.getProcess()); exportDto.setWorkOrderNo(item.getWorkOrderNo()); exportDto.setSalesContractNo(item.getSalesContractNo()); exportDto.setProductOrderNpsNo(item.getProductOrderNpsNo()); exportDto.setProductName(item.getProductName()); exportDto.setProductModelName(item.getProductModelName()); exportDto.setQuantity(item.getQuantity()); exportDto.setScrapQty(item.getScrapQty()); exportDto.setUnit(item.getUnit()); exportDto.setProcessStandardHours(item.getProcessStandardHours()); exportDto.setActualReportHours(item.getActualReportHours()); exportDto.setDailyPersonHours(item.getDailyPersonHours()); exportDto.setCreateTime(item.getCreateTime()); return exportDto; }) .collect(Collectors.toList()); } private void fillHourDefaults(List records) { if (records == null || records.isEmpty()) { return; } records.forEach(item -> { if (item.getProjectTotalHours() == null) { item.setProjectTotalHours(BigDecimal.ZERO); } if (item.getProcessStandardHours() == null) { item.setProcessStandardHours(BigDecimal.ZERO); } if (item.getActualReportHours() == null) { item.setActualReportHours(BigDecimal.ZERO); } if (item.getDailyPersonHours() == null) { item.setDailyPersonHours(BigDecimal.ZERO); } }); } @Override public Boolean addProductMain(ProductionProductMainDto dto) { if (dto.getActionType() == null) { if (dto.getId() != null) { if (dto.getQuantity() == null || dto.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("结束报工失败: 本次生产数量必须大于0"); } return finishReport(dto); } Long workOrderId = dto.getWorkOrderId(); Long itemId = dto.getProductProcessRouteItemId(); if (workOrderId == null || itemId == null) { throw new ServiceException("工单ID和工艺路线项目ID不能为空"); } ProductionProductMain running = getRunning(workOrderId, itemId); if (running != null) { if (dto.getQuantity() == null || dto.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("结束报工失败: 本次生产数量必须大于0"); } dto.setId(running.getId()); return finishReport(dto); } return startReport(dto); } if (dto.getActionType() == 1) { return startReport(dto); } if (dto.getActionType() == 2) { return finishReport(dto); } throw new ServiceException("无效报工动作: " + dto.getActionType()); } @Override public ProductionProductMain getRunning(Long workOrderId, Long productProcessRouteItemId) { if (workOrderId == null || productProcessRouteItemId == null) { throw new ServiceException("工单ID和工艺路线项目ID不能为空"); } Long currentUserId = SecurityUtils.getUserId(); return productionProductMainMapper.selectOne( Wrappers.lambdaQuery() .eq(ProductionProductMain::getWorkOrderId, workOrderId) .eq(ProductionProductMain::getProductProcessRouteItemId, productProcessRouteItemId) .eq(ProductionProductMain::getUserId, currentUserId) .eq(ProductionProductMain::getStatus, 0) .orderByDesc(ProductionProductMain::getReportStartTime) .last("limit 1") ); } @Override public List dailyDuration(Long workOrderId, Long productProcessRouteItemId, LocalDate startDate, LocalDate endDate) { Long userId = SecurityUtils.getUserId(); return productionProductReportDailyMapper.listDailySummary( workOrderId, productProcessRouteItemId, userId, startDate, endDate ); } @Override public ProductionReportStateDto reportState(Long workOrderId, Long productProcessRouteItemId) { ProductionReportStateDto dto = new ProductionReportStateDto(); ProductWorkOrder workOrder = productWorkOrderMapper.selectById(workOrderId); if (workOrder != null) { BigDecimal planQty = workOrder.getPlanQuantity() == null ? BigDecimal.ZERO : workOrder.getPlanQuantity(); BigDecimal completeQty = workOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : workOrder.getCompleteQuantity(); // 生产报工数量已完成 if (planQty.compareTo(BigDecimal.ZERO) > 0 && completeQty.compareTo(planQty) >= 0) { dto.setState(3); return dto; } } ProductionProductMain running = getRunning(workOrderId, productProcessRouteItemId); if (running == null) { dto.setState(1); return dto; } dto.setState(2); dto.setRunningId(running.getId()); dto.setStartTime(running.getReportStartTime()); return dto; } private Boolean startReport(ProductionProductMainDto dto) { if (dto.getWorkOrderId() == null || dto.getProductProcessRouteItemId() == null) { throw new ServiceException("开始报工失败: 工单ID和工艺路线项目ID不能为空"); } if (dto.getUserId() == null) { dto.setUserId(SecurityUtils.getUserId()); } if (dto.getUserId() == null) { throw new ServiceException("开始报工失败: 无法获取当前登录人"); } QueryWrapper runningWrapper = new QueryWrapper<>(); runningWrapper.eq("work_order_id", dto.getWorkOrderId()) .eq("product_process_route_item_id", dto.getProductProcessRouteItemId()) .eq("user_id", dto.getUserId()) .eq("status", 0); Long runningCount = productionProductMainMapper.selectCount(runningWrapper); if (runningCount != null && runningCount > 0) { // 已有进行中的报工时,不再新建,继续沿用到结束报工 return true; } SysUser user = userMapper.selectUserById(dto.getUserId()); if (user == null) { throw new ServiceException("报工人不存在"); } ProductionProductMain productionProductMain = new ProductionProductMain(); String datePrefix = "BG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("MAX(product_no) as maxNo") .likeRight("product_no", datePrefix); List> resultList = productionProductMainMapper.selectMaps(queryWrapper); int sequenceNumber = 1; if (resultList != null && !resultList.isEmpty()) { Map result = resultList.get(0); if (result != null) { Object maxNoObj = result.get("maxNo"); if (maxNoObj != null) { String lastNo = maxNoObj.toString(); System.out.println("lastNo: " + lastNo); if (lastNo.startsWith(datePrefix)) { try { String seqStr = lastNo.substring(datePrefix.length()); sequenceNumber = Integer.parseInt(seqStr) + 1; } catch (NumberFormatException e) { sequenceNumber = 1; } } } } } String productNo = String.format("%s%03d", datePrefix, sequenceNumber); productionProductMain.setProductNo(productNo); productionProductMain.setUserId(dto.getUserId()); productionProductMain.setUserName(user.getNickName()); productionProductMain.setProductProcessRouteItemId(dto.getProductProcessRouteItemId()); productionProductMain.setWorkOrderId(dto.getWorkOrderId()); productionProductMain.setStatus(0); productionProductMain.setReportStartTime(LocalDateTime.now()); productionProductMainMapper.insert(productionProductMain); return true; } private Boolean finishReport(ProductionProductMainDto dto) { if (dto.getId() == null) { throw new ServiceException("结束报工失败: 报工ID不能为空"); } if (dto.getQuantity() == null || dto.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("结束报工失败: 本次生产数量必须大于0"); } ProductionProductMain productionProductMain = productionProductMainMapper.selectById(dto.getId()); if (productionProductMain == null) { throw new ServiceException("结束报工失败: 报工记录不存在"); } if (productionProductMain.getStatus() != null && productionProductMain.getStatus() == 1) { throw new ServiceException("该报工已结束,请勿重复提交"); } if (productionProductMain.getReportStartTime() == null) { throw new ServiceException("该报工缺少开始时间,无法结束"); } LocalDateTime endTime = LocalDateTime.now(); long durationSeconds = Duration.between(productionProductMain.getReportStartTime(), endTime).getSeconds(); BigDecimal durationMinutes = secondsToMinutesExact(durationSeconds); int finishRows = productionProductMainMapper.update( null, Wrappers.lambdaUpdate() .set(ProductionProductMain::getReportEndTime, endTime) .set(ProductionProductMain::getReportDurationMinutes, durationMinutes) .set(ProductionProductMain::getStatus, 1) .eq(ProductionProductMain::getId, productionProductMain.getId()) .eq(ProductionProductMain::getStatus, 0) ); if (finishRows <= 0) { throw new ServiceException("该报工已结束,请勿重复提交"); } productionProductMain.setReportEndTime(endTime); productionProductMain.setReportDurationMinutes(durationMinutes); productionProductMain.setStatus(1); // 写入“每日时长明细”,跨天自动拆分 saveDailyDurations(productionProductMain, productionProductMain.getReportStartTime(), endTime); dto.setWorkOrderId(productionProductMain.getWorkOrderId()); dto.setProductProcessRouteItemId(productionProductMain.getProductProcessRouteItemId()); if (dto.getUserId() == null) { dto.setUserId(productionProductMain.getUserId()); } if (dto.getUserName() == null) { dto.setUserName(productionProductMain.getUserName()); } if (dto.getScrapQty() == null) { dto.setScrapQty(BigDecimal.ZERO); } SysUser user = userMapper.selectUserById(dto.getUserId()); if (user == null) { throw new ServiceException("报工人不存在"); } // 使用工单关联的生产订单产品型号 ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); if (productWorkOrder == null) { throw new ServiceException("结束报工失败: 工单不存在"); } ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); if (productOrder == null) { throw new ServiceException("结束报工失败: 关联生产订单不存在"); } Long outputProductModelId = productOrder.getProductModelId(); if (outputProductModelId == null) { throw new ServiceException("结束报工失败: 生产订单未配置产品型号"); } /*新增报工投入表(无BOM场景: 投入=产出型号, 数量按本次报工数量)*/ ProductionProductInput productionProductInput = new ProductionProductInput(); productionProductInput.setProductModelId(outputProductModelId); productionProductInput.setQuantity(dto.getQuantity()); productionProductInput.setProductMainId(productionProductMain.getId()); productionProductInputMapper.insert(productionProductInput); stockUtils.substractStock(outputProductModelId, dto.getQuantity(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId()); /*新增报工产出表*/ ProductionProductOutput productionProductOutput = new ProductionProductOutput(); productionProductOutput.setProductMainId(productionProductMain.getId()); productionProductOutput.setProductModelId(outputProductModelId); productionProductOutput.setQuantity(dto.getQuantity() != null ? dto.getQuantity() : BigDecimal.ZERO); productionProductOutput.setScrapQty(dto.getScrapQty() != null ? dto.getScrapQty() : BigDecimal.ZERO); productionProductOutputMapper.insert(productionProductOutput); //合格数量=报工数量-报废数量 BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()); // 是否需要质检:按 product_process.is_quality 判断(1-需要,0-不需要) boolean needQuality = isNeedQualityByWorkOrder(productWorkOrder); //只有合格数量>0才能增加相应数据 if (productQty.compareTo(BigDecimal.ZERO) > 0) { // 需要质检时才新增过程检/出厂检 if (needQuality) { createQualityInspect(productionProductMain.getId(), outputProductModelId, productQty, 1, "生产报工"); } stockUtils.addStock(outputProductModelId, productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId()); /*更新工单和生产订单*/ int woRows = productWorkOrderMapper.addCompleteQtyIfNotExceed(dto.getWorkOrderId(), productQty); if (woRows <= 0) { ProductWorkOrder current = productWorkOrderMapper.selectById(dto.getWorkOrderId()); throw new ServiceException("本次生产数量不能大于剩余数量,剩余数量: " + (current == null ? "0" : current.getPlanQuantity().subtract(current.getCompleteQuantity()))); } // 无工艺路线场景:报工即计入生产订单完成数量 // int poRows = productOrderMapper.addCompleteQtyIfNotExceed(productOrder.getId(), productQty); // if (poRows <= 0) { // ProductOrder currentOrder = productOrderMapper.selectById(productOrder.getId()); // throw new ServiceException("本次生产数量不能大于订单剩余数量,剩余数量: " // + (currentOrder == null ? "0" : currentOrder.getQuantity().subtract(currentOrder.getCompleteQuantity()))); // } List productProcessRouteItemDtos = productProcessRouteItemMapper.listItem(productOrder.getId()); ProductOrder currentOrder = productOrderMapper.selectById(productOrder.getId()); if (productProcessRouteItemDtos.get(productProcessRouteItemDtos.size() - 1).getId().equals(dto.getProductProcessRouteItemId())) { int poRows = productOrderMapper.addCompleteQtyIfNotExceed(productOrder.getId(), productQty); if (poRows <= 0) { throw new ServiceException("本次生产数量不能大于订单剩余数量,剩余数量: " + (currentOrder == null ? "0" : currentOrder.getQuantity().subtract(currentOrder.getCompleteQuantity()))); } } if (needQuality && currentOrder != null && currentOrder.getCompleteQuantity() != null && currentOrder.getQuantity() != null && currentOrder.getCompleteQuantity().compareTo(currentOrder.getQuantity()) >= 0) { // 订单完成时新增出厂检 createQualityInspect(productionProductMain.getId(), outputProductModelId, productQty, 2, null); } /*添加生产核算 区分工序是计件还是计时*/ BigDecimal workHours = durationMinutes.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP); SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder() .productMainId(productionProductMain.getId()) .schedulingUserId(user.getUserId()) .schedulingUserName(user.getNickName()) .finishedNum(productQty) .workHours(workHours) .process(resolveProcessTypeName(productWorkOrder)) .schedulingDate(LocalDate.now()) .tenantId(dto.getTenantId()) .build(); salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting); } //如果报废数量>0,需要进入报废的库存 if (ObjectUtils.isNotEmpty(dto.getScrapQty())) { if (dto.getScrapQty().compareTo(BigDecimal.ZERO) > 0) { stockUtils.addUnStock(outputProductModelId, dto.getScrapQty(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId()); } } return true; } /** * 创建质检及质检参数 */ private void createQualityInspect(Long productMainId, Long productModelId, BigDecimal qty, Integer inspectType, String process) { ProductModel productModel = productModelMapper.selectById(productModelId); if (productModel == null) { return; } Product product = productMapper.selectById(productModel.getProductId()); if (product == null) { return; } QualityInspect qualityInspect = new QualityInspect(); qualityInspect.setProductId(product.getId()); qualityInspect.setProductName(product.getProductName()); qualityInspect.setModel(productModel.getModel()); qualityInspect.setUnit(productModel.getUnit()); qualityInspect.setQuantity(qty); qualityInspect.setProcess(process); qualityInspect.setInspectState(0); qualityInspect.setInspectType(inspectType); qualityInspect.setProductMainId(productMainId); qualityInspect.setProductModelId(productModelId); qualityInspectMapper.insert(qualityInspect); List qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process); if (qualityTestStandard.isEmpty()) { return; } qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId())) .forEach(qualityTestStandardParam -> { QualityInspectParam param = new QualityInspectParam(); BeanUtils.copyProperties(qualityTestStandardParam, param); param.setId(null); param.setInspectId(qualityInspect.getId()); qualityInspectParamMapper.insert(param); }); } /** * 是否需要质检:依据工序表 is_quality(1-需要,0-不需要) */ private boolean isNeedQualityByWorkOrder(ProductWorkOrder workOrder) { if (workOrder == null || workOrder.getProductProcessRouteItemId() == null) { return true; } ProductProcessRouteItem routeItem = productProcessRouteItemMapper.selectById(workOrder.getProductProcessRouteItemId()); if (routeItem == null || routeItem.getProcessId() == null) { return true; } ProductProcess process = productProcessMapper.selectById(routeItem.getProcessId()); if (process == null || process.getIsQuality() == null) { return true; } return process.getIsQuality(); } /** * 获取工序对应的“部件类型”文案 */ private String resolveProcessTypeName(ProductWorkOrder workOrder) { if (workOrder == null || workOrder.getProductProcessRouteItemId() == null) { return "其他"; } ProductProcessRouteItem routeItem = productProcessRouteItemMapper.selectById(workOrder.getProductProcessRouteItemId()); if (routeItem == null || routeItem.getProcessId() == null) { return "其他"; } ProductProcess process = productProcessMapper.selectById(routeItem.getProcessId()); if (process == null || process.getType() == null) { return "其他"; } String dictLabel = DictUtils.getDictLabel("product_process_type", String.valueOf(process.getType())); return (dictLabel == null || dictLabel.isEmpty()) ? "其他" : dictLabel; } private void saveDailyDurations(ProductionProductMain main, LocalDateTime start, LocalDateTime end) { if (main == null || start == null || end == null) { return; } if (end.isBefore(start)) { return; } // 防止重复写(例如误重复结束时),先删再插 productionProductReportDailyMapper.delete( Wrappers.lambdaQuery() .eq(ProductionProductReportDaily::getProductMainId, main.getId()) ); LocalDateTime cursor = start; while (cursor.isBefore(end)) { LocalDate date = cursor.toLocalDate(); LocalDateTime nextDayStart = date.plusDays(1).atStartOfDay(); LocalDateTime sliceEnd = end.isBefore(nextDayStart) ? end : nextDayStart; long seconds = Duration.between(cursor, sliceEnd).getSeconds(); BigDecimal minutes = secondsToMinutesExact(seconds); if (minutes.compareTo(BigDecimal.ZERO) > 0) { ProductionProductReportDaily daily = new ProductionProductReportDaily(); daily.setProductMainId(main.getId()); daily.setWorkOrderId(main.getWorkOrderId()); daily.setProductProcessRouteItemId(main.getProductProcessRouteItemId()); daily.setUserId(main.getUserId()); daily.setReportDate(date); daily.setStartTime(cursor); daily.setEndTime(sliceEnd); daily.setDurationMinutes(minutes); productionProductReportDailyMapper.insert(daily); } cursor = sliceEnd; } } /** * 秒转分钟:包含分秒并向上取整到分钟 */ private BigDecimal secondsToMinutesExact(long seconds) { if (seconds <= 0L) { return BigDecimal.ZERO; } return BigDecimal.valueOf(seconds).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP); } @Override public Boolean removeProductMain(Long id) { //判断该条报工是否不合格处理,如果不合格处理了,则不允许删除 List qualityInspects = qualityInspectMapper.selectList(Wrappers.lambdaQuery().eq(QualityInspect::getProductMainId, id)); if (qualityInspects.size() > 0) { List qualityUnqualifieds = qualityUnqualifiedMapper.selectList(Wrappers.lambdaQuery() .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList()))); if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) { throw new ServiceException("该条报工已经不合格处理了,不允许删除"); } } ProductionProductMain productionProductMain = productionProductMainMapper.selectById(id); List outputList = productionProductOutputMapper.selectList( Wrappers.lambdaQuery().eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()) ); ProductionProductOutput productionProductOutput = outputList.isEmpty() ? null : outputList.get(0); /*删除核算*/ salesLedgerProductionAccountingMapper.delete( new LambdaQueryWrapper() .eq(SalesLedgerProductionAccounting::getProductMainId, productionProductMain.getId()) ); /*更新工单和生产订单*/ ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); BigDecimal validQuantity = BigDecimal.ZERO; if (productWorkOrder != null && productionProductOutput != null) { BigDecimal outputQty = productionProductOutput.getQuantity() == null ? BigDecimal.ZERO : productionProductOutput.getQuantity(); BigDecimal scrapQty = productionProductOutput.getScrapQty() == null ? BigDecimal.ZERO : productionProductOutput.getScrapQty(); BigDecimal completeQty = productWorkOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productWorkOrder.getCompleteQuantity(); validQuantity = outputQty.subtract(scrapQty); productWorkOrder.setCompleteQuantity(completeQty.subtract(validQuantity)); productWorkOrder.setActualEndTime(null); productWorkOrderMapper.updateById(productWorkOrder); } else if (productWorkOrder == null) { throw new ServiceException("操作失败:工单信息或产出记录不存在"); } // 无工艺路线场景:删除报工时只要有有效产出就扣减生产订单完成数量 if (productionProductOutput != null && validQuantity.compareTo(BigDecimal.ZERO) > 0) { ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); if (productOrder == null) { throw new ServiceException("关联的生产订单不存在"); } BigDecimal orderCompleteQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity(); BigDecimal newCompleteQty = orderCompleteQty.subtract(validQuantity); productOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty); productOrder.setEndTime(null); productOrderMapper.updateById(productOrder); } //删除质检 qualityInspectMapper.selectList( new LambdaQueryWrapper() .eq(QualityInspect::getProductMainId, productionProductMain.getId()) ).forEach(q -> { qualityInspectParamMapper.delete( new LambdaQueryWrapper() .eq(QualityInspectParam::getInspectId, q.getId())); qualityInspectMapper.deleteById(q.getId()); stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()); }); // 删除产出记录 productionProductOutputMapper.delete(new LambdaQueryWrapper() .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId())); //删除投入记录 productionProductInputMapper.delete(new LambdaQueryWrapper() .eq(ProductionProductInput::getProductMainId, productionProductMain.getId())); //删除报废的入库记录 stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode()); //删除不需要质检的合格入库 stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()); //删除投入对应的出库记录 stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode()); // 删除主表 productionProductMainMapper.deleteById(productionProductMain.getId()); return true; } @Override public ArrayList listMain(List idList) { return productionProductMainMapper.listMain(idList); } }