CostDepartmentProfitServiceImpl.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. package com.imed.costaccount.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.util.StrUtil;
  5. import cn.hutool.poi.excel.ExcelWriter;
  6. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  9. import com.imed.costaccount.common.exception.CostException;
  10. import com.imed.costaccount.common.util.BeanUtil;
  11. import com.imed.costaccount.common.util.DateUtils;
  12. import com.imed.costaccount.common.util.PageUtils;
  13. import com.imed.costaccount.common.util.UserContext;
  14. import com.imed.costaccount.constants.NumberConstant;
  15. import com.imed.costaccount.common.enums.DateStyleEnum;
  16. import com.imed.costaccount.mapper.CostDepartmentProfitMapper;
  17. import com.imed.costaccount.model.*;
  18. import com.imed.costaccount.model.vo.AllocationQueryReportVO;
  19. import com.imed.costaccount.model.vo.CostDepartmentProfitVO;
  20. import com.imed.costaccount.service.*;
  21. import org.apache.poi.ss.usermodel.Sheet;
  22. import org.springframework.stereotype.Service;
  23. import java.math.BigDecimal;
  24. import java.util.*;
  25. import java.util.concurrent.atomic.AtomicReference;
  26. import java.util.stream.Collectors;
  27. @Service("costDepartmentProfitService")
  28. public class CostDepartmentProfitServiceImpl extends ServiceImpl<CostDepartmentProfitMapper, CostDepartmentProfit> implements CostDepartmentProfitService {
  29. private final ReportFormService reportFormService;
  30. private final IncomeCollectionService incomeCollectionService;
  31. private final CostShareLevelService costShareLevelService;
  32. private final ResponsibilityService responsibilityService;
  33. private final ReportRelationService reportRelationService;
  34. private final AllocationService allocationService;
  35. private final AllocationQueryService allocationQueryService;
  36. public CostDepartmentProfitServiceImpl(ReportFormService reportFormService, IncomeCollectionService incomeCollectionService, CostShareLevelService costShareLevelService, ResponsibilityService responsibilityService, ReportRelationService reportRelationService, AllocationService allocationService, AllocationQueryService allocationQueryService) {
  37. this.reportFormService = reportFormService;
  38. this.incomeCollectionService = incomeCollectionService;
  39. this.costShareLevelService = costShareLevelService;
  40. this.responsibilityService = responsibilityService;
  41. this.reportRelationService = reportRelationService;
  42. this.allocationService = allocationService;
  43. this.allocationQueryService = allocationQueryService;
  44. }
  45. /**
  46. * 查询科室损益数据
  47. *
  48. * @param current
  49. * @param pageSize
  50. * @param responsibilityCode
  51. * @param date
  52. * @param hospId
  53. * @return
  54. */
  55. @Override
  56. public PageUtils queryList(Integer current, Integer pageSize, String responsibilityCode, String date, Long hospId) {
  57. int year = 0;
  58. int month = 0;
  59. if (StrUtil.isNotBlank(date)) {
  60. Date dateTime = DateUtils.StringToDate(date, DateStyleEnum.YYYY_MM_DD);
  61. year = DateUtil.year(dateTime);
  62. month = DateUtil.month(dateTime) + 1;
  63. }
  64. Page<CostDepartmentProfit> departmentProfitPage = new Page<>(current, pageSize);
  65. // 查询的时候过过滤那些计算方式是不设置的数据
  66. Page<CostDepartmentProfit> pages = this.page(departmentProfitPage, new QueryWrapper<CostDepartmentProfit>().lambda()
  67. .eq(CostDepartmentProfit::getHospId, hospId)
  68. .eq(StrUtil.isNotBlank(responsibilityCode), CostDepartmentProfit::getResponsibilityCode, responsibilityCode)
  69. .eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getYear, year)
  70. .eq(StrUtil.isNotBlank(date), CostDepartmentProfit::getMonth, month).ne(CostDepartmentProfit::getCalcType, NumberConstant.ZERO));
  71. List<CostDepartmentProfit> records = pages.getRecords();
  72. List<CostDepartmentProfitVO> costDepartmentProfitVOList = BeanUtil.convertList(records, CostDepartmentProfitVO.class);
  73. PageUtils pageUtils = new PageUtils(pages);
  74. pageUtils.setList(costDepartmentProfitVOList);
  75. return pageUtils;
  76. }
  77. /**
  78. * 科室损益计算
  79. *
  80. * @param date
  81. * @param hospId
  82. */
  83. @Override
  84. public void setDepartmentProfit(String date, Long hospId) {
  85. int year = 0;
  86. int month = 0;
  87. if (StrUtil.isNotBlank(date)) {
  88. Date dateTime = DateUtils.StringToDate(date, DateStyleEnum.YYYY_MM_DD);
  89. year = DateUtil.year(dateTime);
  90. month = DateUtil.month(dateTime) + 1;
  91. }
  92. // 先查询指定条件的报表数据 查询损益表的数据
  93. List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
  94. .eq(ReportForm::getHospId, hospId)
  95. .eq(ReportForm::getReportType, NumberConstant.ZERO));
  96. // 遍历报表数据根据报表数据计算方式进行计算
  97. // 查询最后一个层级的责任中心
  98. List<CostShareLevel> costShareLevelList = costShareLevelService.list(new QueryWrapper<CostShareLevel>().lambda()
  99. .eq(CostShareLevel::getHospId, hospId).orderByDesc(CostShareLevel::getLeverSort));
  100. Long id = costShareLevelList.get(0).getId();
  101. // 查询责任中心里面是这个层级的所有的收益中心
  102. List<Responsibility> responsibilityList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
  103. .eq(Responsibility::getHospId, hospId).eq(Responsibility::getResponsibilityType, NumberConstant.ONE).eq(Responsibility::getShareId, id));
  104. // 归集后
  105. List<IncomeCollection> incomeList = incomeCollectionService.list(new QueryWrapper<IncomeCollection>().lambda()
  106. .eq(IncomeCollection::getHospId, hospId)
  107. .eq(year > 0, IncomeCollection::getYear, year).eq(month > 0, IncomeCollection::getMonth, month));
  108. Map<Long, List<ReportRelation>> reportRelationMap = reportRelationService.list(new QueryWrapper<ReportRelation>().lambda().eq(ReportRelation::getHospId, hospId)).stream().collect(Collectors.groupingBy(ReportRelation::getReportId));
  109. // 分摊后的数据getOriginType等于2说明是分摊后的数据
  110. List<AllocationQuery> allocationQueryList = allocationQueryService.list(new QueryWrapper<AllocationQuery>().lambda().eq(AllocationQuery::getHospId, hospId)
  111. .eq(year > 0, AllocationQuery::getDateYear, year)
  112. .eq(month > 0, AllocationQuery::getDateMonth, month)
  113. .eq(AllocationQuery::getOriginType, NumberConstant.TWO));
  114. // 封装数据
  115. List<AllocationQueryReportVO> allocationQueryReportVOList = BeanUtil.convertList(allocationQueryList, AllocationQueryReportVO.class);
  116. allocationQueryReportVOList.forEach(i -> {
  117. i.setAccountingCodes(Arrays.asList(i.getAccountingCode().split(StrUtil.COMMA)));
  118. i.setAccountingNames(Arrays.asList(i.getAccountingName().split(StrUtil.COMMA)));
  119. });
  120. // 查询分摊的报表数据 后面的计算方式需要使用 小计等需要使用
  121. List<Allocation> allocationList = allocationService.list(new QueryWrapper<Allocation>().lambda().eq(Allocation::getHospId, hospId)
  122. .eq(year > 0, Allocation::getDateYear, year).eq(month > 0, Allocation::getDateMonth, month));
  123. // 查询所有指定类型的损益表
  124. // 每个责任中心对应报表都要生成记录
  125. // 封装需要设置的数据
  126. List<CostDepartmentProfitVO> list = new ArrayList<>();
  127. int finalYear = year;
  128. int finalMonth = month;
  129. responsibilityList.forEach(i -> {
  130. reportFormList.forEach(j -> {
  131. CostDepartmentProfitVO costDepartmentProfitVO = new CostDepartmentProfitVO();
  132. costDepartmentProfitVO.setYear(finalYear);
  133. costDepartmentProfitVO.setMonth(finalMonth);
  134. costDepartmentProfitVO.setReportId(j.getId());
  135. costDepartmentProfitVO.setReportNum(j.getNum());
  136. costDepartmentProfitVO.setCalcType(j.getCalcType());
  137. costDepartmentProfitVO.setReportName(j.getReportName());
  138. costDepartmentProfitVO.setCalcFormula(j.getCalcFormula());
  139. costDepartmentProfitVO.setReportParentId(j.getParentId());
  140. costDepartmentProfitVO.setResponsibilityCode(i.getResponsibilityCode());
  141. costDepartmentProfitVO.setResponsibilityName(i.getResponsibilityName());
  142. costDepartmentProfitVO.setCostType(NumberConstant.ONE);
  143. costDepartmentProfitVO.setIncomeType(NumberConstant.ONE);
  144. costDepartmentProfitVO.setHospId(hospId);
  145. list.add(costDepartmentProfitVO);
  146. });
  147. });
  148. Map<Long, List<CostDepartmentProfitVO>> listMap = list.stream().collect(Collectors.groupingBy(CostDepartmentProfitVO::getReportId));
  149. // 记录每一次计算的钱
  150. list.forEach(i -> {
  151. Integer calcType = i.getCostType();
  152. switch (calcType) {
  153. case 1:
  154. // TODO 按照会计科目进行计算
  155. i.setAmount(setAccountReportData(i, incomeList, allocationQueryReportVOList, reportRelationMap));
  156. break;
  157. case 2:
  158. // TODO 按照分摊层级进行计算
  159. i.setAmount(setShareLevelReportData(i, costShareLevelList, reportRelationMap, allocationList));
  160. break;
  161. case 3:
  162. // TODO 按照小计进行计算
  163. i.setAmount(setSubtotal(i, costShareLevelList, listMap, list, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList));
  164. break;
  165. case 4:
  166. // TODO 按照计算公式进行计算
  167. i.setAmount(setCalculation(i, list, costShareLevelList, listMap, incomeList, allocationQueryReportVOList, reportRelationMap, allocationList));
  168. break;
  169. case 5:
  170. // TODO 按照责任中心进行计算
  171. i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList));
  172. break;
  173. default:
  174. i.setAmount(new BigDecimal("0.0000"));
  175. break;
  176. }
  177. });
  178. // 删除这个年月的数据
  179. this.remove(new QueryWrapper<CostDepartmentProfit>().lambda().eq(CostDepartmentProfit::getHospId, hospId)
  180. .eq(CostDepartmentProfit::getYear, year).eq(CostDepartmentProfit::getMonth, month));
  181. // 添加数据
  182. List<CostDepartmentProfit> costDepartmentProfits = BeanUtil.convertList(list, CostDepartmentProfit.class);
  183. long l = System.currentTimeMillis();
  184. costDepartmentProfits.forEach(i -> {
  185. i.setCreateTime(l);
  186. });
  187. this.saveBatch(costDepartmentProfits);
  188. }
  189. /**
  190. * 按照会计科目进行计算
  191. *
  192. * @param i
  193. */
  194. private BigDecimal setAccountReportData(CostDepartmentProfitVO i, List<IncomeCollection> list, List<AllocationQueryReportVO> allocationQueryReportVOList, Map<Long, List<ReportRelation>> reportRelationMap) {
  195. // 在报表关联里面查询当前报表关联的
  196. List<ReportRelation> reportRelationList = reportRelationMap.get(i.getReportId());
  197. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  198. if (CollUtil.isNotEmpty(reportRelationList)) {
  199. // 获取对应的会计科目信息 筛选会计科目的Code
  200. List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
  201. // 查找在归集数据里面当前责任中心对应的这些会计科目的金额
  202. List<IncomeCollection> incomeCollectionList = list.stream().filter(income -> income.getResponsibilityCode().equals(i.getResponsibilityCode()) && accountList.contains(income.getAccountingCode())).collect(Collectors.toList());
  203. // 需要查询分摊后的表
  204. // 归集加
  205. List<AllocationQueryReportVO> reportVOList = allocationQueryReportVOList.stream().filter(m -> m.getResponsibilityCode().equals(i.getResponsibilityCode()) && !Collections.disjoint(accountList, m.getAccountingCodes())).collect(Collectors.toList());
  206. if (CollUtil.isNotEmpty(incomeCollectionList)) {
  207. incomeCollectionList.forEach(m -> {
  208. sum.updateAndGet(v -> v.add(m.getAmount()));
  209. });
  210. }
  211. // 成本减
  212. if (CollUtil.isNotEmpty(reportVOList)) {
  213. reportVOList.forEach(m -> {
  214. sum.updateAndGet(v -> v.add(m.getAmount()));
  215. });
  216. }
  217. }
  218. i.setAmount(new BigDecimal(sum.toString()));
  219. // numMap.put(i.getReportNum()+i.getResponsibilityCode(),new BigDecimal(sum.toString()));
  220. return sum.get();
  221. }
  222. /**
  223. * 按照分摊层级进行计算
  224. * 按照分摊层级计算 报表分摊层级是当前的层级 并且目标责任中心失败当前责任中心
  225. */
  226. private BigDecimal setShareLevelReportData(CostDepartmentProfitVO i, List<CostShareLevel> costShareLevelList, Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList) {
  227. List<ReportRelation> reportRelationList = reportRelationMap.get(i.getReportId());
  228. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  229. if (CollUtil.isNotEmpty(reportRelationList)) {
  230. // 找到对应的分摊层级的Id 但是分摊报表里面存的是分摊层级的序号
  231. List<Long> shareLevelIds = reportRelationList.stream().map(ReportRelation::getRelationCode).map(Long::valueOf).collect(Collectors.toList());
  232. List<Integer> levelShortList = costShareLevelList.stream().filter(m -> shareLevelIds.contains(m.getId())).map(CostShareLevel::getLeverSort).collect(Collectors.toList());
  233. if (CollUtil.isNotEmpty(levelShortList)) {
  234. // 查询报表里面是当前分摊层级的数据
  235. List<Allocation> allocations = allocationList.stream().filter(m -> levelShortList.contains(m.getLevelSort()) && m.getTargetResponsibilityCode().equals(i.getResponsibilityCode())).collect(Collectors.toList());
  236. if (CollUtil.isNotEmpty(allocations)) {
  237. allocations.forEach(m -> {
  238. sum.updateAndGet(v -> v.add(m.getAmount()));
  239. });
  240. }
  241. }
  242. }
  243. i.setAmount(new BigDecimal(sum.toString()));
  244. return sum.get();
  245. }
  246. /**
  247. * 按照责任中心进行计算
  248. * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心
  249. * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心
  250. */
  251. public BigDecimal setResponsibilityCode(CostDepartmentProfitVO costDepartmentProfitVO, Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList) {
  252. // 获取当前报表对应的责任中心
  253. List<ReportRelation> reportRelationList = reportRelationMap.get(costDepartmentProfitVO.getReportId());
  254. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  255. if (CollUtil.isNotEmpty(reportRelationList)) {
  256. // 获取对应的责任中心的Code集合 这个是设置的责任中心
  257. List<String> responsibilityCodes = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
  258. if (CollUtil.isNotEmpty(responsibilityCodes)) {
  259. // 查询报表里面是当前分摊层级的数据
  260. List<Allocation> allocations = allocationList.stream().filter(i -> i.getTargetResponsibilityCode().equals(costDepartmentProfitVO.getResponsibilityCode()) && responsibilityCodes.contains(i.getResponsibilityCode())).collect(Collectors.toList());
  261. if (CollUtil.isNotEmpty(allocations)) {
  262. allocations.forEach(m -> {
  263. sum.updateAndGet(v -> v.add(m.getAmount()));
  264. });
  265. }
  266. }
  267. }
  268. costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString()));
  269. return sum.get();
  270. }
  271. /**
  272. * 按照小计的计算方式
  273. * 同一个目录下相同的其他金额的和
  274. */
  275. public BigDecimal setSubtotal(CostDepartmentProfitVO costDepartmentProfitVO,
  276. List<CostShareLevel> costShareLevelList,
  277. Map<Long, List<CostDepartmentProfitVO>> listMap,
  278. List<CostDepartmentProfitVO> profitVOS,
  279. List<IncomeCollection> list,
  280. List<AllocationQueryReportVO> allocationQueryReportVOList,
  281. Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList) {
  282. // 因为报表是按照报表项目的升序进行排序的 前面的报表是已经进行计算了的
  283. // 查询当前报表的父层级id
  284. Long reportParentId = costDepartmentProfitVO.getReportParentId();
  285. String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode();
  286. // 查询报表里面在当前父层级下的并且不是自己的报表项目
  287. List<CostDepartmentProfitVO> costDepartmentProfitVOS = profitVOS.stream().filter(i -> i.getReportParentId().equals(reportParentId) && i.getResponsibilityCode().equals(responsibilityCode) && !NumberConstant.THREE.equals(i.getCostType())).collect(Collectors.toList());
  288. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
  289. // 遍历数据 之前的已经经过了计算
  290. costDepartmentProfitVOS.forEach(i -> {
  291. Long reportId = i.getReportId();
  292. List<CostDepartmentProfitVO> costDepartmentProfitVOS1 = listMap.get(reportId);
  293. if (CollUtil.isEmpty(costDepartmentProfitVOS1)) {
  294. throw new CostException(500, "报表未找到");
  295. }
  296. BigDecimal amount = getAmount(profitVOS, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap);
  297. sum.updateAndGet(v -> v.add(amount));
  298. });
  299. costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString()));
  300. return sum.get();
  301. }
  302. /***
  303. * 按照计算方式进行计算
  304. */
  305. public BigDecimal setCalculation(CostDepartmentProfitVO costDepartmentProfitVO, List<CostDepartmentProfitVO> costDepartmentProfitVOList, List<CostShareLevel> costShareLevelList, Map<Long, List<CostDepartmentProfitVO>> listMap, List<IncomeCollection> list, List<AllocationQueryReportVO> allocationQueryReportVOList, Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList) {
  306. // 获取当前报表的计算方式 [1]+[2]类型/ [1]-[2]
  307. String calcFormula = costDepartmentProfitVO.getCalcFormula();
  308. String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode();
  309. String replace = calcFormula.replace("[", "").replace("]", "").replace("+", ",").replace("-", ",");
  310. List<Integer> calcFormulaList = Arrays.stream(replace.split(StrUtil.COMMA)).map(Integer::valueOf).collect(Collectors.toList());
  311. // 查询这个编号集合的报表
  312. List<Long> reportIdList = costDepartmentProfitVOList.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode) && calcFormulaList.contains(i.getReportNum())).map(CostDepartmentProfitVO::getReportId).collect(Collectors.toList());
  313. AtomicReference<BigDecimal> bigDecimal = new AtomicReference<>(new BigDecimal("0.0000"));
  314. if (CollUtil.isNotEmpty(reportIdList)) {
  315. reportIdList.forEach(i -> {
  316. List<CostDepartmentProfitVO> profitVOS = listMap.get(i);
  317. if (CollUtil.isEmpty(profitVOS)) {
  318. throw new CostException(500, "报表未找到");
  319. }
  320. BigDecimal amount = getAmount(profitVOS, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap);
  321. bigDecimal.updateAndGet(v -> v.add(amount));
  322. });
  323. }
  324. return bigDecimal.get();
  325. }
  326. /**
  327. * 判断是那种计算方式 调用方法进行计算
  328. */
  329. public BigDecimal getAmount(List<CostDepartmentProfitVO> profitVOS,
  330. List<CostShareLevel> costShareLevelList,
  331. String responsibilityCode, List<IncomeCollection> list,
  332. List<AllocationQueryReportVO> allocationQueryReportVOList,
  333. Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList,
  334. Map<Long, List<CostDepartmentProfitVO>> listMap) {
  335. BigDecimal bigDecimal = new BigDecimal("0.0000");
  336. // 在对这个报表进行过滤
  337. List<CostDepartmentProfitVO> costDepartmentProfitVOS = profitVOS.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  338. // 都一个就是
  339. CostDepartmentProfitVO costDepartmentProfitVO = costDepartmentProfitVOS.get(0);
  340. Integer costType = costDepartmentProfitVO.getCostType();
  341. if (NumberConstant.ONE.equals(costType)) {
  342. // 调用计算的方法 按照会计科目
  343. bigDecimal = setAccountReportData(costDepartmentProfitVO, list, allocationQueryReportVOList, reportRelationMap);
  344. } else if (NumberConstant.TWO.equals(costType)) {
  345. // 按照分摊层级
  346. bigDecimal = setShareLevelReportData(costDepartmentProfitVO, costShareLevelList, reportRelationMap, allocationList);
  347. } else if (NumberConstant.THREE.equals(costType)) {
  348. // 小计
  349. bigDecimal = setSubtotal(costDepartmentProfitVO, costShareLevelList, listMap, profitVOS, list, allocationQueryReportVOList, reportRelationMap, allocationList);
  350. } else if (NumberConstant.FIVE.equals(costType)) {
  351. // 按照责任中心
  352. bigDecimal = setResponsibilityCode(costDepartmentProfitVO, reportRelationMap, allocationList);
  353. }
  354. return bigDecimal;
  355. }
  356. }