AllocationServiceImpl.java 97 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  1. package com.kcim.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.StrUtil;
  6. import cn.hutool.poi.excel.ExcelWriter;
  7. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  8. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  9. import com.kcim.common.constants.NumberConstant;
  10. import com.kcim.common.constants.ParameterConstant;
  11. import com.kcim.common.constants.SQLParameter;
  12. import com.kcim.common.enums.CustomSqlTypeEnum;
  13. import com.kcim.common.exception.CostException;
  14. import com.kcim.common.util.BeanUtil;
  15. import com.kcim.common.util.JacksonUtil;
  16. import com.kcim.common.util.PageUtils;
  17. import com.kcim.common.util.UserContext;
  18. import com.kcim.dao.mapper.AllocationMapper;
  19. import com.kcim.dao.model.*;
  20. import com.kcim.dao.model.dto.StartDTO;
  21. import com.kcim.dao.repository.CostAccountShareDetailRepository;
  22. import com.kcim.dao.repository.CostAccountShareParamRepository;
  23. import com.kcim.dao.repository.CostAccountShareTargetRepository;
  24. import com.kcim.dao.repository.ResponsibilityRepository;
  25. import com.kcim.service.*;
  26. import com.kcim.vo.*;
  27. import lombok.AllArgsConstructor;
  28. import lombok.extern.slf4j.Slf4j;
  29. import org.apache.poi.ss.usermodel.Sheet;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.transaction.annotation.Propagation;
  32. import org.springframework.transaction.annotation.Transactional;
  33. import org.springframework.util.CollectionUtils;
  34. import org.springframework.util.ObjectUtils;
  35. import java.math.BigDecimal;
  36. import java.math.RoundingMode;
  37. import java.util.*;
  38. import java.util.concurrent.atomic.AtomicReference;
  39. import java.util.function.Function;
  40. import java.util.stream.Collectors;
  41. @Slf4j
  42. @AllArgsConstructor
  43. @Service("allocationService")
  44. public class AllocationServiceImpl extends BaseBatchServiceImpl<AllocationMapper, Allocation> implements AllocationService {
  45. // @Value("${file.serverPath}")
  46. // private String fileTempPath;
  47. //
  48. // @Value("${file.serverUrl}")
  49. // private String FILE_PATH;
  50. private final CostCostingGroupService costCostingGroupService;
  51. private final CostShareLevelService shareLevelService;
  52. private final ResponsibilityService responsibilityService;
  53. private final CostAccountShareService accountShareService;
  54. private final ShareParamValueService shareParamValueService;
  55. private final CostShareParamService shareParamService;
  56. private final AllocationQueryService allocationQueryService;
  57. private final ResponsibilityRepository responsibilityRepository;
  58. private final CenterService centerService;
  59. private final SqlService sqlService;
  60. private final CostAccountShareDetailRepository costAccountShareDetailRepository;
  61. private final CostAccountShareParamRepository costAccountShareParamRepository;
  62. private final CostAccountShareTargetRepository costAccountShareTargetRepository;
  63. // public AllocationServiceImpl(CostCostingGroupService costCostingGroupService, CostShareLevelService shareLevelService, ResponsibilityService responsibilityService, CostAccountShareService accountShareService, ShareParamValueService shareParamValueService, CostShareParamService shareParamService, AllocationQueryService allocationQueryService, ResponsibilityRepository responsibilityRepository, CenterService centerService, SqlService sqlService) {
  64. // this.costCostingGroupService = costCostingGroupService;
  65. // this.shareLevelService = shareLevelService;
  66. // this.responsibilityService = responsibilityService;
  67. // this.accountShareService = accountShareService;
  68. // this.shareParamValueService = shareParamValueService;
  69. // this.shareParamService = shareParamService;
  70. // this.allocationQueryService = allocationQueryService;
  71. // this.responsibilityRepository = responsibilityRepository;
  72. // this.centerService = centerService;
  73. // this.sqlService = sqlService;
  74. // }
  75. /**
  76. * 分摊成本数据
  77. *
  78. * @param startDTO {@link StartDTO}
  79. * @param hospId 医院id
  80. */
  81. @Override
  82. public void startAllocation(StartDTO startDTO, Long hospId) {
  83. //获取分摊方式
  84. String parameterValue = centerService.getParameterValue(ParameterConstant.ALLOCATION_TYPE);
  85. if (NumberConstant.ONE_S.equals(parameterValue)) {
  86. //开始按责任中心分摊成本
  87. startCostAllocation(startDTO, hospId);
  88. }
  89. else if (NumberConstant.TWO_S.equals(parameterValue)) {
  90. //按会计科目分摊
  91. startAccountAllocation(startDTO, hospId);
  92. }
  93. //执行分摊后续处理脚本
  94. execAllocationSQL(startDTO);
  95. }
  96. /**
  97. * 按会计科目分摊
  98. * @param startDTO
  99. */
  100. @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
  101. public void startAccountAllocation(StartDTO startDTO, Long hospId){
  102. long timeMillis = System.currentTimeMillis();
  103. // 得到这个月的所有导入的成本数据
  104. List<CostCostingGroup> costingGroups = costCostingGroupService.getByYearAndDate(startDTO.getYear(), startDTO.getMonth(), hospId);
  105. // 没有重新导入
  106. if (costingGroups.isEmpty()) {
  107. throw new CostException("本月分摊数据未导入");
  108. }
  109. // 导入数据按责任中心归类
  110. Map<String, List<CostCostingGroup>> respDirectCostMap = costingGroups.stream().collect(Collectors.groupingBy(CostCostingGroup::getResponsibilityCode));
  111. // 得到这个月导入的成本分摊参数值列表
  112. List<ShareParamValue> respParamValueList = shareParamValueService.getListByYearAndMonth(startDTO.getYear(), startDTO.getMonth(), hospId);
  113. if (respParamValueList.isEmpty()) {
  114. throw new CostException("本月成本分摊参数值未导入");
  115. }
  116. Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup = respParamValueList.stream()
  117. .collect(Collectors.groupingBy(
  118. ShareParamValue::getResponsibilityCode,
  119. Collectors.groupingBy(ShareParamValue::getShareParamCode)
  120. ));
  121. // 得到这个医院所有的分摊层级列表排序
  122. List<CostShareLevelVO> shareLevelVOs = shareLevelService.getAll(hospId);
  123. if (CollUtil.isEmpty(shareLevelVOs)) {
  124. throw new CostException("请先设置医院分摊层级");
  125. }
  126. //优化循环调用 责任中心 分摊层级对应
  127. //成本分摊字典
  128. List<CostShareParamVO> costShareParamList = shareParamService.getAll(hospId);
  129. if (CollUtil.isEmpty(costShareParamList)) {
  130. throw new CostException("请先设置分摊参数字典");
  131. }
  132. Map<String,String> ShareParamNameMap = costShareParamList.stream().collect(Collectors.toMap(CostShareParamVO::getShareParamCode, CostShareParamVO::getShareParamName, (a, b) -> b));
  133. //责任中心
  134. List<Responsibility> responsibilityList = responsibilityRepository.getList(hospId);
  135. if (CollUtil.isEmpty(responsibilityList)) {
  136. throw new CostException("请先设置责任中心");
  137. }
  138. //按shareId分组
  139. Map<Long, List<Responsibility>> responsibilityShareIdMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getShareId));
  140. //按责任中心代码分组
  141. Map<String, List<Responsibility>> responsibilityCodeMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getResponsibilityCode));
  142. //分摊参数对应
  143. List<CostAccountShare> accountShareList = accountShareService.getAll();
  144. if (CollUtil.isEmpty(accountShareList)) {
  145. throw new CostException("请先设置责任中心分摊参数对应");
  146. }
  147. //责任中心的分摊参数对应设置
  148. Map<String, List<CostAccountShare>> accountShareResponsibilityMap = accountShareList.stream().collect(Collectors.groupingBy(CostAccountShare::getResponsibilityCode));
  149. //分摊设置对应的分摊参数明细
  150. List<CostAccountShareParam> costAccountShareParamList = costAccountShareParamRepository.getCostAccountShareParam(null);
  151. if (CollUtil.isEmpty(costAccountShareParamList)) {
  152. throw new CostException("请先设置责任中心的分摊参数");
  153. }
  154. //设置分摊参数名称
  155. costAccountShareParamList.forEach(shareParam->shareParam.setShareParamName(ShareParamNameMap.get(shareParam.getShareParamCode())));
  156. //按分摊设置ID分组
  157. Map<Long, List<CostAccountShareParam>> costAccountShareParamMap = costAccountShareParamList.stream().collect(Collectors.groupingBy(CostAccountShareParam::getAccountShareId));
  158. //分摊设置对应的会计科目明细
  159. List<CostAccountShareDetail> costAccountShareDetailList = costAccountShareDetailRepository.getCostAccountShareDetail(null);
  160. Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap =new HashMap<>();
  161. //全部都是合并计算时会有会计科目明细为空的情况
  162. if(!CollectionUtils.isEmpty(costAccountShareDetailList)) {
  163. costAccountShareDetailMap=costAccountShareDetailList.stream().collect(Collectors.groupingBy(CostAccountShareDetail::getAccountShareId));
  164. }
  165. //分摊设置对应的目标责任中心
  166. List<CostAccountShareTarget> costAccountShareTargetList = costAccountShareTargetRepository.getCostAccountShareTarget(null);
  167. Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap =new HashMap<>();
  168. //全部没有指定分摊时会有目标责任中心为空的情况
  169. if(!CollectionUtils.isEmpty(costAccountShareTargetList)) {
  170. costAccountShareTargetMap=costAccountShareTargetList.stream().collect(Collectors.groupingBy(CostAccountShareTarget::getAccountShareId));
  171. }
  172. //分摊成本列表
  173. List<Allocation> allocationCostList=new ArrayList<>();
  174. //逐级分摊
  175. for (CostShareLevelVO shareLevelVO : shareLevelVOs) {
  176. List<Allocation> shareLevelAllocationList = allocationShareLevelCost(startDTO, shareLevelVO, responsibilityList, responsibilityShareIdMap, respDirectCostMap, respParamValueGroup,
  177. accountShareResponsibilityMap, costAccountShareParamMap, costAccountShareDetailMap, costAccountShareTargetMap,allocationCostList, timeMillis,hospId);
  178. allocationCostList.addAll(shareLevelAllocationList);
  179. }
  180. //没有任何分摊数据
  181. if(CollectionUtils.isEmpty(allocationCostList)){
  182. log.error("没有任何分摊数据......");
  183. return;
  184. }
  185. // 删除该年月已经分摊过的数据
  186. removeData(startDTO, hospId);
  187. //保存分摊结果信息
  188. this.batchInsert(allocationCostList);
  189. //保存分摊结果查询表
  190. applyAllocationQuery(startDTO,respDirectCostMap,allocationCostList,responsibilityCodeMap);
  191. }
  192. public void batchSaveAllocation(List<Allocation> allocationList) {
  193. if (CollUtil.isEmpty(allocationList)) {
  194. return;
  195. }
  196. // 调整批次大小,根据数据库性能测试确定最佳值
  197. int batchSize = 5000;
  198. // 分批次保存
  199. for (int i = 0; i < allocationList.size(); i += batchSize) {
  200. int end = Math.min(i + batchSize, allocationList.size());
  201. this.saveBatch(allocationList.subList(i, end));
  202. }
  203. }
  204. /**
  205. * 一个分摊层级的分摊计算
  206. * @param startDTO 分摊年月所在对象
  207. * @param shareLevelVO 分摊层级
  208. * @param responsibilityList 责任中心字典
  209. * @param responsibilityShareIdMap 各分摊层级的责任中心
  210. * @param respDirectCostMap 直接成本
  211. * @param respParamValueGroup 分摊参数数值
  212. * @param accountShareResponsibilityMap 分摊参数对应
  213. * @param costAccountShareParamMap 分摊设置对应的分摊参数
  214. * @param costAccountShareDetailMap 分摊设置对应的会计科目
  215. * @param allocationCostList 间接成本
  216. * @param timeMillis 时间戳
  217. * @return
  218. */
  219. public List<Allocation> allocationShareLevelCost(StartDTO startDTO, CostShareLevelVO shareLevelVO,
  220. List<Responsibility> responsibilityList,
  221. Map<Long, List<Responsibility>> responsibilityShareIdMap,
  222. Map<String, List<CostCostingGroup>> respDirectCostMap ,
  223. Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
  224. Map<String,List<CostAccountShare>> accountShareResponsibilityMap,
  225. Map<Long, List<CostAccountShareParam>> costAccountShareParamMap,
  226. Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap,
  227. Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap,
  228. List<Allocation> allocationCostList,
  229. long timeMillis, Long hospId){
  230. //分摊成本列表
  231. List<Allocation> allocationList=new ArrayList<>();
  232. // 分摊层级id
  233. Long levelId = shareLevelVO.getId();
  234. // 目标分摊层级,可能不存在
  235. String targetLevel = shareLevelVO.getTargetLevel();
  236. if (StrUtil.isBlank(targetLevel)) {
  237. throw new CostException("未设置目标层级");
  238. }
  239. //目标分摊层级
  240. List<String> targetLevelList = Arrays.stream(targetLevel.split(StrUtil.COMMA)).collect(Collectors.toList());
  241. //目标层级是自己的不需要做分摊处理
  242. if(NumberConstant.ONE.equals(targetLevelList.size())&&Integer.valueOf(targetLevelList.get(NumberConstant.ZERO)).equals(shareLevelVO.getLeverSort())){
  243. return allocationList;
  244. }
  245. // 得到该分摊层级下责任中心列表,如果不存在,下一个
  246. List<Responsibility> responsibilities = responsibilityShareIdMap.get(levelId);
  247. if (CollectionUtils.isEmpty(responsibilities)) {
  248. return allocationList;
  249. }
  250. //目标责任中心列表 - 优化:预先创建Map以提高查找效率
  251. Map<String, Responsibility> targetResponsibilityMap = responsibilityList.stream()
  252. .filter(responsibility -> targetLevelList.contains(String.valueOf(responsibility.getShareLevel())))
  253. .collect(Collectors.toMap(Responsibility::getResponsibilityCode, Function.identity(), (a, b) -> a));
  254. if (targetResponsibilityMap.isEmpty()) {
  255. throw new CostException(String.format("[%s-%s]的分摊目标层级没有对应的责任中心",shareLevelVO.getLeverSort(),shareLevelVO.getShareName()));
  256. }
  257. // 优化:预先创建间接成本的Map以提高查找效率
  258. Map<String, List<Allocation>> indirectCostMap = allocationCostList.stream()
  259. .collect(Collectors.groupingBy(Allocation::getTargetResponsibilityCode));
  260. // 按责任中心逐个开始分摊(并行)
  261. allocationList = responsibilities.parallelStream().flatMap(responsibility -> allocationResponsibilityCost(startDTO, shareLevelVO, responsibility, targetResponsibilityMap, respDirectCostMap, respParamValueGroup,
  262. accountShareResponsibilityMap, costAccountShareParamMap, costAccountShareDetailMap,costAccountShareTargetMap, indirectCostMap, timeMillis,hospId).stream()).collect(Collectors.toList());
  263. return allocationList;
  264. }
  265. /**
  266. * 分摊一个责任中心的成本
  267. * @param startDTO 分摊年月所在对象
  268. * @param shareLevelVO 分摊层级
  269. * @param responsibility 责任中心
  270. * @param respDirectCostMap 直接成本
  271. * @param respParamValueGroup 分摊参数数值
  272. * @param accountShareResponsibilityMap 分摊参数对应
  273. * @param costAccountShareParamMap 分摊设置对应的分摊参数
  274. * @param costAccountShareDetailMap 分摊设置对应的会计科目
  275. * @param indirectCostMap 间接成本
  276. * @param timeMillis 时间戳
  277. */
  278. public List<Allocation> allocationResponsibilityCost(StartDTO startDTO,
  279. CostShareLevelVO shareLevelVO,
  280. Responsibility responsibility,
  281. Map<String, Responsibility> targetResponsibilityMap ,
  282. Map<String, List<CostCostingGroup>> respDirectCostMap ,
  283. Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
  284. Map<String,List<CostAccountShare>> accountShareResponsibilityMap,
  285. Map<Long, List<CostAccountShareParam>> costAccountShareParamMap,
  286. Map<Long, List<CostAccountShareDetail>> costAccountShareDetailMap,
  287. Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap,
  288. Map<String, List<Allocation>> indirectCostMap,
  289. long timeMillis, Long hospId){
  290. //分摊结果列表
  291. List<Allocation> allocationList=new ArrayList<>();
  292. // 得到分摊参数对应记录,不存在,下一个
  293. List<CostAccountShare> accountShares = accountShareResponsibilityMap.get(responsibility.getResponsibilityCode());
  294. if (CollectionUtils.isEmpty(accountShares)) {
  295. return allocationList;
  296. }
  297. // 计算方式 0是合并计算 1是分开计算
  298. Integer calcType = shareLevelVO.getCalcType();
  299. //合并计算时不应该有多个分摊设置
  300. if(NumberConstant.ZERO.equals(calcType) &&NumberConstant.ONE!=accountShares.size()){
  301. throw new CostException(String.format("[%s-%s]的分摊设置有问题,合并计算的责任中心只允许设置一个分摊配置",responsibility.getResponsibilityCode(),responsibility.getResponsibilityName()));
  302. }
  303. //间接成本
  304. List<Allocation> respIndirectCostList =indirectCostMap.get(responsibility.getResponsibilityCode());
  305. //直接成本
  306. List<CostCostingGroup> respDirectCostList = respDirectCostMap.get(responsibility.getResponsibilityCode());
  307. //按分摊设置逐个计算
  308. for (CostAccountShare accountShare : accountShares) {
  309. //分摊设置对应的直接成本
  310. List<CostCostingGroup> paramDirectCostList=new ArrayList<>();
  311. //分摊设置对应的间接成本
  312. List<Allocation> paramIndirectCostList=new ArrayList<>();
  313. //获取分摊设置对应的目标责任中心
  314. List<Responsibility> shareTargetRespCodeList = getShareTargetResponsibility(accountShare, targetResponsibilityMap, costAccountShareTargetMap);
  315. //所有目标责任中心的责任中心代码列表
  316. List<String> targetResponsibilityCodeList = shareTargetRespCodeList.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList());
  317. //合并计算
  318. if(NumberConstant.ZERO.equals(calcType)){
  319. //合并计算时分摊参数的成本=责任中心的成本
  320. paramDirectCostList=respDirectCostList;
  321. paramIndirectCostList=respIndirectCostList;
  322. }else{
  323. //分摊设置对应的会计科目
  324. List<String> accountList = costAccountShareDetailMap.get(accountShare.getId()).stream().map(CostAccountShareDetail::getAccountingCode).collect(Collectors.toList());
  325. if(!CollectionUtils.isEmpty(respDirectCostList)) {
  326. //获取分摊设置对应的直接成本
  327. paramDirectCostList = respDirectCostList.stream().filter(respDirectCost -> accountList.contains(respDirectCost.getAccountCode())).collect(Collectors.toList());
  328. }
  329. //只有包含分摊成本的才有间接成本
  330. if(NumberConstant.ONE.equals(accountShare.getIsShareCost())){
  331. paramIndirectCostList=respIndirectCostList;
  332. }
  333. }
  334. //分摊设置对应的分摊参数
  335. List<CostAccountShareParam> costAccountShareParams = costAccountShareParamMap.get(accountShare.getId());
  336. //按分摊参数逐个计算所有目标责任中心的分摊金额
  337. for (CostAccountShareParam shareParam : costAccountShareParams) {
  338. //获取所有目标责任中心的分摊参数数值信息
  339. List<ShareParamValue> targetResponsibilityParamList =getTargetResponsibilityParamList( respParamValueGroup,targetResponsibilityCodeList,shareParam);
  340. if(CollectionUtils.isEmpty(targetResponsibilityParamList)){
  341. throw new CostException(String.format("[%s-%s]的目标责任中心找不到对应的参数数值,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
  342. }
  343. //按分摊参数计算每个会计科目分摊到的金额
  344. List<Allocation> allocationParamCosts = allocationParamCostCalc(startDTO, shareLevelVO, responsibility, shareTargetRespCodeList, paramDirectCostList,
  345. paramIndirectCostList, accountShares.get(NumberConstant.ZERO), shareParam, targetResponsibilityParamList, timeMillis, hospId);
  346. allocationList.addAll(allocationParamCosts);
  347. }
  348. }
  349. return allocationList;
  350. }
  351. /**
  352. * 获取所有目标责任中心的分摊参数数值信息
  353. * @param respParamValueGroup
  354. * @param targetResponsibilityCodeList
  355. * @param shareParam
  356. * @return
  357. */
  358. public List<ShareParamValue> getTargetResponsibilityParamList(
  359. Map<String, Map<String, List<ShareParamValue>>> respParamValueGroup,
  360. List<String> targetResponsibilityCodeList,
  361. CostAccountShareParam shareParam) {
  362. List<ShareParamValue> targetResponsibilityParamList = new ArrayList<>();
  363. String shareParamCode = shareParam.getShareParamCode();
  364. for (String targetResponsibilityCode : targetResponsibilityCodeList) {
  365. Map<String, List<ShareParamValue>> shareParamValueMap = respParamValueGroup.get(targetResponsibilityCode);
  366. if (shareParamValueMap != null) {
  367. List<ShareParamValue> shareParamValues = shareParamValueMap.get(shareParamCode);
  368. if (shareParamValues != null) {
  369. targetResponsibilityParamList.addAll(shareParamValues);
  370. }
  371. }
  372. }
  373. return targetResponsibilityParamList;
  374. }
  375. /**
  376. * 获取分摊设置的目标责任中心
  377. * @param accountShare
  378. * @param levelTargetResponsibilityMap
  379. * @param costAccountShareTargetMap
  380. * @return
  381. */
  382. public List<Responsibility> getShareTargetResponsibility(CostAccountShare accountShare,
  383. Map<String, Responsibility> levelTargetResponsibilityMap,
  384. Map<Long, List<CostAccountShareTarget>> costAccountShareTargetMap){
  385. //获取分摊设置对应的目标责任中心
  386. List<CostAccountShareTarget> shareTargetResponsibilityList=costAccountShareTargetMap.get(accountShare.getId());
  387. if(CollectionUtils.isEmpty(shareTargetResponsibilityList)){
  388. return new ArrayList<>(levelTargetResponsibilityMap.values());
  389. }
  390. //筛选出指定的目标责任中心
  391. List<String> shareTargetRespCodeList = shareTargetResponsibilityList.stream().map(CostAccountShareTarget::getTargetResponsibilityCode).collect(Collectors.toList());
  392. List<Responsibility> shareTargetRespList = new ArrayList<>();
  393. for (String shareTargetRespCode : shareTargetRespCodeList) {
  394. Responsibility levelTargetResponsibility = levelTargetResponsibilityMap.get(shareTargetRespCode);
  395. if (levelTargetResponsibility == null) {
  396. continue;
  397. }
  398. shareTargetRespList.add(levelTargetResponsibility);
  399. }
  400. if(CollectionUtils.isEmpty(shareTargetRespList)){
  401. throw new CostException(String.format("[%s-%s]找不到对应的目标责任中心,无法继续分摊",accountShare.getResponsibilityName(),accountShare.getAlias()));
  402. }
  403. return shareTargetRespList;
  404. }
  405. /**
  406. * 按分摊参数计算每个会计科目分摊到的金额
  407. * @param startDTO 分摊年月所在对象
  408. * @param shareLevelVO 分摊层级
  409. * @param responsibility 责任中心
  410. * @param targetResponsibilityList 目标责任中心列表
  411. * @param respDirectCostList 直接成本
  412. * @param respIndirectCostList 间接成本
  413. * @param costAccountShare 分摊参数对应
  414. * @param shareParam 分摊参数
  415. * @param targetResponsibilityParamList 目标责任中心的分摊参数数值列表
  416. * @param timeMillis 时间戳
  417. * @return
  418. */
  419. public List<Allocation> allocationParamCostCalc(StartDTO startDTO,
  420. CostShareLevelVO shareLevelVO,
  421. Responsibility responsibility,
  422. List<Responsibility> targetResponsibilityList,
  423. List<CostCostingGroup> respDirectCostList,
  424. List<Allocation> respIndirectCostList,
  425. CostAccountShare costAccountShare,
  426. CostAccountShareParam shareParam,
  427. List<ShareParamValue> targetResponsibilityParamList,
  428. long timeMillis, Long hospId){
  429. //重新定义一个列表用于合并直接成本和间接成本
  430. List<CostCostingGroup> respCostList=new ArrayList<>();
  431. //添加直接成本
  432. if(!CollectionUtils.isEmpty(respDirectCostList)){
  433. respCostList.addAll(respDirectCostList);
  434. }
  435. //添加间接成本
  436. if(!CollectionUtils.isEmpty(respIndirectCostList)){
  437. //转成直接成本的对象
  438. List<CostCostingGroup> respIndirectCosts = BeanUtil.convertList(respIndirectCostList, CostCostingGroup.class);
  439. respCostList.addAll(respIndirectCosts);
  440. }
  441. //计算所有目标责任中心的分摊参数加总
  442. BigDecimal totalParamValue= targetResponsibilityParamList.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
  443. if (NumberConstant.ZERO.equals(totalParamValue.compareTo(BigDecimal.ZERO))){
  444. throw new CostException(String.format("[%s-%s]的目标责任中心参数数值加总为0,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
  445. }
  446. //按责任中心分组,方便取到对应责任中心的分摊参数数值
  447. Map<String, List<ShareParamValue>> targetRespParamGroup = targetResponsibilityParamList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
  448. //创建accountCode到accountName的映射
  449. Map<String, String> accountCodeNameMap = respCostList.stream().collect(Collectors.toMap(CostCostingGroup::getAccountCode,
  450. CostCostingGroup::getAccountName,
  451. (existing, replacement) -> replacement // 处理重复键的情况,保留最后一个值
  452. ));
  453. //按会计科目分组,相同会计科目一起分摊
  454. Map<String, BigDecimal> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode,
  455. Collectors.reducing(BigDecimal.ZERO,CostCostingGroup::getAmount,BigDecimal::add)));
  456. //参数占比
  457. BigDecimal paramRate = shareParam.getShareParamProportion().divide(new BigDecimal(NumberConstant.ONE_HUNDRED), NumberConstant.FOUR, RoundingMode.HALF_UP);
  458. //分摊结果列表
  459. List<Allocation> allocationList=new ArrayList<>();
  460. for (Responsibility targetResponsibility : targetResponsibilityList){
  461. List<ShareParamValue> targetRespParamValues = targetRespParamGroup.get(targetResponsibility.getResponsibilityCode());
  462. //目标责任中心的分摊参数数值
  463. BigDecimal targetRespParamValue = BigDecimal.ZERO;
  464. if(!CollectionUtils.isEmpty(targetRespParamValues)) {
  465. targetRespParamValue = targetRespParamValues.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
  466. }
  467. //没有参数数值就不分摊计算了,不然数据会很多
  468. if(NumberConstant.ZERO.equals(BigDecimal.ZERO.compareTo(targetRespParamValue))){
  469. continue;
  470. }
  471. //计算分摊参数比例
  472. BigDecimal shareParamRate = targetRespParamValue.divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
  473. for (Map.Entry<String, BigDecimal> entry : respDirectCostGroup.entrySet()) {
  474. String accountCode = entry.getKey();
  475. BigDecimal totalAmount = entry.getValue();
  476. //没有金额的会计科目就不分摊计算了,不然数据会很多
  477. if(NumberConstant.ZERO.equals(BigDecimal.ZERO.compareTo(totalAmount))){
  478. continue;
  479. }
  480. //计算分摊到的金额=目标责任中心的分摊参数数值*会计科目总金额/所有目标责任中心的分摊参数数值加总*参数比例
  481. BigDecimal targetAmount = targetRespParamValue.multiply(totalAmount).multiply(paramRate).divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
  482. //生成分摊结果的对象
  483. Allocation targetAllocation = createAllocation(startDTO, shareLevelVO, responsibility, targetResponsibility, costAccountShare, shareParam,timeMillis,hospId);
  484. targetAllocation.setAmount(targetAmount)
  485. .setTotalAmount(totalAmount)
  486. .setShareParamValueNum(targetRespParamValue)
  487. .setShareParamRate(shareParamRate)
  488. .setAccountCode(accountCode)
  489. .setAccountName(accountCodeNameMap.get(accountCode));
  490. allocationList.add(targetAllocation);
  491. }
  492. }
  493. return allocationList;
  494. }
  495. /**
  496. * 按分摊参数计算每个会计科目分摊到的金额(多线程)
  497. * @param startDTO 分摊年月所在对象
  498. * @param shareLevelVO 分摊层级
  499. * @param responsibility 责任中心
  500. * @param targetResponsibilityList 目标责任中心列表
  501. * @param respDirectCostList 直接成本
  502. * @param respIndirectCostList 间接成本
  503. * @param costAccountShare 分摊参数对应
  504. * @param shareParam 分摊参数
  505. * @param targetResponsibilityParamList 目标责任中心的分摊参数数值列表
  506. * @param timeMillis 时间戳
  507. * @return
  508. */
  509. public List<Allocation> synAllocationParamCostCalc(StartDTO startDTO,
  510. CostShareLevelVO shareLevelVO,
  511. Responsibility responsibility,
  512. List<Responsibility> targetResponsibilityList,
  513. List<CostCostingGroup> respDirectCostList,
  514. List<Allocation> respIndirectCostList,
  515. CostAccountShare costAccountShare,
  516. CostAccountShareParam shareParam,
  517. List<ShareParamValue> targetResponsibilityParamList,
  518. long timeMillis, Long hospId){
  519. //重新定义一个列表用于合并直接成本和间接成本
  520. List<CostCostingGroup> respCostList=new ArrayList<>();
  521. //添加直接成本
  522. if(!CollectionUtils.isEmpty(respDirectCostList)){
  523. respCostList.addAll(respDirectCostList);
  524. }
  525. //添加间接成本
  526. if(!CollectionUtils.isEmpty(respIndirectCostList)){
  527. //转成直接成本的对象
  528. List<CostCostingGroup> respIndirectCosts = BeanUtil.convertList(respIndirectCostList, CostCostingGroup.class);
  529. respCostList.addAll(respIndirectCosts);
  530. }
  531. //计算所有目标责任中心的分摊参数加总
  532. BigDecimal totalParamValue= targetResponsibilityParamList.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
  533. if (NumberConstant.ZERO.equals(totalParamValue.compareTo(BigDecimal.ZERO))){
  534. throw new CostException(String.format("[%s-%s]的目标责任中心参数数值加总为0,无法继续分摊",responsibility.getResponsibilityName(),shareParam.getShareParamName()));
  535. }
  536. //按责任中心分组,方便取到对应责任中心的分摊参数数值
  537. Map<String, BigDecimal> targetRespParamGroup=targetResponsibilityParamList.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode,Collectors.reducing(BigDecimal.ZERO, ShareParamValue::getValueNum, BigDecimal::add)));
  538. //创建accountCode到accountName的映射
  539. Map<String, String> accountCodeNameMap = respCostList.stream().collect(Collectors.toMap(
  540. CostCostingGroup::getAccountCode,
  541. CostCostingGroup::getAccountName,
  542. (existing, replacement) -> replacement // 处理重复键的情况,保留最后一个值
  543. ));
  544. //按会计科目分组,相同会计科目一起分摊并计算总金额
  545. Map<String, BigDecimal> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(
  546. CostCostingGroup::getAccountCode,
  547. Collectors.reducing(BigDecimal.ZERO, CostCostingGroup::getAmount, BigDecimal::add)
  548. ));
  549. //预计算参数比例,避免在循环中重复计算
  550. BigDecimal paramRate = shareParam.getShareParamProportion()
  551. .divide(new BigDecimal(NumberConstant.ONE_HUNDRED), NumberConstant.FOUR, RoundingMode.HALF_UP);
  552. //分摊结果列表(使用线程安全的列表)
  553. List<Allocation> allocationList = Collections.synchronizedList(new ArrayList<>());
  554. //使用并行流处理目标责任中心
  555. targetResponsibilityList.parallelStream().forEach(targetResponsibility -> {
  556. //目标责任中心的分摊参数数值
  557. BigDecimal targetRespParamValue = targetRespParamGroup.get(targetResponsibility.getResponsibilityCode());
  558. if(ObjectUtils.isEmpty(targetRespParamValue)){
  559. return;
  560. }
  561. //计算分摊参数比例
  562. BigDecimal shareParamRate = targetRespParamValue.divide(totalParamValue, NumberConstant.FOUR, RoundingMode.HALF_UP);
  563. //预计算基础金额,避免在内层循环中重复计算
  564. BigDecimal baseAmount = targetRespParamValue.multiply(paramRate).divide(totalParamValue, NumberConstant.SIX, RoundingMode.HALF_UP);
  565. //遍历每个会计科目
  566. respDirectCostGroup.entrySet().parallelStream().forEach(entry -> {
  567. String accountCode = entry.getKey();
  568. BigDecimal totalAmount = entry.getValue();
  569. //计算分摊到的金额=目标责任中心的分摊参数数值*会计科目总金额/所有目标责任中心的分摊参数数值加总*参数比例
  570. //优化:使用预计算的baseAmount
  571. BigDecimal targetAmount = totalAmount.multiply(baseAmount);
  572. //生成分摊结果的对象
  573. Allocation targetAllocation = createAllocation(startDTO, shareLevelVO, responsibility, targetResponsibility, costAccountShare, shareParam,timeMillis,hospId);
  574. targetAllocation.setAmount(targetAmount)
  575. .setTotalAmount(totalAmount)
  576. .setShareParamValueNum(targetRespParamValue)
  577. .setShareParamRate(shareParamRate)
  578. .setAccountCode(accountCode)
  579. .setAccountName(accountCodeNameMap.get(accountCode));
  580. //同步添加到结果列表
  581. synchronized(allocationList) {
  582. allocationList.add(targetAllocation);
  583. }
  584. });
  585. });
  586. return new ArrayList<>(allocationList); //返回普通ArrayList
  587. }
  588. /**
  589. * 创建分摊结果对象
  590. * @param startDTO
  591. * @param shareLevelVO
  592. * @param responsibility
  593. * @param targetResponsibility
  594. * @param costAccountShare
  595. * @param shareParam
  596. * @param timeMillis
  597. * @param hospId
  598. * @return
  599. */
  600. public Allocation createAllocation(StartDTO startDTO,
  601. CostShareLevelVO shareLevelVO,
  602. Responsibility responsibility,
  603. Responsibility targetResponsibility,
  604. CostAccountShare costAccountShare,
  605. CostAccountShareParam shareParam,
  606. long timeMillis,
  607. Long hospId) {
  608. Allocation targetAllocation = new Allocation();
  609. targetAllocation.setDateMonth(startDTO.getMonth())
  610. .setDateYear(startDTO.getYear())
  611. .setLevelSort(shareLevelVO.getLeverSort())
  612. .setLevelName(shareLevelVO.getShareName())
  613. .setHospId(hospId)
  614. .setResponsibilityCode(responsibility.getResponsibilityCode())
  615. .setResponsibilityName(responsibility.getResponsibilityName())
  616. .setAccountShareId(costAccountShare.getId())
  617. // .setAmount(targetAmount)
  618. .setCreateTime(timeMillis)
  619. .setTargetResponsibilityCode(targetResponsibility.getResponsibilityCode())
  620. .setTargetResponsibilityName(targetResponsibility.getResponsibilityName())
  621. .setShareParamCode(shareParam.getShareParamCode())
  622. .setShareParamName(shareParam.getShareParamName())
  623. // .setTotalAmount(totalAmount)
  624. // .setShareParamValueNum(targetRespParamValue)
  625. // .setShareParamRate(shareParamRate)
  626. .setShareLevelId(responsibility.getShareId())
  627. .setTargetShareLevelId(targetResponsibility.getShareId());
  628. // .setAccountCode(accountCode)
  629. // .setAccountName(accountCodeNameMap.get(accountCode));
  630. return targetAllocation;
  631. }
  632. /**
  633. * 保存分摊结果查询表
  634. * @param startDTO 分摊年月所在对象
  635. * @param respDirectCostMap 责任中心的直接成本
  636. * @param allocationCostList 所有责任中心的间接成本
  637. * @param responsibilityCodeMap 责任中心字典
  638. */
  639. public void applyAllocationQuery(StartDTO startDTO, Map<String, List<CostCostingGroup>> respDirectCostMap ,List<Allocation> allocationCostList,Map<String, List<Responsibility>> responsibilityCodeMap){
  640. List<AllocationQuery> allocationQueryList=new ArrayList<>();
  641. //处理直接成本,直接成本可能是多次导入的没有按会计科目汇总的,需按责任中心+会计科目汇总保存
  642. respDirectCostMap.forEach((respCode,respCostList)->{
  643. List<AllocationQuery> directAllocationQueryList = createDirectAllocationQuery(startDTO, respCode, respCostList, responsibilityCodeMap);
  644. allocationQueryList.addAll(directAllocationQueryList);
  645. });
  646. //处理间接成本,间接成本肯定是按会计科目汇总的,可直接生成对象
  647. for (Allocation indirectCost : allocationCostList) {
  648. AllocationQuery indirectAllocationQuery = createIndirectAllocationQuery(startDTO, indirectCost);
  649. allocationQueryList.add(indirectAllocationQuery);
  650. }
  651. if(CollectionUtils.isEmpty(allocationQueryList)){
  652. log.error("没有任何分摊结果数据......");
  653. return;
  654. }
  655. //保存分摊结果查询对象信息
  656. allocationQueryService.batchInsertAllocationQuery(allocationQueryList);
  657. }
  658. /**
  659. * 创建直接成本的分摊结果查询对象
  660. * @param startDTO 分摊年月所在对象
  661. * @param respCode 责任中心代码
  662. * @param respCostList 责任中心的直接成本数据
  663. * @param responsibilityCodeMap 责任中心字典
  664. * @return
  665. */
  666. public List<AllocationQuery> createDirectAllocationQuery(StartDTO startDTO,String respCode,List<CostCostingGroup> respCostList, Map<String, List<Responsibility>> responsibilityCodeMap){
  667. List<AllocationQuery> allocationQueryList=new ArrayList<>();
  668. if(!responsibilityCodeMap.containsKey(respCode)){
  669. log.error(String.format("[%s-%s]的责任中心数据已过期",respCode,respCostList.get(NumberConstant.ZERO).getResponsibilityName()));
  670. return allocationQueryList;
  671. }
  672. //责任中心数据
  673. Responsibility responsibility=responsibilityCodeMap.get(respCode).get(NumberConstant.ZERO);
  674. //按会计科目代码分组
  675. Map<String, List<CostCostingGroup>> respDirectCostGroup = respCostList.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode));
  676. //按会计科目逐个生成分摊结果查询对象
  677. respDirectCostGroup.forEach((respAccountCode,respAccountCostList)->{
  678. CostCostingGroup firtsDirectCost = respAccountCostList.get(NumberConstant.ZERO);
  679. //汇总金额
  680. BigDecimal totalAccountCost = respAccountCostList.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  681. //创建分摊结果查询对象
  682. AllocationQuery allocationQuery = new AllocationQuery();
  683. allocationQuery.setDateYear(startDTO.getYear()).setDateMonth(startDTO.getMonth())
  684. .setHospId(UserContext.getHospId()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
  685. .setCreateTime(System.currentTimeMillis())
  686. .setLevelSort(responsibility.getShareLevel()).setLevelName(responsibility.getShareName())
  687. .setTargetResponsibilityCode(responsibility.getResponsibilityCode())
  688. .setTargetResponsibilityName(responsibility.getResponsibilityName())
  689. .setShareLevelId(responsibility.getShareId())
  690. .setOriginId(firtsDirectCost.getId()).setOriginType(Long.valueOf(NumberConstant.ONE)).setAmount(totalAccountCost)
  691. .setAccountingCode(firtsDirectCost.getAccountCode()).setAccountingName(firtsDirectCost.getAccountName());
  692. allocationQueryList.add(allocationQuery);
  693. });
  694. return allocationQueryList;
  695. }
  696. /**
  697. * 创建间接成本的分摊结果查询对象
  698. * @param startDTO 分摊年月所在对象
  699. * @param indirectCost 间接成本对象
  700. * @return
  701. */
  702. public AllocationQuery createIndirectAllocationQuery(StartDTO startDTO,Allocation indirectCost){
  703. AllocationQuery allocationQuery = new AllocationQuery();
  704. allocationQuery.setDateYear(startDTO.getYear()).setDateMonth(startDTO.getMonth())
  705. .setHospId(UserContext.getHospId()).setResponsibilityCode(indirectCost.getResponsibilityCode())
  706. .setResponsibilityName(indirectCost.getResponsibilityName())
  707. .setOriginId(indirectCost.getId()).setOriginType(Long.valueOf(NumberConstant.TWO)).setAmount(indirectCost.getAmount())
  708. .setAccountingCode(indirectCost.getAccountCode()).setAccountingName(indirectCost.getAccountName())
  709. .setCreateTime(System.currentTimeMillis())
  710. .setLevelSort(indirectCost.getLevelSort()).setLevelName(indirectCost.getLevelName())
  711. .setTargetResponsibilityCode(indirectCost.getTargetResponsibilityCode())
  712. .setTargetResponsibilityName(indirectCost.getTargetResponsibilityName())
  713. .setShareLevelId(indirectCost.getShareLevelId());
  714. return allocationQuery;
  715. }
  716. /**
  717. * 执行分摊后续处理脚本
  718. * @param startDTO
  719. */
  720. public void execAllocationSQL(StartDTO startDTO){
  721. //执行分摊后续处理脚本
  722. Map<String,String> sqlParameter = new HashMap<>();
  723. if(startDTO.getMonth()<10){
  724. sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-0"+startDTO.getMonth());
  725. }else{
  726. sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE,startDTO.getYear()+"-"+startDTO.getMonth());
  727. }
  728. sqlService.autoExecuteSql(CustomSqlTypeEnum.COST_ALLOCATION_CALC.getCode(),sqlParameter);
  729. }
  730. /**
  731. * 按责任中心分摊
  732. * @param startDTO
  733. * @param hospId
  734. */
  735. @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
  736. public void startCostAllocation(StartDTO startDTO, Long hospId){
  737. long timeMillis = System.currentTimeMillis();
  738. // 得到这个月的所有导入的成本数据
  739. List<CostCostingGroup> costingGroups = costCostingGroupService.getByYearAndDate(startDTO.getYear(), startDTO.getMonth(), hospId);
  740. // 没有重新导入
  741. if (costingGroups.isEmpty()) {
  742. throw new CostException("本月分摊数据未导入");
  743. }
  744. // 导入数据按责任中心归类
  745. Map<String, List<CostCostingGroup>> responsibilityCodeMap = costingGroups.stream().collect(Collectors.groupingBy(CostCostingGroup::getResponsibilityCode));
  746. // 得到这个月导入的成本分摊参数值列表
  747. List<ShareParamValue> shareParamValues = shareParamValueService.getListByYearAndMonth(startDTO.getYear(), startDTO.getMonth(), hospId);
  748. if (shareParamValues.isEmpty()) {
  749. throw new CostException("本月成本分摊参数值未导入");
  750. }
  751. Map<String, List<ShareParamValue>> paramValueRespCodeMap = shareParamValues.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
  752. // 删除该年月已经分摊过的数据
  753. removeData(startDTO, hospId);
  754. // 得到这个医院所有的分摊层级列表排序
  755. List<CostShareLevelVO> shareLevelVOs = shareLevelService.getAll(hospId);
  756. if (CollUtil.isEmpty(shareLevelVOs)) {
  757. throw new CostException("请先设置医院分摊层级");
  758. }
  759. //优化循环调用 责任中心 分摊层级对应
  760. //成本分摊字典
  761. List<CostShareParamVO> costShareParamList = shareParamService.getAll(hospId);
  762. if (CollUtil.isEmpty(costShareParamList)) {
  763. throw new CostException("请先设置分摊参数字典");
  764. }
  765. Map<String,String> ShareParamNameMap = costShareParamList.stream().collect(Collectors.toMap(CostShareParamVO::getShareParamCode, CostShareParamVO::getShareParamName, (a, b) -> b));
  766. //责任中心
  767. List<Responsibility> responsibilityList = responsibilityRepository.getList(hospId);
  768. if (CollUtil.isEmpty(responsibilityList)) {
  769. throw new CostException("请先设置责任中心");
  770. }
  771. //按shareId分组
  772. Map<Long, List<Responsibility>> responsibilityShareIdMap = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getShareId));
  773. Map<String,String> responsibilityNameMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getResponsibilityCode, Responsibility::getResponsibilityName, (a, b) -> b));
  774. Map<String,Long> responsibilityShareIdDictMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getResponsibilityCode, Responsibility::getShareId, (a, b) -> b));
  775. //分摊参数对应
  776. List<CostAccountShare> accountShareList = accountShareService.getAll();
  777. if (CollUtil.isEmpty(accountShareList)) {
  778. throw new CostException("请先设置责任中心分摊参数对应");
  779. }
  780. Map<String, List<CostAccountShare>> accountShareResponsibilityMap = accountShareList.stream().collect(Collectors.groupingBy(CostAccountShare::getResponsibilityCode));
  781. List<Allocation> allocations = new LinkedList<>();
  782. // key 责任中心代码, value 分摊过来的钱
  783. // Map<String, BigDecimal> costMap = new ConcurrentReaderHashMap();
  784. List<Allocation> costList = new ArrayList<>();
  785. for (CostShareLevelVO shareLevelVO : shareLevelVOs) {
  786. // 分摊层级id
  787. Long levelId = shareLevelVO.getId();
  788. // 目标分摊层级,可能不存在
  789. String targetLevel = shareLevelVO.getTargetLevel();
  790. if (StrUtil.isBlank(targetLevel)) {
  791. throw new CostException("未设置目标层级");
  792. }
  793. // 计算方式 0是合并计算 1是分开计算
  794. Integer calcType = shareLevelVO.getCalcType();
  795. // 得到该分摊层级下责任中心列表,如果不存在,下一个
  796. List<Responsibility> responsibilities = responsibilityShareIdMap.get(levelId);
  797. // List<Responsibility> responsibilities = responsibilityService.getLevelIdByCode(levelId, hospId);
  798. // if (responsibilities.isEmpty()) {
  799. // continue;
  800. // }
  801. if(CollectionUtils.isEmpty(responsibilities)){
  802. continue;
  803. }
  804. // 优化
  805. // 遍历责任中心得到对应的分摊参数对应
  806. for (Responsibility responsibility : responsibilities) {
  807. // String responsibilityCode = responsibility.getResponsibilityCode();
  808. // 得到分摊参数对应记录,不存在,下一个
  809. List<CostAccountShare> accountShares = accountShareResponsibilityMap.get(responsibility.getResponsibilityCode());
  810. // List<CostAccountShare> accountShares = accountShareService.getByResponsibility(responsibilityCode, hospId);
  811. if (CollectionUtils.isEmpty(accountShares)) {
  812. continue;
  813. }
  814. // 遍历分摊参数对应记录
  815. for (CostAccountShare accountShare : accountShares) {
  816. Long accountShareId = accountShare.getId();
  817. String paramList = accountShare.getParamList();
  818. // 如果分摊比例未设置直接报错
  819. if (StrUtil.isBlank(paramList)) {
  820. throw new CostException("责任中心:" + accountShare.getResponsibilityName() + ";会计科目为:" + accountShare.getAccountingNames() + ";未设置分摊参数比例");
  821. }
  822. List<AccountShareVO> accountShareVOs = JacksonUtil.str2ObjList(paramList, List.class, AccountShareVO.class);
  823. // List<CostCostingGroup> groups = responsibilityCodeMap.get(responsibilityCode);
  824. // if (CollUtil.isEmpty(groups)) {
  825. // continue;
  826. // }
  827. // 计算本次分摊的钱
  828. BigDecimal totalAmount = this.getCostAmount(accountShare, calcType, responsibilityCodeMap, costList);
  829. if (totalAmount.equals(BigDecimal.ZERO)) {
  830. continue;
  831. }
  832. // 相关的分摊参数比例
  833. if (!CollectionUtils.isEmpty(accountShareVOs)) {
  834. for (AccountShareVO accountShareVO : accountShareVOs) {
  835. // String paramCode = accountShareVO.getShareParamCode();
  836. String shareParamPopout = accountShareVO.getShareParamPopout();
  837. BigDecimal bigDecimal = new BigDecimal(shareParamPopout);
  838. BigDecimal rate = bigDecimal.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
  839. // BigDecimal rate = new BigDecimal("1");
  840. // if (!"100".equals(shareParamPopout)) {
  841. // rate = new BigDecimal("0." + shareParamPopout);
  842. // }
  843. // 本次的分摊比例计算
  844. BigDecimal thisAmount = rate.multiply(totalAmount);
  845. // 得到目标层级责任中心列表
  846. List<Responsibility> targetResponsibilities = this.getTargetResponsibility(targetLevel, hospId, shareLevelVO.getLeverSort());
  847. if (targetResponsibilities.isEmpty()) {
  848. throw new CostException("找不到目标责任中心");
  849. }
  850. // 目标责任中心得到对应
  851. List<ShareParamValue> targetShareParamValue = getTarget(targetResponsibilities, accountShareVO, paramValueRespCodeMap);
  852. if (CollUtil.isEmpty(targetShareParamValue)) {
  853. throw new CostException("找不到目标责任中心对应的分摊参数【"+accountShareVO.getShareParamCode()+"】值");
  854. }
  855. // 分母
  856. BigDecimal reduce = targetShareParamValue.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
  857. for (ShareParamValue paramValue : targetShareParamValue) {
  858. // 分子
  859. BigDecimal numerator = paramValue.getValueNum();
  860. BigDecimal targetAmount = reduce.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : thisAmount.multiply(numerator).divide(reduce, RoundingMode.HALF_UP);
  861. BigDecimal percent = reduce.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : numerator.divide(reduce, RoundingMode.HALF_UP);
  862. Allocation targetAllocation = new Allocation();
  863. String valueResponsibilityCode = paramValue.getResponsibilityCode();
  864. //优化循环调用
  865. String targetRespName = responsibilityNameMap.get(valueResponsibilityCode);
  866. // String targetRespName = responsibilityService.getByCode(valueResponsibilityCode, hospId);
  867. Long targetShareLevelId = responsibilityShareIdDictMap.get(valueResponsibilityCode);
  868. // Long targetShareLevelId = responsibilityService.getLevelIdByCode(valueResponsibilityCode, hospId);
  869. if (Objects.isNull(targetShareLevelId)) {
  870. throw new CostException("目标责任中心分摊层级异常");
  871. }
  872. String shareParamName = ShareParamNameMap.get(paramValue.getShareParamCode());
  873. // String shareParamName = shareParamService.getByCode(paramValue.getShareParamCode(), hospId);
  874. targetAllocation.setDateMonth(startDTO.getMonth()).setDateYear(startDTO.getYear()).setLevelSort(shareLevelVO.getLeverSort())
  875. .setLevelName(shareLevelVO.getShareName()).setHospId(hospId).setResponsibilityCode(responsibility.getResponsibilityCode())
  876. .setResponsibilityName(responsibility.getResponsibilityName()).setAccountShareId(accountShareId).setAmount(targetAmount)
  877. .setCreateTime(timeMillis).setTargetResponsibilityCode(valueResponsibilityCode).setTargetResponsibilityName(targetRespName)
  878. .setShareParamCode(paramValue.getShareParamCode()).setShareParamName(shareParamName).setTotalAmount(totalAmount).setShareParamValueNum(paramValue.getValueNum())
  879. .setShareParamRate(percent).setShareLevelId(levelId).setTargetShareLevelId(targetShareLevelId);
  880. // todo 目标分摊层级责任中心 就是当前列个表中的责任中心
  881. allocations.add(targetAllocation);
  882. costList.add(targetAllocation);
  883. }
  884. }
  885. }
  886. }
  887. }
  888. }
  889. this.saveBatch(allocations);
  890. List<Allocation> list = this.list(
  891. new LambdaQueryWrapper<Allocation>()
  892. .eq(Allocation::getHospId, hospId).eq(Allocation::getDateYear, startDTO.getYear()).eq(Allocation::getDateMonth, startDTO.getMonth())
  893. );
  894. if (list.isEmpty()) {
  895. log.error("未分摊到数据......");
  896. return;
  897. }
  898. // 入cost_allocation_query 表 便于后续操作
  899. this.saveAllocationQuery(list, hospId, startDTO.getYear(), startDTO.getMonth(),shareLevelVOs,accountShareList);
  900. }
  901. private void removeData(StartDTO startDTO, Long hospId) {
  902. this.remove(
  903. new LambdaQueryWrapper<Allocation>()
  904. .eq(Allocation::getDateYear, startDTO.getYear())
  905. .eq(Allocation::getDateMonth, startDTO.getMonth())
  906. .eq(Allocation::getHospId, hospId)
  907. );
  908. allocationQueryService.remove(
  909. new LambdaQueryWrapper<AllocationQuery>()
  910. .eq(AllocationQuery::getDateYear, startDTO.getYear())
  911. .eq(AllocationQuery::getDateMonth, startDTO.getMonth())
  912. .eq(AllocationQuery::getHospId, hospId)
  913. );
  914. }
  915. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
  916. public void saveAllocationQuery(List<Allocation> list, Long hospId,
  917. Integer year, Integer month, List<CostShareLevelVO> shareLevelVOs, List<CostAccountShare> accountShareList) {
  918. List<AllocationQuery> saveList = new ArrayList<>();
  919. List<Long> maxId = shareLevelService.getMaxId(hospId);
  920. // List<Allocation> maxList = list.stream().filter(i -> maxId.contains(i.getTargetShareLevelId())).collect(Collectors.toList());
  921. Map<Long, List<Allocation>> collect = list.stream().collect(Collectors.groupingBy(Allocation::getTargetShareLevelId));
  922. //优化 去除循环调用
  923. // List<CostAccountShare> all = accountShareService.getAll();
  924. Map<Long,CostAccountShare> accountShareMap = accountShareList.stream().collect(Collectors.toMap(CostAccountShare::getId, costAccountShare -> costAccountShare, (a, b) -> b));
  925. // 得到这个月的所有导入的成本数据用责任中心关联取得shareId 优化 去除循环调用
  926. List<CostCostingGroup> costingGroups = costCostingGroupService.getRealData(CollUtil.newArrayList(), hospId, year, month);
  927. Map<Long, List<CostCostingGroup>> costShareIdGroup = costingGroups.stream().collect(Collectors.groupingBy(CostCostingGroup::getShareId));
  928. for (CostShareLevelVO shareLevelVO : shareLevelVOs) {
  929. List<Allocation> allocations = collect.get(shareLevelVO.getId());
  930. if(!CollectionUtils.isEmpty(allocations)){
  931. setAfterAllocation(allocations, hospId, saveList,accountShareMap);
  932. }
  933. if(!CollectionUtils.isEmpty(costShareIdGroup.get(shareLevelVO.getId()))){
  934. setPreAllocation(hospId,saveList,shareLevelVO,costShareIdGroup.get(shareLevelVO.getId()));
  935. }
  936. }
  937. allocationQueryService.saveBatch(saveList);
  938. }
  939. private void setPreAllocation(Long hospId, List<AllocationQuery> saveList,
  940. CostShareLevelVO shareLevelVO, List<CostCostingGroup> costingGroups) {
  941. // List<CostCostingGroup> costingGroups = costCostingGroupService.getRealData(CollUtil.newArrayList(maxId), hospId, year, month);
  942. costingGroups.forEach(i -> {
  943. AllocationQuery allocationQuery = new AllocationQuery();
  944. allocationQuery.setDateYear(i.getDateYear()).setDateMonth(i.getDateMonth())
  945. .setHospId(hospId).setResponsibilityCode(i.getResponsibilityCode()).setResponsibilityName(i.getResponsibilityName())
  946. .setOriginId(i.getId()).setOriginType(1L).setAmount(i.getAmount())
  947. .setAccountingCode(i.getAccountCode()).setAccountingName(i.getAccountName())
  948. .setCreateTime(System.currentTimeMillis())
  949. .setLevelSort(shareLevelVO.getLeverSort()).setLevelName(shareLevelVO.getShareName())
  950. .setTargetResponsibilityCode(i.getResponsibilityCode())
  951. .setTargetResponsibilityName(i.getResponsibilityName())
  952. .setShareLevelId(0L);
  953. saveList.add(allocationQuery);
  954. });
  955. }
  956. private void setAfterAllocation(List<Allocation> list, Long hospId, List<AllocationQuery> saveList, Map<Long,
  957. CostAccountShare> accountShareMap) {
  958. list.forEach(i -> {
  959. Long accountShareId = i.getAccountShareId();
  960. CostAccountShare byId = accountShareMap.get(accountShareId);
  961. if (Objects.isNull(byId)) {
  962. return;
  963. }
  964. String accountingCodes = byId.getAccountingCodes();
  965. if (StrUtil.isBlank(accountingCodes)) {
  966. return;
  967. }
  968. String accountingNames = byId.getAccountingNames();
  969. String alias = byId.getAlias();
  970. if (StrUtil.isNotBlank(alias)) {
  971. accountingNames = alias;
  972. }
  973. AllocationQuery allocationQuery = new AllocationQuery();
  974. allocationQuery.setDateYear(i.getDateYear()).setDateMonth(i.getDateMonth())
  975. .setHospId(hospId).setResponsibilityCode(i.getResponsibilityCode())
  976. .setResponsibilityName(i.getResponsibilityName())
  977. .setOriginId(i.getId()).setOriginType(2L).setAmount(i.getAmount())
  978. .setAccountingCode(accountingCodes).setAccountingName(accountingNames)
  979. .setCreateTime(System.currentTimeMillis())
  980. .setLevelSort(i.getLevelSort()).setLevelName(i.getLevelName())
  981. .setTargetResponsibilityCode(i.getTargetResponsibilityCode())
  982. .setTargetResponsibilityName(i.getTargetResponsibilityName())
  983. .setShareLevelId(i.getShareLevelId());
  984. saveList.add(allocationQuery);
  985. });
  986. }
  987. /**
  988. * 得到目标月成本分摊参数值数据
  989. *
  990. * @param targetResponsibilities
  991. * @param map
  992. * @return
  993. */
  994. private List<ShareParamValue> getTarget(List<Responsibility> targetResponsibilities, AccountShareVO accountShareVO, Map<String, List<ShareParamValue>> map) {
  995. // 目标的责任中心
  996. List<ShareParamValue> shareParamValues = map.entrySet().stream().map(Map.Entry::getValue).flatMap(Collection::stream).collect(Collectors.toList());
  997. List<String> originRespCodes = targetResponsibilities.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList());
  998. return shareParamValues.stream().filter(j -> originRespCodes.contains(j.getResponsibilityCode()))
  999. .filter(i -> i.getShareParamCode().equals(accountShareVO.getShareParamCode())).collect(Collectors.toList());
  1000. }
  1001. /**
  1002. * 计算本次的成本金额
  1003. *
  1004. * @return
  1005. */
  1006. private BigDecimal getCostAmount(CostAccountShare accountShare, Integer calcType, Map<String, List<CostCostingGroup>> map, List<Allocation> costList) {
  1007. // 是否包含分摊成本 0不包含 1 包含
  1008. Integer isShareCost = accountShare.getIsShareCost();
  1009. String accountingCodes = accountShare.getAccountingCodes();
  1010. String responsibilityCode = accountShare.getResponsibilityCode();
  1011. List<CostCostingGroup> costingGroups = map.get(responsibilityCode);
  1012. if (CollUtil.isEmpty(costingGroups)) {
  1013. List<Allocation> all = costList.stream().filter(i -> i.getTargetResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  1014. if (CollUtil.isEmpty(all) || isShareCost == 0) {
  1015. return BigDecimal.ZERO;
  1016. }
  1017. BigDecimal reduce = all.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1018. return reduce;
  1019. } else {
  1020. BigDecimal costAmount = BigDecimal.ZERO;
  1021. List<Allocation> all = new ArrayList<>();
  1022. if (!costList.isEmpty()) {
  1023. all = costList.stream().filter(i -> i.getTargetResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  1024. }
  1025. // 计算方式 0是合并计算 1是分开计算
  1026. if (calcType == 0) {
  1027. costAmount = costingGroups.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1028. if (!all.isEmpty()) {
  1029. BigDecimal bigDecimal = all.stream()
  1030. .map(Allocation::getAmount)
  1031. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1032. if (Objects.nonNull(bigDecimal)) {
  1033. costAmount = costAmount.add(bigDecimal);
  1034. }
  1035. }
  1036. } else {
  1037. if (StrUtil.isBlank(accountingCodes)) {
  1038. return BigDecimal.ZERO;
  1039. }
  1040. ArrayList<String> accountCodes = CollUtil.newArrayList(accountingCodes.split(StrUtil.COMMA));
  1041. List<CostCostingGroup> costGroups = costingGroups.stream().filter(i -> accountCodes.contains(i.getAccountCode())).collect(Collectors.toList());
  1042. costAmount = costGroups.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1043. if (isShareCost == 1) {
  1044. if (!all.isEmpty()) {
  1045. BigDecimal bigDecimal = all.stream()
  1046. .map(Allocation::getAmount)
  1047. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1048. if (Objects.nonNull(bigDecimal)) {
  1049. costAmount = costAmount.add(bigDecimal);
  1050. }
  1051. }
  1052. }
  1053. }
  1054. return costAmount;
  1055. }
  1056. }
  1057. /**
  1058. * 通过目标层级获取目标责任中心
  1059. *
  1060. * @param targetLevel 目标层级 2,3,4
  1061. * @param leverSort
  1062. * @return List
  1063. */
  1064. private List<Responsibility> getTargetResponsibility(String targetLevel, Long hospId, Integer leverSort) {
  1065. ArrayList<String> targetLevelList = CollUtil.newArrayList(StrUtil.split(targetLevel, StrUtil.COMMA));
  1066. if (targetLevelList.size() == 1) {
  1067. if (leverSort.equals(Integer.parseInt(targetLevelList.get(0)))) {
  1068. return new ArrayList<>();
  1069. }
  1070. }
  1071. List<CostShareLevel> shareLevels = shareLevelService.getListByLevelSort(targetLevelList, hospId);
  1072. if (shareLevels.isEmpty()) {
  1073. throw new CostException("请重新设置分摊层级");
  1074. }
  1075. List<Long> shareLevelIds = shareLevels.stream().map(CostShareLevel::getId).collect(Collectors.toList());
  1076. return responsibilityService.getByLevelIds(shareLevelIds, hospId);
  1077. }
  1078. /**
  1079. * 分摊后查询列表
  1080. *
  1081. * @param year 年月 (yyyy-MM-dd)
  1082. * @param responsibilityCode 责任中心代码
  1083. * @param current 当前页
  1084. * @param pageSize 当前页展示的数据大小
  1085. * @param hospId 医院id
  1086. * @return PageUtils
  1087. */
  1088. @Override
  1089. public PageUtils queryAfterAllocation(String year, String responsibilityCode, Integer current, Integer pageSize, Long hospId) {
  1090. Integer dateYear = null;
  1091. Integer dateMonth = null;
  1092. if (StrUtil.isNotBlank(year)) {
  1093. DateTime dateTime = DateUtil.parseDate(year);
  1094. dateYear = DateUtil.year(dateTime);
  1095. dateMonth = DateUtil.month(dateTime) + 1;
  1096. }
  1097. Integer startIndex = (current - 1) * pageSize;
  1098. List<AfterAllocationVO> list = baseMapper.queryAfterAllocationList(dateYear, dateMonth, responsibilityCode, startIndex, pageSize, hospId);
  1099. int totalCount = baseMapper.queryAfterAllocationListCount(dateYear, dateMonth, responsibilityCode, hospId);
  1100. BigDecimal sum = baseMapper.queryAfterAllocationListSum(dateYear, dateMonth, responsibilityCode, hospId);
  1101. return new PageUtils(list, totalCount, pageSize, current, sum);
  1102. }
  1103. /**
  1104. * 分摊报表导出
  1105. *
  1106. * @param writer {@link ExcelWriter}
  1107. * @param levelSort 分摊层级 就是第几次分摊
  1108. * @param sheet 报表
  1109. * @param year 年
  1110. * @param month 月
  1111. * @param shareLevelId
  1112. * @return
  1113. */
  1114. @Override
  1115. public ExcelWriter getShareReportTemplate(ExcelWriter writer, Integer levelSort, Sheet sheet, Integer year, Integer month, Long shareLevelId) {
  1116. // 获取数据
  1117. Map<String,List<String>> targetTotalMoneys = new HashMap<>();
  1118. List<AllocationReportVO> allocationReportVOList = getAllocationReportVOS(levelSort, year, month, shareLevelId,targetTotalMoneys);
  1119. // 设置导出
  1120. Map<String, List<AllocationReportVO>> responsibilityMap = allocationReportVOList.stream().collect(Collectors.groupingBy(AllocationReportVO::getResponsibilityCode));
  1121. Map<String, List<AllocationReportVO>> targetResponsibilityMap = allocationReportVOList.stream().collect(Collectors.groupingBy(AllocationReportVO::getTargetResponsibilityCode));
  1122. // 以会计科目查
  1123. Map<String, AllocationReportVO> allAccMap = allocationReportVOList.stream().collect(Collectors.toMap(k -> k.getResponsibilityName() + k.getAccountName() + k.getTargetResponsibilityName() + k.getShareParamName(), synOne -> synOne));
  1124. // 用别名查 过滤别名不为空的
  1125. Map<String, AllocationReportVO> allAliMap = allocationReportVOList.stream().filter(i -> StrUtil.isNotBlank(i.getAlias())).collect(Collectors.toMap(k -> k.getResponsibilityName() + k.getAlias() + k.getTargetResponsibilityName() + k.getShareParamName(), synOne -> synOne));
  1126. // Map<String, AllocationReportVO> allAliMap = allocationReportVOList.stream().collect(Collectors.toMap(k -> k.getResponsibilityName() + k.getAlias() + k.getTargetResponsibilityName() + k.getShareParamName(), synOne -> synOne));
  1127. // 当前责任中心下面有几个会计科目 后面进行合并使用
  1128. final int[] numResponsibility = new int[1];
  1129. levelSort=levelSort+1;
  1130. // // 从第几列开始编写数据
  1131. final int[] column = {levelSort + 3};
  1132. responsibilityMap.forEach((key,value)->{
  1133. Map<String, AllocationReportVO> linkedHashMap = new LinkedHashMap<>();
  1134. value.forEach(i -> {
  1135. String s = i.getResponsibilityCode() + i.getAccountCode();
  1136. if (!linkedHashMap.containsKey(s)) {
  1137. linkedHashMap.put(s, i);
  1138. }
  1139. });
  1140. numResponsibility[0] = linkedHashMap.size();
  1141. if (numResponsibility[0] >= NumberConstant.TWO) {
  1142. Set<String> strings = linkedHashMap.keySet();
  1143. for (String s : strings) {
  1144. AllocationReportVO allocationReportVO = linkedHashMap.get(s);
  1145. if (StrUtil.isBlank(allocationReportVO.getAlias())) {
  1146. writer.writeCellValue(column[0], 0, allocationReportVO.getResponsibilityName());
  1147. // 别名不存在
  1148. writer.writeCellValue(column[0], 1, allocationReportVO.getAccountName());
  1149. } else {
  1150. // 不为空 设置别名
  1151. writer.writeCellValue(column[0], 0, allocationReportVO.getResponsibilityName());
  1152. writer.writeCellValue(column[0], 1, allocationReportVO.getAlias());
  1153. }
  1154. writer.writeCellValue(column[0], 2, allocationReportVO.getTotalAmounts());
  1155. column[0]++;
  1156. }
  1157. } else {
  1158. // 不需要合并单元格
  1159. writer.writeCellValue(column[0], 0, value.get(0).getResponsibilityName());
  1160. if (StrUtil.isNotBlank(value.get(0).getAlias())) {
  1161. writer.writeCellValue(column[0], 1, value.get(0).getAlias());
  1162. } else {
  1163. writer.writeCellValue(column[0], 1, value.get(0).getAccountName());
  1164. }
  1165. writer.writeCellValue(column[0], 2, value.get(0).getTotalAmounts());
  1166. column[0]++;
  1167. }
  1168. });
  1169. // for (String key : keySet) {
  1170. // List<AllocationReportVO> allocationReportVOS = responsibilityMap.get(key);
  1171. // Map<String, AllocationReportVO> linkedHashMap = new LinkedHashMap<>();
  1172. // allocationReportVOS.forEach(i -> {
  1173. // String s = i.getResponsibilityCode() + i.getAccountCode();
  1174. // if (!linkedHashMap.containsKey(s)) {
  1175. // linkedHashMap.put(s, i);
  1176. // }
  1177. // });
  1178. // numResponsibility[0] = linkedHashMap.size();
  1179. // if (numResponsibility[0] >= NumberConstant.TWO) {
  1180. // Set<String> strings = linkedHashMap.keySet();
  1181. // for (String s : strings) {
  1182. // AllocationReportVO allocationReportVO = linkedHashMap.get(s);
  1183. // if (StrUtil.isBlank(allocationReportVO.getAlias())) {
  1184. // writer.writeCellValue(column[0], 0, allocationReportVO.getResponsibilityName());
  1185. // // 别名不存在
  1186. // writer.writeCellValue(column[0], 1, allocationReportVO.getAccountName());
  1187. // } else {
  1188. // // 不为空 设置别名
  1189. // writer.writeCellValue(column[0], 0, allocationReportVO.getResponsibilityName());
  1190. // writer.writeCellValue(column[0], 1, allocationReportVO.getAlias());
  1191. // }
  1192. // writer.writeCellValue(column[0], 2, allocationReportVO.getTotalAmounts());
  1193. // column[0]++;
  1194. // }
  1195. // } else {
  1196. // // 不需要合并单元格
  1197. // writer.writeCellValue(column[0], 0, allocationReportVOS.get(0).getResponsibilityName());
  1198. // if (StrUtil.isNotBlank(allocationReportVOS.get(0).getAlias())) {
  1199. // writer.writeCellValue(column[0], 1, allocationReportVOS.get(0).getAlias());
  1200. // } else {
  1201. // writer.writeCellValue(column[0], 1, allocationReportVOS.get(0).getAccountName());
  1202. // }
  1203. // writer.writeCellValue(column[0], 2, allocationReportVOS.get(0).getTotalAmounts());
  1204. // column[0]++;
  1205. // }
  1206. // }
  1207. // 设置单元格合并
  1208. for (int j = 1; j < levelSort; j++) {
  1209. writer.merge(0, 1, j, j, "第" + j + "次分摊", false);
  1210. }
  1211. // 目标责任集合
  1212. writer.passCurrentRow();
  1213. // 从第三行开始
  1214. int num = 3;
  1215. Set<String> targetSet = targetResponsibilityMap.keySet();
  1216. int t = 0;
  1217. for (String target : targetSet) {
  1218. List<AllocationReportVO> allocationReportVOS = targetResponsibilityMap.get(target);
  1219. Map<String, AllocationReportVO> linkedHashMap = new LinkedHashMap<>();
  1220. allocationReportVOS.forEach(i -> {
  1221. String s = i.getTargetResponsibilityCode() + i.getShareParamName();
  1222. if (!linkedHashMap.containsKey(s)) {
  1223. linkedHashMap.put(s, i);
  1224. }
  1225. });
  1226. int shareParamSize = linkedHashMap.size();
  1227. if (shareParamSize >= NumberConstant.TWO) {
  1228. // 责任中心
  1229. AllocationReportVO costCostingVO = allocationReportVOS.get(0);
  1230. // 设置第几次分摊的值
  1231. List<String> targetShareMoneyList = targetTotalMoneys.get(target);
  1232. // for (int k = 0; k < levelSort - 1; k++) {
  1233. // writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, costCostingVO.getTargetShareMoneys().get(t++), false);
  1234. //
  1235. // }
  1236. for (int k = 0; k < levelSort - 1; k++) {
  1237. Object allocationAmount = getAllocationAmount(levelSort, k, allocationReportVOS, targetShareMoneyList);
  1238. writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, allocationAmount, false);
  1239. }
  1240. // if(!CollectionUtils.isEmpty(targetShareMoneyList)){
  1241. // for (int k = 0; k < levelSort - 1; k++) {
  1242. // if(k==levelSort-2){
  1243. // BigDecimal totalAmount = allocationReportVOS.stream().map(AllocationReportVO::getAmount)
  1244. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  1245. // writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, totalAmount, false);
  1246. // }else {
  1247. // writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, targetShareMoneyList.get(k), false);
  1248. // }
  1249. // }
  1250. // }else {
  1251. // for (int k = 0; k < levelSort - 1; k++) {
  1252. // if(k==levelSort-2){
  1253. // BigDecimal totalAmount = allocationReportVOS.stream().map(AllocationReportVO::getAmount)
  1254. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  1255. // writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, totalAmount, false);
  1256. // }else {
  1257. // writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, "0.0000", false);
  1258. // }
  1259. // }
  1260. // }
  1261. // 设置对应的分摊参数值
  1262. Set<String> strings = linkedHashMap.keySet();
  1263. for (String s : strings) {
  1264. AllocationReportVO allocationReportVO = linkedHashMap.get(s);
  1265. writer.writeCellValue(0, num, allocationReportVO.getTargetResponsibilityName());
  1266. writer.writeCellValue(levelSort, num, allocationReportVO.getShareParamName());
  1267. writer.writeCellValue(levelSort + 1, num, allocationReportVO.getShareParamValueNums());
  1268. writer.writeCellValue(levelSort + 2, num, allocationReportVO.getShareParamRates());
  1269. for (int m = levelSort + 3; m < column[0]; m++) {
  1270. // x是m y是num
  1271. // 获取当前这一列对应的责任中心 以及会计科目
  1272. // 第一行责任中心
  1273. String responsibilityName = sheet.getRow(0).getCell(m).getStringCellValue();
  1274. // 第二行的会计科目或者
  1275. String accountNameOrAlias = sheet.getRow(1).getCell(m).getStringCellValue();
  1276. // 这一行的目标责任中心
  1277. String otherResponsibilityName = sheet.getRow(num).getCell(0).getStringCellValue();
  1278. // 分摊参数
  1279. String shareName = sheet.getRow(num).getCell(levelSort).getStringCellValue();
  1280. String sss = responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName;
  1281. AllocationReportVO vo = allAliMap.get(sss);
  1282. AllocationReportVO allocationReportVO2 = allAccMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  1283. AllocationReportVO allocationReportVO3 = allAliMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  1284. if (Objects.nonNull(allocationReportVO2)) {
  1285. writer.writeCellValue(m, num, allocationReportVO2.getAmounts());
  1286. } else if (Objects.nonNull(allocationReportVO3)) {
  1287. writer.writeCellValue(m, num, allocationReportVO3.getAmounts());
  1288. } else {
  1289. writer.writeCellValue(m, num, 0);
  1290. }
  1291. }
  1292. num++;
  1293. }
  1294. }
  1295. if (shareParamSize < NumberConstant.TWO) {
  1296. writer.writeCellValue(0, num, allocationReportVOS.get(0).getTargetResponsibilityName());
  1297. // for (int k = 0; k < levelSort - 1; k++) {
  1298. // writer.writeCellValue(k + 1, num, allocationReportVOS.get(0).getTargetShareMoneys().get(k));
  1299. // }
  1300. List<String> targetShareMoneyList = targetTotalMoneys.get(target);
  1301. for (int k = 0; k < levelSort - 1; k++) {
  1302. Object allocationAmount = getAllocationAmount(levelSort, k, allocationReportVOS, targetShareMoneyList);
  1303. writer.writeCellValue(k + 1, num, allocationAmount);
  1304. }
  1305. // if(!CollectionUtils.isEmpty(targetShareMoneyList)){
  1306. // for (int k = 0; k < levelSort - 1; k++) {
  1307. // if(k==levelSort-2){
  1308. // BigDecimal totalAmount = allocationReportVOS.stream().map(AllocationReportVO::getAmount)
  1309. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  1310. // writer.writeCellValue(k + 1, num, totalAmount);
  1311. // }else {
  1312. // writer.writeCellValue(k + 1, num, targetShareMoneyList.get(k));
  1313. // }
  1314. // }
  1315. // }else {
  1316. // for (int k = 0; k < levelSort - 1; k++) {
  1317. // if(k==levelSort-2){
  1318. // BigDecimal totalAmount = allocationReportVOS.stream().map(AllocationReportVO::getAmount)
  1319. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  1320. // writer.writeCellValue(k + 1, num, totalAmount);
  1321. // }else {
  1322. // writer.writeCellValue(k + 1, num, "0.0000");
  1323. // }
  1324. // }
  1325. // }
  1326. writer.writeCellValue(levelSort, num, allocationReportVOS.get(0).getShareParamName());
  1327. writer.writeCellValue(levelSort + 1, num, allocationReportVOS.get(0).getShareParamValueNums());
  1328. writer.writeCellValue(levelSort + 2, num, allocationReportVOS.get(0).getShareParamRates());
  1329. for (int m = levelSort + 3; m < column[0]; m++) {
  1330. // x是m y是num
  1331. // 获取当前这一列对应的责任中心 以及会计科目
  1332. // 第一行责任中心
  1333. String responsibilityName = sheet.getRow(0).getCell(m).getStringCellValue();
  1334. // 第二行的会计科目或者
  1335. String accountNameOrAlias = sheet.getRow(1).getCell(m).getStringCellValue();
  1336. // 这一行的目标责任中心
  1337. String otherResponsibilityName = sheet.getRow(num).getCell(0).getStringCellValue();
  1338. // 分摊参数
  1339. String shareName = sheet.getRow(num).getCell(levelSort).getStringCellValue();
  1340. AllocationReportVO allocationReportVO2 = allAccMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  1341. AllocationReportVO allocationReportVO3 = allAliMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  1342. if (Objects.nonNull(allocationReportVO2)) {
  1343. writer.writeCellValue(m, num, allocationReportVO2.getAmounts());
  1344. } else if (Objects.nonNull(allocationReportVO3)) {
  1345. writer.writeCellValue(m, num, allocationReportVO3.getAmounts());
  1346. } else {
  1347. writer.writeCellValue(m, num, 0);
  1348. }
  1349. }
  1350. num++;
  1351. }
  1352. }
  1353. Map<String, Integer> rowMap = new HashMap<>();
  1354. int cc = levelSort + 3;
  1355. // 合并行
  1356. boolean otherData = false;
  1357. for (int m = levelSort + 3; m < column[0] - 1; m++) {
  1358. // String cellValue = sheet.getRow(0).getCell(m).getStringCellValue();
  1359. // if (!rowMap.containsKey(cellValue)){
  1360. // rowMap.put(cellValue,m);
  1361. // Integer integer = rowMap.get(sheet.getRow(0).getCell(m).getStringCellValue());
  1362. // String value = sheet.getRow(0).getCell(m ).getStringCellValue();
  1363. // writer.merge(0, 0, rowMap.get(sheet.getRow(0).getCell(m-1).getStringCellValue()), m-1, sheet.getRow(0).getCell(m-1).getStringCellValue(), false);
  1364. // }
  1365. String cellValue1 = sheet.getRow(0).getCell(m).getStringCellValue();
  1366. String cellValue2 = sheet.getRow(0).getCell(m + 1).getStringCellValue();
  1367. if (!cellValue1.equals(cellValue2)) {
  1368. if (cc != m) {
  1369. writer.merge(0, 0, cc, m, cellValue1, false);
  1370. } else {
  1371. writer.writeCellValue(cc, 0, cellValue1);
  1372. }
  1373. cc = m + 1;
  1374. } else if (m == column[0] - 2) {
  1375. writer.merge(0, 0, cc, m + 1, sheet.getRow(0).getCell(m + 1).getStringCellValue(), false);
  1376. }
  1377. }
  1378. // 合并列
  1379. int jj = 3;
  1380. for (int i = 3; i < num - 1; i++) {
  1381. String cellValue1 = sheet.getRow(i).getCell(0).getStringCellValue();
  1382. String cellValue2 = sheet.getRow(i + 1).getCell(0).getStringCellValue();
  1383. if (!cellValue1.equals(cellValue2)) {
  1384. if (jj != i) {
  1385. writer.merge(jj, i, 0, 0, cellValue1, false);
  1386. } else {
  1387. writer.writeCellValue(0, jj, cellValue1);
  1388. }
  1389. jj = i + 1;
  1390. } else if (i == num - 2) {
  1391. writer.merge(jj, i + 1, 0, 0, cellValue1, false);
  1392. }
  1393. }
  1394. for (int i = 0; i < 30; i++) {
  1395. // 调整每一列宽度
  1396. sheet.autoSizeColumn((short) i);
  1397. // 解决自动设置列宽中文失效的问题
  1398. sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 14 / 10);
  1399. }
  1400. return writer;
  1401. }
  1402. /**
  1403. * 获取责任中心对应层级的分摊金额
  1404. * @param levelSort
  1405. * @param index
  1406. * @param allocationReportVOS
  1407. * @param targetShareMoneyList
  1408. * @return
  1409. */
  1410. public Object getAllocationAmount(int levelSort,int index,List<AllocationReportVO> allocationReportVOS,List<String> targetShareMoneyList){
  1411. //当前层级取分摊金额加总
  1412. if(index==levelSort-2){
  1413. BigDecimal totalAmount = allocationReportVOS.stream().map(AllocationReportVO::getAmount)
  1414. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1415. return totalAmount;
  1416. }
  1417. //取不到对应层级的分摊总金额
  1418. if(CollectionUtils.isEmpty(targetShareMoneyList)||targetShareMoneyList.size()<=index){
  1419. return BigDecimal.valueOf(NumberConstant.ZERO,NumberConstant.FOUR);
  1420. }
  1421. //取对应层级的分摊总金额
  1422. return targetShareMoneyList.get(index);
  1423. }
  1424. /**
  1425. * 查询数据
  1426. *
  1427. * @param levelSort
  1428. * @param year
  1429. * @param month
  1430. * @param targetTotalMoneys
  1431. * @return
  1432. */
  1433. private List<AllocationReportVO> getAllocationReportVOS(Integer levelSort, Integer year, Integer month, Long shareLevelId,
  1434. Map<String, List<String>> targetTotalMoneys) {
  1435. Long hospId = UserContext.getCurrentLoginHospId();
  1436. if (Objects.isNull(levelSort) || Objects.isNull(year) || Objects.isNull(month)) {
  1437. throw new CostException(500, "参数异常");
  1438. }
  1439. // 处理第几次分摊计算值
  1440. // List<Allocation> allocationList = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
  1441. // .eq(Allocation::getHospId, hospId).eq(Allocation::getLevelSort, levelSort).eq(Allocation::getShareLevelId, shareLevelId).eq(Allocation::getDateYear, year)
  1442. // .eq(Allocation::getDateMonth, month));
  1443. List<Allocation> allocationList =baseMapper.getLevelSortAllocation(hospId,year,month,shareLevelId);
  1444. // 找会计科室的时候使用的
  1445. List<Allocation> allocations = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
  1446. .eq(Allocation::getHospId, hospId).eq(Allocation::getDateYear, year)
  1447. .eq(Allocation::getDateMonth, month));
  1448. Map<String, List<Allocation>> accrepMap = allocations.stream().collect(Collectors.groupingBy(k -> k.getLevelSort() + "cost" + k.getTargetResponsibilityCode()));
  1449. LinkedList<String> shareMoney = new LinkedList<>();
  1450. List<CostAccountShare> costAccountShareList = accountShareService.list(new QueryWrapper<CostAccountShare>().lambda()
  1451. .eq(CostAccountShare::getHospId, hospId));
  1452. Map<Long, CostAccountShare> accountShareMap = costAccountShareList.stream().collect(Collectors.toMap(CostAccountShare::getId, synOne -> synOne));
  1453. List<AllocationReportVO> allocationReportVOList = BeanUtil.convertList(allocationList, AllocationReportVO.class);
  1454. List<CostShareParamVO> shareParamVOList = shareParamService.getAll(hospId);
  1455. Map<String,Integer> shareParamStatusMap = shareParamVOList.stream().collect(Collectors.toMap(CostShareParamVO::getShareParamCode, paramVO -> paramVO.getStatus() == null ? NumberConstant.ONE : paramVO.getStatus(), (a, b) -> b));
  1456. List<AllocationReportVO> removeList = new ArrayList<>();
  1457. // 设置会计科目的
  1458. allocationReportVOList.forEach(i -> {
  1459. Long accountShareId = i.getAccountShareId();
  1460. CostAccountShare costAccountShare = accountShareMap.get(accountShareId);
  1461. if (Objects.isNull(costAccountShare)) {
  1462. throw new CostException(500, "成本参数参数设置对应不存在");
  1463. }
  1464. i.setAccountCode(costAccountShare.getAccountingCodes());
  1465. i.setAccountName(costAccountShare.getAccountingNames());
  1466. i.setAlias(costAccountShare.getAlias());
  1467. if (levelSort > 1) {
  1468. List<String> targetMoney = new ArrayList<>();
  1469. for (int j = 1; j < levelSort; j++) {
  1470. // 每一次计算要设置为0
  1471. AtomicReference<BigDecimal> money = new AtomicReference<>(new BigDecimal("0.0000"));
  1472. List<Allocation> allocations1 = accrepMap.get(j + "cost" + i.getTargetResponsibilityCode());
  1473. if (CollUtil.isNotEmpty(allocations1)) {
  1474. allocations1.forEach(m -> {
  1475. money.updateAndGet(v -> v.add(m.getAmount()));
  1476. // System.out.println(m.getAmount());
  1477. });
  1478. } else {
  1479. // TODO 封装测试数据
  1480. shareMoney.add("0");
  1481. }
  1482. // System.out.println("第"+j+"次"+money);
  1483. shareMoney.add(money.toString());
  1484. targetMoney.add(money.toString());
  1485. }
  1486. if(!CollectionUtils.isEmpty(targetTotalMoneys)){
  1487. List<String> strings = targetTotalMoneys.get(i.getTargetResponsibilityCode());
  1488. if(CollectionUtils.isEmpty(strings)){
  1489. targetTotalMoneys.put(i.getTargetResponsibilityCode(),targetMoney);
  1490. }
  1491. }else {
  1492. targetTotalMoneys.put(i.getTargetResponsibilityCode(),targetMoney);
  1493. }
  1494. }
  1495. i.setTargetShareMoneys(shareMoney);
  1496. // 设置字符串类型数据
  1497. i.setTotalAmounts(i.getTotalAmount().toString());
  1498. i.setShareParamValueNums(i.getShareParamValueNum().toString());
  1499. i.setShareParamRates(i.getShareParamRate().toString());
  1500. i.setAmounts(i.getAmount().toString());
  1501. //校验是否有分摊参数未启用
  1502. Integer status = shareParamStatusMap.get(i.getShareParamCode());
  1503. if(status != null&&status.equals(NumberConstant.ZERO)){
  1504. removeList.add(i);
  1505. }
  1506. });
  1507. //校验是否有分摊参数未启用 未启用分摊参数 移除
  1508. if(!CollectionUtils.isEmpty(removeList)){
  1509. allocationReportVOList.removeAll(removeList);
  1510. }
  1511. return allocationReportVOList;
  1512. }
  1513. /**
  1514. * 分摊后报表
  1515. *
  1516. * @param year 年月(yyyy-MM-dd)
  1517. * @param responsibilityCode 责任中心代码
  1518. * @param hospId 医院id
  1519. * @return List
  1520. */
  1521. @Override
  1522. public CollectDataFormVO queryAfterAllocationForm(String year, String responsibilityCode, Long hospId) {
  1523. DateTime dateTime = DateUtil.parseDate(year);
  1524. int dateYear = DateUtil.year(dateTime);
  1525. int month = DateUtil.month(dateTime) + 1;
  1526. List<CodeAndNameVO> responsibilityCodeAndNames = allocationQueryService.getRespCodeAndName(hospId, dateYear, month);
  1527. List<CodeAndNameVO> accountCodeAndNames = allocationQueryService.getAccountCodeAndName(hospId, dateYear, month);
  1528. // todo 校验两个List是否为空
  1529. // 填充
  1530. responsibilityCodeAndNames.add(0, new CodeAndNameVO("#", "#"));
  1531. responsibilityCodeAndNames.add(responsibilityCodeAndNames.size(), new CodeAndNameVO("合计", "合计"));
  1532. List<String> titleData = responsibilityCodeAndNames.stream().map(CodeAndNameVO::getName).collect(Collectors.toList());
  1533. List<String> respCodes = responsibilityCodeAndNames.stream().map(CodeAndNameVO::getCode).collect(Collectors.toList());
  1534. Map<Integer, String> titleMap = new HashMap<>();
  1535. for (int i = 0; i < titleData.size(); i++) {
  1536. titleMap.put(i + 1, titleData.get(i));
  1537. }
  1538. List<Map<Integer, Object>> realDatas = new ArrayList<>();
  1539. List<String> accountCodes = accountCodeAndNames.stream().map(CodeAndNameVO::getCode).collect(Collectors.toList());
  1540. for (CodeAndNameVO account : accountCodeAndNames) {
  1541. Map<Integer, Object> map = new HashMap<>();
  1542. for (int i = 0; i < responsibilityCodeAndNames.size(); i++) {
  1543. if (i == 0) {
  1544. map.put(i + 1, account.getName());
  1545. continue;
  1546. } else if (i == responsibilityCodeAndNames.size() - 1) {
  1547. // todo 计算最右侧合计的钱
  1548. BigDecimal amount = allocationQueryService.getTotalByAccountAndResps(hospId, dateYear, month, account.getCode(), respCodes);
  1549. map.put(i + 1, amount);
  1550. continue;
  1551. }
  1552. // TODO: 2021/8/26 计算 中间的钱
  1553. BigDecimal amount = allocationQueryService.getTotalByAccountAndRespCode(hospId, dateYear, month, account.getCode(), respCodes.get(i));
  1554. map.put(i + 1, amount);
  1555. }
  1556. realDatas.add(map);
  1557. }
  1558. // 尾栏计算
  1559. Map<Integer, Object> map = new HashMap<>();
  1560. for (int i = 0; i < titleData.size(); i++) {
  1561. if (i == 0) {
  1562. map.put(i + 1, "合计");
  1563. continue;
  1564. } else if (i == titleData.size() - 1) {
  1565. // TODO: 2021/8/26 计算
  1566. BigDecimal bigDecimal = allocationQueryService.getTotalMoney(dateYear, month, hospId);
  1567. map.put(i + 1, bigDecimal);
  1568. continue;
  1569. }
  1570. BigDecimal bigDecimal = allocationQueryService.getCountByRespAndAccounts(hospId, dateYear, month, responsibilityCodeAndNames.get(i).getCode(), accountCodes);
  1571. map.put(i + 1, bigDecimal);
  1572. }
  1573. return new CollectDataFormVO(titleMap, realDatas, map);
  1574. }
  1575. /**
  1576. * 分摊后报表输出
  1577. *
  1578. * @param date yyyy-MM-dd
  1579. * @param hospId 医院id
  1580. * @return List
  1581. */
  1582. @Override
  1583. public List<AfterAllocationFormVO> afterAllocationFormList(String date, Long hospId) {
  1584. DateTime parse = DateUtil.parse(date);
  1585. int year = DateUtil.year(parse);
  1586. int month = DateUtil.month(parse) + 1;
  1587. // 得到这个月的分摊过的分摊层级
  1588. List<Allocation> list = baseMapper.getAllSortLevel(hospId, year, month);
  1589. Map<Long, CostShareLevel> map = shareLevelService.list(new QueryWrapper<CostShareLevel>().lambda().eq(CostShareLevel::getHospId, hospId)).stream().collect(Collectors.toMap(CostShareLevel::getId, synOne -> synOne));
  1590. // list.
  1591. List<AfterAllocationFormVO> vos = list.stream().map(i -> {
  1592. AfterAllocationFormVO vo = new AfterAllocationFormVO();
  1593. vo.setId(i.getId());
  1594. vo.setYear(i.getDateYear());
  1595. vo.setMonth(i.getDateMonth());
  1596. vo.setShareLevel(i.getLevelSort());
  1597. vo.setShareReportName(map.get(i.getShareLevelId()).getShareName() + "分摊");
  1598. vo.setShareTime(DateUtil.date(i.getCreateTime()));
  1599. vo.setShareLevelId(i.getShareLevelId());
  1600. return vo;
  1601. }).collect(Collectors.toList());
  1602. return vos;
  1603. }
  1604. /**
  1605. * 按时间计算分摊数据
  1606. *
  1607. * @param year 年月
  1608. * @param month 月
  1609. * @param hospId
  1610. * @return
  1611. */
  1612. @Override
  1613. public List<Allocation> getByDate(int year, int month, Long hospId) {
  1614. return this.list(
  1615. new LambdaQueryWrapper<Allocation>()
  1616. .eq(Allocation::getDateYear, year)
  1617. .eq(Allocation::getDateMonth, month)
  1618. .eq(Allocation::getHospId, hospId)
  1619. );
  1620. }
  1621. }