package com.kcim.service.impl; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.kcim.common.constants.NumberConstant; import com.kcim.common.enums.DateStyleEnum; import com.kcim.common.exception.CostException; import com.kcim.common.util.*; import com.kcim.dao.mapper.AllocationMapper; import com.kcim.dao.mapper.AllocationQueryMapper; import com.kcim.dao.mapper.CostCostingGroupMapper; import com.kcim.dao.model.*; import com.kcim.service.*; import com.kcim.vo.AllocationVO; import com.kcim.vo.CommonDepartVo; import com.kcim.vo.CostingGroupStartVO; import com.kcim.vo.IncomeErrorMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.multipart.MultipartFile; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @Service("costCostingGroupService") @Slf4j public class CostCostingGroupServiceImpl extends ServiceImpl implements CostCostingGroupService { private final CostIncomeGroupServiceImpl costIncomeGroupService; private final AccountingService accountingService; private final AccountingProductService accountingProductService; private final CostIncomeFileService costIncomeFileService; private final ResponsibilityService responsibilityService; private final AllocationMapper allocationMapper; private final AllocationQueryMapper allocationQueryMapper; public CostCostingGroupServiceImpl(CostIncomeGroupServiceImpl costIncomeGroupService, AccountingService accountingService, AccountingProductService accountingProductService, CostIncomeFileService costIncomeFileService, ResponsibilityService responsibilityService, AllocationMapper allocationMapper, AllocationQueryMapper allocationQueryMapper) { this.costIncomeGroupService = costIncomeGroupService; this.accountingService = accountingService; this.accountingProductService = accountingProductService; this.costIncomeFileService = costIncomeFileService; this.responsibilityService = responsibilityService; this.allocationMapper = allocationMapper; this.allocationQueryMapper = allocationQueryMapper; } /** * 分摊前查询 * * @param current 当前页 * @param pageSize 每页数据大小 * @param responsibilityCode 责任中心代码 * @param accountCode 会计中心代码 * @param date 日期 yyyy-MM * @param hospId 医院id * @param departmentCode * @param filter * @return 分摊前查询列表 */ @Override public PageUtils queryStartAllocation(Integer current, Integer pageSize, String responsibilityCode, String accountCode, String date, Long hospId, String departmentCode, String filter) { Integer startIndex = (current - 1) * pageSize; int year = 0; int month = 0; if (StrUtil.isNotBlank(date)) { Date dateTime = DateUtils.StringToDate(date, DateStyleEnum.YYYY_MM); year = DateUtil.year(dateTime); month = DateUtil.month(dateTime) + 1; } // DateTime dateTime = DateUtil.parseDate(date); // // Integer year = DateUtil.year(dateTime); // Integer month = DateUtil.month(dateTime) + 1; List list = baseMapper.queryStartAllocation(startIndex, pageSize, responsibilityCode, accountCode, year, month, hospId, departmentCode, filter); int count = baseMapper.queryStartAllocationCount(responsibilityCode, accountCode, year, month, hospId, departmentCode, filter); BigDecimal totalAmount = baseMapper.queryStartAllocationTotalAmount(responsibilityCode, accountCode, year, month, hospId); BigDecimal departmentAmount = baseMapper.queryStartAllocationDepartmentAmount(responsibilityCode, accountCode, year, month, hospId, departmentCode, filter); return new PageUtils(list, count, pageSize, current, totalAmount, departmentAmount); } /** * 成本分摊列表 * * @param current 当前页 * @param pageSize 每页数据大小 * @param date 日期 这里是 yyyy-MM-dd * @param hospId * @return 分页对象 */ @Override public PageUtils queryAllocation(Integer current, Integer pageSize, String date, Long hospId) { Integer year = null; Integer month = null; if (StrUtil.isNotBlank(date)) { DateTime dateTime = DateUtil.parseDate(date); year = DateUtil.year(dateTime); month = DateUtil.month(dateTime) + 1; } Integer startIndex = (current - 1) * pageSize; List list = baseMapper.queryAllocation(startIndex, pageSize, year, month, hospId); list.forEach(i -> { Allocation allocation = allocationMapper.selectOne(new LambdaQueryWrapper().eq(Allocation::getDateYear, i.getYear()) .eq(Allocation::getDateMonth, i.getMonth()) .eq(Allocation::getHospId, hospId) .last("LIMIT 1") ); if (!ObjectUtils.isEmpty(allocation)) { i.setIsAllocation(true); } }); int count = baseMapper.queryAllocationCount(year, month, hospId); return new PageUtils(list, count, pageSize, current); } /** * 通过code获取名称 * * @param accountCode * @return */ private Accounting getAccountByCode(String accountCode, Long hospId) { Accounting byCode = accountingService.getByCode(accountCode, hospId); if (Objects.isNull(byCode)) { throw new CostException("会计科目不存在"); } return byCode; } /** * 是否固定成本 * * @param hospId 医院id * @param i {@link CostCostingGroup} * @return 是否固定成本 0.不是,1.是(支出的时候才会存在) */ private Integer getIsBaseCost(Long hospId, CostCostingGroup i) { String accountCode = i.getAccountCode(); Accounting accounting = accountingService.getByCode(accountCode, hospId); if (Objects.isNull(accountCode)) { return null; } // 是否固定成本 0.不是,1.是(支出的时候才会存在) (成本数据) return accounting.getIsBaseCost(); } /** * 批量导入成本数据 * * @param list * @param file * @param dateTime * @param fileType * @return */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public Result importCostingGroup(List> list, MultipartFile file, String dateTime, Integer fileType) { // 先检验当前年月是否存在数据 int year = 0; int month = 0; if (StrUtil.isNotBlank(dateTime)) { Date date = DateUtils.StringToDate(dateTime, DateStyleEnum.YYYY_MM); year = DateUtil.year(date); month = DateUtil.month(date) + 1; } Long hospId = UserContext.getCurrentLoginHospId(); // List groups = this.list(new QueryWrapper().lambda().eq(CostCostingGroup::getHospId, hospId) // .eq(CostCostingGroup::getDateYear, year).eq(CostCostingGroup::getDateMonth, month)); // if (!CollectionUtils.isEmpty(groups)) { // throw new CostException(500, year + "年" + month + "月数据已存在"); // } // for (int i = list.size() - 1; i >= 0; i--) { // if (i == NumberConstant.ZERO || i == NumberConstant.ONE || i == NumberConstant.TWO || i == NumberConstant.THREE) { // } // } list.remove(list.get(0)); List incomeErrorMessageList = new ArrayList<>(); //获取所有的科室 成本项目 责任中心 会计科目 Map departmentMap = costIncomeGroupService.getDepartmentByCodeNameMap(hospId); Map productMap = costIncomeGroupService.getProductByCodeNameMap(hospId); Map responsibilityMap = costIncomeGroupService.getResponsibilityIdResponsibilityMap(hospId); Map accountingMap = costIncomeGroupService.getAccountIdAccountingMap(hospId); List responsibilityDepartmentList = costIncomeGroupService.getResponsibilityDepartments(hospId); if (CollectionUtils.isEmpty(responsibilityDepartmentList)) { throw new CostException(500, "没有科室责任中心对照数据"); } List accountingProductList = accountingProductService.list(new QueryWrapper().lambda().eq(AccountingProduct::getHospId, hospId)); if (CollectionUtils.isEmpty(accountingProductList)) { throw new CostException(500, "没有成本会计对照数据"); } Map responsibilityDepMap = costIncomeGroupService.getDepartmentIdResponsibilityIdMap(responsibilityDepartmentList); Map accountProMap = costIncomeGroupService.getProductIdAccountIdMap(accountingProductList); String endStatus = list.get(0).get(list.get(0).size() - 1).toString(); // 判断最后科室代码的最后一个字符是否是-1 if (!"-1".equals(endStatus)) { // 如果没有-1说明终结符 IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(5); incomeErrorMessage.setErrMessage("科室代码末尾没有-1终结符"); incomeErrorMessageList.add(incomeErrorMessage); // 文件上传 String uploadFile = costIncomeGroupService.uploadFile(file); // 上传记录保存 if (StrUtil.isBlank(uploadFile)) { throw new CostException(500, "文件上传异常"); } // 记录文件上传记录 CostIncomeFile costIncomeFile = costIncomeFileService.saveCostIncomeFile(list, file, hospId, incomeErrorMessageList, uploadFile, fileType, year, month); return Result.build(500, "数据未成功导入", null); } // 检验数据的合理性 // 检验成本数据 // 要保存的数据 costCostingGroupArrayList = new ArrayList<>(); checkCostData(list, incomeErrorMessageList, departmentMap, productMap, responsibilityMap, accountingMap, responsibilityDepMap, accountProMap, year, month); // 文件上传 String uploadFile = costIncomeGroupService.uploadFile(file); // 上传记录保存 if (StrUtil.isBlank(uploadFile)) { throw new CostException(500, "文件上传异常"); } // 记录文件上传记录 CostIncomeFile costIncomeFile = costIncomeFileService.saveCostIncomeFile(list, file, hospId, incomeErrorMessageList, uploadFile, fileType, year, month); Long id = costIncomeFile.getId(); // 设置文件Id List removeList = new ArrayList<>(); for (CostCostingGroup i : costCostingGroupArrayList) { if (Objects.nonNull(i)) { i.setFileId(id); } else { removeList.add(null); } } if (!CollectionUtils.isEmpty(removeList)) { costCostingGroupArrayList.removeAll(removeList); } if (CollectionUtils.isEmpty(incomeErrorMessageList)) { this.saveBatch(costCostingGroupArrayList); return Result.build(200, "数据导入成功", null); } else { return Result.build(200, "数据未成功导入", null); } } /** * 检验成本数据 * * @param list * @param incomeErrorMessageList * @param departmentMap * @param productMap * @param responsibilityMap * @param accountingMap * @param responsibilityDepMap * @param accountProMap */ private void checkCostData(List> list, List incomeErrorMessageList, Map departmentMap, Map productMap, Map responsibilityMap, Map accountingMap, Map responsibilityDepMap, Map accountProMap, Integer year, Integer month) { // Pattern pattern = Pattern.compile("^\\d+(\\.\\d+)?$"); List departmentCodes = list.get(0); List departmentNames = list.get(1); //检验数据是否准确 Responsibility responsibilityServiceOne = responsibilityService.getOne(new QueryWrapper().lambda().eq(Responsibility::getHospId, UserContext.getHospId()).eq(Responsibility::getIsDefault, NumberConstant.ONE)); ExecutorService pool = Executors.newFixedThreadPool(10); for (int i = 2; i < list.size(); i++) { System.out.println("计算进度:" + i + "/" + list.size()); // int row = i + 5; List data = list.get(i); if (CollectionUtils.isEmpty(incomeErrorMessageList)) { int emptyStatus = 0; //判断数据 是否全为0 for (int j = 2; j < data.size() - 1; j++) { BigDecimal parseInt = new BigDecimal(data.get(j).toString()); if (!BigDecimal.ZERO.equals(parseInt)) { emptyStatus = 1; break; } } //转换数据格式并将未维护的数据填充 0 for (int j = 2; j < departmentCodes.size(); j++) { //转换数据格式 if (data.size() > j) { if (Objects.isNull(data.get(j))) { data.set(j, NumberConstant.ZERO); } else { data.set(j, Double.parseDouble(data.get(j).toString())); } } else { data.add(NumberConstant.ZERO); } } // 检验成本项目是否正确 CostCostingGroup costCostingGroupRequest = new CostCostingGroup(); if (Objects.nonNull(data.get(0)) && Objects.nonNull(data.get(1))) { String productCode = data.get(0).toString(); String productName = data.get(1).toString(); Product product = productMap.get(productCode + productName); AfterCostGroup afterCostGroupRequest = new AfterCostGroup(); if (Objects.nonNull(product)) { Long id = product.getId(); Long accountTingId = accountProMap.get(id); if (Objects.nonNull(accountTingId)) { Accounting accounting = accountingMap.get(accountTingId); if (Objects.nonNull(accounting)) { costCostingGroupRequest.setProductCode(productCode); costCostingGroupRequest.setProductName(productName); costCostingGroupRequest.setAccountCode(accounting.getAccountingCode()); costCostingGroupRequest.setAccountName(accounting.getAccountingName()); afterCostGroupRequest.setProductCode(productCode); afterCostGroupRequest.setProductName(productName); afterCostGroupRequest.setAccountCode(accounting.getAccountingCode()); afterCostGroupRequest.setAccountName(accounting.getAccountingName()); } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(1); incomeErrorMessage.setErrMessage("成本代码" + productCode + " 成本名称" + productName + " 不存在对应的会计科目不存在"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(1); incomeErrorMessage.setErrMessage("成本代码" + productCode + " 成本名称" + productName + " 不存在对应的会计科目不存在"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(1); incomeErrorMessage.setErrMessage("成本代码" + productCode + " 成本名称" + productName + "不存在"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } // 0表示全为0 1表示不全为0 查看合计项 BigDecimal combined = new BigDecimal(data.get(data.size() - 1).toString()); if (!BigDecimal.ZERO.equals(combined) && NumberConstant.ZERO.equals(emptyStatus)) { // 这条数据是保存到其他责任中心的 CostCostingGroup costCostingGroup = BeanUtil.convertObj(afterCostGroupRequest, CostCostingGroup.class); // AfterCostGroup afterCostGroup = BeanUtil.convertObj(afterCostGroupRequest, AfterCostGroup.class); // TODO 设置其他责任中心 if (Objects.nonNull(responsibilityServiceOne)) { costCostingGroup.setResponsibilityCode(responsibilityServiceOne.getResponsibilityCode()); costCostingGroup.setResponsibilityName(responsibilityServiceOne.getResponsibilityName()); // 设置统计数据 // afterCostGroup.setOtherResponsibilityCode(responsibilityServiceOne.getResponsibilityCode()); // afterCostGroup.setOtherResponsibilityName(responsibilityServiceOne.getResponsibilityName()); } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(i); incomeErrorMessage.setErrMessage("不存在默认责任中心"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } costCostingGroup.setProductCode(costCostingGroupRequest.getProductCode()); costCostingGroup.setProductName(costCostingGroupRequest.getProductName()); costCostingGroup.setAccountCode(costCostingGroupRequest.getAccountCode()); costCostingGroup.setAccountName(costCostingGroupRequest.getAccountName()); costCostingGroup.setAmount(combined); costCostingGroup.setHospId(UserContext.getHospId()); costCostingGroup.setCreateTime(System.currentTimeMillis()); costCostingGroup.setDateYear(year); costCostingGroup.setDateMonth(month); // afterCostGroup.setAmount(combined); // String s = -JsonUtil.toJSONString(afterCostGroup); String s = JacksonUtil.obj2Str(combined); costCostingGroup.setAfterCostGroup(s); increment(costCostingGroup); // costCostingGroupArrayList.add(costCostingGroup); } else { for (int j = 2; j < data.size() - 1; j++) { int finalJ = j; pool.execute(new Runnable() { @Override public void run() { AfterCostGroup afterCostGroup = BeanUtil.convertObj(afterCostGroupRequest, AfterCostGroup.class); CostCostingGroup costCostingGroup = BeanUtil.convertObj(costCostingGroupRequest, CostCostingGroup.class); // 检验科室信息是否准确 String departmentCode = departmentCodes.get(finalJ).toString(); String departmentName = departmentNames.get(finalJ).toString(); Department department = departmentMap.get(departmentCode + departmentName); if (Objects.nonNull(department)) { // 检测责任中心是否存在 Long id = department.getId(); Long responsibilityId = responsibilityDepMap.get(id); if (Objects.nonNull(responsibilityId)) { Responsibility responsibility = responsibilityMap.get(responsibilityId); if (Objects.nonNull(responsibility)) { costCostingGroup.setDepartmentCode(departmentCode); costCostingGroup.setDepartmentName(departmentName); costCostingGroup.setResponsibilityCode(responsibility.getResponsibilityCode()); costCostingGroup.setResponsibilityName(responsibility.getResponsibilityName()); // afterCostGroup.setResponsibilityCode(responsibility.getResponsibilityCode()); // afterCostGroup.setResponsibilityName(responsibility.getResponsibilityName()); // afterCostGroup.setDepartmentCode(departmentCode); // afterCostGroup.setDepartmentName(departmentName); } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(finalJ); incomeErrorMessage.setErrMessage("第" + finalJ + "列科室信息对应的责任中心不存在"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(finalJ); incomeErrorMessage.setErrMessage("第" + finalJ + "列科室信息不存在对应的责任中心"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } } else { IncomeErrorMessage incomeErrorMessage = new IncomeErrorMessage(); incomeErrorMessage.setTotal(finalJ); incomeErrorMessage.setErrMessage("第" + finalJ + "列科室信息不存在"); if (incomeErrorMessageList != null) { incomeErrorMessageList.add(incomeErrorMessage); } } costCostingGroup.setAmount(new BigDecimal((Objects.isNull(data.get(finalJ)) || "0".equals(data.get(finalJ).toString())) ? "0.00" : data.get(finalJ).toString())); costCostingGroup.setHospId(UserContext.getHospId()); costCostingGroup.setCreateTime(System.currentTimeMillis()); costCostingGroup.setDateYear(year); costCostingGroup.setDateMonth(month); afterCostGroup.setAmount(new BigDecimal((Objects.isNull(data.get(finalJ)) || "0".equals(data.get(finalJ).toString())) ? "0.00" : data.get(finalJ).toString())); // String s = JsonUtil.toJSONString(afterCostGroup); // String s = JacksonUtil.obj2Str(afterCostGroup); // costCostingGroup.setAfterCostGroup(s); increment(costCostingGroup); // costCostingGroupArrayList.add(costCostingGroup); } }); // Runnable runnable = () -> { // }; // pool.execute(runnable); } } } } } pool.shutdown(); while (true) { if (pool.isTerminated()) { break; } } } static List costCostingGroupArrayList = new ArrayList<>(); public static synchronized void increment(CostCostingGroup group) { costCostingGroupArrayList.add(group); } /** * 得到这个月的所有导入的成本数据 * * @param year 年 * @param month 月 * @param hospId 医院id * @return List */ @Override public List getByYearAndDate(Integer year, Integer month, Long hospId) { return this.list( new LambdaQueryWrapper() .eq(CostCostingGroup::getDateYear, year) .eq(CostCostingGroup::getDateMonth, month) .eq(CostCostingGroup::getHospId, hospId) ); } /** * 撤销分摊 * * @param year * @param month * @param hospId */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public void cancelAllocation(Integer year, Integer month, Long hospId) { allocationMapper.delete( new LambdaQueryWrapper() .eq(Allocation::getDateYear, year) .eq(Allocation::getDateMonth, month) .eq(Allocation::getHospId, hospId) ); allocationQueryMapper.delete( new LambdaQueryWrapper() .eq(AllocationQuery::getDateYear, year) .eq(AllocationQuery::getDateMonth, month) .eq(AllocationQuery::getHospId, hospId) ); } @Override public List getRealData(List maxId, Long hospId, Integer year, Integer month) { if (!CollectionUtils.isEmpty(maxId)) { return baseMapper.getRealData(maxId, hospId, month, year); } else { return baseMapper.getAllRealData(hospId, month, year); } } /** * @param type * @param computeDate * @param departmentName * @return */ @Override public List getDepartment(Integer type, String computeDate, String departmentName) { int year = 0; int month = 0; Date date = DateUtils.StringToDate(computeDate, DateStyleEnum.YYYY_MM); if (StrUtil.isNotBlank(computeDate)) { year = DateUtil.year(date); month = DateUtil.month(date) + 1; } return baseMapper.getDepartment(year, month, UserContext.getHospId(), departmentName); } /** * @param computeDate */ @Override public void removeCost(String computeDate) { int year = 0; int month = 0; Date date = DateUtils.StringToDate(computeDate, DateStyleEnum.YYYY_MM); if (StrUtil.isNotBlank(computeDate)) { year = DateUtil.year(date); month = DateUtil.month(date) + 1; } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(!NumberConstant.ZERO.equals(year), CostCostingGroup::getDateYear, year); queryWrapper.eq(!NumberConstant.ZERO.equals(month), CostCostingGroup::getDateMonth, month); queryWrapper.eq(CostCostingGroup::getHospId, UserContext.getHospId()); List list = this.list(queryWrapper); if (!CollectionUtils.isEmpty(list)) { List collect = list.stream().map(CostCostingGroup::getId).collect(Collectors.toList()); this.removeByIds(collect); } } }