AllocationServiceImpl.java 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. package com.imed.costaccount.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.imed.costaccount.common.constants.NumberConstant;
  11. import com.imed.costaccount.common.exception.CostException;
  12. import com.imed.costaccount.common.util.BeanUtil;
  13. import com.imed.costaccount.common.util.JacksonUtil;
  14. import com.imed.costaccount.common.util.PageUtils;
  15. import com.imed.costaccount.common.util.UserContext;
  16. import com.imed.costaccount.mapper.AllocationMapper;
  17. import com.imed.costaccount.model.*;
  18. import com.imed.costaccount.model.dto.StartDTO;
  19. import com.imed.costaccount.model.vo.*;
  20. import com.imed.costaccount.service.*;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.apache.poi.ss.usermodel.Sheet;
  23. import org.springframework.beans.factory.annotation.Value;
  24. import org.springframework.stereotype.Service;
  25. import org.springframework.transaction.annotation.Propagation;
  26. import org.springframework.transaction.annotation.Transactional;
  27. import java.math.BigDecimal;
  28. import java.util.*;
  29. import java.util.concurrent.atomic.AtomicReference;
  30. import java.util.stream.Collectors;
  31. @Slf4j
  32. @Service("allocationService")
  33. public class AllocationServiceImpl extends ServiceImpl<AllocationMapper, Allocation> implements AllocationService {
  34. @Value("${file.serverPath}")
  35. private String fileTempPath;
  36. @Value("${file.serverUrl}")
  37. private String FILE_PATH;
  38. private final CostCostingGroupService costCostingGroupService;
  39. private final CostShareLevelService shareLevelService;
  40. private final ResponsibilityService responsibilityService;
  41. private final CostAccountShareService accountShareService;
  42. private final ShareParamValueService shareParamValueService;
  43. private final CostShareParamService shareParamService;
  44. private final AllocationQueryService allocationQueryService;
  45. public AllocationServiceImpl(CostCostingGroupService costCostingGroupService,
  46. CostShareLevelService shareLevelService,
  47. ResponsibilityService responsibilityService,
  48. CostAccountShareService accountShareService,
  49. ShareParamValueService shareParamValueService, CostShareParamService shareParamService, AllocationQueryService allocationQueryService, AllocationQueryService allocationQueryService1) {
  50. this.costCostingGroupService = costCostingGroupService;
  51. this.shareLevelService = shareLevelService;
  52. this.responsibilityService = responsibilityService;
  53. this.accountShareService = accountShareService;
  54. this.shareParamValueService = shareParamValueService;
  55. this.shareParamService = shareParamService;
  56. this.allocationQueryService = allocationQueryService1;
  57. }
  58. /**
  59. * 分摊成本数据
  60. *
  61. * @param startDTO {@link StartDTO}
  62. * @param hospId 医院id
  63. */
  64. @Override
  65. @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
  66. public void startAllocation(StartDTO startDTO, Long hospId) {
  67. long timeMillis = System.currentTimeMillis();
  68. // 得到这个月的所有导入的成本数据
  69. List<CostCostingGroup> costingGroups = costCostingGroupService.getByYearAndDate(startDTO.getYear(), startDTO.getMonth(), hospId);
  70. // 没有重新导入
  71. if (costingGroups.isEmpty()) {
  72. throw new CostException("本月分摊数据未导入");
  73. }
  74. // 导入数据按责任中心归类
  75. Map<String, List<CostCostingGroup>> responsibilityCodeMap = costingGroups.stream().collect(Collectors.groupingBy(CostCostingGroup::getResponsibilityCode));
  76. // 得到这个月导入的成本分摊参数值列表
  77. List<ShareParamValue> shareParamValues = shareParamValueService.getListByYearAndMonth(startDTO.getYear(), startDTO.getMonth(), hospId);
  78. if (shareParamValues.isEmpty()) {
  79. throw new CostException("本月成本分摊参数值未导入");
  80. }
  81. Map<String, List<ShareParamValue>> paramValueRespCodeMap = shareParamValues.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
  82. // 删除该年月已经分摊过的数据
  83. removeData(startDTO, hospId);
  84. // 得到这个医院所有的分摊层级列表排序
  85. List<CostShareLevelVO> shareLevelVOs = shareLevelService.getAll(hospId);
  86. if (CollUtil.isEmpty(shareLevelVOs)) {
  87. throw new CostException("请先设置医院分摊层级");
  88. }
  89. List<Allocation> allocations = new LinkedList<>();
  90. // key 责任中心代码, value 分摊过来的钱
  91. // Map<String, BigDecimal> costMap = new ConcurrentReaderHashMap();
  92. List<Allocation> costList = new ArrayList<>();
  93. for (CostShareLevelVO shareLevelVO : shareLevelVOs) {
  94. // 分摊层级id
  95. Long levelId = shareLevelVO.getId();
  96. // 目标分摊层级,可能不存在
  97. String targetLevel = shareLevelVO.getTargetLevel();
  98. if (StrUtil.isBlank(targetLevel)) {
  99. throw new CostException("未设置目标层级");
  100. }
  101. // 计算方式 0是合并计算 1是分开计算
  102. Integer calcType = shareLevelVO.getCalcType();
  103. // 得到该分摊层级下责任中心列表,如果不存在,下一个
  104. List<Responsibility> responsibilities = responsibilityService.getLevelIdByCode(levelId, hospId);
  105. if (responsibilities.isEmpty()) {
  106. continue;
  107. }
  108. // 遍历责任中心得到对应的分摊参数对应
  109. for (Responsibility responsibility : responsibilities) {
  110. String responsibilityCode = responsibility.getResponsibilityCode();
  111. // 得到分摊参数对应记录,不存在,下一个
  112. List<CostAccountShare> accountShares = accountShareService.getByResponsibility(responsibilityCode, hospId);
  113. if (accountShares.isEmpty()) {
  114. continue;
  115. }
  116. // 遍历分摊参数对应记录
  117. for (CostAccountShare accountShare : accountShares) {
  118. Long accountShareId = accountShare.getId();
  119. String paramList = accountShare.getParamList();
  120. List<AccountShareVO> accountShareVOs = JacksonUtil.str2ObjList(paramList, List.class, AccountShareVO.class);
  121. // 如果分摊比例未设置直接报错
  122. if (StrUtil.isBlank(paramList)) {
  123. throw new CostException("责任中心:" + accountShare.getResponsibilityName() + ";会计中心为:" + accountShare.getAccountingNames() + ";未设置分摊参数比例");
  124. }
  125. // List<CostCostingGroup> groups = responsibilityCodeMap.get(responsibilityCode);
  126. // if (CollUtil.isEmpty(groups)) {
  127. // continue;
  128. // }
  129. // 计算本次分摊的钱
  130. BigDecimal totalAmount = this.getCostAmount(accountShare, calcType, responsibilityCodeMap, costList);
  131. if (totalAmount.equals(BigDecimal.ZERO)) {
  132. continue;
  133. }
  134. // 相关的分摊参数比例
  135. for (AccountShareVO accountShareVO : accountShareVOs) {
  136. String paramCode = accountShareVO.getShareParamCode();
  137. String shareParamPopout = accountShareVO.getShareParamPopout();
  138. BigDecimal rate = new BigDecimal("1");
  139. if (!"100".equals(shareParamPopout)) {
  140. rate = new BigDecimal("0." + shareParamPopout);
  141. }
  142. // 本次的分摊比例计算
  143. BigDecimal thisAmount = rate.multiply(totalAmount);
  144. // 得到目标层级责任中心列表
  145. List<Responsibility> targetResponsibilities = this.getTargetResponsibility(targetLevel, hospId, shareLevelVO.getLeverSort());
  146. if (targetResponsibilities.isEmpty()) {
  147. throw new CostException("找不到目标责任中心");
  148. }
  149. // 目标责任中心得到对应
  150. List<ShareParamValue> targetShareParmValue = getTarget(targetResponsibilities, accountShareVO, paramValueRespCodeMap);
  151. if (CollUtil.isEmpty(targetResponsibilities)) {
  152. throw new CostException("找不到目标责任中心对应的分摊参数值");
  153. }
  154. // 分母
  155. BigDecimal reduce = targetShareParmValue.stream().map(ShareParamValue::getValueNum).reduce(BigDecimal.ZERO, BigDecimal::add);
  156. for (ShareParamValue paramValue : targetShareParmValue) {
  157. // 分子
  158. BigDecimal numerator = paramValue.getValueNum();
  159. BigDecimal targetAmount = thisAmount.multiply(numerator).divide(reduce, 4);
  160. Allocation targetAllocation = new Allocation();
  161. String valueResponsibilityCode = paramValue.getResponsibilityCode();
  162. String targetRespName = responsibilityService.getByCode(valueResponsibilityCode, hospId);
  163. Long targetShareLevelId = responsibilityService.getLevelIdByCode(valueResponsibilityCode, hospId);
  164. if (Objects.isNull(targetShareLevelId)) {
  165. throw new CostException("目标责任中心分摊层级异常");
  166. }
  167. String shareParamName = shareParamService.getByCode(paramValue.getShareParamCode(), hospId);
  168. targetAllocation.setDateMonth(startDTO.getMonth()).setDateYear(startDTO.getYear()).setLevelSort(shareLevelVO.getLeverSort())
  169. .setLevelName(shareLevelVO.getShareName()).setHospId(hospId).setResponsibilityCode(responsibility.getResponsibilityCode())
  170. .setResponsibilityName(responsibility.getResponsibilityName()).setAccountShareId(accountShareId).setAmount(targetAmount)
  171. .setCreateTime(timeMillis).setTargetResponsibilityCode(valueResponsibilityCode).setTargetResponsibilityName(targetRespName)
  172. .setShareParamCode(paramValue.getShareParamCode()).setShareParamName(shareParamName).setTotalAmount(totalAmount).setShareParamValueNum(paramValue.getValueNum())
  173. .setShareParamRate(numerator.divide(reduce, 4)).setShareLevelId(levelId).setTargetShareLevelId(targetShareLevelId)
  174. ;
  175. // todo 目标分摊层级责任中心 就是当前列个表中的责任中心
  176. allocations.add(targetAllocation);
  177. costList.add(targetAllocation);
  178. }
  179. }
  180. }
  181. }
  182. }
  183. this.saveBatch(allocations);
  184. List<Allocation> list = this.list(
  185. new LambdaQueryWrapper<Allocation>()
  186. .eq(Allocation::getHospId, hospId).eq(Allocation::getDateYear, startDTO.getYear()).eq(Allocation::getDateMonth, startDTO.getMonth())
  187. );
  188. if (list.isEmpty()) {
  189. log.error("未分摊到数据......");
  190. return;
  191. }
  192. // 入cost_allocation_query 表 便于后续操作
  193. this.saveAllocationQuery(list, costingGroups, hospId, startDTO.getYear(), startDTO.getMonth());
  194. }
  195. private void removeData(StartDTO startDTO, Long hospId) {
  196. this.remove(
  197. new LambdaQueryWrapper<Allocation>()
  198. .eq(Allocation::getDateYear, startDTO.getYear())
  199. .eq(Allocation::getDateMonth, startDTO.getMonth())
  200. .eq(Allocation::getHospId, hospId)
  201. );
  202. allocationQueryService.remove(
  203. new LambdaQueryWrapper<AllocationQuery>()
  204. .eq(AllocationQuery::getDateYear, startDTO.getYear())
  205. .eq(AllocationQuery::getDateMonth, startDTO.getMonth())
  206. .eq(AllocationQuery::getHospId, hospId)
  207. );
  208. }
  209. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
  210. public void saveAllocationQuery(List<Allocation> list, List<CostCostingGroup> costingGroups, Long hospId, Integer year, Integer month) {
  211. List<AllocationQuery> saveList = new ArrayList<>();
  212. List<Long> maxId = shareLevelService.getMaxId(hospId);
  213. list = list.stream().filter(i -> maxId.contains(i.getTargetShareLevelId())).collect(Collectors.toList());
  214. list.forEach(i -> {
  215. Long accountShareId = i.getAccountShareId();
  216. CostAccountShare byId = accountShareService.getById(accountShareId);
  217. if (Objects.isNull(byId)) {
  218. return;
  219. }
  220. String accountingCodes = byId.getAccountingCodes();
  221. if (StrUtil.isBlank(accountingCodes)) {
  222. return;
  223. }
  224. String accountingNames = byId.getAccountingNames();
  225. String alias = byId.getAlias();
  226. if (StrUtil.isNotBlank(alias)) {
  227. accountingNames = alias;
  228. }
  229. AllocationQuery allocationQuery = new AllocationQuery();
  230. allocationQuery.setDateYear(i.getDateYear()).setDateMonth(i.getDateMonth())
  231. .setHospId(hospId).setResponsibilityCode(i.getResponsibilityCode())
  232. .setResponsibilityName(i.getResponsibilityName())
  233. .setOriginId(i.getId()).setOriginType(2L).setAmount(i.getAmount())
  234. .setAccountingCode(accountingCodes).setAccountingName(accountingNames)
  235. .setCreateTime(System.currentTimeMillis())
  236. .setLevelSort(i.getLevelSort()).setLevelName(i.getLevelName())
  237. .setTargetResponsibilityCode(i.getTargetResponsibilityCode())
  238. .setTargetResponsibilityName(i.getTargetResponsibilityName())
  239. .setShareLevelId(i.getShareLevelId())
  240. ;
  241. saveList.add(allocationQuery);
  242. });
  243. costingGroups = costCostingGroupService.getRealData(CollUtil.newArrayList(maxId), hospId, year, month);
  244. costingGroups.forEach(i -> {
  245. AllocationQuery allocationQuery = new AllocationQuery();
  246. String responsibilityCode = i.getResponsibilityCode();
  247. Long levelId = responsibilityService.getLevelIdByCode(responsibilityCode, hospId);
  248. if (Objects.isNull(levelId)) {
  249. throw new CostException("责任中心" + i.getResponsibilityName() + "数据异常");
  250. }
  251. CostShareLevel byId = shareLevelService.getById(levelId);
  252. if (Objects.isNull(byId)) {
  253. throw new CostException("责任中心" + i.getResponsibilityName() + "分摊层级数据异常");
  254. }
  255. allocationQuery.setDateYear(i.getDateYear()).setDateMonth(i.getDateMonth())
  256. .setHospId(hospId).setResponsibilityCode(responsibilityCode).setResponsibilityName(i.getResponsibilityName())
  257. .setOriginId(i.getId()).setOriginType(1L).setAmount(i.getAmount())
  258. .setAccountingCode(i.getAccountCode()).setAccountingName(i.getAccountName())
  259. .setCreateTime(System.currentTimeMillis())
  260. .setLevelSort(byId.getLeverSort()).setLevelName(byId.getShareName())
  261. .setTargetResponsibilityCode(responsibilityCode)
  262. .setTargetResponsibilityName(i.getResponsibilityName())
  263. .setShareLevelId(0L)
  264. ;
  265. saveList.add(allocationQuery);
  266. });
  267. allocationQueryService.saveBatch(saveList);
  268. }
  269. /**
  270. * 得到目标月成本分摊参数值数据
  271. *
  272. * @param targetResponsibilities
  273. * @param map
  274. * @return
  275. */
  276. private List<ShareParamValue> getTarget(List<Responsibility> targetResponsibilities, AccountShareVO accountShareVO, Map<String, List<ShareParamValue>> map) {
  277. // 目标的责任中心
  278. List<ShareParamValue> shareParamValues = map.entrySet().stream().map(Map.Entry::getValue).flatMap(Collection::stream).collect(Collectors.toList());
  279. List<String> originRespCodes = targetResponsibilities.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList());
  280. return shareParamValues.stream().filter(j -> originRespCodes.contains(j.getResponsibilityCode()))
  281. .filter(i -> i.getShareParamCode().equals(accountShareVO.getShareParamCode())).collect(Collectors.toList());
  282. }
  283. /**
  284. * 计算本次的成本金额
  285. *
  286. * @return
  287. */
  288. private BigDecimal getCostAmount(CostAccountShare accountShare, Integer calcType, Map<String, List<CostCostingGroup>> map, List<Allocation> costList) {
  289. // 是否包含分摊成本 0不包含 1 包含
  290. Integer isShareCost = accountShare.getIsShareCost();
  291. String accountingCodes = accountShare.getAccountingCodes();
  292. String responsibilityCode = accountShare.getResponsibilityCode();
  293. List<CostCostingGroup> costingGroups = map.get(responsibilityCode);
  294. if (CollUtil.isEmpty(costingGroups)) {
  295. List<Allocation> all = costList.stream().filter(i -> i.getTargetResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  296. if (CollUtil.isEmpty(all) || isShareCost == 0) {
  297. return BigDecimal.ZERO;
  298. }
  299. BigDecimal reduce = all.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  300. return reduce;
  301. } else {
  302. BigDecimal costAmount = BigDecimal.ZERO;
  303. List<Allocation> all = new ArrayList<>();
  304. if (!costList.isEmpty()) {
  305. all = costList.stream().filter(i -> i.getTargetResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  306. }
  307. // 计算方式 0是合并计算 1是分开计算
  308. if (calcType == 0) {
  309. costAmount = costingGroups.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  310. if (!all.isEmpty()) {
  311. BigDecimal bigDecimal = all.stream()
  312. .map(Allocation::getAmount)
  313. .reduce(BigDecimal.ZERO, BigDecimal::add);
  314. if (Objects.nonNull(bigDecimal)) {
  315. costAmount = costAmount.add(bigDecimal);
  316. }
  317. }
  318. } else {
  319. if (StrUtil.isBlank(accountingCodes)) {
  320. return BigDecimal.ZERO;
  321. }
  322. ArrayList<String> accountCodes = CollUtil.newArrayList(accountingCodes.split(StrUtil.COMMA));
  323. List<CostCostingGroup> costGroups = costingGroups.stream().filter(i -> accountCodes.contains(i.getAccountCode())).collect(Collectors.toList());
  324. costAmount = costGroups.stream().map(CostCostingGroup::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  325. if (isShareCost == 1) {
  326. if (!all.isEmpty()) {
  327. BigDecimal bigDecimal = all.stream()
  328. .map(Allocation::getAmount)
  329. .reduce(BigDecimal.ZERO, BigDecimal::add);
  330. if (Objects.nonNull(bigDecimal)) {
  331. costAmount = costAmount.add(bigDecimal);
  332. }
  333. }
  334. }
  335. }
  336. return costAmount;
  337. }
  338. }
  339. /**
  340. * 通过目标层级获取目标责任中心
  341. *
  342. * @param targetLevel 目标层级 2,3,4
  343. * @param leverSort
  344. * @return List
  345. */
  346. private List<Responsibility> getTargetResponsibility(String targetLevel, Long hospId, Integer leverSort) {
  347. ArrayList<String> targetLevelList = CollUtil.newArrayList(StrUtil.split(targetLevel, StrUtil.COMMA));
  348. if (targetLevelList.size() == 1) {
  349. if (leverSort.equals(Integer.parseInt(targetLevelList.get(0)))) {
  350. return new ArrayList<>();
  351. }
  352. }
  353. List<CostShareLevel> shareLevels = shareLevelService.getListByLevelSort(targetLevelList, hospId);
  354. if (shareLevels.isEmpty()) {
  355. throw new CostException("请重新设置分摊层级");
  356. }
  357. List<Long> shareLevelIds = shareLevels.stream().map(CostShareLevel::getId).collect(Collectors.toList());
  358. return responsibilityService.getByLevelIds(shareLevelIds, hospId);
  359. }
  360. /**
  361. * 分摊后查询列表
  362. *
  363. * @param year 年月 (yyyy-MM-dd)
  364. * @param responsibilityCode 责任中心代码
  365. * @param current 当前页
  366. * @param pageSize 当前页展示的数据大小
  367. * @param hospId 医院id
  368. * @return PageUtils
  369. */
  370. @Override
  371. public PageUtils queryAfterAllocation(String year, String responsibilityCode, Integer current, Integer pageSize, Long hospId) {
  372. Integer dateYear = null;
  373. Integer dateMonth = null;
  374. if (StrUtil.isNotBlank(year)) {
  375. DateTime dateTime = DateUtil.parseDate(year);
  376. dateYear = DateUtil.year(dateTime);
  377. dateMonth = DateUtil.month(dateTime) + 1;
  378. }
  379. Integer startIndex = (current - 1) * pageSize;
  380. List<AfterAllocationVO> list = baseMapper.queryAfterAllocationList(dateYear, dateMonth, responsibilityCode, startIndex, pageSize, hospId);
  381. int totalCount = baseMapper.queryAfterAllocationListCount(dateYear, dateMonth, responsibilityCode, hospId);
  382. BigDecimal sum = baseMapper.queryAfterAllocationListSum(dateYear, dateMonth, responsibilityCode, hospId);
  383. return new PageUtils(list, totalCount, pageSize, current, sum);
  384. }
  385. /**
  386. * 分摊报表导出
  387. *
  388. * @param writer {@link ExcelWriter}
  389. * @param levelSort 分摊层级 就是第几次分摊
  390. * @param sheet 报表
  391. * @param year 年
  392. * @param month 月
  393. * @param shareLevelId
  394. * @return
  395. */
  396. @Override
  397. public ExcelWriter getShareReportTemplate(ExcelWriter writer, Integer levelSort, Sheet sheet, Integer year, Integer month, Long shareLevelId) {
  398. // 获取数据
  399. List<AllocationReportVO> allocationReportVOList = getAllocationReportVOS(levelSort, year, month, shareLevelId);
  400. // 设置导出
  401. Map<String, List<AllocationReportVO>> responsibilityMap = allocationReportVOList.stream().collect(Collectors.groupingBy(AllocationReportVO::getResponsibilityCode));
  402. Map<String, List<AllocationReportVO>> targetResponsibilityMap = allocationReportVOList.stream().collect(Collectors.groupingBy(AllocationReportVO::getTargetResponsibilityCode));
  403. // 以会计科目查
  404. Map<String, AllocationReportVO> allAccMap = allocationReportVOList.stream().collect(Collectors.toMap(k -> k.getResponsibilityName() + k.getAccountName() + k.getTargetResponsibilityName() + k.getShareParamName(), synOne -> synOne));
  405. // 用别名查 过滤别名不为空的
  406. 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));
  407. // Map<String, AllocationReportVO> allAliMap = allocationReportVOList.stream().collect(Collectors.toMap(k -> k.getResponsibilityName() + k.getAlias() + k.getTargetResponsibilityName() + k.getShareParamName(), synOne -> synOne));
  408. // 当前责任中心下面有几个会计科目 后面进行合并使用
  409. int numResponsibility;
  410. // // 从第几列开始编写数据
  411. int column = levelSort + 3;
  412. Set<String> keySet = responsibilityMap.keySet();
  413. for (String key : keySet) {
  414. List<AllocationReportVO> allocationReportVOS = responsibilityMap.get(key);
  415. Map<String, AllocationReportVO> linkedHashMap = new LinkedHashMap<>();
  416. allocationReportVOS.forEach(i -> {
  417. String s = i.getResponsibilityCode() + i.getAccountCode();
  418. if (!linkedHashMap.containsKey(s)) {
  419. linkedHashMap.put(s, i);
  420. }
  421. });
  422. numResponsibility = linkedHashMap.size();
  423. if (numResponsibility >= NumberConstant.TWO) {
  424. Set<String> strings = linkedHashMap.keySet();
  425. for (String s : strings) {
  426. AllocationReportVO allocationReportVO = linkedHashMap.get(s);
  427. if (StrUtil.isBlank(allocationReportVO.getAlias())) {
  428. writer.writeCellValue(column, 0, allocationReportVO.getResponsibilityName());
  429. // 别名不存在
  430. writer.writeCellValue(column, 1, allocationReportVO.getAccountName());
  431. } else {
  432. // 不为空 设置别名
  433. writer.writeCellValue(column, 0, allocationReportVO.getResponsibilityName());
  434. writer.writeCellValue(column, 1, allocationReportVO.getAlias());
  435. }
  436. writer.writeCellValue(column, 2, allocationReportVO.getTotalAmounts());
  437. column++;
  438. }
  439. } else {
  440. // 不需要合并单元格
  441. writer.writeCellValue(column, 0, allocationReportVOS.get(0).getResponsibilityName());
  442. if (StrUtil.isNotBlank(allocationReportVOS.get(0).getAlias())) {
  443. writer.writeCellValue(column, 1, allocationReportVOS.get(0).getAlias());
  444. } else {
  445. writer.writeCellValue(column, 1, allocationReportVOS.get(0).getAccountName());
  446. }
  447. writer.writeCellValue(column, 2, allocationReportVOS.get(0).getTotalAmounts());
  448. column++;
  449. }
  450. }
  451. // 设置单元格合并
  452. for (int j = 1; j < levelSort; j++) {
  453. writer.merge(0, 1, j, j, "第" + j + "次分摊", false);
  454. }
  455. // 目标责任集合
  456. writer.passCurrentRow();
  457. // 从第三行开始
  458. int num = 3;
  459. Set<String> targetSet = targetResponsibilityMap.keySet();
  460. for (String target : targetSet) {
  461. List<AllocationReportVO> allocationReportVOS = targetResponsibilityMap.get(target);
  462. Map<String, AllocationReportVO> linkedHashMap = new LinkedHashMap<>();
  463. allocationReportVOS.forEach(i -> {
  464. String s = i.getTargetResponsibilityCode() + i.getShareParamName();
  465. if (!linkedHashMap.containsKey(s)) {
  466. linkedHashMap.put(s, i);
  467. }
  468. });
  469. int shareParamSize = linkedHashMap.size();
  470. if (shareParamSize >= NumberConstant.TWO) {
  471. // 责任中心
  472. AllocationReportVO costCostingVO = allocationReportVOS.get(0);
  473. // 设置第几次分摊的值
  474. for (int k = 0; k < levelSort - 1; k++) {
  475. writer.merge(num, num + shareParamSize - 1, k + 1, k + 1, costCostingVO.getTargetShareMoneys().get(k), false);
  476. }
  477. // 设置对应的分摊参数值
  478. Set<String> strings = linkedHashMap.keySet();
  479. for (String s : strings) {
  480. AllocationReportVO allocationReportVO = linkedHashMap.get(s);
  481. writer.writeCellValue(0, num, allocationReportVO.getTargetResponsibilityName());
  482. writer.writeCellValue(levelSort, num, allocationReportVO.getShareParamName());
  483. writer.writeCellValue(levelSort + 1, num, allocationReportVO.getShareParamValueNums());
  484. writer.writeCellValue(levelSort + 2, num, allocationReportVO.getShareParamRates());
  485. for (int m = levelSort + 3; m < column; m++) {
  486. // x是m y是num
  487. // 获取当前这一列对应的责任中心 以及会计科目
  488. // 第一行责任中心
  489. String responsibilityName = sheet.getRow(0).getCell(m).getStringCellValue();
  490. // 第二行的会计科目或者
  491. String accountNameOrAlias = sheet.getRow(1).getCell(m).getStringCellValue();
  492. // 这一行的目标责任中心
  493. String otherResponsibilityName = sheet.getRow(num).getCell(0).getStringCellValue();
  494. // 分摊参数
  495. String shareName = sheet.getRow(num).getCell(levelSort).getStringCellValue();
  496. String sss = responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName;
  497. AllocationReportVO vo = allAliMap.get(sss);
  498. AllocationReportVO allocationReportVO2 = allAccMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  499. AllocationReportVO allocationReportVO3 = allAliMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  500. if (Objects.nonNull(allocationReportVO2)) {
  501. writer.writeCellValue(m, num, allocationReportVO2.getAmounts());
  502. } else if (Objects.nonNull(allocationReportVO3)) {
  503. writer.writeCellValue(m, num, allocationReportVO3.getAmounts());
  504. } else {
  505. writer.writeCellValue(m, num, 0);
  506. }
  507. }
  508. num++;
  509. }
  510. }
  511. if (shareParamSize < NumberConstant.TWO) {
  512. writer.writeCellValue(0, num, allocationReportVOS.get(0).getTargetResponsibilityName());
  513. for (int k = 0; k < levelSort - 1; k++) {
  514. writer.writeCellValue(k + 1, num, allocationReportVOS.get(0).getTargetShareMoneys().get(k));
  515. }
  516. writer.writeCellValue(levelSort, num, allocationReportVOS.get(0).getShareParamName());
  517. writer.writeCellValue(levelSort + 1, num, allocationReportVOS.get(0).getShareParamValueNums());
  518. writer.writeCellValue(levelSort + 2, num, allocationReportVOS.get(0).getShareParamRates());
  519. for (int m = levelSort + 3; m < column; m++) {
  520. // x是m y是num
  521. // 获取当前这一列对应的责任中心 以及会计科目
  522. // 第一行责任中心
  523. String responsibilityName = sheet.getRow(0).getCell(m).getStringCellValue();
  524. // 第二行的会计科目或者
  525. String accountNameOrAlias = sheet.getRow(1).getCell(m).getStringCellValue();
  526. // 这一行的目标责任中心
  527. String otherResponsibilityName = sheet.getRow(num).getCell(0).getStringCellValue();
  528. // 分摊参数
  529. String shareName = sheet.getRow(num).getCell(levelSort).getStringCellValue();
  530. AllocationReportVO allocationReportVO2 = allAccMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  531. AllocationReportVO allocationReportVO3 = allAliMap.get(responsibilityName + accountNameOrAlias + otherResponsibilityName + shareName);
  532. if (Objects.nonNull(allocationReportVO2)) {
  533. writer.writeCellValue(m, num, allocationReportVO2.getAmounts());
  534. } else if (Objects.nonNull(allocationReportVO3)) {
  535. writer.writeCellValue(m, num, allocationReportVO3.getAmounts());
  536. } else {
  537. writer.writeCellValue(m, num, 0);
  538. }
  539. }
  540. num++;
  541. }
  542. }
  543. Map<String, Integer> rowMap = new HashMap<>();
  544. int cc = levelSort + 3;
  545. // 合并行
  546. boolean otherData = false;
  547. for (int m = levelSort + 3; m < column - 1; m++) {
  548. // String cellValue = sheet.getRow(0).getCell(m).getStringCellValue();
  549. // if (!rowMap.containsKey(cellValue)){
  550. // rowMap.put(cellValue,m);
  551. // Integer integer = rowMap.get(sheet.getRow(0).getCell(m).getStringCellValue());
  552. // String value = sheet.getRow(0).getCell(m ).getStringCellValue();
  553. // writer.merge(0, 0, rowMap.get(sheet.getRow(0).getCell(m-1).getStringCellValue()), m-1, sheet.getRow(0).getCell(m-1).getStringCellValue(), false);
  554. // }
  555. String cellValue1 = sheet.getRow(0).getCell(m).getStringCellValue();
  556. String cellValue2 = sheet.getRow(0).getCell(m + 1).getStringCellValue();
  557. if (!cellValue1.equals(cellValue2)) {
  558. if (cc != m) {
  559. writer.merge(0, 0, cc, m, cellValue1, false);
  560. } else {
  561. writer.writeCellValue(cc, 0, cellValue1);
  562. }
  563. cc = m + 1;
  564. } else if (m == column - 2) {
  565. writer.merge(0, 0, cc, m + 1, sheet.getRow(0).getCell(m + 1).getStringCellValue(), false);
  566. }
  567. }
  568. // 合并列
  569. int jj = 3;
  570. for (int i = 3; i < num - 1; i++) {
  571. String cellValue1 = sheet.getRow(i).getCell(0).getStringCellValue();
  572. String cellValue2 = sheet.getRow(i + 1).getCell(0).getStringCellValue();
  573. if (!cellValue1.equals(cellValue2)) {
  574. if (jj != i) {
  575. writer.merge(jj, i, 0, 0, cellValue1, false);
  576. } else {
  577. writer.writeCellValue(0, jj, cellValue1);
  578. }
  579. jj = i + 1;
  580. } else if (i == num - 2) {
  581. writer.merge(jj, i + 1, 0, 0, cellValue1, false);
  582. }
  583. }
  584. for (int i = 0; i < 30; i++) {
  585. // 调整每一列宽度
  586. sheet.autoSizeColumn((short) i);
  587. // 解决自动设置列宽中文失效的问题
  588. sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 14 / 10);
  589. }
  590. return writer;
  591. }
  592. /**
  593. * 查询数据
  594. *
  595. * @param levelSort
  596. * @param year
  597. * @param month
  598. * @return
  599. */
  600. private List<AllocationReportVO> getAllocationReportVOS(Integer levelSort, Integer year, Integer month, Long shareLevelId) {
  601. Long hospId = UserContext.getHospId();
  602. if (Objects.isNull(levelSort) || Objects.isNull(year) || Objects.isNull(month)) {
  603. throw new CostException(500, "参数异常");
  604. }
  605. // 处理第几次分摊计算值
  606. List<Allocation> allocationList = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
  607. .eq(Allocation::getHospId, hospId).eq(Allocation::getLevelSort, levelSort).eq(Allocation::getShareLevelId, shareLevelId).eq(Allocation::getDateYear, year)
  608. .eq(Allocation::getDateMonth, month));
  609. // 找会计科室的时候使用的
  610. List<Allocation> allocations = baseMapper.selectList(new QueryWrapper<Allocation>().lambda()
  611. .eq(Allocation::getHospId, hospId).eq(Allocation::getDateYear, year)
  612. .eq(Allocation::getDateMonth, month));
  613. Map<String, List<Allocation>> accrepMap = allocations.stream().collect(Collectors.groupingBy(k -> k.getLevelSort() + "cost" + k.getTargetResponsibilityCode()));
  614. LinkedList<String> shareMoney = new LinkedList<>();
  615. List<CostAccountShare> costAccountShareList = accountShareService.list(new QueryWrapper<CostAccountShare>().lambda()
  616. .eq(CostAccountShare::getHospId, hospId));
  617. Map<Long, CostAccountShare> accountShareMap = costAccountShareList.stream().collect(Collectors.toMap(CostAccountShare::getId, synOne -> synOne));
  618. List<AllocationReportVO> allocationReportVOList = BeanUtil.convertList(allocationList, AllocationReportVO.class);
  619. // 设置会计科目的
  620. allocationReportVOList.forEach(i -> {
  621. Long accountShareId = i.getAccountShareId();
  622. CostAccountShare costAccountShare = accountShareMap.get(accountShareId);
  623. if (Objects.isNull(costAccountShare)) {
  624. throw new CostException(500, "成本参数参数设置对应不存在");
  625. }
  626. i.setAccountCode(costAccountShare.getAccountingCodes());
  627. i.setAccountName(costAccountShare.getAccountingNames());
  628. i.setAlias(costAccountShare.getAlias());
  629. if (levelSort > 1) {
  630. AtomicReference<BigDecimal> money = new AtomicReference<>(new BigDecimal("0.0000"));
  631. for (int j = 1; j < levelSort; j++) {
  632. // 每一次计算要设置为0
  633. List<Allocation> allocations1 = accrepMap.get(j + "cost" + i.getTargetResponsibilityCode());
  634. if (CollUtil.isNotEmpty(allocations1)) {
  635. allocations1.forEach(m -> {
  636. money.updateAndGet(v -> v.add(m.getAmount()));
  637. // System.out.println(m.getAmount());
  638. });
  639. } else {
  640. // TODO 封装测试数据
  641. shareMoney.add("0");
  642. }
  643. // System.out.println("第"+j+"次"+money);
  644. shareMoney.add(money.toString());
  645. }
  646. }
  647. i.setTargetShareMoneys(shareMoney);
  648. // 设置字符串类型数据
  649. i.setTotalAmounts(i.getTotalAmount().toString());
  650. i.setShareParamValueNums(i.getShareParamValueNum().toString());
  651. i.setShareParamRates(i.getShareParamRate().toString());
  652. i.setAmounts(i.getAmount().toString());
  653. });
  654. return allocationReportVOList;
  655. }
  656. /**
  657. * 分摊后报表
  658. *
  659. * @param year 年月(yyyy-MM-dd)
  660. * @param responsibilityCode 责任中心代码
  661. * @param hospId 医院id
  662. * @return List
  663. */
  664. @Override
  665. public CollectDataFormVO queryAfterAllocationForm(String year, String responsibilityCode, Long hospId) {
  666. DateTime dateTime = DateUtil.parseDate(year);
  667. int dateYear = DateUtil.year(dateTime);
  668. int month = DateUtil.month(dateTime) + 1;
  669. List<CodeAndNameVO> responsibilityCodeAndNames = allocationQueryService.getRespCodeAndName(hospId, dateYear, month);
  670. List<CodeAndNameVO> accountCodeAndNames = allocationQueryService.getAccountCodeAndName(hospId, dateYear, month);
  671. // todo 校验两个List是否为空
  672. // 填充
  673. responsibilityCodeAndNames.add(0, new CodeAndNameVO("#", "#"));
  674. responsibilityCodeAndNames.add(responsibilityCodeAndNames.size(), new CodeAndNameVO("合计", "合计"));
  675. List<String> titleData = responsibilityCodeAndNames.stream().map(CodeAndNameVO::getName).collect(Collectors.toList());
  676. List<String> respCodes = responsibilityCodeAndNames.stream().map(CodeAndNameVO::getCode).collect(Collectors.toList());
  677. Map<Integer, String> titleMap = new HashMap<>();
  678. for (int i = 0; i < titleData.size(); i++) {
  679. titleMap.put(i + 1, titleData.get(i));
  680. }
  681. List<Map<Integer, Object>> realDatas = new ArrayList<>();
  682. List<String> accountCodes = accountCodeAndNames.stream().map(CodeAndNameVO::getCode).collect(Collectors.toList());
  683. for (CodeAndNameVO account : accountCodeAndNames) {
  684. Map<Integer, Object> map = new HashMap<>();
  685. for (int i = 0; i < responsibilityCodeAndNames.size(); i++) {
  686. if (i == 0) {
  687. map.put(i + 1, account.getName());
  688. continue;
  689. } else if (i == responsibilityCodeAndNames.size() - 1) {
  690. // todo 计算最右侧合计的钱
  691. BigDecimal amount = allocationQueryService.getTotalByAccountAndResps(hospId, dateYear, month, account.getCode(), respCodes);
  692. map.put(i + 1, amount);
  693. continue;
  694. }
  695. // TODO: 2021/8/26 计算 中间的钱
  696. BigDecimal amount = allocationQueryService.getTotalByAccountAndRespCode(hospId, dateYear, month, account.getCode(), respCodes.get(i));
  697. map.put(i + 1, amount);
  698. }
  699. realDatas.add(map);
  700. }
  701. // 尾栏计算
  702. Map<Integer, Object> map = new HashMap<>();
  703. for (int i = 0; i < titleData.size(); i++) {
  704. if (i == 0) {
  705. map.put(i + 1, "合计");
  706. continue;
  707. } else if (i == titleData.size() - 1) {
  708. // TODO: 2021/8/26 计算
  709. BigDecimal bigDecimal = allocationQueryService.getTotalMoney(dateYear, month, hospId);
  710. map.put(i + 1, bigDecimal);
  711. continue;
  712. }
  713. BigDecimal bigDecimal = allocationQueryService.getCountByRespAndAccounts(hospId, dateYear, month, responsibilityCodeAndNames.get(i).getCode(), accountCodes);
  714. map.put(i + 1, bigDecimal);
  715. }
  716. return new CollectDataFormVO(titleMap, realDatas, map);
  717. }
  718. /**
  719. * 分摊后报表输出
  720. *
  721. * @param date yyyy-MM-dd
  722. * @param hospId 医院id
  723. * @return List
  724. */
  725. @Override
  726. public List<AfterAllocationFormVO> afterAllocationFormList(String date, Long hospId) {
  727. DateTime parse = DateUtil.parse(date);
  728. int year = DateUtil.year(parse);
  729. int month = DateUtil.month(parse) + 1;
  730. // 得到这个月的分摊过的分摊层级
  731. List<Allocation> list = baseMapper.getAllSortLevel(hospId, year, month);
  732. Map<Long, CostShareLevel> map = shareLevelService.list(new QueryWrapper<CostShareLevel>().lambda().eq(CostShareLevel::getHospId, hospId)).stream().collect(Collectors.toMap(CostShareLevel::getId, synOne -> synOne));
  733. // list.
  734. List<AfterAllocationFormVO> vos = list.stream().map(i -> {
  735. AfterAllocationFormVO vo = new AfterAllocationFormVO();
  736. vo.setId(i.getId());
  737. vo.setYear(i.getDateYear());
  738. vo.setMonth(i.getDateMonth());
  739. vo.setShareLevel(i.getLevelSort());
  740. vo.setShareReportName(map.get(i.getShareLevelId()).getShareName() + "分摊");
  741. vo.setShareTime(DateUtil.date(i.getCreateTime()));
  742. vo.setShareLevelId(i.getShareLevelId());
  743. return vo;
  744. }).collect(Collectors.toList());
  745. return vos;
  746. }
  747. /**
  748. * 按时间计算分摊数据
  749. *
  750. * @param year 年月
  751. * @param month 月
  752. * @param hospId
  753. * @return
  754. */
  755. @Override
  756. public List<Allocation> getByDate(int year, int month, Long hospId) {
  757. return this.list(
  758. new LambdaQueryWrapper<Allocation>()
  759. .eq(Allocation::getDateYear, year)
  760. .eq(Allocation::getDateMonth, month)
  761. .eq(Allocation::getHospId, hospId)
  762. );
  763. }
  764. }