package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.production.bean.dto.ProductionAccountDto; import com.ruoyi.production.bean.dto.ProductionProductMainDto; import com.ruoyi.production.bean.vo.ProductionAccountVo; import com.ruoyi.production.mapper.ProductionAccountMapper; import com.ruoyi.production.mapper.ProductionOperationTaskMapper; import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.mapper.ProductionProductOutputMapper; import com.ruoyi.production.pojo.ProductionAccount; import com.ruoyi.production.pojo.ProductionOperationTask; import com.ruoyi.production.pojo.ProductionOrderRoutingOperation; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.production.pojo.ProductionProductOutput; import com.ruoyi.technology.mapper.TechnologyOperationMapper; import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper; import com.ruoyi.technology.pojo.TechnologyOperation; import com.ruoyi.technology.pojo.TechnologyRoutingOperation; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.production.service.ProductionAccountService; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.exception.ServiceException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.List; @Service @RequiredArgsConstructor public class ProductionAccountServiceImpl extends ServiceImpl implements ProductionAccountService { private final ProductionProductMainMapper productionProductMainMapper; private final ProductionProductOutputMapper productionProductOutputMapper; private final ProductionOperationTaskMapper productionOperationTaskMapper; private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper; private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper; private final TechnologyOperationMapper technologyOperationMapper; private final SysUserMapper sysUserMapper; @Override public IPage listPage(Page page, ProductionAccountDto dto) { // 分页查询生产核算数据 ProductionAccountDto queryDto = normalizeDateQuery(dto); return baseMapper.listPage(page, queryDto); } @Override public IPage listProductionDetails(ProductionAccountDto dto, Page page) { // 查询生产核算明细 ProductionAccountDto queryDto = normalizeDateQuery(dto); if (queryDto.getAuditStatus() == null) { queryDto.setAuditStatus(1); } return productionProductMainMapper.listProductionDetails(queryDto, page); } @Override @Transactional(rollbackFor = Exception.class) public Boolean batchAccounting(ProductionAccountDto dto) { ProductionAccountDto queryDto = normalizeDateQuery(dto); LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() .eq(ProductionProductMain::getAuditStatus, 1) .in(ProductionProductMain::getReportType, Arrays.asList(0, 1)); if (queryDto.getSchedulingUserId() != null) { queryWrapper.eq(ProductionProductMain::getUserId, queryDto.getSchedulingUserId()); } if (queryDto.getSchedulingUserName() != null && !queryDto.getSchedulingUserName().isEmpty()) { queryWrapper.like(ProductionProductMain::getUserName, queryDto.getSchedulingUserName()); } if (queryDto.getEntryDate() != null) { queryWrapper.apply("date(create_time) = {0}", queryDto.getEntryDate()); } if (queryDto.getEntryDateStart() != null) { queryWrapper.ge(ProductionProductMain::getCreateTime, queryDto.getEntryDateStart().atStartOfDay()); } if (queryDto.getEntryDateEnd() != null) { queryWrapper.le(ProductionProductMain::getCreateTime, queryDto.getEntryDateEnd().atTime(23, 59, 59)); } List reportList = productionProductMainMapper.selectList(queryWrapper); for (ProductionProductMain report : reportList) { rebuildAccount(report); } return Boolean.TRUE; } @Override @Transactional(rollbackFor = Exception.class) public Boolean singleAdjust(ProductionAccountDto dto) { if (dto == null || (dto.getProductionProductMainId() == null && dto.getSchedulingUserId() == null)) { throw new ServiceException("请选择需要修正的人员"); } BigDecimal adjustAmount = dto.getAdjustAmount(); if (adjustAmount == null || adjustAmount.compareTo(BigDecimal.ZERO) == 0) { throw new ServiceException("修正金额不能为空"); } if (dto.getProductionProductMainId() != null) { ProductionAccount account = new ProductionAccount(); account.setAdjustAmount(adjustAmount); account.setAdjustRemark(dto.getAdjustRemark()); account.setAdjustUser(dto.getAdjustUser()); account.setAdjustTime(LocalDateTime.now()); baseMapper.update(account, new LambdaQueryWrapper() .eq(ProductionAccount::getProductionProductMainId, dto.getProductionProductMainId())); } else { ProductionAccount account = new ProductionAccount(); account.setSchedulingUserId(dto.getSchedulingUserId()); account.setSchedulingUserName(dto.getSchedulingUserName()); account.setTechnologyOperationName("工资修正"); account.setAdjustAmount(adjustAmount); account.setAdjustRemark(dto.getAdjustRemark()); account.setAdjustUser(dto.getAdjustUser()); account.setAdjustTime(LocalDateTime.now()); account.setSchedulingDate(LocalDateTime.now()); account.setWorkHours(BigDecimal.ZERO); account.setFinishedNum(BigDecimal.ZERO); account.setAccountingBatchNo("ADJ-" + LocalDate.now()); baseMapper.insert(account); } return Boolean.TRUE; } @Override @Transactional(rollbackFor = Exception.class) public Boolean rebuildByProductionProductMainId(Long productionProductMainId) { if (productionProductMainId == null) { return Boolean.FALSE; } ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productionProductMainId); if (productionProductMain == null) { return Boolean.FALSE; } if (productionProductMain.getAuditStatus() == null || productionProductMain.getAuditStatus() != 1) { productionAccountDelete(productionProductMainId); return Boolean.FALSE; } if (productionProductMain.getReportType() == null || (!Integer.valueOf(0).equals(productionProductMain.getReportType()) && !Integer.valueOf(1).equals(productionProductMain.getReportType()))) { productionAccountDelete(productionProductMainId); return Boolean.FALSE; } rebuildAccount(productionProductMain); return Boolean.TRUE; } private void rebuildAccount(ProductionProductMain productionProductMain) { if (productionProductMain == null || productionProductMain.getId() == null) { return; } ProductionAccount existedAccount = baseMapper.selectOne(Wrappers.lambdaQuery() .eq(ProductionAccount::getProductionProductMainId, productionProductMain.getId()) .last("limit 1")); BigDecimal existedAdjustAmount = existedAccount == null ? null : existedAccount.getAdjustAmount(); String existedAdjustRemark = existedAccount == null ? null : existedAccount.getAdjustRemark(); Long existedAdjustUser = existedAccount == null ? null : existedAccount.getAdjustUser(); LocalDateTime existedAdjustTime = existedAccount == null ? null : existedAccount.getAdjustTime(); productionAccountDelete(productionProductMain.getId()); ProductionProductOutput output = productionProductOutputMapper.selectOne( Wrappers.lambdaQuery() .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()) .last("limit 1")); if (output == null || output.getQuantity() == null || output.getQuantity().compareTo(BigDecimal.ZERO) <= 0) { return; } ProductionOperationTask task = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId()); if (task == null) { return; } ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(task.getProductionOrderRoutingOperationId()); if (routingOperation == null) { return; } TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId()); TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId()); SysUser user = sysUserMapper.selectUserById(productionProductMain.getUserId()); ProductionAccount account = new ProductionAccount(); account.setProductionProductMainId(productionProductMain.getId()); account.setSchedulingUserId(user == null ? productionProductMain.getUserId() : user.getUserId()); account.setSchedulingUserName(user == null ? productionProductMain.getUserName() : user.getNickName()); account.setFinishedNum(output.getQuantity()); account.setWorkHours(technologyOperation == null ? null : technologyOperation.getSalaryQuota()); account.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName()); account.setSchedulingDate(LocalDateTime.now()); account.setAccountingBatchNo("BATCH-" + LocalDate.now()); account.setAdjustAmount(existedAdjustAmount); account.setAdjustRemark(existedAdjustRemark); account.setAdjustUser(existedAdjustUser); account.setAdjustTime(existedAdjustTime); baseMapper.insert(account); } private void productionAccountDelete(Long productionProductMainId) { if (productionProductMainId == null) { return; } baseMapper.delete(new LambdaQueryWrapper() .eq(ProductionAccount::getProductionProductMainId, productionProductMainId)); } private ProductionAccountDto normalizeDateQuery(ProductionAccountDto dto) { // 规范日期查询范围,补齐缺失的开始或结束时间 if (dto == null) { return new ProductionAccountDto(); } if ((dto.getEntryDateStart() == null || dto.getEntryDateEnd() == null) && dto.getDateRange() != null && dto.getDateRange().length > 0) { LocalDate rangeStart = parseDate(dto.getDateRange()[0]); LocalDate rangeEnd = dto.getDateRange().length > 1 ? parseDate(dto.getDateRange()[1]) : rangeStart; if (dto.getEntryDateStart() == null) { dto.setEntryDateStart(rangeStart); } if (dto.getEntryDateEnd() == null) { dto.setEntryDateEnd(rangeEnd); } } String dateType = dto.getDateType(); if ("day".equalsIgnoreCase(dateType)) { if (dto.getEntryDate() == null && dto.getDateRange() != null && dto.getDateRange().length > 0) { dto.setEntryDate(parseDate(dto.getDateRange()[0])); } if (dto.getEntryDate() == null) { dto.setEntryDate(dto.getEntryDateStart()); } dto.setEntryDateStart(null); dto.setEntryDateEnd(null); } else if ("month".equalsIgnoreCase(dateType)) { if ((dto.getEntryDateStart() == null || dto.getEntryDateEnd() == null) && dto.getEntryDate() != null) { LocalDate monthDate = dto.getEntryDate(); dto.setEntryDateStart(monthDate.withDayOfMonth(1)); dto.setEntryDateEnd(monthDate.withDayOfMonth(monthDate.lengthOfMonth())); } dto.setEntryDate(null); } return dto; } private LocalDate parseDate(String dateValue) { if (dateValue == null || dateValue.isEmpty()) { return null; } try { return LocalDate.parse(dateValue); } catch (DateTimeParseException e) { throw new ServiceException("日期格式错误,请使用 yyyy-MM-dd"); } } }