ComputeItemCostServiceImpl.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. package com.kcim.service.impl;
  2. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  3. import com.kcim.common.constants.NumberConstant;
  4. import com.kcim.common.constants.ParameterConstant;
  5. import com.kcim.common.constants.RedisKeyConstant;
  6. import com.kcim.common.enums.EmpCostComputeTypeEnum;
  7. import com.kcim.common.enums.ItemTypeEnum;
  8. import com.kcim.common.enums.ReportItemTypeEnum;
  9. import com.kcim.common.exception.CostException;
  10. import com.kcim.common.token.RedisUtil;
  11. import com.kcim.common.util.BeanUtil;
  12. import com.kcim.common.util.PageUtils;
  13. import com.kcim.dao.model.*;
  14. import com.kcim.dao.model.dto.ComputeItemCostPageDto;
  15. import com.kcim.dao.repository.*;
  16. import com.kcim.service.CenterService;
  17. import com.kcim.service.ComputeItemCostService;
  18. import com.kcim.vo.CommonParameterVo;
  19. import com.kcim.vo.SessionUserVO;
  20. import lombok.AllArgsConstructor;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  23. import org.springframework.stereotype.Service;
  24. import org.springframework.transaction.TransactionDefinition;
  25. import org.springframework.transaction.annotation.Isolation;
  26. import org.springframework.transaction.annotation.Propagation;
  27. import org.springframework.transaction.annotation.Transactional;
  28. import org.springframework.util.CollectionUtils;
  29. import org.springframework.web.context.request.RequestAttributes;
  30. import org.springframework.web.context.request.RequestContextHolder;
  31. import javax.sql.DataSource;
  32. import java.math.BigDecimal;
  33. import java.math.RoundingMode;
  34. import java.util.*;
  35. import java.util.stream.Collectors;
  36. /**
  37. * @program: CostAccount
  38. * @description: 收费项目成本计算接口实现类
  39. * @author: Wang.YS
  40. * @create: 2023-10-25 14:39
  41. **/
  42. @Service("ComputeItemCostService")
  43. @Slf4j
  44. @AllArgsConstructor
  45. public class ComputeItemCostServiceImpl implements ComputeItemCostService {
  46. /**
  47. * 项目成本计算主表
  48. */
  49. ComputeItemCostRepository repository;
  50. /**
  51. * 项目成本计算明细表
  52. */
  53. ComputeItemCostDetailRepository detailRepository;
  54. /**
  55. * 项目导入数据
  56. */
  57. ImportPatientItemRepository importPatientItemRepository;
  58. /**
  59. * 人事成本计算数据
  60. */
  61. ComputeEmpCostRepository computeEmpCostRepository;
  62. /**
  63. * 药品成本
  64. */
  65. DrugRepository drugRepository;
  66. /**
  67. * 材料成本
  68. */
  69. MaterialRepository materialRepository;
  70. /**
  71. * 设备字典
  72. */
  73. EquipmentRepository equipmentRepository;
  74. /**
  75. * 空间字典
  76. */
  77. SpaceRepository spaceRepository;
  78. /**
  79. * 标准项目字典
  80. */
  81. StandItemRepository standItemRepository;
  82. /**
  83. * 标准项目与人员对照
  84. */
  85. StandItemEmpMapRepository standItemEmpMapRepository;
  86. /**
  87. * 标准项目与设备对照
  88. */
  89. StandItemEquipmentMapRepository standItemEquipmentMapRepository;
  90. /**
  91. * 标准项目与空间对照
  92. */
  93. StandItemSpaceMapRepository standItemSpaceMapRepository;
  94. /**
  95. * 人事分类字典
  96. */
  97. EmpCostTypeRepository empCostTypeRepository;
  98. /**
  99. * 人事分类人员对照
  100. */
  101. EmpCostMapRepository empCostMapRepository;
  102. /**
  103. * 收费项目管理
  104. */
  105. ItemRepository itemRepository;
  106. CenterService centerService;
  107. DataSourceTransactionManager dataSourceTransactionManager;
  108. TransactionDefinition transactionDefinition;
  109. DataSource dataSource;
  110. RedisUtil redisUtil;
  111. private static final Integer LIMIT = 1000;
  112. /**
  113. * 成本核算-收费项目成本计算-获取列表
  114. *
  115. * @param current 当前页
  116. * @param pageSize 页容量
  117. * @param computeDate 核算年月
  118. * @param itemType 项目类别
  119. * @param itemName 项目名称
  120. * @return 列表
  121. */
  122. @Override
  123. public Object getItemCostCalculateList(Integer current, Integer pageSize, String computeDate, String itemType, String itemName) {
  124. Page<ComputeItemCostPageDto> page = repository.getByPage(current, pageSize, computeDate, itemType, itemName);
  125. if (CollectionUtils.isEmpty(page.getRecords())) {
  126. return new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current);
  127. }
  128. return new PageUtils(page.getRecords(), Math.toIntExact(page.getTotal()), pageSize, current);
  129. }
  130. /**
  131. * 成本核算-收费项目成本计算-计算
  132. *
  133. * @param computeDate 核算年月
  134. * @param currentUser
  135. * @param requestAttributes
  136. * @param progressKey
  137. */
  138. @Override
  139. @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
  140. public void itemCostCalculate(String computeDate, SessionUserVO currentUser, RequestAttributes requestAttributes, String progressKey) {
  141. // 从主线程获取用户数据 放到局部变量中
  142. try {
  143. RequestContextHolder.setRequestAttributes(requestAttributes, true);
  144. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 1.0);
  145. // connection.setAutoCommit(false);
  146. long itemSize = importPatientItemRepository.getCount(computeDate, currentUser);
  147. if (Objects.equals(itemSize, NumberConstant.ZERO_L)) {
  148. log.error("当前核算年月【" + computeDate + "】未导入收费项目数据,计算中止");
  149. throw new CostException("当前核算年月【" + computeDate + "】未导入收费项目数据,计算中止");
  150. }
  151. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 2.0);
  152. //把当月需要计算数据置成0
  153. importPatientItemRepository.updateCalculateFlag(computeDate, currentUser);
  154. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 4.0);
  155. List<Integer> integers = repository.removeByComputeDate(computeDate, currentUser);
  156. if (!CollectionUtils.isEmpty(integers)) {
  157. detailRepository.removeByItemCostId(integers, currentUser);
  158. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 10.0);
  159. }
  160. // redisUtil.set(RedisKeyConstant.PROGRESS+ progressKey,100.0);
  161. // List<PatientItemVo> items = importPatientItemRepository.getAllGroupByCompute(computeDate);
  162. //人事项目成本
  163. List<ComputeEmpCost> computeEmpCosts = computeEmpCostRepository.getByComputeDate(computeDate, currentUser);
  164. if (CollectionUtils.isEmpty(computeEmpCosts)) {
  165. log.error("当前核算年月【" + computeDate + "】人事成本未完成计算,请先完成人事成本计算,当前项目计算中止");
  166. throw new CostException("当前核算年月【" + computeDate + "】人事成本未完成计算,请先完成人事成本计算,当前项目计算中止");
  167. }
  168. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 12.0);
  169. CommonParameterVo parameter = centerService.getParameter(ParameterConstant.ITEM_CONTAINS_SPACE);
  170. String ITEM_CONTAINS_SPACE = Objects.nonNull(parameter.getValue()) ? parameter.getValue() : "0";
  171. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 14.0);
  172. //药品成本
  173. Map<String, BigDecimal> drugCostMap = drugRepository.getCostMap(currentUser);
  174. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 15.0);
  175. //材料成本
  176. Map<String, BigDecimal> materialCostMap = materialRepository.getCostMap(currentUser);
  177. //人事项目成本
  178. // List<ComputeEmpCost> computeEmpCosts = computeEmpCostRepository.getByComputeDate(computeDate,currentUser);
  179. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 16.0);
  180. //按人事分类进行分组
  181. Map<String, List<ComputeEmpCost>> empComputeCostGroup = computeEmpCosts.stream().collect(Collectors.groupingBy(ComputeEmpCost::getEmpType));
  182. //标准项目字典
  183. Map<String, StandItem> standItemMap = getStandItem(currentUser);
  184. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 17.0);
  185. //人事成本分类
  186. Map<String, EmpCostType> empCostType = getEmpCostType(currentUser);
  187. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 18.0);
  188. Map<String, String> itemStandMap = getItemStandMap(currentUser);
  189. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 20.0);
  190. //获取设备每分钟成本
  191. Map<String, BigDecimal> equipmentMinuteMap = equipmentRepository.getEquipmentMinuteMap(currentUser);
  192. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 21.0);
  193. Map<String, BigDecimal> spaceMinuteMap = spaceRepository.getSpaceMinuteMap(currentUser);
  194. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 22.0);
  195. //主表公共对象
  196. ComputeItemCost computeItemCost = new ComputeItemCost();
  197. computeItemCost.setComputeDate(computeDate);
  198. computeItemCost.setHospId(currentUser.getHospId());
  199. computeItemCost.setCreateUser(String.valueOf(currentUser.getId()));
  200. computeItemCost.setCreateTime(new Date());
  201. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 24.0);
  202. //明细表公共对象
  203. ComputeItemCostDetail costDetail = new ComputeItemCostDetail();
  204. costDetail.setHospId(currentUser.getHospId());
  205. costDetail.setCreateUser(String.valueOf(currentUser.getId()));
  206. costDetail.setCreateTime(new Date());
  207. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 25.0);
  208. long count = (itemSize + LIMIT - 1) / LIMIT;
  209. long l = 0;
  210. for (int j = 0; j < count; j++) {
  211. List<ImportPatientItem> items = importPatientItemRepository.getByNoCalculateComputeDate(computeDate, currentUser);
  212. List<ComputeItemCostDetail> saveDetails = new ArrayList<>();
  213. List<ComputeItemCost> saveCost = new ArrayList<>();
  214. if (!CollectionUtils.isEmpty(items)) {
  215. for (int i = 0; i < items.size(); i++) {
  216. ImportPatientItem item = items.get(i);
  217. ComputeItemCost itemCost = BeanUtil.convertObj(computeItemCost, ComputeItemCost.class);
  218. itemCost.setVisitNo(item.getVisitNo());
  219. itemCost.setCode(item.getItemCode());
  220. itemCost.setName(item.getItemName());
  221. String typeCode = item.getItemTypeCode();
  222. itemCost.setItemTypeCode(typeCode);
  223. itemCost.setItemType(item.getItemType());
  224. itemCost.setOrderCode(item.getOrderCode());
  225. itemCost.setOrderName(item.getOrderName());
  226. itemCost.setNum(item.getNum());
  227. itemCost.setIndex(i);
  228. saveCost.add(itemCost);
  229. costDetail.setIndex(i);
  230. List<ComputeItemCostDetail> details = setDetails(drugCostMap, materialCostMap, empComputeCostGroup, standItemMap,
  231. empCostType, equipmentMinuteMap, spaceMinuteMap, costDetail, item, typeCode, ITEM_CONTAINS_SPACE, itemStandMap);
  232. if (!CollectionUtils.isEmpty(details)) {
  233. saveDetails.addAll(details);
  234. }
  235. double percent = (l + 1) / (double) itemSize * 100;
  236. //这里对小数采用向下取整,例如99.5会取整为99
  237. percent = Math.floor(percent / 2 + 25.0);
  238. if (l == itemSize - 1) {
  239. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 98.0);
  240. } else {
  241. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, percent);
  242. }
  243. System.out.println(l + "-" + itemSize);
  244. l++;
  245. }
  246. if (!CollectionUtils.isEmpty(saveCost)) {
  247. //作废当前核算年月已有数据
  248. repository.saveBatch(saveCost, 100);
  249. if (!CollectionUtils.isEmpty(saveDetails)) {
  250. Map<Integer, Integer> indexId = saveCost.stream().collect(Collectors.toMap(ComputeItemCost::getIndex, ComputeItemCost::getId, (a, b) -> b));
  251. Map<Integer, List<ComputeItemCostDetail>> collect = saveDetails.stream().collect(Collectors.groupingBy(ComputeItemCostDetail::getIndex));
  252. List<ComputeItemCostDetail> saveCostDetails = new ArrayList<>();
  253. collect.keySet().forEach(integer -> {
  254. Integer costId = indexId.get(integer);
  255. List<ComputeItemCostDetail> details = collect.get(integer);
  256. details.forEach(detail -> detail.setItemCostId(costId));
  257. saveCostDetails.addAll(details);
  258. });
  259. detailRepository.saveBatch(saveCostDetails, 100);
  260. }
  261. }
  262. //保存完把已计算过的置1
  263. importPatientItemRepository.updateCalculateFlag(items);
  264. // connection.commit();
  265. }
  266. }
  267. redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 100.0);
  268. } catch (Exception e) {
  269. throw new CostException("收费项目计算错误:"+ e.getMessage());
  270. }
  271. // Result result = new Result();
  272. // result.setStatus(200);
  273. // result.setMsg("计算完成");
  274. // return result;
  275. }
  276. private Map<String, String> getItemStandMap(SessionUserVO currentUser) {
  277. List<Item> list = itemRepository.getList(currentUser);
  278. if (!CollectionUtils.isEmpty(list)) {
  279. List<Item> collect = list.stream().filter(f -> Objects.nonNull(f.getStandItemCode())).collect(Collectors.toList());
  280. if (!CollectionUtils.isEmpty(collect)) {
  281. return collect.stream().collect(Collectors.toMap(Item::getCode, Item::getStandItemCode, (a, b) -> b));
  282. }
  283. }
  284. return new HashMap<>();
  285. }
  286. /**
  287. * 计算收费项目明细
  288. *
  289. * @param drugCostMap 药品成本字典
  290. * @param materialCostMap 材料成本字典
  291. * @param empComputeCostGroup 人员成本计算
  292. * @param standItemMap 标准项目字典
  293. * @param empCostType 人员类别字典
  294. * @param equipmentMinuteMap 设备每分钟成本
  295. * @param spaceMinuteMap 空间每分钟成本
  296. * @param costDetail 明细表入参
  297. * @param item 收费项目
  298. * @param typeCode 项目类别
  299. * @param ITEM_CONTAINS_SPACE
  300. * @param itemStandMap
  301. * @return 项目明细出参
  302. */
  303. private List<ComputeItemCostDetail> setDetails(Map<String, BigDecimal> drugCostMap, Map<String, BigDecimal> materialCostMap,
  304. Map<String, List<ComputeEmpCost>> empComputeCostGroup, Map<String, StandItem> standItemMap,
  305. Map<String, EmpCostType> empCostType, Map<String, BigDecimal> equipmentMinuteMap,
  306. Map<String, BigDecimal> spaceMinuteMap, ComputeItemCostDetail costDetail,
  307. ImportPatientItem item, String typeCode, String ITEM_CONTAINS_SPACE,
  308. Map<String, String> itemStandMap) {
  309. List<ComputeItemCostDetail> details = new ArrayList<>();
  310. if (typeCode.equals(ItemTypeEnum.DRUG.getCode())) {
  311. // 药品 取药品收入 药品成本
  312. //取药品收入
  313. ComputeItemCostDetail income = getIncome(costDetail, item);
  314. income.setType(ReportItemTypeEnum.DRUG_INCOME.getCode());
  315. details.add(income);
  316. //药品成本
  317. ComputeItemCostDetail cost = getCost(costDetail, item, drugCostMap);
  318. cost.setType(ReportItemTypeEnum.DRUG_COST.getCode());
  319. details.add(cost);
  320. } else if (typeCode.equals(ItemTypeEnum.MATERIAL.getCode())) {
  321. //材料 取材料收入 材料成本
  322. //取材料收入
  323. ComputeItemCostDetail income = getIncome(costDetail, item);
  324. income.setType(ReportItemTypeEnum.MATERIAL_INCOME.getCode());
  325. details.add(income);
  326. //材料成本
  327. ComputeItemCostDetail cost = getCost(costDetail, item, materialCostMap);
  328. cost.setType(ReportItemTypeEnum.MATERIAL_COST.getCode());
  329. details.add(cost);
  330. } else if (typeCode.equals(ItemTypeEnum.ITEM.getCode())) {
  331. //项目 取项目收入 项目成本
  332. //取项目收费
  333. ComputeItemCostDetail income = getIncome(costDetail, item);
  334. income.setType(ReportItemTypeEnum.ITEM_INCOME.getCode());
  335. details.add(income);
  336. //当前项目的标准项目
  337. BigDecimal num = item.getNum();
  338. if (!CollectionUtils.isEmpty(itemStandMap)) {
  339. StandItem standItem = standItemMap.get(itemStandMap.get(item.getItemCode()));
  340. if (Objects.nonNull(standItem)) {
  341. BigDecimal weight = new BigDecimal("0.005");
  342. //人力成本
  343. List<StandItemEmpMap> empMaps = standItem.getEmpMaps();
  344. BigDecimal empCost = getEmpCost(empMaps, empComputeCostGroup, empCostType, item);
  345. ComputeItemCostDetail empCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  346. BigDecimal empCostNum = new BigDecimal("0.0000");
  347. if (num != null) {
  348. empCostNum = empCost.multiply(num);
  349. }
  350. empCostResult.setComputeResult(empCostNum);
  351. empCostResult.setComputeSingleResult(empCost);
  352. empCostResult.setType(ReportItemTypeEnum.WEIGHT_EMP_COST.getCode());
  353. details.add(empCostResult);
  354. // 2023.12.18 添加加成算法
  355. BigDecimal riskDegree = standItem.getRiskDegree();
  356. BigDecimal technicalDifficulty = standItem.getTechnicalDifficulty();
  357. if (riskDegree == null) {
  358. riskDegree = BigDecimal.ZERO;
  359. }
  360. if (technicalDifficulty == null) {
  361. technicalDifficulty = BigDecimal.ZERO;
  362. }
  363. BigDecimal technical = technicalDifficulty.multiply(weight).add(BigDecimal.ONE);
  364. BigDecimal risk = riskDegree.multiply(weight).add(BigDecimal.ONE);
  365. BigDecimal bigDecimal = empCost.multiply(technical).multiply(risk).setScale(4, RoundingMode.HALF_UP);
  366. BigDecimal bigDecimalNum = empCostNum.multiply(technical).multiply(risk).setScale(4, RoundingMode.HALF_UP);
  367. ComputeItemCostDetail empWeightCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  368. empWeightCostResult.setComputeResult(bigDecimalNum);
  369. empWeightCostResult.setComputeSingleResult(bigDecimal);
  370. empWeightCostResult.setType(ReportItemTypeEnum.EMP_COST.getCode());
  371. details.add(empWeightCostResult);
  372. //设备成本
  373. List<StandItemEquipmentMap> equipmentMaps = standItem.getEquipmentMaps();
  374. BigDecimal equipmentCost = getEquipmentCost(equipmentMaps, equipmentMinuteMap);
  375. ComputeItemCostDetail equipmentCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  376. BigDecimal equipmentCostNum = new BigDecimal("0.0000");
  377. if (num != null) {
  378. equipmentCostNum = equipmentCost.multiply(num);
  379. }
  380. equipmentCostResult.setComputeResult(equipmentCostNum);
  381. equipmentCostResult.setComputeSingleResult(equipmentCost);
  382. equipmentCostResult.setType(ReportItemTypeEnum.EQUIPMENT_COST.getCode());
  383. details.add(equipmentCostResult);
  384. //空间成本
  385. List<StandItemSpaceMap> spaceMaps = standItem.getSpaceMaps();
  386. BigDecimal spaceCost = getSpaceCost(spaceMaps, spaceMinuteMap);
  387. ComputeItemCostDetail spaceCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  388. BigDecimal spaceCostNum = new BigDecimal("0.0000");
  389. if (num != null) {
  390. spaceCostNum = spaceCost.multiply(num);
  391. }
  392. spaceCostResult.setComputeSingleResult(spaceCost);
  393. spaceCostResult.setComputeResult(spaceCostNum);
  394. spaceCostResult.setType(ReportItemTypeEnum.SPACE_COST.getCode());
  395. details.add(spaceCostResult);
  396. //项目成本=人力成本+设备成本+空间成本
  397. ComputeItemCostDetail cost = getCost(costDetail, item, materialCostMap);
  398. cost.setType(ReportItemTypeEnum.ITEM_COST.getCode());
  399. if (ITEM_CONTAINS_SPACE.equals(NumberConstant.ONE_S)) {
  400. //项目成本=人力成本+设备成本
  401. cost.setComputeResult(bigDecimalNum.add(equipmentCostNum));
  402. cost.setComputeSingleResult(bigDecimal.add(equipmentCost));
  403. } else {
  404. //项目成本=人力成本+设备成本+空间成本
  405. cost.setComputeResult(bigDecimalNum.add(equipmentCostNum).add(spaceCostNum));
  406. cost.setComputeSingleResult(bigDecimal.add(equipmentCost).add(spaceCost));
  407. }
  408. details.add(cost);
  409. } else {
  410. //人力成本
  411. ComputeItemCostDetail empCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  412. if (empCostResult != null) {
  413. empCostResult.setComputeResult(BigDecimal.ZERO);
  414. empCostResult.setComputeSingleResult(BigDecimal.ZERO);
  415. empCostResult.setType(ReportItemTypeEnum.EMP_COST.getCode());
  416. }
  417. details.add(empCostResult);
  418. //设备成本
  419. ComputeItemCostDetail equipmentCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  420. if (equipmentCostResult != null) {
  421. equipmentCostResult.setComputeResult(BigDecimal.ZERO);
  422. equipmentCostResult.setComputeSingleResult(BigDecimal.ZERO);
  423. equipmentCostResult.setType(ReportItemTypeEnum.EQUIPMENT_COST.getCode());
  424. }
  425. details.add(equipmentCostResult);
  426. //空间成本
  427. ComputeItemCostDetail spaceCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  428. if (spaceCostResult != null) {
  429. spaceCostResult.setComputeResult(BigDecimal.ZERO);
  430. spaceCostResult.setComputeSingleResult(BigDecimal.ZERO);
  431. spaceCostResult.setType(ReportItemTypeEnum.SPACE_COST.getCode());
  432. }
  433. details.add(spaceCostResult);
  434. //项目成本=人力成本+设备成本+空间成本
  435. ComputeItemCostDetail cost = getCost(costDetail, item, materialCostMap);
  436. cost.setType(ReportItemTypeEnum.ITEM_COST.getCode());
  437. cost.setComputeResult(BigDecimal.ZERO);
  438. cost.setComputeSingleResult(BigDecimal.ZERO);
  439. details.add(cost);
  440. }
  441. } else {
  442. //人力成本
  443. ComputeItemCostDetail empCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  444. if (empCostResult != null) {
  445. empCostResult.setComputeResult(BigDecimal.ZERO);
  446. empCostResult.setComputeSingleResult(BigDecimal.ZERO);
  447. empCostResult.setType(ReportItemTypeEnum.EMP_COST.getCode());
  448. }
  449. details.add(empCostResult);
  450. //设备成本
  451. ComputeItemCostDetail equipmentCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  452. if (equipmentCostResult != null) {
  453. equipmentCostResult.setComputeResult(BigDecimal.ZERO);
  454. equipmentCostResult.setComputeSingleResult(BigDecimal.ZERO);
  455. equipmentCostResult.setType(ReportItemTypeEnum.EQUIPMENT_COST.getCode());
  456. }
  457. details.add(equipmentCostResult);
  458. //空间成本
  459. ComputeItemCostDetail spaceCostResult = BeanUtil.convertObj(costDetail, ComputeItemCostDetail.class);
  460. if (spaceCostResult != null) {
  461. spaceCostResult.setComputeResult(BigDecimal.ZERO);
  462. spaceCostResult.setComputeSingleResult(BigDecimal.ZERO);
  463. spaceCostResult.setType(ReportItemTypeEnum.SPACE_COST.getCode());
  464. }
  465. details.add(spaceCostResult);
  466. //项目成本=人力成本+设备成本+空间成本
  467. ComputeItemCostDetail cost = getCost(costDetail, item, materialCostMap);
  468. cost.setType(ReportItemTypeEnum.ITEM_COST.getCode());
  469. cost.setComputeResult(BigDecimal.ZERO);
  470. cost.setComputeSingleResult(BigDecimal.ZERO);
  471. details.add(cost);
  472. }
  473. } //其他 目前不知算法
  474. return details;
  475. }
  476. /**
  477. * 获取空间成本
  478. *
  479. * @param spaceMaps 标准项目空间成本对照
  480. * @param spaceMinuteMap 每分钟空间成本
  481. * @return 空间成本
  482. */
  483. private BigDecimal getSpaceCost(List<StandItemSpaceMap> spaceMaps, Map<String, BigDecimal> spaceMinuteMap) {
  484. if (!CollectionUtils.isEmpty(spaceMaps)) {
  485. BigDecimal totalCost = new BigDecimal("0.0000");
  486. for (StandItemSpaceMap space : spaceMaps) {
  487. //设备每分钟成本
  488. BigDecimal bigDecimal = spaceMinuteMap.get(space.getSpaceCode());
  489. //设备成本=每分钟成本*数量*执行时间
  490. totalCost = bigDecimal != null ? totalCost.add(bigDecimal.multiply(space.getExecuteTime()).multiply(space.getNum())) : totalCost.add(BigDecimal.ZERO);
  491. }
  492. return totalCost;
  493. } else {
  494. return new BigDecimal("0.0000");
  495. }
  496. }
  497. /**
  498. * 获取设备成本
  499. *
  500. * @param equipmentMaps 标准项目设备对照
  501. * @param equipmentMinuteMap 设备每分钟成字典
  502. * @return 设备成本
  503. */
  504. private BigDecimal getEquipmentCost(List<StandItemEquipmentMap> equipmentMaps, Map<String, BigDecimal> equipmentMinuteMap) {
  505. if (!CollectionUtils.isEmpty(equipmentMaps)) {
  506. BigDecimal totalCost = new BigDecimal("0.0000");
  507. for (StandItemEquipmentMap equipmentMap : equipmentMaps) {
  508. //设备每分钟成本
  509. BigDecimal bigDecimal = equipmentMinuteMap.get(equipmentMap.getEquipmentCode());
  510. //设备成本=每分钟成本*数量*执行时间
  511. totalCost = totalCost.add(bigDecimal.multiply(equipmentMap.getExecuteTime()).multiply(equipmentMap.getNum()));
  512. }
  513. return totalCost;
  514. } else {
  515. return new BigDecimal("0.0000");
  516. }
  517. }
  518. private BigDecimal getEmpCost(List<StandItemEmpMap> empMaps, Map<String, List<ComputeEmpCost>> empCostGroup,
  519. Map<String, EmpCostType> empCostType, ImportPatientItem item) {
  520. /*
  521. 单位人事成本获取规则:
  522. 人员类别的计算方式为科室的:按执行科室取对应科室的每分钟成本,取不到则取执行人对应人事分类的每分钟成本
  523. 人员类别的计算方式为岗位的:取执行人对应岗位的每分钟成本,取不到则取执行人对应人事分类的每分钟成本
  524. 人员类别的计算方式为人事分类的:取执行人对应人事分类的每分钟成本
  525. 人力成本=每分钟成本*数量*执行时间
  526. */
  527. if (!CollectionUtils.isEmpty(empMaps)) {
  528. BigDecimal totalCost = new BigDecimal("0.0000");
  529. for (StandItemEmpMap empMap : empMaps) {
  530. //标准项目人员对照
  531. String empTypeCode = empMap.getEmpTypeCode();
  532. BigDecimal num = empMap.getNum();
  533. BigDecimal executeTime = empMap.getExecuteTime();
  534. //人事分类
  535. EmpCostType costType = empCostType.get(empTypeCode);
  536. //计算方式
  537. String computeType = costType.getComputeType();
  538. //人事成本计算数据
  539. List<ComputeEmpCost> computeEmpCosts = empCostGroup.get(empTypeCode);
  540. //每分钟成本
  541. Map<String, BigDecimal> minuteCost = computeEmpCosts.stream().collect(Collectors.toMap(ComputeEmpCost::getCode, ComputeEmpCost::getMinuteCost, (a, b) -> b));
  542. //人事分类对应的人员信息
  543. if (computeType.equals(EmpCostComputeTypeEnum.DEPARTMENT.getCode())) {
  544. //人员类别的计算方式为科室的:按执行科室取对应科室的每分钟成本,取不到当前人事分类的每分钟成本
  545. //当前项目执行科室
  546. String departmentCode = item.getExecuteDepartmentCode();
  547. BigDecimal bigDecimal = minuteCost.get(departmentCode);
  548. if (bigDecimal == null) {
  549. bigDecimal = minuteCost.get(empTypeCode);
  550. }
  551. totalCost = totalCost.add(bigDecimal.multiply(executeTime).multiply(num));
  552. } else if (computeType.equals(EmpCostComputeTypeEnum.POSITION.getCode())) {
  553. String userCode = item.getExecuteUserCode();
  554. List<EmpCostMap> empCostTypeMaps = costType.getEmpCostMaps();
  555. if (!CollectionUtils.isEmpty(empCostTypeMaps)) {
  556. Map<String, String> empPositionMap = empCostTypeMaps.stream().collect(Collectors.toMap(EmpCostMap::getAccount, EmpCostMap::getPosition, (a, b) -> b));
  557. String position = empPositionMap.get(userCode);
  558. BigDecimal bigDecimal = minuteCost.get(position);
  559. if (bigDecimal == null) {
  560. bigDecimal = minuteCost.get(empTypeCode);
  561. }
  562. totalCost = totalCost.add(bigDecimal.multiply(executeTime).multiply(num));
  563. } else {
  564. BigDecimal bigDecimal = minuteCost.get(empTypeCode);
  565. totalCost = totalCost.add(bigDecimal.multiply(executeTime).multiply(num));
  566. }
  567. } else {
  568. BigDecimal bigDecimal = minuteCost.get(empTypeCode);
  569. totalCost = totalCost.add(bigDecimal.multiply(executeTime).multiply(num));
  570. }
  571. }
  572. return totalCost;
  573. } else {
  574. return new BigDecimal("0.0000");
  575. }
  576. }
  577. private Map<String, EmpCostType> getEmpCostType(SessionUserVO currentUser) {
  578. List<EmpCostType> empCostTypes = empCostTypeRepository.getList(currentUser);
  579. if (CollectionUtils.isEmpty(empCostTypes)) {
  580. throw new CostException("人事成本分类,请先添加人事成本分类再进行计算,当前项目计算中止");
  581. }
  582. List<EmpCostMap> empCostMaps = empCostMapRepository.getList(currentUser);
  583. Map<String, List<EmpCostMap>> empMapGroup = new HashMap<>();
  584. if (!CollectionUtils.isEmpty(empCostMaps)) {
  585. empMapGroup = empCostMaps.stream().collect(Collectors.groupingBy(EmpCostMap::getCostTypeCode));
  586. }
  587. Map<String, EmpCostType> map = new HashMap<>();
  588. for (EmpCostType empCostType : empCostTypes) {
  589. empCostType.setEmpCostMaps(empMapGroup.get(empCostType.getCostTypeCode()));
  590. map.put(empCostType.getCostTypeCode(), empCostType);
  591. }
  592. return map;
  593. }
  594. /**
  595. * 获取标准项目字典
  596. *
  597. * @return 字典列表
  598. */
  599. private Map<String, StandItem> getStandItem(SessionUserVO currentUser) {
  600. //标准项目字典
  601. List<StandItem> list = standItemRepository.getList(currentUser);
  602. if (CollectionUtils.isEmpty(list)) {
  603. throw new CostException("标准项目未维护,请先添加标准项目再进行计算,当前项目计算中止");
  604. }
  605. //标准项目字典人员对照
  606. List<StandItemEmpMap> empMapList = standItemEmpMapRepository.getList(currentUser);
  607. Map<String, List<StandItemEmpMap>> empMapGroup = new HashMap<>();
  608. if (!CollectionUtils.isEmpty(empMapList)) {
  609. empMapGroup = empMapList.stream().collect(Collectors.groupingBy(StandItemEmpMap::getStandItemCode));
  610. }
  611. //标准项目字典空间对照
  612. List<StandItemSpaceMap> spaceMapList = standItemSpaceMapRepository.getList(currentUser);
  613. Map<String, List<StandItemSpaceMap>> spaceMapGroup = new HashMap<>();
  614. if (!CollectionUtils.isEmpty(spaceMapList)) {
  615. spaceMapGroup = spaceMapList.stream().collect(Collectors.groupingBy(StandItemSpaceMap::getStandItemCode));
  616. }
  617. //标准项目字典设备对照
  618. List<StandItemEquipmentMap> equipmentMapList = standItemEquipmentMapRepository.getList(currentUser);
  619. Map<String, List<StandItemEquipmentMap>> equipmentMapGroup = new HashMap<>();
  620. if (!CollectionUtils.isEmpty(equipmentMapList)) {
  621. equipmentMapGroup = equipmentMapList.stream().collect(Collectors.groupingBy(StandItemEquipmentMap::getStandItemCode));
  622. }
  623. Map<String, StandItem> map = new HashMap<>();
  624. for (StandItem standItem : list) {
  625. standItem.setEmpMaps(empMapGroup.get(standItem.getCode()));
  626. standItem.setEquipmentMaps(equipmentMapGroup.get(standItem.getCode()));
  627. standItem.setSpaceMaps(spaceMapGroup.get(standItem.getCode()));
  628. map.put(standItem.getCode(), standItem);
  629. }
  630. return map;
  631. }
  632. /**
  633. * 获取收入对象
  634. *
  635. * @param detail 公用明细
  636. * @param item 导入项目
  637. * @return 收入对象
  638. */
  639. private ComputeItemCostDetail getIncome(ComputeItemCostDetail detail, ImportPatientItem item) {
  640. ComputeItemCostDetail result = BeanUtil.convertObj(detail, ComputeItemCostDetail.class);
  641. result.setComputeResult(item.getAmount());
  642. result.setComputeSingleResult(item.getPrice());
  643. return result;
  644. }
  645. /**
  646. * 获取成本对象
  647. *
  648. * @param detail 公用明细
  649. * @param item 导入项目
  650. * @param costMap 成本字典
  651. * @return 成本对象
  652. */
  653. private ComputeItemCostDetail getCost(ComputeItemCostDetail detail, ImportPatientItem item, Map<String, BigDecimal> costMap) {
  654. ComputeItemCostDetail result = BeanUtil.convertObj(detail, ComputeItemCostDetail.class);
  655. BigDecimal bigDecimal = costMap.get(item.getItemCode());
  656. BigDecimal num = item.getNum();
  657. if (bigDecimal != null && num != null) {
  658. result.setComputeResult(bigDecimal.multiply(num));
  659. result.setComputeSingleResult(bigDecimal);
  660. } else if(bigDecimal != null){
  661. result.setComputeSingleResult(bigDecimal);
  662. }else {
  663. log.info("【" + item.getItemName() + "】未找到成本信息,默认为 0");
  664. result.setComputeResult(BigDecimal.ZERO);
  665. result.setComputeSingleResult(BigDecimal.ZERO);
  666. }
  667. return result;
  668. }
  669. @Override
  670. public List<String> getItemTypeList() {
  671. List<String> s = new ArrayList<>();
  672. s.add(ReportItemTypeEnum.DRUG_INCOME.getCode());
  673. s.add(ReportItemTypeEnum.MATERIAL_INCOME.getCode());
  674. s.add(ReportItemTypeEnum.ITEM_INCOME.getCode());
  675. s.add(ReportItemTypeEnum.DRUG_COST.getCode());
  676. s.add(ReportItemTypeEnum.MATERIAL_COST.getCode());
  677. s.add(ReportItemTypeEnum.ITEM_COST.getCode());
  678. s.add(ReportItemTypeEnum.EMP_COST.getCode());
  679. s.add(ReportItemTypeEnum.EQUIPMENT_COST.getCode());
  680. s.add(ReportItemTypeEnum.SPACE_COST.getCode());
  681. return s;
  682. }
  683. }