HospProfitAndLossServiceImpl.java 128 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462
  1. package com.kcim.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DatePattern;
  4. import cn.hutool.core.date.DateTime;
  5. import cn.hutool.core.date.DateUtil;
  6. import cn.hutool.core.util.ReUtil;
  7. import cn.hutool.core.util.StrUtil;
  8. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  9. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  10. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  11. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  12. import com.google.common.collect.ImmutableMap;
  13. import com.kcim.common.constants.Constant;
  14. import com.kcim.common.constants.NumberConstant;
  15. import com.kcim.common.constants.ParameterConstant;
  16. import com.kcim.common.constants.SQLParameter;
  17. import com.kcim.common.enums.*;
  18. import com.kcim.common.exception.CostException;
  19. import com.kcim.common.file.MinioConfig;
  20. import com.kcim.common.file.MinioFileUtil;
  21. import com.kcim.common.util.*;
  22. import com.kcim.common.util.excel.ExcelPoiUtil;
  23. import com.kcim.common.util.excel.entity.ColEntity;
  24. import com.kcim.common.util.excel.entity.TitleEntity;
  25. import com.kcim.dao.mapper.HospProfitAndLossMapper;
  26. import com.kcim.dao.model.*;
  27. import com.kcim.service.*;
  28. import com.kcim.vo.*;
  29. import com.kcim.web.reponse.BatchCostProfitResponse;
  30. import lombok.extern.slf4j.Slf4j;
  31. import org.apache.commons.fileupload.FileItem;
  32. import org.apache.commons.fileupload.FileItemFactory;
  33. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  34. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  35. import org.jetbrains.annotations.NotNull;
  36. import org.springframework.stereotype.Service;
  37. import org.springframework.transaction.annotation.Propagation;
  38. import org.springframework.transaction.annotation.Transactional;
  39. import org.springframework.util.CollectionUtils;
  40. import org.springframework.util.ObjectUtils;
  41. import org.springframework.web.multipart.MultipartFile;
  42. import org.springframework.web.multipart.commons.CommonsMultipartFile;
  43. import java.io.IOException;
  44. import java.io.InputStream;
  45. import java.io.OutputStream;
  46. import java.math.BigDecimal;
  47. import java.math.RoundingMode;
  48. import java.text.DecimalFormat;
  49. import java.util.*;
  50. import java.util.concurrent.ConcurrentHashMap;
  51. import java.util.concurrent.atomic.AtomicReference;
  52. import java.util.function.UnaryOperator;
  53. import java.util.stream.Collectors;
  54. @Slf4j
  55. @Service("hospProfitAndLossService")
  56. public class HospProfitAndLossServiceImpl extends ServiceImpl<HospProfitAndLossMapper, HospProfitAndLoss> implements HospProfitAndLossService {
  57. // @Value("${file.filelocal}")
  58. // private String hospProfitReportUrl;
  59. //
  60. // @Value("${file.serverUrl}")
  61. // private String serverUrl;
  62. private final ReportFormService reportFormService;
  63. private final IncomeCollectionService collectionService;
  64. private final AllocationQueryService allocationQueryService;
  65. private final AllocationService allocationService;
  66. private final ReportRelationService reportRelationService;
  67. private final CostShareLevelService shareLevelService;
  68. private final CostOtherPaymentsDataService otherPaymentsDataService;
  69. private final ResponsibilityService responsibilityService;
  70. private final CostAccountShareService accountShareService;
  71. private final FileRecordService fileRecordService;
  72. private final SqlService sqlService;
  73. private final CenterService centerService;
  74. private final MinioConfig minioConfig;
  75. private final MinioFileUtil minioFileUtil;
  76. public HospProfitAndLossServiceImpl(ReportFormService reportFormService,
  77. IncomeCollectionService collectionService,
  78. AllocationQueryService allocationQueryService,
  79. AllocationService allocationService, ReportRelationService reportRelationService,
  80. CostShareLevelService shareLevelService,
  81. CostOtherPaymentsDataService otherPaymentsDataService,
  82. ResponsibilityService responsibilityService,
  83. CostAccountShareService accountShareService,
  84. FileRecordService fileRecordService,
  85. MinioConfig minioConfig,
  86. MinioFileUtil minioFileUtil,
  87. SqlService sqlService,
  88. CenterService centerService
  89. ) {
  90. this.reportFormService = reportFormService;
  91. this.collectionService = collectionService;
  92. this.allocationQueryService = allocationQueryService;
  93. this.allocationService = allocationService;
  94. this.reportRelationService = reportRelationService;
  95. this.shareLevelService = shareLevelService;
  96. this.otherPaymentsDataService = otherPaymentsDataService;
  97. this.responsibilityService = responsibilityService;
  98. this.accountShareService = accountShareService;
  99. this.fileRecordService = fileRecordService;
  100. this.minioConfig = minioConfig;
  101. this.minioFileUtil = minioFileUtil;
  102. this.sqlService=sqlService;
  103. this.centerService=centerService;
  104. }
  105. /**
  106. * 计算全院损益
  107. *
  108. * @param date yyyy-MM-dd 时间
  109. * @param hospId 医院id
  110. */
  111. @Override
  112. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
  113. public void calc(String date, Long hospId) {
  114. reportFormService.checkExistLoss(hospId);
  115. DateTime parse = DateUtil.parse(date);
  116. int year = DateUtil.year(parse);
  117. int month = DateUtil.month(parse) + 1;
  118. this.remove(new LambdaQueryWrapper<HospProfitAndLoss>().eq(HospProfitAndLoss::getDateYear, year).eq(HospProfitAndLoss::getDateMonth, month).eq(HospProfitAndLoss::getHospId, hospId));
  119. // 得到全院损益计算报表
  120. List<ReportForm> reportForms = reportFormService.getListByReportType(hospId, ReportTypeEnum.HOSP_PROFIT_LOSS.getType());
  121. if (CollUtil.isEmpty(reportForms)) {
  122. throw new CostException("医院未设置全院损益计算报表");
  123. }
  124. // 得到这个月所有收入数据
  125. List<IncomeCollection> incomes = collectionService.getCollectionsByDate(year, month, hospId);
  126. if (incomes.isEmpty()) {
  127. throw new CostException("医院未归集本月收入数据");
  128. }
  129. // 得到这个月的所有成本数据
  130. List<AllocationQuery> allocationQueries = allocationQueryService.getAllByDate(hospId, year, month);
  131. if (allocationQueries.isEmpty()) {
  132. throw new CostException("医院未分摊本月数据");
  133. }
  134. List<HospProfitAndLoss> list = new ArrayList<>();
  135. List<ReportForm> parentForms = reportForms.stream().filter(i -> i.getParentId().equals(0L)).collect(Collectors.toList());
  136. for (ReportForm parentForm : parentForms) {
  137. Long parentId = parentForm.getId();
  138. List<ReportForm> children = reportForms.stream().filter(i -> i.getParentId().equals(parentId)).collect(Collectors.toList());
  139. for (ReportForm child : children) {
  140. Integer calcType = child.getCalcType();
  141. if (calcType == CalcTypeEnum.BY_ACCOUNT.getType()) {
  142. // 按会计科目计算单的话
  143. calcByAccount(hospId, child, incomes, list, allocationQueries, month, year);
  144. } else if (calcType == CalcTypeEnum.BY_SHARE_LEVEL.getType()) {
  145. // 分摊层级计算
  146. calcByShareLevel(hospId, child, list, year, month);
  147. } else if (calcType == CalcTypeEnum.LITTER_COUNT.getType()) {
  148. // 处理小计 todo 默认认为 小计都是在同一个下面最后一个
  149. calcByLitterCount(year, month, child, children, list, hospId);
  150. } else if (calcType == CalcTypeEnum.CALC_FORMULA.getType()) {
  151. // 按公式 (要保证总合计放到最后呀)
  152. calcByFormula(year, month, child, children, list);
  153. } else if (calcType == CalcTypeEnum.BY_RESPONSIBILITY.getType()) {
  154. // 责任中心
  155. calcByResponsibility(hospId, child, allocationQueries, list, year, month);
  156. } else if (calcType == CalcTypeEnum.NO_CONFIG.getType()) {
  157. // 不设置不计算
  158. } else {
  159. }
  160. }
  161. }
  162. // 处理医院其他收支
  163. List<CostOtherPaymentsData> otherPaymentsDatas = otherPaymentsDataService.getByMonth(year, month, hospId);
  164. if (!otherPaymentsDatas.isEmpty()) {
  165. otherPaymentsDatas.forEach(ele -> {
  166. HospProfitAndLoss loss = new HospProfitAndLoss();
  167. loss.setDateYear(year).setDateMonth(month).setReportName(ele.getPaymentsName()).setReportNum(ele.getId().intValue())
  168. .setCreateTime(System.currentTimeMillis()).setAmount(ele.getTotalAmount()).setHospId(hospId);
  169. // if (ele.getPaymentsType() == 2) {
  170. // loss.setAmount(BigDecimal.ZERO.subtract(ele.getTotalAmount()));
  171. // }
  172. list.add(loss);
  173. });
  174. }
  175. this.saveBatch(list);
  176. }
  177. /**
  178. * 计算全院损益
  179. * @param date yyyy-MM-dd 时间
  180. * @param hospId 医院id
  181. * @param reportType 报表类型
  182. */
  183. @Override
  184. public void calcHospProfit(String date, Long hospId, Integer reportType){
  185. calcHospProfitAction(date,hospId,reportType);
  186. //需要用代码计算同环比时
  187. if(IsNeedCalcYM()){
  188. handleSpecificMonthsCalculation(hospId, date, reportType);
  189. }
  190. execHospProfitSql(date,date);
  191. }
  192. @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
  193. public void calcHospProfitAction(String date, Long hospId, Integer reportType) {
  194. List<Responsibility> leafResp = responsibilityService.getLeafResp(hospId);
  195. DateTime parse = DateUtil.parse(date);
  196. int year = DateUtil.year(parse);
  197. int month = DateUtil.month(parse) + 1;
  198. this.remove(
  199. new LambdaQueryWrapper<HospProfitAndLoss>()
  200. .eq(HospProfitAndLoss::getDateYear, year)
  201. .eq(HospProfitAndLoss::getDateMonth, month)
  202. .eq(HospProfitAndLoss::getHospId, hospId)
  203. .eq(HospProfitAndLoss::getReportType, reportType)
  204. );
  205. // 得到全院损益计算报表
  206. List<ReportForm> reportForms = reportFormService.getListByReportType(hospId, reportType);
  207. if (CollUtil.isEmpty(reportForms)) {
  208. throw new CostException("医院未设置全院损益计算报表");
  209. }
  210. reportFormService.checkExistLoss(hospId,reportType);
  211. // 得到这个月所有收入数据
  212. List<IncomeCollection> incomes = collectionService.getCollectionsByDate(year, month, hospId);
  213. if (incomes.isEmpty()) {
  214. throw new CostException("医院未归集本月收入数据");
  215. }
  216. Map<Long, List<ReportRelation>> reportRelationMap = reportRelationService.list(new QueryWrapper<ReportRelation>().lambda().eq(ReportRelation::getHospId, hospId)).stream().collect(Collectors.groupingBy(ReportRelation::getReportId));
  217. // 得到这个月的所有成本数据
  218. List<AllocationQuery> allocationQueries = allocationQueryService.getAllByDate(hospId, year, month);
  219. if (allocationQueries.isEmpty()) {
  220. throw new CostException("医院未分摊本月数据");
  221. }
  222. List<AllocationQueryReportVO> allocationQueryReportVOList = BeanUtil.convertList(allocationQueries, AllocationQueryReportVO.class);
  223. allocationQueryReportVOList.forEach(i -> {
  224. i.setAccountingCodes(Arrays.asList(i.getAccountingCode().split(StrUtil.COMMA)));
  225. i.setAccountingNames(Arrays.asList(i.getAccountingName().split(StrUtil.COMMA)));
  226. });
  227. // 查询分摊的报表数据 后面的计算方式需要使用 小计等需要使用
  228. List<Allocation> allocationList = allocationService.list(new QueryWrapper<Allocation>().lambda().eq(Allocation::getHospId, hospId)
  229. .eq(year > 0, Allocation::getDateYear, year).eq(month > 0, Allocation::getDateMonth, month));
  230. if (CollUtil.isEmpty(allocationList)) {
  231. throw new CostException(500, "分摊报表数据不存在");
  232. }
  233. // 查询最后一个层级的责任中心
  234. List<CostShareLevel> costShareLevelList = shareLevelService.list(new QueryWrapper<CostShareLevel>().lambda()
  235. .eq(CostShareLevel::getHospId, hospId).orderByDesc(CostShareLevel::getLeverSort));
  236. if (CollUtil.isEmpty(costShareLevelList)) {
  237. throw new CostException(500, "分摊层级未设置");
  238. }
  239. List<HospProfitAndLossVo> listVo = new ArrayList<>();
  240. // List<ReportForm> parentForms = reportForms.stream().filter(i -> i.getParentId().equals(0L)).collect(Collectors.toList());
  241. int finalYear = year;
  242. int finalMonth = month;
  243. leafResp.forEach(i -> {
  244. reportForms.forEach(j -> {
  245. HospProfitAndLossVo hospProfitAndLossVo = new HospProfitAndLossVo();
  246. hospProfitAndLossVo.setDateYear(finalYear);
  247. hospProfitAndLossVo.setDateMonth(finalMonth);
  248. hospProfitAndLossVo.setReportNum(j.getNum());
  249. hospProfitAndLossVo.setReportName(j.getReportName());
  250. hospProfitAndLossVo.setResponsibilityCode(i.getResponsibilityCode());
  251. hospProfitAndLossVo.setResponsibilityName(i.getResponsibilityName());
  252. hospProfitAndLossVo.setCostType(NumberConstant.ZERO);
  253. hospProfitAndLossVo.setIncomeType(NumberConstant.ZERO);
  254. hospProfitAndLossVo.setHospId(hospId);
  255. hospProfitAndLossVo.setType(j.getCostType());
  256. hospProfitAndLossVo.setFraction(j.getFraction());
  257. hospProfitAndLossVo.setReportId(j.getId());
  258. hospProfitAndLossVo.setReportNum(j.getNum());
  259. hospProfitAndLossVo.setCalcType(j.getCalcType());
  260. hospProfitAndLossVo.setReportName(j.getReportName());
  261. hospProfitAndLossVo.setCalcFormula(j.getCalcFormula());
  262. hospProfitAndLossVo.setReportParentId(j.getParentId());
  263. listVo.add(hospProfitAndLossVo);
  264. });
  265. });
  266. Map<Long, List<HospProfitAndLossVo>> listMap = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getReportId));
  267. List<HospProfitAndLossVo> allList = BeanUtil.convertList(listVo, HospProfitAndLossVo.class);
  268. // 记录每一次计算的钱
  269. //所有小计 总计单独处理
  270. listVo.forEach(i -> {
  271. Integer calcType = i.getCalcType();
  272. if (NumberConstant.ONE.equals(calcType)) {
  273. // TODO 按照会计科目进行计算
  274. i.setAmount(setAccountReportData(i, incomes, allocationQueryReportVOList, reportRelationMap));
  275. } else if (NumberConstant.TWO.equals(calcType)) {
  276. // TODO 按照分摊层级进行计算
  277. i.setAmount(setShareLevelReportData(i, reportRelationMap, allocationList));
  278. } else if (NumberConstant.THREE.equals(calcType)) {
  279. // TODO 按照小计进行计算
  280. i.setAmount(setSubtotal(i, costShareLevelList, listMap, listVo, incomes, allocationQueryReportVOList, reportRelationMap, allocationList, allList));
  281. } else if (NumberConstant.FOUR.equals(calcType)) {
  282. // TODO 按照计算公式进行计算
  283. // i.setAmount(setCalculation(i, listVo, costShareLevelList, listMap, incomes, allocationQueryReportVOList, reportRelationMap, allocationList, allList));
  284. } else if (NumberConstant.FIVE.equals(calcType)) {
  285. // TODO 按照责任中心进行计算
  286. i.setAmount(setResponsibilityCode(i, reportRelationMap, allocationList, allList));
  287. } else {
  288. i.setAmount(new BigDecimal("0.000000"));
  289. }
  290. });
  291. //计算占比
  292. if (CollectionUtils.isEmpty(listVo)) {
  293. return;
  294. }
  295. List<HospProfitAndLossVo> listSum = new ArrayList<>();
  296. //把所有数据按报表项目汇总
  297. for (ReportForm j : reportForms) {
  298. HospProfitAndLossVo hospProfitAndLossVo = new HospProfitAndLossVo();
  299. hospProfitAndLossVo.setDateYear(finalYear);
  300. hospProfitAndLossVo.setDateMonth(finalMonth);
  301. hospProfitAndLossVo.setReportNum(j.getNum());
  302. hospProfitAndLossVo.setReportName(j.getReportName());
  303. hospProfitAndLossVo.setCostType(NumberConstant.ZERO);
  304. hospProfitAndLossVo.setIncomeType(NumberConstant.ZERO);
  305. hospProfitAndLossVo.setHospId(hospId);
  306. hospProfitAndLossVo.setType(j.getCostType());
  307. hospProfitAndLossVo.setFraction(j.getFraction());
  308. hospProfitAndLossVo.setReportId(j.getId());
  309. hospProfitAndLossVo.setReportNum(j.getNum());
  310. hospProfitAndLossVo.setCalcType(j.getCalcType());
  311. hospProfitAndLossVo.setReportName(j.getReportName());
  312. hospProfitAndLossVo.setCalcFormula(j.getCalcFormula());
  313. hospProfitAndLossVo.setReportParentId(j.getParentId());
  314. listSum.add(hospProfitAndLossVo);
  315. }
  316. Map<Integer, List<HospProfitAndLossVo>> reportNumGroup = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getReportNum));
  317. Map<Integer, BigDecimal> reportNumSumMap = new HashMap<>();
  318. reportNumGroup.forEach((reportNum, hospProfitAndLossList) -> {
  319. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000000"));
  320. for (HospProfitAndLossVo hospProfitAndLoss : hospProfitAndLossList) {
  321. if (hospProfitAndLoss.getAmount() != null) {
  322. sum.updateAndGet(f -> f.add(hospProfitAndLoss.getAmount()));
  323. }
  324. }
  325. reportNumSumMap.put(reportNum, sum.get());
  326. });
  327. for (HospProfitAndLossVo costProfitVo : listSum) {
  328. BigDecimal bigDecimal = reportNumSumMap.get(costProfitVo.getReportNum());
  329. if (bigDecimal != null) {
  330. costProfitVo.setAmount(bigDecimal);
  331. } else {
  332. costProfitVo.setAmount(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP));
  333. }
  334. }
  335. //单独计算计算公式数据
  336. setCalculationAmount(listSum);
  337. //收入
  338. List<HospProfitAndLossVo> profitIncomeList = listSum.stream().filter(f -> f.getType().equals(NumberConstant.ONE)).collect(Collectors.toList());
  339. List<HospProfitAndLossVo> profitIncome = costPercent(profitIncomeList);
  340. //成本
  341. List<HospProfitAndLossVo> profitCostList = listSum.stream().filter(f -> f.getType().equals(NumberConstant.TWO)).collect(Collectors.toList());
  342. List<HospProfitAndLossVo> profitCost = costPercent(profitCostList);
  343. //不计算项目
  344. List<HospProfitAndLossVo> noCompute = listSum.stream().filter(f -> f.getFraction().equals(NumberConstant.THREE)).collect(Collectors.toList());
  345. noCompute.forEach(profitVO -> profitVO.setPercent(null));
  346. List<HospProfitAndLossVo> listAllVo = new ArrayList<>();
  347. if (!CollectionUtils.isEmpty(profitIncome) && !CollectionUtils.isEmpty(profitCost) && !CollectionUtils.isEmpty(noCompute)) {
  348. listAllVo.addAll(profitIncome);
  349. listAllVo.addAll(profitCost);
  350. listAllVo.addAll(noCompute);
  351. } else if (!CollectionUtils.isEmpty(profitIncome) && !CollectionUtils.isEmpty(noCompute)) {
  352. listAllVo.addAll(noCompute);
  353. listAllVo.addAll(profitIncome);
  354. } else if (!CollectionUtils.isEmpty(profitCost) && !CollectionUtils.isEmpty(noCompute)) {
  355. listAllVo.addAll(noCompute);
  356. listAllVo.addAll(profitCost);
  357. } else if (!CollectionUtils.isEmpty(noCompute)) {
  358. listAllVo.addAll(noCompute);
  359. }
  360. List<HospProfitAndLoss> list = BeanUtil.convertList(listAllVo, HospProfitAndLoss.class);
  361. // 处理医院其他收支
  362. List<CostOtherPaymentsData> otherPaymentsDatas = otherPaymentsDataService.getByMonth(year, month, hospId);
  363. if (!otherPaymentsDatas.isEmpty()) {
  364. otherPaymentsDatas.forEach(ele -> {
  365. HospProfitAndLoss loss = new HospProfitAndLoss();
  366. loss.setDateYear(year).setDateMonth(month).setReportName(ele.getPaymentsName()).setReportNum((int) (-ele.getId()))
  367. .setCreateTime(System.currentTimeMillis()).setAmount(ele.getTotalAmount()).setHospId(hospId)
  368. .setResponsibilityName("全院").setResponsibilityCode("-1").setPercent(null);
  369. list.add(loss);
  370. });
  371. }
  372. long l = System.currentTimeMillis();
  373. list.forEach(i -> {
  374. i.setCreateTime(l);
  375. i.setReportType(reportType);
  376. });
  377. this.saveBatch(list);
  378. }
  379. /**
  380. * 是否需要计算同环比
  381. * @return
  382. */
  383. public boolean IsNeedCalcYM() {
  384. String parameterValue = centerService.getParameterValue(ParameterConstant.HOSP_YM_CALC_TYPE);
  385. return NumberConstant.ONE_S.equals(parameterValue);
  386. }
  387. /**
  388. * 处理指定月份及关联月份的计算(当前月、下个月、明年同月)
  389. *
  390. * @param hospId 院区ID
  391. * @param computeDate 日期字符串,格式:YYYY-MM
  392. * @param shareType 报表类型
  393. */
  394. public void handleSpecificMonthsCalculation(Long hospId, String computeDate, Integer shareType) {
  395. // 解析输入的年月
  396. Integer currentYear = ComputeDateUtils.getComputeYear(computeDate);
  397. Integer currentMonth = ComputeDateUtils.getComputeMonth(computeDate);
  398. // 计算需要处理的期间信息
  399. List<PeriodInfoVO> periods = calculateAllRelatedPeriods(currentYear, currentMonth);
  400. // 获取所有相关的期间数据
  401. Map<String, List<HospProfitAndLoss>> allDataMap = loadAllPeriodData(hospId, shareType, periods);
  402. // 对每个期间执行计算
  403. for (PeriodInfoVO period : periods) {
  404. String currentKey = buildPeriodKey(period.getYear(), period.getMonth());
  405. if (allDataMap.containsKey(currentKey) && !CollectionUtils.isEmpty(allDataMap.get(currentKey))) {
  406. List<HospProfitAndLoss> currentRecords = allDataMap.get(currentKey);
  407. List<HospProfitAndLoss> prevRecords = getPeriodData(allDataMap, period.getPrevYear(), period.getPrevMonth());
  408. List<HospProfitAndLoss> lastYearRecords = getPeriodData(allDataMap, period.getLastYear(), period.getLastMonth());
  409. // 执行批量计算
  410. calculatePeriodComparisonWithPreloadedData(currentRecords, prevRecords, lastYearRecords);
  411. }
  412. }
  413. }
  414. /**
  415. * 构建所有需要处理的期间信息
  416. */
  417. private List<PeriodInfoVO> calculateAllRelatedPeriods(int baseYear, int baseMonth) {
  418. List<PeriodInfoVO> result = new ArrayList<>();
  419. // 添加当前期间
  420. result.add(calculatePeriodInfo(baseYear, baseMonth));
  421. // 下个月
  422. int nextMonth = baseMonth + 1;
  423. int nextMonthYear = baseYear;
  424. if (baseMonth == 12) {
  425. nextMonth = 1;
  426. nextMonthYear += 1;
  427. }
  428. result.add(calculatePeriodInfo(nextMonthYear, nextMonth));
  429. // 明年同月
  430. result.add(calculatePeriodInfo(baseYear + 1, baseMonth));
  431. return result;
  432. }
  433. /**
  434. * 构建单个期间的信息(当前月、上月、去年同期)
  435. */
  436. private PeriodInfoVO calculatePeriodInfo(int year, int month) {
  437. PeriodInfoVO info = new PeriodInfoVO();
  438. info.setYear( year);
  439. info.setMonth( month);
  440. // 上期
  441. if (month == 1) {
  442. info.setPrevYear(year - 1);
  443. info.setPrevMonth(12);
  444. } else {
  445. info.setPrevYear( year);
  446. info.setPrevMonth(month - 1);
  447. }
  448. // 同期
  449. info.setLastYear(year - 1);
  450. info.setLastMonth( month);
  451. return info;
  452. }
  453. /**
  454. * 加载所有相关期间的数据(去重处理)
  455. */
  456. private Map<String, List<HospProfitAndLoss>> loadAllPeriodData(Long hospId, Integer shareType, List<PeriodInfoVO> periods) {
  457. Set<String> allPeriodKeys = new HashSet<>();
  458. // 收集所有需要查询的年月组合
  459. for (PeriodInfoVO period : periods) {
  460. allPeriodKeys.add(buildPeriodKey(period.getYear(), period.getMonth()));
  461. allPeriodKeys.add(buildPeriodKey(period.getPrevYear(), period.getPrevMonth()));
  462. allPeriodKeys.add(buildPeriodKey(period.getLastYear(), period.getLastMonth()));
  463. }
  464. // 去重后查询
  465. Map<String, List<HospProfitAndLoss>> result = new HashMap<>();
  466. Set<String> processedKeys = new HashSet<>(); // 已处理的键集合
  467. for (String key : allPeriodKeys) {
  468. if (!processedKeys.contains(key)) {
  469. int[] ym = parsePeriodKey(key);
  470. List<HospProfitAndLoss> records = getPeriodRecords(hospId, shareType, ym[0], ym[1]);
  471. result.put(key, records);
  472. processedKeys.add(key); // 标记为已处理
  473. }
  474. }
  475. return result;
  476. }
  477. /**
  478. * 获取指定期间的数据
  479. *
  480. * @param hospId 院区ID
  481. * @param shareType 报表类型
  482. * @param year 年份
  483. * @param month 月份
  484. * @return 符合条件的数据列表
  485. */
  486. private List<HospProfitAndLoss> getPeriodRecords(Long hospId, Integer shareType, int year, int month) {
  487. return this.list(new QueryWrapper<HospProfitAndLoss>().lambda()
  488. .eq(HospProfitAndLoss::getHospId, hospId)
  489. .eq(HospProfitAndLoss::getReportType, shareType)
  490. .eq(HospProfitAndLoss::getDateYear, year)
  491. .eq(HospProfitAndLoss::getDateMonth, month)
  492. .eq(HospProfitAndLoss::getDeleteTime, 0));
  493. }
  494. /**
  495. * 根据年月获取对应的数据(从内存中查找)
  496. */
  497. private List<HospProfitAndLoss> getPeriodData(Map<String, List<HospProfitAndLoss>> dataMap, int year, int month) {
  498. String key = buildPeriodKey(year, month);
  499. return dataMap.getOrDefault(key, Collections.emptyList());
  500. }
  501. /**
  502. * 批量计算同环比及同期金额(使用预加载数据)
  503. */
  504. public void calculatePeriodComparisonWithPreloadedData(
  505. List<HospProfitAndLoss> currentRecords,
  506. List<HospProfitAndLoss> prevRecords,
  507. List<HospProfitAndLoss> lastYearRecords) {
  508. if (CollectionUtils.isEmpty(currentRecords)) {
  509. return;
  510. }
  511. // 创建报表编号到记录的映射
  512. Map<String, HospProfitAndLoss> prevMap = new HashMap<>();
  513. for (HospProfitAndLoss record : prevRecords) {
  514. String key = buildRecordKey(record);
  515. prevMap.put(key, record);
  516. }
  517. Map<String, HospProfitAndLoss> lastYearMap = new HashMap<>();
  518. for (HospProfitAndLoss record : lastYearRecords) {
  519. String key = buildRecordKey(record);
  520. lastYearMap.put(key, record);
  521. }
  522. // 批量更新数据
  523. for (HospProfitAndLoss record : currentRecords) {
  524. String key = buildRecordKey(record);
  525. HospProfitAndLoss prevRecord = prevMap.get(key);
  526. HospProfitAndLoss lastYearRecord = lastYearMap.get(key);
  527. // 设置上期和同期金额
  528. record.setPrevPeriodAmount(prevRecord != null ? prevRecord.getAmount() : BigDecimal.ZERO);
  529. record.setSamePeriodAmount(lastYearRecord != null ? lastYearRecord.getAmount() : BigDecimal.ZERO);
  530. // 计算环比和同比
  531. record.setMomRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getPrevPeriodAmount()));
  532. record.setYoyRate(calculateProfitRate(record.getAmount().subtract(record.getSamePeriodAmount()), record.getSamePeriodAmount()));
  533. }
  534. // 批量更新数据库
  535. this.updateBatchById(currentRecords);
  536. }
  537. /**
  538. * 构建期间键(用于存储和检索数据)
  539. */
  540. private String buildPeriodKey(int year, int month) {
  541. return year + "_" + month;
  542. }
  543. /**
  544. * 解析期间键为年月数组
  545. */
  546. private int[] parsePeriodKey(String key) {
  547. String[] parts = key.split("_");
  548. return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1])};
  549. }
  550. /**
  551. * 构建记录的唯一标识键(责任码 + 报表编号)
  552. */
  553. private String buildRecordKey(HospProfitAndLoss record) {
  554. return String.valueOf(record.getReportNum());
  555. }
  556. /**
  557. * 安全地计算百分比:避免除零错误
  558. */
  559. private BigDecimal calculateProfitRate(BigDecimal current, BigDecimal base) {
  560. if (base == null || base.compareTo(BigDecimal.ZERO) == 0) {
  561. return BigDecimal.ZERO;
  562. }
  563. BigDecimal bigDecimal = current.divide(base, 4, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
  564. return bigDecimal;
  565. }
  566. /**
  567. * 执行全院损益后续脚本
  568. * @param date
  569. * @param reportType
  570. */
  571. public void execHospProfitSql(String date,String reportType){
  572. Map<String,String> sqlParameter = new HashMap<>();
  573. sqlParameter.put(SQLParameter.COMPUTE_DATE_CODE, DateUtils.StringToString(date, DateStyleEnum.YYYY_MM));
  574. sqlParameter.put(SQLParameter.REPORT_TYPE_CODE,reportType.toString());
  575. sqlService.autoExecuteSql(CustomSqlTypeEnum.HOSP_PROFIT_CALC.getCode(),sqlParameter);
  576. }
  577. // 计算公式中钱
  578. private BigDecimal calcAmount(List<HospProfitAndLoss> list, String calcFormula, ReportForm reportForm) {
  579. // 得到所有的编号
  580. String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
  581. ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
  582. // 得到编号的map
  583. Map<Integer, Integer> numMap = new ConcurrentHashMap<>();
  584. for (int j = 0; j < numList.size(); j++) {
  585. numMap.put(j, Integer.parseInt(numList.get(j)));
  586. }
  587. List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
  588. .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
  589. // 得到预算表达式 得到所有表达式的Map + - 相关的
  590. Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
  591. for (int k = 0; k < expressions.size(); k++) {
  592. expressionMap.put(k, expressions.get(k));
  593. }
  594. // 数字的索引和表达式的索引累加计算
  595. Set<Integer> numSet = numMap.keySet();
  596. List<Integer> nums = new ArrayList<>(numSet);
  597. AtomicReference<BigDecimal> totalAmount = new AtomicReference<>();
  598. totalAmount.set(BigDecimal.ZERO);
  599. for (int i = 0; i < nums.size(); i++) {
  600. // 编号
  601. Integer num = numMap.get(i);
  602. List<HospProfitAndLoss> losses = list.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList());
  603. if (CollUtil.isEmpty(losses)) {
  604. continue;
  605. }
  606. // log.info("data={}", reportForm);
  607. // if (losses.size() != 0 && losses.size() != 1) {
  608. // throw new CostException("数据异常");
  609. // }
  610. HospProfitAndLoss loss = losses.get(0);
  611. BigDecimal amount = loss.getAmount();
  612. String str = expressionMap.get(i);
  613. if (str.equals("+")) {
  614. totalAmount.set(totalAmount.get().add(amount));
  615. } else {
  616. totalAmount.set(totalAmount.get().subtract(amount));
  617. }
  618. }
  619. return totalAmount.get();
  620. }
  621. /**
  622. * 按责任中心计算
  623. *
  624. * @param hospId 医院id
  625. * @param reportForm 报表
  626. * @param allocationQueries 分摊成本数据
  627. * @param list
  628. * @param year
  629. * @param month
  630. */
  631. private void calcByResponsibility(Long hospId, ReportForm reportForm, List<AllocationQuery> allocationQueries, List<HospProfitAndLoss> list, int year, int month) {
  632. List<RelationVO> responsibilities = reportRelationService.getResponsibilities(reportForm.getId(), hospId);
  633. if (responsibilities.isEmpty()) {
  634. return;
  635. }
  636. List<String> accountCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList());
  637. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  638. calcTotal.set(BigDecimal.ZERO);
  639. accountCodes.forEach(i -> {
  640. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount)
  641. .reduce(BigDecimal.ZERO, BigDecimal::add);
  642. calcTotal.set(calcTotal.get().add(costAmount));
  643. });
  644. HospProfitAndLoss loss = new HospProfitAndLoss();
  645. loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
  646. .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month);
  647. list.add(loss);
  648. }
  649. /**
  650. * 按计算公式计算
  651. */
  652. private void calcByFormula(Integer year, Integer month, ReportForm child, List<ReportForm> reportForms, List<HospProfitAndLoss> list) {
  653. // 得到当前下按公式计算的
  654. List<ReportForm> calcFormulas = reportForms.stream().filter(i -> i.getCalcType() == CalcTypeEnum.CALC_FORMULA.getType()).collect(Collectors.toList());
  655. calcFormulas = calcFormulas.stream().filter(i -> i.getNum().equals(child.getNum())).collect(Collectors.toList());
  656. for (ReportForm i : calcFormulas) {
  657. String calcFormula = i.getCalcFormula();
  658. // TODO: 2021/8/27 校验公式合法性
  659. if (StrUtil.isBlank(calcFormula)) {
  660. throw new CostException("reportForm名称为" + i.getReportName() + "计算公式不正确");
  661. }
  662. BigDecimal bigDecimal = calcAmount(list, calcFormula, i);
  663. HospProfitAndLoss loss = new HospProfitAndLoss();
  664. loss.setDateYear(year).setDateMonth(month).setReportNum(i.getNum()).setReportName(i.getReportName())
  665. .setAmount(bigDecimal).setCreateTime(System.currentTimeMillis()).setHospId(i.getHospId());
  666. list.add(loss);
  667. }
  668. }
  669. /**
  670. * 按小计计算
  671. */
  672. private void calcByLitterCount(Integer year, Integer month, ReportForm child, List<ReportForm> reportForms, List<HospProfitAndLoss> list, Long hospId) {
  673. // 其他的
  674. List<ReportForm> calcList = reportForms.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList());
  675. List<HospProfitAndLoss> thisList = new ArrayList<>();
  676. list.forEach(i -> {
  677. calcList.forEach(j -> {
  678. if (i.getReportNum().equals(j.getNum())) {
  679. thisList.add(i);
  680. }
  681. });
  682. });
  683. if (thisList.isEmpty()) {
  684. return;
  685. }
  686. BigDecimal reduce = thisList.stream().map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  687. HospProfitAndLoss loss = new HospProfitAndLoss();
  688. loss.setDateYear(year).setDateMonth(month).setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
  689. // 小计只能有一个
  690. loss.setReportNum(child.getNum()).setReportName(child.getReportName());
  691. list.add(loss);
  692. }
  693. /**
  694. * 按分摊层级计算、
  695. *
  696. * @param hospId 医院id
  697. * @param reportForm 报表
  698. * @param list
  699. * @param year
  700. * @param month
  701. */
  702. private void calcByShareLevel(Long hospId, ReportForm reportForm, List<HospProfitAndLoss> list, int year, int month) {
  703. List<RelationVO> shareLevels = reportRelationService.getShareLevel(reportForm.getId(), hospId);
  704. List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList());
  705. if (CollUtil.isEmpty(shareLevelId)) {
  706. return;
  707. }
  708. List<CostShareLevel> costShareLevels = shareLevelService.listByIds(shareLevelId);
  709. if (costShareLevels.isEmpty()) {
  710. throw new CostException("医院分摊层级设置错误," + reportForm.getReportName());
  711. }
  712. List<Integer> levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList());
  713. List<AllocationQuery> allocations = allocationQueryService.getByDate(year, month, hospId, shareLevelId);
  714. if (allocations.isEmpty()) {
  715. throw new CostException("医院未分摊本月数据");
  716. }
  717. List<CostAccountShare> accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId);
  718. if (accountShares.isEmpty()) {
  719. return;
  720. }
  721. // allocations = allocations.stream().filter(i -> levelSorts.contains(i.getLevelSort())).collect(Collectors.toList());
  722. BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  723. HospProfitAndLoss loss = new HospProfitAndLoss();
  724. loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
  725. .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month);
  726. list.add(loss);
  727. }
  728. /**
  729. * 计算按会计科目下的科目名称
  730. *
  731. * @param hospId 医院id
  732. * @param reportForm 报表
  733. * @param incomes 归集收入数据
  734. * @param list
  735. * @param allocationQueries 分摊成本数据
  736. * @param month
  737. * @param year
  738. */
  739. private void calcByAccount(Long hospId, ReportForm reportForm, List<IncomeCollection> incomes, List<HospProfitAndLoss> list, List<AllocationQuery> allocationQueries, int month, int year) {
  740. // check 这个医院是否有对应的损益标识
  741. reportFormService.checkExistLoss(hospId);
  742. // 报表项目关联的会计科目对象
  743. List<RelationVO> accountRelations = reportRelationService.getAccountRelation(reportForm.getId(), hospId);
  744. if (accountRelations.isEmpty()) {
  745. return;
  746. }
  747. List<String> accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList());
  748. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  749. calcTotal.set(BigDecimal.ZERO);
  750. accountCodes.forEach(i -> {
  751. BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount)
  752. .reduce(BigDecimal.ZERO, BigDecimal::add);
  753. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount)
  754. .reduce(BigDecimal.ZERO, BigDecimal::add);
  755. BigDecimal total = incomeAmount.add(costAmount);
  756. calcTotal.set(calcTotal.get().add(total));
  757. });
  758. HospProfitAndLoss loss = new HospProfitAndLoss();
  759. loss.setReportName(reportForm.getReportName()).setReportNum(reportForm.getNum())
  760. .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month);
  761. list.add(loss);
  762. }
  763. /**
  764. * 全院损益列表
  765. *
  766. * @param current 当前页
  767. * @param pageSize 每页展示数据大小
  768. * @param date 日期
  769. * @param hospId 医院id
  770. * @return PageUtils
  771. */
  772. @Override
  773. public PageUtils getHospProfits(Integer current, Integer pageSize, String date, Long hospId) {
  774. reportFormService.checkExistLoss(hospId);
  775. DateTime parse = DateUtil.parse(date);
  776. int year = DateUtil.year(parse);
  777. int month = DateUtil.month(parse) + 1;
  778. int startIndex = (current - 1) * pageSize;
  779. List<HospProfitAndLoss> list = baseMapper.getPageList(startIndex, pageSize, year, month, hospId);
  780. // 损益的时候计算下
  781. list.forEach(i -> {
  782. ReportForm one = reportFormService.getOne(
  783. new LambdaQueryWrapper<ReportForm>().select(ReportForm::getId)
  784. .eq(ReportForm::getNum, i.getReportNum())
  785. .eq(ReportForm::getHospId, hospId)
  786. .eq(ReportForm::getReportType, 3)
  787. .eq(ReportForm::getIsLoss, 1)
  788. .last(Constant.LIMIT)
  789. );
  790. if (Objects.nonNull(one)) {
  791. List<CostOtherPaymentsData> byMonth = otherPaymentsDataService.getByMonth(year, month, hospId);
  792. AtomicReference<BigDecimal> total = new AtomicReference<>();
  793. total.set(BigDecimal.ZERO);
  794. byMonth.forEach(j -> {
  795. if (j.getPaymentsType().equals(1)) {
  796. total.set(total.get().add(j.getTotalAmount()));
  797. } else {
  798. total.set(total.get().subtract(j.getTotalAmount()));
  799. }
  800. });
  801. i.setAmount(i.getAmount().add(total.get()));
  802. }
  803. });
  804. int totalCount = baseMapper.getPageCount(year, month, hospId);
  805. return new PageUtils(list, totalCount, pageSize, current);
  806. }
  807. /**
  808. * 导出全院损益计算
  809. *
  810. * @param date yyyy-MM-dd
  811. * @param hospId
  812. */
  813. @Override
  814. public void hospProfitReport(String date, Long hospId) {
  815. DateTime parse = DateUtil.parse(date);
  816. int year = DateUtil.year(parse);
  817. int month = DateUtil.month(parse) + 1;
  818. // 得到所有责任中心的子节点
  819. List<Responsibility> responsibilityList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda().eq(Responsibility::getHospId, hospId));
  820. // List<Responsibility> leafResp = responsibilityService.getLeafResp(hospId);
  821. List<CostOtherPaymentsData> byMonth = otherPaymentsDataService.getByMonth(year, month, hospId);
  822. // if (!byMonth.isEmpty()) {
  823. // Responsibility responsibility = new Responsibility("-1", "全院", -1L);
  824. // responsibilityList.add(responsibility);
  825. // }
  826. Map<String, Long> responseCodeParentIdMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getResponsibilityCode, Responsibility::getParentId, (a, b) -> b));
  827. Map<Long, Responsibility> responsibilityIdMap = responsibilityList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b));
  828. // 查询所有的全院损益数据 内存溢出问题
  829. List<HospProfitAndLoss> hospProfitAndLosses = getAllDataByDate(year, month, hospId,NumberConstant.THREE);
  830. if (CollectionUtils.isEmpty(hospProfitAndLosses)) {
  831. throw new CostException(500, "未进行全院损益计算");
  832. }
  833. //判断是否有全院的数据 有单独取出另算
  834. List<HospProfitAndLoss> hospAllList = hospProfitAndLosses.stream().filter(f -> f.getResponsibilityCode().equals("-1")).collect(Collectors.toList());
  835. if (!CollectionUtils.isEmpty(hospAllList)) {
  836. hospProfitAndLosses.removeAll(hospAllList);
  837. }
  838. //多层级责任 中心 添加父类责任中心 方便excel分组
  839. for (HospProfitAndLoss hospProfitAndLoss : hospProfitAndLosses) {
  840. Long aLong = responseCodeParentIdMap.get(hospProfitAndLoss.getResponsibilityCode());
  841. if (aLong != null) {
  842. if (aLong.equals(NumberConstant.ZERO_L)) {
  843. // Long aLong1 = responseCodeIdMap.get(departmentProfit.getResponsibilityCode());
  844. hospProfitAndLoss.setParentResponsibilityCode(hospProfitAndLoss.getResponsibilityCode());
  845. hospProfitAndLoss.setParentResponsibilityName(hospProfitAndLoss.getResponsibilityName());
  846. } else if (aLong.equals(-1L)) {
  847. hospProfitAndLoss.setParentResponsibilityCode("-1");
  848. hospProfitAndLoss.setParentResponsibilityName("全院");
  849. } else {
  850. Responsibility responsibility = responsibilityIdMap.get(aLong);
  851. if (Objects.nonNull(responsibility)) {
  852. hospProfitAndLoss.setParentResponsibilityCode(responsibility.getResponsibilityCode());
  853. hospProfitAndLoss.setParentResponsibilityName(responsibility.getResponsibilityName());
  854. }
  855. }
  856. }
  857. }
  858. //损益表设置
  859. List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
  860. .eq(ReportForm::getHospId, hospId)
  861. .eq(ReportForm::getReportType, NumberConstant.THREE));
  862. if (CollUtil.isEmpty(reportFormList)) {
  863. throw new CostException(500, "损益表未找到");
  864. }
  865. if (!byMonth.isEmpty()) {
  866. // 手动构造全院数据表头 生成全院其他收支
  867. //添加全院其他报表项目
  868. //最上层
  869. ReportForm parentReport = new ReportForm();
  870. parentReport.setId(-1L);
  871. parentReport.setReportType(NumberConstant.THREE);
  872. parentReport.setParentId(NumberConstant.ZERO_L);
  873. parentReport.setSort(0);
  874. parentReport.setReportName("全院其他收支");
  875. parentReport.setNum(-1);
  876. reportFormList.add(parentReport);
  877. //第二层按全院收支数据自动生成
  878. for (int i = 0; i < byMonth.size(); i++) {
  879. CostOtherPaymentsData data = byMonth.get(i);
  880. ReportForm reportForm = new ReportForm();
  881. // reportForm.setId(-1L -i - byMonth.size());
  882. reportForm.setId(-System.currentTimeMillis() - i);
  883. reportForm.setReportType(NumberConstant.THREE);
  884. reportForm.setParentId(-1L);
  885. reportForm.setSort(0);
  886. reportForm.setReportName(data.getPaymentsName());
  887. reportForm.setNum((int) (-data.getId()));
  888. reportFormList.add(reportForm);
  889. }
  890. }
  891. Map<Long, List<ReportForm>> collect = reportFormList.stream().collect(Collectors.groupingBy(ReportForm::getParentId));
  892. Map<String, List<ColEntity>> heads = new HashMap<>();// 最终导出的多个sheet的表头
  893. Map<String, List<Map<String, String>>> datas = new HashMap<>();// 最终导出的多个sheet的内容
  894. Map<String, Integer> types = new HashMap<>();
  895. Map<String, List<Integer>> mergeindexs = new HashMap<>();// 最终导出的每个sheet的需要纵向合并的单元格列号
  896. //第一层
  897. List<ReportForm> firstTitle = collect.get(NumberConstant.ZERO_L);
  898. List<TitleEntity> titleList = new ArrayList<>();
  899. titleList.add(new TitleEntity("0", null, "全院损益 \n" + "制表时间:" + DateUtil.now(), false, NumberConstant.ZERO));
  900. //添加默认三列责任中心 父类责任中心 子类责任中心 项目名称
  901. setDefaultColumn(titleList);
  902. for (ReportForm reportForm : firstTitle) {
  903. TitleEntity entity = new TitleEntity();
  904. entity.setId(String.valueOf(reportForm.getId()));
  905. entity.setPid(String.valueOf(reportForm.getParentId()));
  906. entity.setContent(reportForm.getReportName());
  907. entity.setFieldName(String.valueOf(reportForm.getNum()));
  908. entity.setWidth(20);
  909. entity.setSort(reportForm.getSort());
  910. boolean child = getChild(titleList, reportForm, collect);
  911. entity.setLast(child);
  912. titleList.add(entity);
  913. }
  914. titleList.sort(Comparator.comparing(TitleEntity::getSort));
  915. hospProfitAndLosses.sort(Comparator.comparing(HospProfitAndLoss::getParentResponsibilityCode));
  916. //行
  917. Map<String, List<HospProfitAndLoss>> lineMap = hospProfitAndLosses.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getParentResponsibilityCode));
  918. //列
  919. List<TitleEntity> titleEntities = titleList.stream().filter(TitleEntity::isLast).collect(Collectors.toList());
  920. List<Map<String, String>> rowList = new ArrayList<>();
  921. //行数据
  922. setRowList(lineMap, titleEntities, rowList);
  923. //添加 全院其他收支数据
  924. setHospRowList(hospAllList, titleEntities, rowList);
  925. try {
  926. ExcelPoiUtil excelTool = new ExcelPoiUtil();
  927. excelTool.setTitle("全院损益");
  928. Map<String, String> param = ImmutableMap.<String, String>builder().put("id", "id").put("pid", "pid")
  929. .put("content", "content").put("fieldName", "fieldName").put("width", "width").build();
  930. List<ColEntity> titleData = excelTool.colEntityTransformer(titleList, param, "0");
  931. Map<String, List<Integer>> autoRowHeights = new HashMap<>();
  932. heads.put("全院损益", titleData);// 每个sheet的表头,sheet名称为key
  933. datas.put("全院损益", rowList);// 每个sheet的内容,sheet名称为key
  934. types.put("全院损益", 0);// 每个sheet的样式类型,sheet名称为key
  935. mergeindexs.put("全院损益", Arrays.asList(0, 1));// 每个sheet的默认行高,sheet名称为key
  936. autoRowHeights.put("全院损益", Arrays.asList(1, 2, 3, 4, 5));
  937. // 多个sheet导出
  938. HSSFWorkbook workbook = excelTool.exportWorkbook(heads, datas, types, autoRowHeights, mergeindexs);
  939. // excelTool.save(workbook, "D:\\全院损益.xls");
  940. // // 得到上一层的title子节点
  941. //// ExcelWriter writer = ExcelUtil.getWriter();
  942. // String time = DateUtil.format(DateUtil.date(), "yyyy年MM月dd日HH时mm分ss秒");
  943. // //todo:后面调整为上传到文件服务器,先启动确认环境
  944. // String fileName = "全院损益" + time + ".xlsx";
  945. // ExcelWriter writer = ExcelUtil.getWriter(fileName);
  946. //
  947. // List<String> secondTitleListCode = leafResp.stream().map(Responsibility::getResponsibilityCode).collect(Collectors.toList());
  948. // writer.merge(leafResp.size() + 1, "全院损益计算导出 \n" + "制表时间:" + DateUtil.now());
  949. // // 得到两层结构
  950. // writer.setColumnWidth(-1, 20);
  951. // writer.passCurrentRow();
  952. // writer.merge(2, 2, 0, 1, "项目", true);
  953. // int oldSize = 2;
  954. // Map<Long, Object> map = new HashMap<>();
  955. // for (int i = 0; i < leafResp.size(); i++) {
  956. // Responsibility responsibility = leafResp.get(i);
  957. // String str = responsibility.getResponsibilityName();
  958. // writer.writeCellValue(i + 2, 2, str);
  959. // // 写父亲层级
  960. // Long parentId = responsibility.getParentId();
  961. // if (map.get(parentId) != null) {
  962. // // 如果parentId = 0
  963. // if (parentId != 0L) {
  964. // continue;
  965. // }
  966. // }
  967. // Responsibility byId = responsibilityService.getById(parentId);
  968. // String name = "";
  969. // if (byId != null) {
  970. // name = byId.getResponsibilityName();
  971. // }
  972. // int count = (int) leafResp.stream().filter(o -> o.getParentId().equals(parentId)).count();
  973. //
  974. // if (count == 1) {
  975. // writer.writeCellValue(oldSize, 1, name);
  976. // } else if (count == 0) {
  977. // writer.writeCellValue(oldSize, 1, "全院其他");
  978. // } else {
  979. // writer.merge(1, 1, oldSize, oldSize + count - 1, name, false);
  980. // }
  981. //
  982. // oldSize = oldSize + count;
  983. // map.put(parentId, oldSize);
  984. //
  985. // }
  986. // // 得到全院损益报表处理 树状结构(only 2层)
  987. // List<ReportFormVO> allHospList = reportFormService.getAllHospList(hospId);
  988. // if (allHospList.isEmpty()) {
  989. // throw new CostException("请先设置全院损益报表");
  990. // }
  991. //
  992. // if (!byMonth.isEmpty()) {
  993. // // 构造假数据 生成全院其他收支
  994. // ReportFormVO vo = new ReportFormVO(-1L, -1, "全院其他收支", 0L, new ArrayList<>());
  995. // for (CostOtherPaymentsData data : byMonth) {
  996. // ReportFormVO reportFormVO = new ReportFormVO(-2L, (int) (-data.getId()), data.getPaymentsName(), -1L, null);
  997. // vo.getChildren().add(reportFormVO);
  998. // }
  999. // allHospList.add(allHospList.size() - 1, vo);
  1000. // }
  1001. // // 查询所有的全院损益数据 内存溢出问题
  1002. // List<HospProfitAndLoss> list = getAllDataByDate(year, month, hospId);
  1003. // int lastRow = 3;
  1004. // for (int i = 0; i < allHospList.size(); i++) {
  1005. // ReportFormVO parentFormVO = allHospList.get(i);
  1006. // List<ReportFormVO> children = parentFormVO.getChildren();
  1007. // if (CollUtil.isEmpty(children)) {
  1008. // continue;
  1009. // }
  1010. // int size = children.size();
  1011. // // 当最后一个的时候写上全院其他收支
  1012. // if (allHospList.size() == 1) {
  1013. // writer.writeCellValue(0, lastRow, parentFormVO.getReportName());
  1014. // } else {
  1015. // writer.merge(lastRow, lastRow + size - 1, 0, 0, parentFormVO.getReportName(), true);
  1016. // }
  1017. //
  1018. // // 具体的报表项目
  1019. // for (int j = 0; j < size; j++) {
  1020. // // todo 可以抽取出单独方法
  1021. // ReportFormVO childFormVO = children.get(j);
  1022. // // 第二列的数据
  1023. // writer.writeCellValue(1, lastRow + j, childFormVO.getReportName());
  1024. // // 单独计每个数据的责任中心对应的金额
  1025. // for (int k = 0; k < secondTitleListCode.size(); k++) {
  1026. //
  1027. // String responsibilityCode = secondTitleListCode.get(k);
  1028. // Integer num = childFormVO.getNum();
  1029. // HospProfitAndLoss loss = list.stream().filter(o -> o.getReportNum().equals(num) && o.getResponsibilityCode().equals(responsibilityCode)).findAny()
  1030. // .orElse(null);
  1031. // BigDecimal bigDecimal = Objects.isNull(loss) ? BigDecimal.ZERO : loss.getAmount();
  1032. // writer.writeCellValue(k + 2, lastRow + j, bigDecimal);
  1033. // if (k == secondTitleListCode.size() - 1) {
  1034. // bigDecimal = list.stream().filter(o -> o.getReportNum().equals(num)).map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1035. // writer.writeCellValue(k + 2, lastRow + j, bigDecimal);
  1036. //
  1037. // if (j == size - 1 && i == allHospList.size() - 1) {
  1038. // // 计算 其他
  1039. // BigDecimal another = BigDecimal.ZERO;
  1040. // for (CostOtherPaymentsData costOtherPaymentsData : byMonth) {
  1041. // if (costOtherPaymentsData.getPaymentsType() == 1) {
  1042. // another = another.add(costOtherPaymentsData.getTotalAmount());
  1043. // } else {
  1044. // another = another.subtract(costOtherPaymentsData.getTotalAmount());
  1045. // }
  1046. // }
  1047. // bigDecimal = bigDecimal.add(another);
  1048. // writer.writeCellValue(k + 2, lastRow + j, bigDecimal);
  1049. // }
  1050. // }
  1051. //
  1052. //
  1053. // }
  1054. //
  1055. // }
  1056. // lastRow = lastRow + size;
  1057. // }
  1058. String time = DateUtil.format(DateUtil.date(), "yyyy年MM月dd日HH时mm分ss秒");
  1059. FileItemFactory factory = new DiskFileItemFactory(5242880, null);
  1060. FileItem fileItem = factory.createItem("file", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8", true, "全院损益" + time + ".xls");
  1061. String file = "";
  1062. OutputStream outputStream = fileItem.getOutputStream();
  1063. // writer.flush(outputStream,true);
  1064. workbook.write(outputStream);
  1065. MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
  1066. //上传 excel
  1067. file = uploadFile(multipartFile);
  1068. //保存文件记录
  1069. FileRecord fileRecord = new FileRecord();
  1070. fileRecord.setFileName("全院损益" + time + ".xls")
  1071. .setFileSource(1)
  1072. .setFileType("全院损益")
  1073. .setFileUrl(file)
  1074. .setHospId(hospId)
  1075. .setDateYear(year).setDateMonth(month)
  1076. .setCreateTime(System.currentTimeMillis());
  1077. fileRecordService.save(fileRecord);
  1078. workbook.close();
  1079. } catch (Exception e) {
  1080. throw new RuntimeException(e);
  1081. }
  1082. }
  1083. private static void setHospRowList(List<HospProfitAndLoss> hospAllList, List<TitleEntity> titleEntities, List<Map<String, String>> rowList) {
  1084. List<Map<String, String>> amountRowList = new ArrayList<>();
  1085. for (Map<String, String> map : rowList) {
  1086. String itemType = map.get("itemType");
  1087. if (itemType.equals("金额")) {
  1088. amountRowList.add(map);
  1089. }
  1090. }
  1091. //相 同key 的数值 进行汇总
  1092. // for (int i = 0; i < 2; i++) {
  1093. Map<String, String> hospMap = new HashMap<>();
  1094. for (TitleEntity titleEntity : titleEntities) {
  1095. AtomicReference<BigDecimal> total = new AtomicReference<>(new BigDecimal("0.00"));
  1096. for (Map<String, String> map : amountRowList) {
  1097. String s = map.get(titleEntity.getFieldName());
  1098. if (!titleEntity.getFieldName().equals("child") && !titleEntity.getFieldName().equals("parent") && !titleEntity.getFieldName().equals("itemType")) {
  1099. // if(StringUtils.isEmpty(s)){
  1100. // total.updateAndGet(v -> v.add(BigDecimal.ZERO));
  1101. // }else {
  1102. total.updateAndGet(v -> v.add(new BigDecimal(s)));
  1103. // }
  1104. }
  1105. }
  1106. if (titleEntity.getFieldName().equals("parent")) {
  1107. hospMap.put("parent", "全院");
  1108. } else if (titleEntity.getFieldName().equals("child")) {
  1109. hospMap.put("child", "全院");
  1110. } else if (titleEntity.getFieldName().equals("itemType")) {
  1111. // if (i == 0) {
  1112. hospMap.put("itemType", "金额");
  1113. // } else {
  1114. // hospMap.put("itemType", "占比");
  1115. // }
  1116. } else {
  1117. // if (i == 0) {
  1118. hospMap.put(titleEntity.getFieldName(), total.get().toString());
  1119. if (!CollectionUtils.isEmpty(hospAllList)) {
  1120. for (HospProfitAndLoss data : hospAllList) {
  1121. hospMap.put(data.getReportNum().toString(), data.getAmount().setScale(2, RoundingMode.HALF_UP).toString());
  1122. }
  1123. }
  1124. // } else {
  1125. // hospMap.put(titleEntity.getFieldName(), "");
  1126. // }
  1127. }
  1128. }
  1129. rowList.add(hospMap);
  1130. // }
  1131. }
  1132. private static void setRowList(Map<String, List<HospProfitAndLoss>> lineMap, List<TitleEntity> titleEntities, List<Map<String, String>> rowList) {
  1133. DecimalFormat df = new DecimalFormat("0.00%");
  1134. for (String parentCode : lineMap.keySet()) {
  1135. List<HospProfitAndLoss> costDepartmentProfits1 = lineMap.get(parentCode);
  1136. Map<String, List<HospProfitAndLoss>> listMap = costDepartmentProfits1.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getResponsibilityCode));
  1137. for (String s : listMap.keySet()) {
  1138. List<HospProfitAndLoss> costDepartmentProfits2 = listMap.get(s);
  1139. Map<String, HospProfitAndLoss> map = costDepartmentProfits2.stream().collect(Collectors.toMap(profit -> String.valueOf(profit.getReportNum()), profit -> profit, (a, b) -> b));
  1140. for (int i = 0; i < 2; i++) {
  1141. Map<String, String> m = new HashMap<String, String>();
  1142. for (TitleEntity titleEntity : titleEntities) {
  1143. if (titleEntity.getId().equals("parentResponsibility")) {
  1144. m.put("parent", costDepartmentProfits2.get(0).getParentResponsibilityName());
  1145. } else if (titleEntity.getId().equals("childResponsibility")) {
  1146. m.put("child", costDepartmentProfits2.get(0).getResponsibilityName());
  1147. } else if (titleEntity.getId().equals("item")) {
  1148. if (i == 0) {
  1149. m.put("itemType", "金额");
  1150. } else {
  1151. m.put("itemType", "占比");
  1152. }
  1153. } else if (titleEntity.getId().contains("-")) {
  1154. HospProfitAndLoss profit = map.get(titleEntity.getFieldName());
  1155. if (Objects.nonNull(profit)) {
  1156. if (i == 0) {
  1157. m.put(titleEntity.getFieldName(), profit.getAmount().setScale(2, RoundingMode.HALF_UP).toString());
  1158. } else {
  1159. if (profit.getPercent() != null) {
  1160. m.put(titleEntity.getFieldName(), df.format(profit.getPercent()));
  1161. } else {
  1162. m.put(titleEntity.getFieldName(), "");
  1163. }
  1164. }
  1165. } else {
  1166. m.put(titleEntity.getFieldName(), "0.00");
  1167. }
  1168. } else {
  1169. HospProfitAndLoss profit = map.get(titleEntity.getFieldName());
  1170. if (Objects.nonNull(profit)) {
  1171. if (i == 0) {
  1172. m.put(titleEntity.getFieldName(), profit.getAmount().setScale(2, RoundingMode.HALF_UP).toString());
  1173. } else {
  1174. if (profit.getPercent() != null) {
  1175. m.put(titleEntity.getFieldName(), df.format(profit.getPercent()));
  1176. } else {
  1177. m.put(titleEntity.getFieldName(), "");
  1178. }
  1179. }
  1180. }
  1181. }
  1182. }
  1183. rowList.add(m);
  1184. }
  1185. }
  1186. }
  1187. }
  1188. private void setDefaultColumn(List<TitleEntity> titleList) {
  1189. TitleEntity parentResponsibility = new TitleEntity();
  1190. parentResponsibility.setId("parentResponsibility");
  1191. parentResponsibility.setPid("0");
  1192. parentResponsibility.setContent("");
  1193. parentResponsibility.setFieldName("parent");
  1194. parentResponsibility.setWidth(15);
  1195. parentResponsibility.setSort(NumberConstant.ZERO);
  1196. parentResponsibility.setLast(true);
  1197. titleList.add(parentResponsibility);
  1198. TitleEntity childResponsibility = new TitleEntity();
  1199. childResponsibility.setId("childResponsibility");
  1200. childResponsibility.setPid("0");
  1201. childResponsibility.setContent("");
  1202. childResponsibility.setFieldName("child");
  1203. childResponsibility.setWidth(15);
  1204. childResponsibility.setSort(NumberConstant.ZERO);
  1205. childResponsibility.setLast(true);
  1206. titleList.add(childResponsibility);
  1207. TitleEntity item = new TitleEntity();
  1208. item.setId("item");
  1209. item.setPid("0");
  1210. item.setContent("");
  1211. item.setFieldName("itemType");
  1212. item.setWidth(10);
  1213. item.setSort(NumberConstant.ZERO);
  1214. item.setLast(true);
  1215. titleList.add(item);
  1216. }
  1217. private boolean getChild(List<TitleEntity> titleList, ReportForm reportForm, Map<Long, List<ReportForm>> collect) {
  1218. List<ReportForm> forms = collect.get(reportForm.getId());
  1219. if (!CollectionUtils.isEmpty(forms)) {
  1220. for (ReportForm form : forms) {
  1221. TitleEntity entity = new TitleEntity();
  1222. entity.setId(String.valueOf(form.getId()));
  1223. entity.setPid(String.valueOf(form.getParentId()));
  1224. entity.setContent(form.getReportName());
  1225. entity.setFieldName(String.valueOf(form.getNum()));
  1226. entity.setWidth(15);
  1227. entity.setSort(form.getSort());
  1228. boolean last = getChild(titleList, form, collect);
  1229. entity.setLast(last);
  1230. titleList.add(entity);
  1231. }
  1232. return false;
  1233. } else {
  1234. return true;
  1235. }
  1236. }
  1237. public String uploadFile(MultipartFile file) {
  1238. Long hospId = UserContext.getCurrentLoginHospId();
  1239. String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf(".")) + System.currentTimeMillis() + ".xls";
  1240. DateTime date = DateUtil.date();
  1241. int month = DateUtil.month(date) + 1;
  1242. int year = DateUtil.year(date);
  1243. int day = DateUtil.dayOfMonth(date);
  1244. String fileUrl = "";
  1245. try {
  1246. // file.transferTo(new File(localFilePath));
  1247. String format = DateUtil.format(date, DatePattern.PURE_DATETIME_PATTERN);
  1248. String originalFilename = format + fileName;
  1249. String dataDirectory = minioConfig.getBucketName();
  1250. String uploadFileName = "hospReport" + "/" + hospId + "/" + year + "/" + month + "/" + day + "/" + originalFilename;
  1251. InputStream inputStream = file.getInputStream();
  1252. minioFileUtil.putObject(dataDirectory, uploadFileName, inputStream);
  1253. fileUrl = minioFileUtil.getObjectUrl(dataDirectory, uploadFileName);
  1254. } catch (IOException e) {
  1255. log.error("【文件上传至服务器】失败,绝对路径:{}", e.getMessage());
  1256. throw new CostException(ErrorCodeEnum.FILE_UPLOAD_ERROR);
  1257. }
  1258. return fileUrl;
  1259. }
  1260. @Override
  1261. public PageUtils hospProfitReports(Integer current, Integer pageSize, Long hospId, String date) {
  1262. DateTime parse = DateUtil.parse(date);
  1263. int year = DateUtil.year(parse);
  1264. int month = DateUtil.month(parse) + 1;
  1265. Page<FileRecord> page = new Page<>(current, pageSize);
  1266. Page<FileRecord> pageUtils = fileRecordService.page(page,
  1267. new LambdaQueryWrapper<FileRecord>()
  1268. .eq(FileRecord::getHospId, hospId)
  1269. .eq(FileRecord::getFileType, "全院损益")
  1270. .eq(FileRecord::getDateYear, year)
  1271. .eq(FileRecord::getDateMonth, month)
  1272. .orderByDesc(FileRecord::getCreateTime)
  1273. );
  1274. return new PageUtils(pageUtils);
  1275. }
  1276. @Override
  1277. public Object getHospProfitResponsibilities(String responsibilityName) {
  1278. List<Responsibility> responsibilityList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
  1279. .eq(Responsibility::getHospId, UserContext.getHospId())
  1280. .and(q -> q.eq(Responsibility::getStatus, NumberConstant.ONE).or().eq(Responsibility::getStatus, null))
  1281. .like(StrUtil.isNotBlank(responsibilityName), Responsibility::getResponsibilityName, responsibilityName));
  1282. List<Responsibility> responsibilityAllList = responsibilityService.list(new QueryWrapper<Responsibility>().lambda()
  1283. .eq(Responsibility::getHospId, UserContext.getHospId()));
  1284. Map<Long, Responsibility> map = responsibilityAllList.stream().collect(Collectors.toMap(Responsibility::getId, responsibility -> responsibility, (a, b) -> b));
  1285. List<Responsibility> addList = new ArrayList<>();
  1286. for (Responsibility responsibility : responsibilityList) {
  1287. Responsibility responsibility1 = map.get(responsibility.getParentId());
  1288. if (Objects.nonNull(responsibility1)) {
  1289. addList.add(responsibility1);
  1290. if (!responsibility1.getParentId().equals(NumberConstant.ZERO_L)) {
  1291. getResponsibilityParent(responsibility1, map, addList);
  1292. }
  1293. }
  1294. }
  1295. if (!CollectionUtils.isEmpty(addList)) {
  1296. //去重
  1297. List<Responsibility> collect = addList.stream().distinct().collect(Collectors.toList());
  1298. responsibilityList.addAll(collect);
  1299. }
  1300. Map<Long, List<Responsibility>> collect = responsibilityList.stream().collect(Collectors.groupingBy(Responsibility::getParentId));
  1301. List<Responsibility> responsibilities = collect.get(NumberConstant.ZERO_L);
  1302. collect.remove(NumberConstant.ZERO_L);
  1303. for (Responsibility responsibility : responsibilities) {
  1304. List<Responsibility> responsibilities1 = collect.get(responsibility.getId());
  1305. if (!CollectionUtils.isEmpty(responsibilities1)) {
  1306. responsibility.setChildren(setResponsibilityChildren(responsibilities1, collect));
  1307. }
  1308. }
  1309. responsibilitySort(responsibilities);
  1310. return responsibilities;
  1311. }
  1312. @Override
  1313. public Object getHospProfitList(String computeDate, Long hospId, String reportType) {
  1314. DateTime parse = DateUtil.parse(computeDate);
  1315. int year = DateUtil.year(parse);
  1316. int month = DateUtil.month(parse) + 1;
  1317. //查询全院损益报表配置
  1318. Integer integerReportType = Integer.valueOf(reportType);
  1319. // Integer year = ComputeDateUtils.getComputeYear(computeDate);
  1320. // Integer month = ComputeDateUtils.getComputeMonth(computeDate);
  1321. // 查询所有的全院损益数据 内存溢出问题
  1322. List<HospProfitAndLoss> hospProfitAndLosses = getAllDataByDate(year, month, hospId,integerReportType);
  1323. if (CollectionUtils.isEmpty(hospProfitAndLosses)) {
  1324. throw new CostException(500, "未进行全院损益计算");
  1325. }
  1326. //判断是否有全院的数据 有单独取出另算
  1327. List<HospProfitAndLoss> hospAllList = hospProfitAndLosses.stream().filter(f -> f.getResponsibilityCode().equals("-1")).collect(Collectors.toList());
  1328. if (!CollectionUtils.isEmpty(hospAllList)) {
  1329. hospProfitAndLosses.removeAll(hospAllList);
  1330. }
  1331. List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
  1332. .eq(ReportForm::getHospId, hospId)
  1333. .eq(ReportForm::getReportType, integerReportType).eq(ReportForm::getHide, NumberConstant.ONE));
  1334. if (CollUtil.isEmpty(reportFormList)) {
  1335. throw new CostException(500, "未找到全院损益表配置");
  1336. }
  1337. List<HospProfitVO> costProfitVos = BeanUtil.convertList(reportFormList, HospProfitVO.class);
  1338. //把所有数据按报表项目汇总
  1339. Map<Integer, List<HospProfitAndLoss>> reportNumGroup = hospProfitAndLosses.stream().collect(Collectors.groupingBy(HospProfitAndLoss::getReportNum));
  1340. Map<Integer, BigDecimal> reportNumSumMap = new HashMap<>();
  1341. reportNumGroup.forEach((reportNum, hospProfitAndLossList) -> {
  1342. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000000"));
  1343. hospProfitAndLossList.stream().<UnaryOperator<BigDecimal>>map(hospProfitAndLoss -> f -> f.add(hospProfitAndLoss.getAmount())).forEach(sum::updateAndGet);
  1344. reportNumSumMap.put(reportNum, sum.get());
  1345. });
  1346. for (HospProfitVO costProfitVo : costProfitVos) {
  1347. BigDecimal bigDecimal = reportNumSumMap.get(costProfitVo.getNum());
  1348. if (bigDecimal != null) {
  1349. costProfitVo.setAmount(bigDecimal);
  1350. } else {
  1351. costProfitVo.setAmount(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP));
  1352. }
  1353. }
  1354. //判断有无其他全院数据 有组装进去
  1355. if (!CollectionUtils.isEmpty(hospAllList)) {
  1356. //全院其他收支
  1357. HospProfitVO hospProfitVO = new HospProfitVO();
  1358. hospProfitVO.setId(-1L);
  1359. hospProfitVO.setNum(-1);
  1360. hospProfitVO.setParentId(0L);
  1361. hospProfitVO.setReportName("全院其他收支");
  1362. hospProfitVO.setSort(costProfitVos.size());
  1363. hospProfitVO.setReportType(integerReportType);
  1364. hospProfitVO.setFraction(3);
  1365. costProfitVos.add(hospProfitVO);
  1366. for (int i = 0, hospAllListSize = hospAllList.size(); i < hospAllListSize; i++) {
  1367. costProfitVos.add(getHospProfitVO(hospAllList, i,integerReportType));
  1368. }
  1369. }
  1370. //取出所有成本项目
  1371. List<HospProfitVO> costFractionList = costProfitVos.stream().filter(f -> f.getCostType() != null && f.getCostType().equals(NumberConstant.TWO) && f.getFraction().equals(NumberConstant.TWO)).collect(Collectors.toList());
  1372. if (CollectionUtils.isEmpty(costFractionList)) {
  1373. throw new CostException("全院损益未配置成本占比计算分母");
  1374. } else {
  1375. if (costFractionList.size() > 1) {
  1376. throw new CostException("全院损益成本占比计算分母有且只能有一个");
  1377. }
  1378. }
  1379. List<HospProfitVO> inComeFractionList = costProfitVos.stream().filter(f -> f.getCostType() != null && f.getCostType().equals(NumberConstant.ONE) && f.getFraction().equals(NumberConstant.TWO)).collect(Collectors.toList());
  1380. if (CollectionUtils.isEmpty(inComeFractionList)) {
  1381. throw new CostException("全院损益未配置收入占比计算分母");
  1382. } else {
  1383. if (inComeFractionList.size() > 1) {
  1384. throw new CostException("全院损益收入占比计算分母有且只能有一个");
  1385. }
  1386. }
  1387. HospProfitVO inComeFraction = inComeFractionList.get(0);
  1388. HospProfitVO costFraction = costFractionList.get(0);
  1389. for (HospProfitVO costProfitVo : costProfitVos) {
  1390. if (costProfitVo.getCostType() != null) {
  1391. if (costProfitVo.getCostType().equals(NumberConstant.ONE) && costProfitVo.getFraction().equals(NumberConstant.ONE)) {
  1392. //收入
  1393. BigDecimal denominator = inComeFraction.getAmount();
  1394. //收入分子
  1395. if (denominator.compareTo(BigDecimal.ZERO) == 0) {
  1396. costProfitVo.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP));
  1397. } else {
  1398. costProfitVo.setPercent(costProfitVo.getAmount().divide(denominator, 4, RoundingMode.HALF_UP));
  1399. }
  1400. } else if (costProfitVo.getCostType().equals(NumberConstant.TWO) && costProfitVo.getFraction().equals(NumberConstant.ONE)) {
  1401. //成本
  1402. BigDecimal denominator = costFraction.getAmount();
  1403. if (denominator.compareTo(BigDecimal.ZERO) == 0) {
  1404. costProfitVo.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP));
  1405. } else {
  1406. costProfitVo.setPercent(costProfitVo.getAmount().divide(denominator, 4, RoundingMode.HALF_UP));
  1407. }
  1408. }
  1409. }
  1410. }
  1411. Map<Long, List<HospProfitVO>> collect = costProfitVos.stream().collect(Collectors.groupingBy(HospProfitVO::getParentId));
  1412. List<HospProfitVO> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
  1413. collect.remove(NumberConstant.ZERO_L);
  1414. for (HospProfitVO costProfitVo : costProfitParentVos) {
  1415. List<HospProfitVO> costProfitVo1 = collect.get(costProfitVo.getId());
  1416. if (!CollectionUtils.isEmpty(costProfitVo1)) {
  1417. costProfitVo.setChild(setChildren(costProfitVo1, collect));
  1418. }
  1419. }
  1420. if (!CollectionUtils.isEmpty(costProfitParentVos)) {
  1421. costProfitParentVos.sort(Comparator.comparing(HospProfitVO::getSort, Comparator.nullsLast(Integer::compareTo)));
  1422. }
  1423. return costProfitParentVos;
  1424. }
  1425. @Override
  1426. public Object getBatchHospProfitList(String beginComputeDate, String endComputeDate, Long hospId, Integer reportType) {
  1427. List<HospProfitAndLoss> hospProfitAndLossByDateRange = getHospProfitAndLossByDateRange(beginComputeDate, endComputeDate);
  1428. if (CollectionUtils.isEmpty(hospProfitAndLossByDateRange)) {
  1429. throw new CostException(500, "未进行全院损益计算");
  1430. }
  1431. //获取全院损益表配置信息
  1432. List<ReportForm> reportFormList=getReportFormList(hospId,reportType);
  1433. if (CollectionUtils.isEmpty(reportFormList)) {
  1434. throw new CostException(500, "未找到全院损益表配置");
  1435. }
  1436. //按年-月进行分组
  1437. Map<String, List<HospProfitAndLoss>> groupedByYearMonth = hospProfitAndLossByDateRange.stream()
  1438. .collect(Collectors.groupingBy(
  1439. item -> item.getDateYear() + "-" + (item.getDateMonth() < 10 ? "0" + item.getDateMonth() : item.getDateMonth())
  1440. ));
  1441. List<BatchCostProfitResponse> responses = new ArrayList<>();
  1442. List<CostProfitVo> allCostProfitVo=new ArrayList<>();
  1443. //按年-月处理科室损益数据
  1444. for (Map.Entry<String, List<HospProfitAndLoss>> entry : groupedByYearMonth.entrySet()){
  1445. List<HospProfitAndLoss> hospProfitAndLossList = entry.getValue();
  1446. List<CostProfitVo> costProfitVos = convertToCostProfitVoList(hospProfitAndLossList, reportFormList);
  1447. //记录所有月份的损益数据
  1448. allCostProfitVo.addAll(costProfitVos);
  1449. //生成出参样式
  1450. BatchCostProfitResponse response = new BatchCostProfitResponse();
  1451. if(hospProfitAndLossList.get(0).getDateMonth()==13){
  1452. response.setComputeDate(String.format("%s-%s", hospProfitAndLossList.get(0).getDateYear(), "12A"));
  1453. }else {
  1454. response.setComputeDate(entry.getKey());
  1455. }
  1456. response.setProfitVoList(costProfitVos);
  1457. response.setAllowDrillDown(false);
  1458. responses.add(response);
  1459. }
  1460. //起止年月不同时代表有多月份需要处理月累计
  1461. if(!beginComputeDate.equals(endComputeDate)){
  1462. //获取月度汇总数据
  1463. List<CostProfitVo> costProfitVos = generateSummaryForMultipleMonths(allCostProfitVo);
  1464. if(!CollectionUtils.isEmpty(costProfitVos)){
  1465. BatchCostProfitResponse response = new BatchCostProfitResponse();
  1466. response.setComputeDate(String.format("%s至%s", beginComputeDate, endComputeDate));
  1467. response.setProfitVoList(costProfitVos);
  1468. response.setAllowDrillDown(false);
  1469. responses.add(NumberConstant.ZERO,response);
  1470. }
  1471. }
  1472. return responses;
  1473. }
  1474. /**
  1475. * 生成多月份汇总的科室损益数据
  1476. *
  1477. * @param allCostProfitVo 原始数据列表
  1478. * @return 汇总后的科室损益数据
  1479. */
  1480. private List<CostProfitVo> generateSummaryForMultipleMonths(List<CostProfitVo> allCostProfitVo){
  1481. // 参数校验
  1482. if (CollectionUtils.isEmpty(allCostProfitVo)) {
  1483. return Collections.emptyList();
  1484. }
  1485. //排除掉13月的数据
  1486. List<CostProfitVo> activeCostProfitVo = allCostProfitVo.stream().filter(profitVo -> profitVo.getMonth() != 13).collect(Collectors.toList());
  1487. if (CollectionUtils.isEmpty(activeCostProfitVo)) {
  1488. return Collections.emptyList();
  1489. }
  1490. List<CostProfitVo> profitVoList=new ArrayList<>() ;
  1491. Map<Long, List<CostProfitVo>> reportGroup = allCostProfitVo.stream().collect(Collectors.groupingBy(CostProfitVo::getReportId));
  1492. reportGroup.forEach((reportId, profitVos) -> {
  1493. CostProfitVo costProfitVo = BeanUtil.convertObj(profitVos.get(NumberConstant.ZERO), CostProfitVo.class);
  1494. BigDecimal totalAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getAmount()).orElse(BigDecimal.ZERO))
  1495. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1496. BigDecimal totalBudgetAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getBudgetAmount()).orElse(BigDecimal.ZERO))
  1497. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1498. BigDecimal totalPrevPeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getPrevPeriodAmount()).orElse(BigDecimal.ZERO))
  1499. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1500. BigDecimal totalSamePeriodAmount = profitVos.stream().map(vo -> Optional.ofNullable(vo.getSamePeriodAmount()).orElse(BigDecimal.ZERO))
  1501. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1502. costProfitVo.setAmount(totalAmount);
  1503. costProfitVo.setBudgetAmount(totalBudgetAmount);
  1504. costProfitVo.setPrevPeriodAmount(totalPrevPeriodAmount);
  1505. costProfitVo.setSamePeriodAmount(totalSamePeriodAmount);
  1506. costProfitVo.setCompletionRate(calculateProfitRate(costProfitVo.getAmount(), costProfitVo.getBudgetAmount()));
  1507. costProfitVo.setMomRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getPrevPeriodAmount()), costProfitVo.getPrevPeriodAmount()));
  1508. costProfitVo.setYoyRate(calculateProfitRate(costProfitVo.getAmount().subtract(costProfitVo.getSamePeriodAmount()), costProfitVo.getSamePeriodAmount()));
  1509. profitVoList.add(costProfitVo);
  1510. });
  1511. //转成树状结构
  1512. List<CostProfitVo> costProfitVoTree = converToCostProfitVoTree(profitVoList);
  1513. return costProfitVoTree;
  1514. }
  1515. /**
  1516. * 转换为多层级样式全院损益数据
  1517. * @param hospProfitAndLossList
  1518. * @param reportFormList
  1519. * @return
  1520. */
  1521. public List<CostProfitVo> convertToCostProfitVoList(List<HospProfitAndLoss> hospProfitAndLossList,List<ReportForm> reportFormList ){
  1522. //全院其他收支项目
  1523. List<HospProfitAndLoss> otherHospProfitAndLoss = hospProfitAndLossList.stream().filter(i -> NumberConstant.ONE.equals(i.getOriginType())).collect(Collectors.toList());
  1524. //按报表项目编号map
  1525. Map<Integer, HospProfitAndLoss> hospProfitAndLossMap = hospProfitAndLossList.stream().collect(Collectors.toMap(HospProfitAndLoss::getReportNum, b -> b));
  1526. List<CostProfitVo> costProfitVos = BeanUtil.convertList(reportFormList, CostProfitVo.class);
  1527. //组装全院损益及报表项目信息
  1528. for (CostProfitVo profitVo : costProfitVos) {
  1529. //处理年月数据
  1530. profitVo.setYear(hospProfitAndLossList.get(0).getDateYear());
  1531. profitVo.setMonth(hospProfitAndLossList.get(0).getDateMonth());
  1532. //添加损益数据
  1533. HospProfitAndLoss hospProfitAndLoss = hospProfitAndLossMap.get(profitVo.getReportNum());
  1534. if (ObjectUtils.isEmpty(hospProfitAndLoss)) {
  1535. profitVo.setAmount(BigDecimal.ZERO);
  1536. profitVo.setSamePeriodAmount(BigDecimal.ZERO);
  1537. profitVo.setPrevPeriodAmount(BigDecimal.ZERO);
  1538. profitVo.setBudgetAmount(BigDecimal.ZERO);
  1539. profitVo.setYoyRate(BigDecimal.ZERO);
  1540. profitVo.setMomRate(BigDecimal.ZERO);
  1541. profitVo.setCompletionRate(BigDecimal.ZERO);
  1542. } else {
  1543. profitVo.setAmount(hospProfitAndLoss.getAmount());
  1544. profitVo.setSamePeriodAmount(hospProfitAndLoss.getSamePeriodAmount());
  1545. profitVo.setPrevPeriodAmount(hospProfitAndLoss.getPrevPeriodAmount());
  1546. profitVo.setBudgetAmount(hospProfitAndLoss.getBudgetAmount());
  1547. profitVo.setYoyRate(hospProfitAndLoss.getYoyRate());
  1548. profitVo.setMomRate(hospProfitAndLoss.getMomRate());
  1549. profitVo.setCompletionRate(hospProfitAndLoss.getCompletionRate());
  1550. }
  1551. }
  1552. //有全院其他收支时添加全院其他收支
  1553. if(CollectionUtils.isEmpty(otherHospProfitAndLoss)){
  1554. //找到配置的损益项目
  1555. Optional<ReportForm> firstLossReport = reportFormList.stream().filter(i -> NumberConstant.ONE.equals(i.getIsLoss())).findFirst();
  1556. if(!firstLossReport.isPresent()){
  1557. throw new CostException(500, "全院损益报表配置有误,未设置损益项目");
  1558. }
  1559. ReportForm reportForm = firstLossReport.get();
  1560. for (HospProfitAndLoss hospProfitAndLoss : otherHospProfitAndLoss) {
  1561. CostProfitVo costProfitVo = BeanUtil.convertObj(reportForm, CostProfitVo.class);
  1562. //处理年月数据
  1563. costProfitVo.setYear(hospProfitAndLoss.getDateYear());
  1564. costProfitVo.setMonth(hospProfitAndLoss.getDateMonth());
  1565. costProfitVo.setAmount(hospProfitAndLoss.getAmount());
  1566. costProfitVo.setSamePeriodAmount(hospProfitAndLoss.getSamePeriodAmount());
  1567. costProfitVo.setPrevPeriodAmount(hospProfitAndLoss.getPrevPeriodAmount());
  1568. costProfitVo.setBudgetAmount(hospProfitAndLoss.getBudgetAmount());
  1569. costProfitVo.setYoyRate(hospProfitAndLoss.getYoyRate());
  1570. costProfitVo.setMomRate(hospProfitAndLoss.getMomRate());
  1571. costProfitVo.setCompletionRate(hospProfitAndLoss.getCompletionRate());
  1572. //全院其他收支项目排在损益项目后面
  1573. costProfitVo.setSort(reportForm.getSort()+1);
  1574. costProfitVos.add(costProfitVo);
  1575. }
  1576. }
  1577. //转成树状结构的损益数据
  1578. List<CostProfitVo> costProfitVoTree = converToCostProfitVoTree(costProfitVos);
  1579. return costProfitVoTree;
  1580. }
  1581. /**
  1582. * 转成树状结构的损益数据
  1583. * @param costProfitVos
  1584. * @return
  1585. */
  1586. public List<CostProfitVo> converToCostProfitVoTree(List<CostProfitVo> costProfitVos){
  1587. // 参数校验
  1588. if (CollectionUtils.isEmpty(costProfitVos)) {
  1589. return Collections.emptyList();
  1590. }
  1591. Map<Long, List<CostProfitVo>> collect = costProfitVos.stream().collect(Collectors.groupingBy(CostProfitVo::getReportParentId));
  1592. List<CostProfitVo> costProfitParentVos = collect.get(NumberConstant.ZERO_L);
  1593. collect.remove(NumberConstant.ZERO_L);
  1594. for (CostProfitVo costProfitVo : costProfitParentVos) {
  1595. List<CostProfitVo> costProfitVo1 = collect.get(costProfitVo.getReportId());
  1596. if (!CollectionUtils.isEmpty(costProfitVo1)) {
  1597. costProfitVo.setChildren(setChildrenProfitVo(costProfitVo1, collect));
  1598. }
  1599. }
  1600. if (!CollectionUtils.isEmpty(costProfitParentVos)) {
  1601. costProfitParentVos.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
  1602. }
  1603. return costProfitParentVos;
  1604. }
  1605. private List<CostProfitVo> setChildrenProfitVo(List<CostProfitVo> child, Map<Long, List<CostProfitVo>> collect) {
  1606. for (CostProfitVo costProfitVo : child) {
  1607. if (!CollectionUtils.isEmpty(collect.get(costProfitVo.getReportId()))) {
  1608. costProfitVo.setChildren(setChildrenProfitVo(collect.get(costProfitVo.getReportId()), collect));
  1609. }
  1610. }
  1611. if (!CollectionUtils.isEmpty(child)) {
  1612. child.sort(Comparator.comparing(CostProfitVo::getSort, Comparator.nullsLast(Integer::compareTo)));
  1613. }
  1614. return child;
  1615. }
  1616. /**
  1617. * 获取全院损益表配置信息
  1618. * @param hospId
  1619. * @param reportType
  1620. * @return
  1621. */
  1622. public List<ReportForm> getReportFormList(Long hospId,Integer reportType ) {
  1623. List<ReportForm> reportFormList = reportFormService.list(new QueryWrapper<ReportForm>().lambda()
  1624. .eq(ReportForm::getHospId, hospId)
  1625. .eq(ReportForm::getReportType, reportType)
  1626. .eq(ReportForm::getDeleteTime , NumberConstant.ZERO)
  1627. .eq(ReportForm::getHide, NumberConstant.ONE));
  1628. return reportFormList;
  1629. }
  1630. /**
  1631. * 获取指定年月区间的全院损益数据
  1632. * @param beginComputeDate
  1633. * @param endComputeDate
  1634. * @return
  1635. */
  1636. public List<HospProfitAndLoss> getHospProfitAndLossByDateRange(String beginComputeDate, String endComputeDate) {
  1637. // 解析开始和结束时间
  1638. int startYear = Integer.parseInt(beginComputeDate.split("-")[0]);
  1639. int startMonth = Integer.parseInt(beginComputeDate.split("-")[1]);
  1640. int endYear = Integer.parseInt(endComputeDate.split("-")[0]);
  1641. int endMonth = Integer.parseInt(endComputeDate.split("-")[1]);
  1642. if( startYear * 100 + startMonth> endYear * 100 + endMonth){
  1643. throw new CostException("开始时间不能大于结束时间");
  1644. }
  1645. //如果截止月份是12月要自动添加第13月的数据
  1646. if(endMonth==12)
  1647. {
  1648. endMonth=13;
  1649. }
  1650. List<HospProfitAndLoss> list = this.list(new QueryWrapper<HospProfitAndLoss>().lambda()
  1651. .eq(HospProfitAndLoss::getDeleteTime, NumberConstant.ZERO)
  1652. .eq(HospProfitAndLoss::getHospId, UserContext.getHospId())
  1653. .apply("({0} * 100 + {1}) >= {2}",
  1654. "date_year", "date_month", startYear * 100 + startMonth)
  1655. .apply("({0} * 100 + {1}) <= {2}",
  1656. "date_year", "date_month", endYear * 100 + endMonth));
  1657. return list;
  1658. }
  1659. private static @NotNull HospProfitVO getHospProfitVO(List<HospProfitAndLoss> hospAllList, int i,int reportType) {
  1660. HospProfitAndLoss hospProfitAndLoss = hospAllList.get(i);
  1661. HospProfitVO hospProfitVO1 = new HospProfitVO();
  1662. hospProfitVO1.setId(Long.valueOf(hospProfitAndLoss.getReportNum()));
  1663. hospProfitVO1.setNum(hospProfitAndLoss.getReportNum());
  1664. hospProfitVO1.setParentId(-1L);
  1665. hospProfitVO1.setReportName(hospProfitAndLoss.getReportName());
  1666. hospProfitVO1.setSort(i);
  1667. hospProfitVO1.setReportType(reportType);
  1668. hospProfitVO1.setAmount(hospProfitAndLoss.getAmount());
  1669. hospProfitVO1.setFraction(3);
  1670. return hospProfitVO1;
  1671. }
  1672. private List<HospProfitAndLoss> getAllDataByDate(int year, int month, Long hospId,int reportType) {
  1673. return this.list(
  1674. new LambdaQueryWrapper<HospProfitAndLoss>()
  1675. .eq(HospProfitAndLoss::getHospId, hospId)
  1676. .eq(HospProfitAndLoss::getDateMonth, month)
  1677. .eq(HospProfitAndLoss::getDateYear, year)
  1678. .eq(HospProfitAndLoss::getReportType, reportType)
  1679. );
  1680. }
  1681. /**
  1682. * @param date
  1683. * @param hospId
  1684. */
  1685. @Override
  1686. public void calcByResponsibility(String date, Long hospId) {
  1687. calcHospProfit(date,hospId,ReportTypeEnum.HOSP_PROFIT_LOSS.getType());
  1688. }
  1689. private void setCalculationAmount(List<HospProfitAndLossVo> listVo) {
  1690. Map<Integer, List<HospProfitAndLossVo>> collect = listVo.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getCalcType));
  1691. //取出所有计算公式数据
  1692. List<HospProfitAndLossVo> costDepartmentProfitVOS = collect.get(NumberConstant.FOUR);
  1693. costDepartmentProfitVOS.sort(Comparator.comparing(HospProfitAndLossVo::getReportNum, Comparator.nullsLast(Integer::compareTo)));
  1694. for (HospProfitAndLossVo profitVO : costDepartmentProfitVOS) {
  1695. // 获取当前报表的计算方式 [1]+[2]类型/ [1]-[2] [1]*[2] [1]/[2]
  1696. String formula = profitVO.getCalcFormula();
  1697. //找出公式当中所有代码
  1698. String replace = formula.replace("[", "")
  1699. .replace("]", "")
  1700. .replace("-", ",")
  1701. .replace("+", ",")
  1702. .replace("*", ",")
  1703. .replace("/", ",");
  1704. ArrayList<String> codeList = CollUtil.newArrayList(replace.split(","));
  1705. Map<Integer, String> codeMap = new ConcurrentHashMap<>();
  1706. for (int j = 0; j < codeList.size(); j++) {
  1707. codeMap.put(j, codeList.get(j));
  1708. }
  1709. List<String> expressions = ReUtil.findAll("[^0-9]", "+" + formula.replace("[", "")
  1710. .replace("]", "").trim(), 0)
  1711. .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
  1712. // 得到预算表达式 得到所有表达式的Map + - 相关的
  1713. Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
  1714. for (int k = 0; k < expressions.size(); k++) {
  1715. expressionMap.put(k, expressions.get(k));
  1716. }
  1717. // 数字的索引和表达式的索引累加计算
  1718. Set<Integer> codeSet = codeMap.keySet();
  1719. List<Integer> codes = new ArrayList<>(codeSet);
  1720. AtomicReference<BigDecimal> totalAmount = new AtomicReference<>(new BigDecimal("0.000000"));
  1721. for (int i = 0; i < codes.size(); i++) {
  1722. // 编号
  1723. String code = codeMap.get(i);
  1724. BigDecimal amount = null;
  1725. for (HospProfitAndLossVo costDepartmentProfitVO : listVo) {
  1726. if (costDepartmentProfitVO.getReportNum().equals(Integer.valueOf(code))) {
  1727. amount = costDepartmentProfitVO.getAmount();
  1728. }
  1729. }
  1730. if (amount == null) {
  1731. continue;
  1732. }
  1733. // BigDecimal amount = new BigDecimal(o.toString());
  1734. String str = expressionMap.get(i);
  1735. if (str.equals("+")) {
  1736. totalAmount.set(totalAmount.get().add(amount));
  1737. } else if (str.contains("-")) {
  1738. totalAmount.set(totalAmount.get().subtract(amount));
  1739. } else if (str.contains("*")) {
  1740. totalAmount.set(totalAmount.get().multiply(amount));
  1741. } else if (str.contains("/")) {
  1742. if (amount.compareTo(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP)) == 0) {
  1743. totalAmount.set(BigDecimal.ZERO);
  1744. break;
  1745. } else {
  1746. totalAmount.set(totalAmount.get().divide(amount, 6, RoundingMode.HALF_UP));
  1747. }
  1748. }
  1749. }
  1750. profitVO.setAmount(totalAmount.get());
  1751. }
  1752. }
  1753. /**
  1754. * 按照责任中心进行计算
  1755. * 原始责任中心是设置的责任中心 目标责任中心是报表的责任中心
  1756. * 查询分摊报表里面目标责任中心是当前责任中心 报表责任中心是当前设置的责任中心
  1757. */
  1758. public BigDecimal setResponsibilityCode(HospProfitAndLossVo costDepartmentProfitVO, Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList, List<HospProfitAndLossVo> allList) {
  1759. // 获取当前报表对应的责任中心
  1760. List<ReportRelation> reportRelationList = reportRelationMap.get(costDepartmentProfitVO.getReportId());
  1761. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  1762. if (CollUtil.isNotEmpty(reportRelationList)) {
  1763. // 获取对应的责任中心的Code集合 这个是设置的责任中心
  1764. List<String> responsibilityCodes = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
  1765. if (CollUtil.isNotEmpty(responsibilityCodes)) {
  1766. // 查询报表里面是当前分摊层级的数据
  1767. List<Allocation> allocations = allocationList.stream().filter(i -> i.getTargetResponsibilityCode().equals(costDepartmentProfitVO.getResponsibilityCode()) && responsibilityCodes.contains(i.getResponsibilityCode())).collect(Collectors.toList());
  1768. if (CollUtil.isNotEmpty(allocations)) {
  1769. BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1770. sum.set(reduce);
  1771. // allocations.forEach(m -> {
  1772. // sum.updateAndGet(v -> v.add(m.getAmount()));
  1773. // });
  1774. }
  1775. }
  1776. }
  1777. // costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString()));
  1778. return sum.get();
  1779. }
  1780. /***
  1781. * 按照计算方式进行计算
  1782. */
  1783. public BigDecimal setCalculation(HospProfitAndLossVo costDepartmentProfitVO, List<HospProfitAndLossVo> costDepartmentProfitVOList,
  1784. List<CostShareLevel> costShareLevelList, Map<Long, List<HospProfitAndLossVo>> listMap,
  1785. List<IncomeCollection> list, List<AllocationQueryReportVO> allocationQueryReportVOList,
  1786. Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList, List<HospProfitAndLossVo> allList) {
  1787. // 获取当前报表的计算方式 [1]+[2]类型/ [1]-[2]
  1788. String calcFormula = costDepartmentProfitVO.getCalcFormula();
  1789. String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode();
  1790. String replace = calcFormula.replace("[", "").replace("]", "").replace("+", ",").replace("-", ",-");
  1791. List<Integer> calcFormulaList = Arrays.stream(replace.split(StrUtil.COMMA)).map(Integer::valueOf).collect(Collectors.toList());
  1792. // 查询这个编号集合的报表
  1793. AtomicReference<BigDecimal> bigDecimal = new AtomicReference<>(new BigDecimal("0.0000"));
  1794. calcFormulaList.forEach(calc -> {
  1795. Integer calcNum = Math.abs(calc);
  1796. List<Long> reportIdList = allList.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode) && calcNum.equals(i.getReportNum())).map(HospProfitAndLossVo::getReportId).collect(Collectors.toList());
  1797. if (CollUtil.isNotEmpty(reportIdList)) {
  1798. reportIdList.forEach(i -> {
  1799. List<HospProfitAndLossVo> profitVOS = listMap.get(i);
  1800. if (CollUtil.isEmpty(profitVOS)) {
  1801. throw new CostException(500, "报表未找到");
  1802. }
  1803. BigDecimal amount = getAmount(profitVOS, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap, allList);
  1804. if (calc > 0) {
  1805. bigDecimal.updateAndGet(v -> v.add(amount));
  1806. } else {
  1807. bigDecimal.updateAndGet(v -> v.subtract(amount));
  1808. }
  1809. });
  1810. }
  1811. });
  1812. return bigDecimal.get();
  1813. }
  1814. /**
  1815. * 按照小计的计算方式
  1816. * 同一个目录下相同的其他金额的和
  1817. */
  1818. public BigDecimal setSubtotal(HospProfitAndLossVo costDepartmentProfitVO,
  1819. List<CostShareLevel> costShareLevelList,
  1820. Map<Long, List<HospProfitAndLossVo>> listMap,
  1821. List<HospProfitAndLossVo> profitVOS,
  1822. List<IncomeCollection> list,
  1823. List<AllocationQueryReportVO> allocationQueryReportVOList,
  1824. Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList, List<HospProfitAndLossVo> allList) {
  1825. // 因为报表是按照报表项目的升序进行排序的 前面的报表是已经进行计算了的
  1826. // 查询当前报表的父层级id
  1827. Long reportParentId = costDepartmentProfitVO.getReportParentId();
  1828. String responsibilityCode = costDepartmentProfitVO.getResponsibilityCode();
  1829. // 查询报表里面在当前父层级下的并且不是自己的报表项目
  1830. List<HospProfitAndLossVo> costDepartmentProfitVOS = allList.stream().filter(i -> i.getReportParentId().equals(reportParentId) && i.getResponsibilityCode().equals(responsibilityCode) && !NumberConstant.THREE.equals(i.getCalcType())).collect(Collectors.toList());
  1831. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.0000"));
  1832. // 遍历数据 之前的已经经过了计算
  1833. costDepartmentProfitVOS.forEach(i -> {
  1834. Long reportId = i.getReportId();
  1835. List<HospProfitAndLossVo> costDepartmentProfitVOS1 = listMap.get(reportId);
  1836. if (CollUtil.isEmpty(costDepartmentProfitVOS1)) {
  1837. throw new CostException(500, "报表未找到");
  1838. }
  1839. BigDecimal amount = getAmount(costDepartmentProfitVOS1, costShareLevelList, responsibilityCode, list, allocationQueryReportVOList, reportRelationMap, allocationList, listMap, allList);
  1840. sum.set(amount.add(sum.get()));
  1841. ;
  1842. });
  1843. // costDepartmentProfitVO.setAmount(new BigDecimal(sum.toString()));
  1844. return sum.get();
  1845. }
  1846. /**
  1847. * 判断是那种计算方式 调用方法进行计算
  1848. */
  1849. public BigDecimal getAmount(List<HospProfitAndLossVo> profitVOS,
  1850. List<CostShareLevel> costShareLevelList,
  1851. String responsibilityCode, List<IncomeCollection> list,
  1852. List<AllocationQueryReportVO> allocationQueryReportVOList,
  1853. Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList,
  1854. Map<Long, List<HospProfitAndLossVo>> listMap, List<HospProfitAndLossVo> allList) {
  1855. BigDecimal bigDecimal = new BigDecimal("0.0000");
  1856. // 在对这个报表进行过滤
  1857. List<HospProfitAndLossVo> costDepartmentProfitVOS = profitVOS.stream().filter(i -> i.getResponsibilityCode().equals(responsibilityCode)).collect(Collectors.toList());
  1858. // 都一个就是
  1859. HospProfitAndLossVo costDepartmentProfitVO = costDepartmentProfitVOS.get(0);
  1860. Integer calcType = costDepartmentProfitVO.getCalcType();
  1861. if (NumberConstant.ONE.equals(calcType)) {
  1862. // 调用计算的方法 按照会计科目
  1863. bigDecimal = setAccountReportData(costDepartmentProfitVO, list, allocationQueryReportVOList, reportRelationMap);
  1864. } else if (NumberConstant.TWO.equals(calcType)) {
  1865. // 按照分摊层级
  1866. bigDecimal = setShareLevelReportData(costDepartmentProfitVO, reportRelationMap, allocationList);
  1867. } else if (NumberConstant.THREE.equals(calcType)) {
  1868. // 小计
  1869. bigDecimal = setSubtotal(costDepartmentProfitVO, costShareLevelList, listMap, profitVOS, list, allocationQueryReportVOList, reportRelationMap, allocationList, allList);
  1870. } else if (NumberConstant.FIVE.equals(calcType)) {
  1871. // 按照责任中心
  1872. bigDecimal = setResponsibilityCode(costDepartmentProfitVO, reportRelationMap, allocationList, allList);
  1873. } else if (NumberConstant.FOUR.equals(calcType)) {
  1874. bigDecimal = setCalculation(costDepartmentProfitVO, costDepartmentProfitVOS, costShareLevelList, listMap, list, allocationQueryReportVOList, reportRelationMap, allocationList, allList);
  1875. }
  1876. return bigDecimal;
  1877. }
  1878. private BigDecimal setAccountReportData(HospProfitAndLossVo i, List<IncomeCollection> list, List<AllocationQueryReportVO> allocationQueryReportVOList, Map<Long, List<ReportRelation>> reportRelationMap) {
  1879. // 在报表关联里面查询当前报表关联的
  1880. Long reportId = i.getReportId();
  1881. List<ReportRelation> reportRelationList = reportRelationMap.get(reportId);
  1882. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  1883. if (CollUtil.isNotEmpty(reportRelationList)) {
  1884. // 获取对应的会计科目信息 筛选会计科目的Code
  1885. List<String> accountList = reportRelationList.stream().map(ReportRelation::getRelationCode).collect(Collectors.toList());
  1886. // 查找在归集数据里面当前责任中心对应的这些会计科目的金额
  1887. List<IncomeCollection> incomeCollectionList = list.stream().filter(income -> income.getResponsibilityCode().equals(i.getResponsibilityCode()) && accountList.contains(income.getAccountingCode())).collect(Collectors.toList());
  1888. // 需要查询分摊后的表
  1889. List<AllocationQueryReportVO> reportVOList = allocationQueryReportVOList.stream().filter(m -> m.getTargetResponsibilityCode().equals(i.getResponsibilityCode()) && accountList.contains(m.getAccountingCode())).collect(Collectors.toList());
  1890. if (CollUtil.isNotEmpty(incomeCollectionList)) {
  1891. incomeCollectionList.forEach(m -> {
  1892. sum.updateAndGet(v -> v.add(m.getAmount()));
  1893. });
  1894. }
  1895. // 成本减
  1896. if (CollUtil.isNotEmpty(reportVOList)) {
  1897. reportVOList.forEach(m -> {
  1898. sum.updateAndGet(v -> v.add(m.getAmount()));
  1899. });
  1900. }
  1901. }
  1902. // i.setAmount(new BigDecimal(sum.toString()));
  1903. // numMap.put(i.getReportNum()+i.getResponsibilityCode(),new BigDecimal(sum.toString()));
  1904. return sum.get();
  1905. }
  1906. private BigDecimal setShareLevelReportData(HospProfitAndLossVo i, Map<Long, List<ReportRelation>> reportRelationMap, List<Allocation> allocationList) {
  1907. List<ReportRelation> reportRelationList = reportRelationMap.get(i.getReportId());
  1908. AtomicReference<BigDecimal> sum = new AtomicReference<>(new BigDecimal("0.000"));
  1909. if (CollUtil.isNotEmpty(reportRelationList)) {
  1910. // 找到对应的分摊层级的Id 但是分摊报表里面存的是分摊层级的序号
  1911. List<Long> shareLevelIds = reportRelationList.stream().map(ReportRelation::getRelationCode).map(Long::valueOf).collect(Collectors.toList());
  1912. // List<Integer> levelShortList = costShareLevelList.stream()
  1913. // .filter(m -> shareLevelIds.contains(m.getId()))
  1914. // .map(CostShareLevel::getLeverSort).collect(Collectors.toList());
  1915. if (CollUtil.isNotEmpty(shareLevelIds)) {
  1916. // 查询报表里面是当前分摊层级的数据
  1917. List<Allocation> allocations = allocationList.stream().filter(m -> shareLevelIds.contains(m.getShareLevelId()) && m.getTargetResponsibilityCode().equals(i.getResponsibilityCode())).collect(Collectors.toList());
  1918. if (CollUtil.isNotEmpty(allocations)) {
  1919. // allocations.forEach(m -> {
  1920. // sum.updateAndGet(v -> v.add(m.getAmount()));
  1921. // });
  1922. BigDecimal reduce = allocations.stream().map(Allocation::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1923. sum.set(reduce);
  1924. }
  1925. }
  1926. }
  1927. // i.setAmount(new BigDecimal(sum.toString()));
  1928. return sum.get();
  1929. }
  1930. private void calcByLitterCountResp(HospProfitAndLossVo lossVo, Map<Long, List<HospProfitAndLossVo>> listParentMap, List<HospProfitAndLossVo> listVo, Long hospId) {
  1931. //lossVo 当前 小计对象
  1932. //listParentMap 与小计同级别的对象
  1933. //listVo 存储计算过的对象
  1934. // 通地当前小计 找出 同级别需要合计的对象 再从计算过的对象取出数值合计
  1935. Long reportParentId = lossVo.getReportParentId();
  1936. List<HospProfitAndLossVo> hospProfitAndLossVos = listParentMap.get(reportParentId);
  1937. //去除小计本身
  1938. hospProfitAndLossVos.remove(lossVo);
  1939. List<Integer> reportNums = hospProfitAndLossVos.stream().map(HospProfitAndLossVo::getReportNum).collect(Collectors.toList());
  1940. List<HospProfitAndLossVo> collect = listVo.stream().filter(i -> reportNums.contains(i.getReportNum()) && i.getResponsibilityCode().equals(lossVo.getResponsibilityCode())).collect(Collectors.toList());
  1941. if (collect.isEmpty()) {
  1942. return;
  1943. }
  1944. BigDecimal reduce = collect.stream().map(HospProfitAndLossVo::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  1945. lossVo.setAmount(reduce);
  1946. }
  1947. private List<HospProfitAndLossVo> costPercent(List<HospProfitAndLossVo> profitIncomeList) {
  1948. List<HospProfitAndLossVo> list = new ArrayList<>();
  1949. Map<Integer, List<HospProfitAndLossVo>> collect = profitIncomeList.stream().collect(Collectors.groupingBy(HospProfitAndLossVo::getFraction));
  1950. //分母只有一个
  1951. List<HospProfitAndLossVo> denominatorList = collect.get(NumberConstant.TWO);
  1952. if (denominatorList.size() > 1) {
  1953. throw new CostException("收入项目分母大于一个,请查证后再计算科室损益");
  1954. }
  1955. BigDecimal denominator = denominatorList.get(0).getAmount();
  1956. //收入分子
  1957. List<HospProfitAndLossVo> numeratorList = collect.get(NumberConstant.ONE);
  1958. if (denominator.compareTo(BigDecimal.ZERO) == 0) {
  1959. for (HospProfitAndLossVo profitVO : numeratorList) {
  1960. profitVO.setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP));
  1961. }
  1962. denominatorList.get(0).setPercent(BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP));
  1963. } else {
  1964. for (HospProfitAndLossVo profitVO : numeratorList) {
  1965. profitVO.setPercent(profitVO.getAmount().divide(denominator, 4, RoundingMode.HALF_UP));
  1966. }
  1967. denominatorList.get(0).setPercent(BigDecimal.ONE.setScale(4, RoundingMode.HALF_UP));
  1968. }
  1969. list.add(denominatorList.get(0));
  1970. list.addAll(numeratorList);
  1971. return list;
  1972. }
  1973. private void calcByResponsibilityResp(Long hospId, HospProfitAndLossVo lossVo) {
  1974. List<RelationVO> responsibilities = reportRelationService.getResponsibilities(lossVo.getReportId(), hospId);
  1975. if (responsibilities.isEmpty()) {
  1976. return;
  1977. }
  1978. List<String> responsibilityCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList());
  1979. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  1980. calcTotal.set(BigDecimal.ZERO);
  1981. List<AllocationQuery> allocationQueries = allocationQueryService.getByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode());
  1982. responsibilityCodes.forEach(i -> {
  1983. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount)
  1984. .reduce(BigDecimal.ZERO, BigDecimal::add);
  1985. calcTotal.set(calcTotal.get().add(costAmount));
  1986. });
  1987. lossVo.setAmount(calcTotal.get());
  1988. }
  1989. private void calcByResponsibilityResp(Long hospId, ReportForm child, List<HospProfitAndLoss> list, int year, int month, Responsibility responsibility) {
  1990. List<RelationVO> responsibilities = reportRelationService.getResponsibilities(child.getId(), hospId);
  1991. if (responsibilities.isEmpty()) {
  1992. return;
  1993. }
  1994. List<String> responsibilityCodes = responsibilities.stream().map(RelationVO::getCode).collect(Collectors.toList());
  1995. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  1996. calcTotal.set(BigDecimal.ZERO);
  1997. List<AllocationQuery> allocationQueries = allocationQueryService.getByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode());
  1998. responsibilityCodes.forEach(i -> {
  1999. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getResponsibilityCode())).map(AllocationQuery::getAmount)
  2000. .reduce(BigDecimal.ZERO, BigDecimal::add);
  2001. calcTotal.set(calcTotal.get().add(costAmount));
  2002. });
  2003. HospProfitAndLoss loss = new HospProfitAndLoss();
  2004. loss.setReportName(child.getReportName()).setReportNum(child.getNum()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
  2005. .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month);
  2006. list.add(loss);
  2007. }
  2008. private void calcByFormulaResp(HospProfitAndLossVo lossVo, List<HospProfitAndLossVo> list) {
  2009. // 得到这个责任中心下所有的已经收集的数据
  2010. List<HospProfitAndLossVo> hadCalcLosses = list.stream().filter(i -> i.getResponsibilityCode().equals(lossVo.getResponsibilityCode())).collect(Collectors.toList());
  2011. String calcFormula = lossVo.getCalcFormula();
  2012. // TODO: 2021/8/27 校验公式合法性
  2013. if (StrUtil.isBlank(calcFormula)) {
  2014. throw new CostException("reportForm名称为" + lossVo.getReportName() + "计算公式不正确");
  2015. }
  2016. BigDecimal bigDecimal = calcAmountRes(hadCalcLosses, calcFormula);
  2017. lossVo.setAmount(bigDecimal);
  2018. }
  2019. private void calcByFormulaResp(int year, int month, ReportForm child, List<HospProfitAndLoss> list, Responsibility responsibility) {
  2020. // 得到这个责任中心下所有的已经收集的数据
  2021. List<HospProfitAndLoss> hadCalcLosses = list.stream().filter(i -> i.getResponsibilityCode().equals(responsibility.getResponsibilityCode())).collect(Collectors.toList());
  2022. String calcFormula = child.getCalcFormula();
  2023. // TODO: 2021/8/27 校验公式合法性
  2024. if (StrUtil.isBlank(calcFormula)) {
  2025. throw new CostException("reportForm名称为" + child.getReportName() + "计算公式不正确");
  2026. }
  2027. BigDecimal bigDecimal = calcAmountResp(hadCalcLosses, calcFormula);
  2028. HospProfitAndLoss loss = new HospProfitAndLoss();
  2029. loss.setDateYear(year).setDateMonth(month).setReportNum(child.getNum()).setReportName(child.getReportName())
  2030. .setAmount(bigDecimal).setCreateTime(System.currentTimeMillis()).setHospId(child.getHospId()).setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName());
  2031. list.add(loss);
  2032. }
  2033. private BigDecimal calcAmountRes(List<HospProfitAndLossVo> hadCalcLosses, String calcFormula) {
  2034. // 得到所有的编号
  2035. String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
  2036. ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
  2037. // 得到编号的map
  2038. Map<Integer, Integer> numMap = new ConcurrentHashMap<>();
  2039. for (int j = 0; j < numList.size(); j++) {
  2040. numMap.put(j, Integer.parseInt(numList.get(j)));
  2041. }
  2042. List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
  2043. .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
  2044. // 得到预算表达式 得到所有表达式的Map + - 相关的
  2045. Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
  2046. for (int k = 0; k < expressions.size(); k++) {
  2047. expressionMap.put(k, expressions.get(k));
  2048. }
  2049. // 数字的索引和表达式的索引累加计算
  2050. Set<Integer> numSet = numMap.keySet();
  2051. List<Integer> nums = new ArrayList<>(numSet);
  2052. AtomicReference<BigDecimal> totalAmount = new AtomicReference<>();
  2053. totalAmount.set(BigDecimal.ZERO);
  2054. for (int i = 0; i < nums.size(); i++) {
  2055. // 编号
  2056. Integer num = numMap.get(i);
  2057. List<HospProfitAndLossVo> losses = hadCalcLosses.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList());
  2058. if (CollUtil.isEmpty(losses)) {
  2059. continue;
  2060. }
  2061. HospProfitAndLossVo loss = losses.get(0);
  2062. BigDecimal amount = loss.getAmount();
  2063. String str = expressionMap.get(i);
  2064. if (str.equals("+")) {
  2065. totalAmount.set(totalAmount.get().add(amount));
  2066. } else {
  2067. totalAmount.set(totalAmount.get().subtract(amount));
  2068. }
  2069. }
  2070. return totalAmount.get();
  2071. }
  2072. private BigDecimal calcAmountResp(List<HospProfitAndLoss> hadCalcLosses, String calcFormula) {
  2073. // 得到所有的编号
  2074. String replace = calcFormula.replace("[", "").replace("]", "").replace("-", ",").replace("+", ",");
  2075. ArrayList<String> numList = CollUtil.newArrayList(replace.split(","));
  2076. // 得到编号的map
  2077. Map<Integer, Integer> numMap = new ConcurrentHashMap<>();
  2078. for (int j = 0; j < numList.size(); j++) {
  2079. numMap.put(j, Integer.parseInt(numList.get(j)));
  2080. }
  2081. List<String> expressions = ReUtil.findAll("[^0-9]", "+" + calcFormula.replace("[", "").replace("]", "").trim(), 0)
  2082. .stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
  2083. // 得到预算表达式 得到所有表达式的Map + - 相关的
  2084. Map<Integer, String> expressionMap = new ConcurrentHashMap<>();
  2085. for (int k = 0; k < expressions.size(); k++) {
  2086. expressionMap.put(k, expressions.get(k));
  2087. }
  2088. // 数字的索引和表达式的索引累加计算
  2089. Set<Integer> numSet = numMap.keySet();
  2090. List<Integer> nums = new ArrayList<>(numSet);
  2091. AtomicReference<BigDecimal> totalAmount = new AtomicReference<>();
  2092. totalAmount.set(BigDecimal.ZERO);
  2093. for (int i = 0; i < nums.size(); i++) {
  2094. // 编号
  2095. Integer num = numMap.get(i);
  2096. List<HospProfitAndLoss> losses = hadCalcLosses.stream().filter(item -> item.getReportNum().equals(num)).collect(Collectors.toList());
  2097. if (CollUtil.isEmpty(losses)) {
  2098. continue;
  2099. }
  2100. HospProfitAndLoss loss = losses.get(0);
  2101. BigDecimal amount = loss.getAmount();
  2102. String str = expressionMap.get(i);
  2103. if (str.equals("+")) {
  2104. totalAmount.set(totalAmount.get().add(amount));
  2105. } else {
  2106. totalAmount.set(totalAmount.get().subtract(amount));
  2107. }
  2108. }
  2109. return totalAmount.get();
  2110. }
  2111. private void calcByLitterCountResp(int year, int month, ReportForm child, List<ReportForm> children,
  2112. List<HospProfitAndLoss> list, Long hospId, Responsibility responsibility) {
  2113. List<HospProfitAndLoss> thisRespCodeList = list.stream().filter(i -> i.getResponsibilityCode().equals(responsibility.getResponsibilityCode())).collect(Collectors.toList());
  2114. List<ReportForm> thisForEachList = children.stream().filter(i -> !i.getCalcType().equals(CalcTypeEnum.LITTER_COUNT.getType())).collect(Collectors.toList());
  2115. List<HospProfitAndLoss> collect = thisRespCodeList.stream().filter(i -> thisForEachList.stream().map(ReportForm::getNum).collect(Collectors.toList()).contains(i.getReportNum())).collect(Collectors.toList());
  2116. if (collect.isEmpty()) {
  2117. return;
  2118. }
  2119. BigDecimal reduce = collect.stream().map(HospProfitAndLoss::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  2120. HospProfitAndLoss loss = new HospProfitAndLoss();
  2121. loss.setDateYear(year).setDateMonth(month)
  2122. .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId);
  2123. // 小计只能有一个
  2124. loss.setReportNum(child.getNum()).setReportName(child.getReportName())
  2125. .setResponsibilityCode(responsibility.getResponsibilityCode())
  2126. .setResponsibilityName(responsibility.getResponsibilityName());
  2127. list.add(loss);
  2128. }
  2129. private void calcByShareLevelResp(Long hospId, ReportForm child, List<HospProfitAndLoss> list, int year, int month, Responsibility responsibility) {
  2130. List<RelationVO> shareLevels = reportRelationService.getShareLevel(child.getId(), hospId);
  2131. List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList());
  2132. if (CollUtil.isEmpty(shareLevelId)) {
  2133. return;
  2134. }
  2135. List<CostShareLevel> costShareLevels = shareLevelService.listByIds(shareLevelId);
  2136. if (costShareLevels.isEmpty()) {
  2137. throw new CostException("医院分摊层级设置错误," + child.getReportName());
  2138. }
  2139. List<Integer> levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList());
  2140. List<AllocationQuery> allocations = allocationQueryService.getByDateRespn(year, month, hospId, shareLevelId, responsibility.getResponsibilityCode());
  2141. if (allocations.isEmpty()) {
  2142. throw new CostException("医院未分摊本月数据");
  2143. }
  2144. List<CostAccountShare> accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId);
  2145. if (accountShares.isEmpty()) {
  2146. return;
  2147. }
  2148. BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  2149. HospProfitAndLoss loss = new HospProfitAndLoss();
  2150. loss.setReportName(child.getReportName()).setReportNum(child.getNum())
  2151. .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month)
  2152. .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
  2153. ;
  2154. list.add(loss);
  2155. }
  2156. private void calcByShareLevelResp(Long hospId, HospProfitAndLossVo lossVo) {
  2157. List<RelationVO> shareLevels = reportRelationService.getShareLevel(lossVo.getReportId(), hospId);
  2158. List<Long> shareLevelId = shareLevels.stream().map(RelationVO::getCode).map(Long::valueOf).sorted(Long::compareTo).collect(Collectors.toList());
  2159. if (CollUtil.isEmpty(shareLevelId)) {
  2160. return;
  2161. }
  2162. List<CostShareLevel> costShareLevels = shareLevelService.listByIds(shareLevelId);
  2163. if (costShareLevels.isEmpty()) {
  2164. throw new CostException("医院分摊层级设置错误," + lossVo.getReportName());
  2165. }
  2166. List<Integer> levelSorts = costShareLevels.stream().map(CostShareLevel::getLeverSort).collect(Collectors.toList());
  2167. List<AllocationQuery> allocations = allocationQueryService.getByDateRespn(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, shareLevelId, lossVo.getResponsibilityCode());
  2168. if (allocations.isEmpty()) {
  2169. throw new CostException("医院未分摊本月数据");
  2170. }
  2171. List<CostAccountShare> accountShares = accountShareService.getByShareLevelSort(levelSorts, hospId);
  2172. if (accountShares.isEmpty()) {
  2173. return;
  2174. }
  2175. BigDecimal reduce = allocations.stream().map(AllocationQuery::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
  2176. lossVo.setAmount(reduce);
  2177. // HospProfitAndLoss loss = new HospProfitAndLoss();
  2178. // loss.setReportName(child.getReportName()).setReportNum(child.getNum())
  2179. // .setAmount(reduce).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month)
  2180. // .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
  2181. // ;
  2182. // list.add(loss);
  2183. }
  2184. private void calcByAccountByResp(Long hospId, HospProfitAndLossVo lossVo) {
  2185. // 报表项目关联的会计科目对象
  2186. List<RelationVO> accountRelations = reportRelationService.getAccountRelation(lossVo.getReportId(), hospId);
  2187. if (accountRelations.isEmpty()) {
  2188. return;
  2189. }
  2190. List<String> accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList());
  2191. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  2192. calcTotal.set(BigDecimal.ZERO);
  2193. List<IncomeCollection> incomes = collectionService.getCollectionsByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode());
  2194. List<AllocationQuery> allocationQueries = allocationQueryService.getByDateAndResp(lossVo.getDateYear(), lossVo.getDateMonth(), hospId, lossVo.getResponsibilityCode());
  2195. accountCodes.forEach(i -> {
  2196. BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount)
  2197. .reduce(BigDecimal.ZERO, BigDecimal::add);
  2198. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount)
  2199. .reduce(BigDecimal.ZERO, BigDecimal::add);
  2200. BigDecimal total = incomeAmount.add(costAmount);
  2201. calcTotal.set(calcTotal.get().add(total));
  2202. });
  2203. // HospProfitAndLoss loss = new HospProfitAndLoss();
  2204. lossVo.setAmount(calcTotal.get());
  2205. // loss.setReportName(child.getReportName()).setReportNum(child.getNum())
  2206. // .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month)
  2207. // .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName());
  2208. // list.add(loss);
  2209. }
  2210. private void calcByAccountByResp(Long hospId, ReportForm child, List<HospProfitAndLoss> list, int month, int year, Responsibility responsibility) {
  2211. // 报表项目关联的会计科目对象
  2212. List<RelationVO> accountRelations = reportRelationService.getAccountRelation(child.getId(), hospId);
  2213. if (accountRelations.isEmpty()) {
  2214. return;
  2215. }
  2216. List<String> accountCodes = accountRelations.stream().map(RelationVO::getCode).collect(Collectors.toList());
  2217. AtomicReference<BigDecimal> calcTotal = new AtomicReference<>();
  2218. calcTotal.set(BigDecimal.ZERO);
  2219. List<IncomeCollection> incomes = collectionService.getCollectionsByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode());
  2220. List<AllocationQuery> allocationQueries = allocationQueryService.getByDateAndResp(year, month, hospId, responsibility.getResponsibilityCode());
  2221. accountCodes.forEach(i -> {
  2222. BigDecimal incomeAmount = incomes.stream().filter(j -> i.equals(j.getAccountingCode())).map(IncomeCollection::getAmount)
  2223. .reduce(BigDecimal.ZERO, BigDecimal::add);
  2224. BigDecimal costAmount = allocationQueries.stream().filter(j -> i.equals(j.getAccountingCode())).map(AllocationQuery::getAmount)
  2225. .reduce(BigDecimal.ZERO, BigDecimal::add);
  2226. BigDecimal total = incomeAmount.add(costAmount);
  2227. calcTotal.set(calcTotal.get().add(total));
  2228. });
  2229. HospProfitAndLoss loss = new HospProfitAndLoss();
  2230. loss.setReportName(child.getReportName()).setReportNum(child.getNum())
  2231. .setAmount(calcTotal.get()).setCreateTime(System.currentTimeMillis()).setHospId(hospId).setDateYear(year).setDateMonth(month)
  2232. .setResponsibilityCode(responsibility.getResponsibilityCode()).setResponsibilityName(responsibility.getResponsibilityName())
  2233. ;
  2234. list.add(loss);
  2235. }
  2236. private void responsibilitySort(List<Responsibility> responsibilityList) {
  2237. for (Responsibility responsibility : responsibilityList) {
  2238. if (!CollectionUtils.isEmpty(responsibility.getChildren())) {
  2239. responsibilitySort(responsibility.getChildren());
  2240. }
  2241. }
  2242. responsibilityList.sort(Comparator.comparing(Responsibility::getSort, Comparator.nullsLast(Integer::compareTo)));
  2243. }
  2244. private List<Responsibility> setResponsibilityChildren(List<Responsibility> child, Map<Long, List<Responsibility>> collect) {
  2245. for (Responsibility responsibility : child) {
  2246. if (!CollectionUtils.isEmpty(collect.get(responsibility.getId()))) {
  2247. responsibility.setChildren(setResponsibilityChildren(collect.get(responsibility.getId()), collect));
  2248. }
  2249. }
  2250. return child;
  2251. }
  2252. private void getResponsibilityParent(Responsibility responsibility, Map<Long, Responsibility> collect, List<Responsibility> addList) {
  2253. Responsibility responsibility1 = collect.get(responsibility.getParentId());
  2254. if (Objects.nonNull(responsibility1)) {
  2255. addList.add(responsibility1);
  2256. if (!responsibility1.getParentId().equals(NumberConstant.ZERO_L)) {
  2257. getResponsibilityParent(responsibility1, collect, addList);
  2258. }
  2259. }
  2260. }
  2261. private List<HospProfitVO> setChildren(List<HospProfitVO> child, Map<Long, List<HospProfitVO>> collect) {
  2262. for (HospProfitVO costProfitVo : child) {
  2263. if (!CollectionUtils.isEmpty(collect.get(costProfitVo.getId()))) {
  2264. costProfitVo.setChild(setChildren(collect.get(costProfitVo.getId()), collect));
  2265. }
  2266. }
  2267. if (!CollectionUtils.isEmpty(child)) {
  2268. child.sort(Comparator.comparing(HospProfitVO::getSort, Comparator.nullsLast(Integer::compareTo)));
  2269. }
  2270. return child;
  2271. }
  2272. }