AllocationServiceImpl.java 87 KB

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