SiZyFeeService.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. package thyyxxk.sizyfeeoprnsystm.service;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.web.client.RestTemplate;
  6. import thyyxxk.sizyfeeoprnsystm.dao.SiLogDao;
  7. import thyyxxk.sizyfeeoprnsystm.dao.SiZyDao;
  8. import thyyxxk.sizyfeeoprnsystm.dicts.MdtrtCertType;
  9. import thyyxxk.sizyfeeoprnsystm.dicts.PsnSetlWay;
  10. import thyyxxk.sizyfeeoprnsystm.dicts.SiFunction;
  11. import thyyxxk.sizyfeeoprnsystm.dicts.YesOrNo;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.stereotype.Service;
  15. import thyyxxk.sizyfeeoprnsystm.pojo.*;
  16. import thyyxxk.sizyfeeoprnsystm.utils.*;
  17. import java.text.SimpleDateFormat;
  18. import java.util.*;
  19. import java.util.concurrent.ConcurrentHashMap;
  20. import java.util.concurrent.atomic.AtomicInteger;
  21. /**
  22. * @author dj
  23. */
  24. @Slf4j
  25. @Service
  26. public class SiZyFeeService {
  27. private static final String RESULT_CODE = "infcode";
  28. private static final String ERROR_MESSAGE = "err_msg";
  29. private static final String OUTPUT = "output";
  30. private final SiZyDao zyDao;
  31. private final SiLogDao logDao;
  32. private final ExecService exec;
  33. @Value("${upld-notify-url}")
  34. private String upldNotifyUrl;
  35. @Autowired
  36. public SiZyFeeService(SiZyDao zyDao, SiLogDao logDao, ExecService exec) {
  37. this.zyDao = zyDao;
  38. this.logDao = logDao;
  39. this.exec = exec;
  40. }
  41. private void revokeUploadFees(ZyPatientInfo p) {
  42. if (null == p.getDetailSns() || p.getDetailSns().isEmpty()) {
  43. return;
  44. }
  45. SiPatInfo siPatInfo = zyDao.selectSiPatInfoForZy(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
  46. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  47. return;
  48. }
  49. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_HOSPITALIZATION_FEE_DETAILS,
  50. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  51. JSONArray data = new JSONArray();
  52. p.getDetailSns().forEach(detailSn -> {
  53. JSONObject item = new JSONObject();
  54. item.put("feedetl_sn", detailSn);
  55. item.put("mdtrt_id", siPatInfo.getMdtrtId());
  56. item.put("psn_no", siPatInfo.getPsnNo());
  57. data.add(item);
  58. });
  59. input.getJSONObject("input").put("data", data);
  60. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_HOSPITALIZATION_FEE_DETAILS);
  61. log.info("【操作员:{}】撤销已上传的费用:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  62. if (null == result || null == result.getInteger(RESULT_CODE)) {
  63. ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  64. return;
  65. }
  66. if (result.getIntValue(RESULT_CODE) == 0) {
  67. if (null == p.getDetailSns() || p.getDetailSns().isEmpty()) {
  68. zyDao.revokeAllUploadFee(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
  69. zyDao.deleteSiChrmTemp(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
  70. } else {
  71. zyDao.revokePartUploadFee(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), p.getDetailSns());
  72. zyDao.deletePartSiChrmTemp(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), p.getDetailSns());
  73. }
  74. ResultVoUtil.success("撤销费用上传成功。");
  75. }
  76. }
  77. public ResultVo<String> uploadFeeDetail(Overview o) {
  78. if (null == o.getLedgerSn()) {
  79. Integer ledger = zyDao.selectMaxLedgerSn(o.getInpatientNo(), o.getAdmissTimes());
  80. if (null == ledger) {
  81. ledger = 1;
  82. }
  83. o.setLedgerSn(ledger);
  84. }
  85. if (null == o.getMidSetl()) {
  86. o.setMidSetl(false);
  87. }
  88. SiPatInfo siPatInfo = zyDao.selectSiPatInfoForZy(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn());
  89. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  90. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保在院信息!");
  91. }
  92. beforeUpload(o);
  93. zyDao.hisRecount(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn());
  94. ZyPatientInfo p = zyDao.selectPatientInfo(o.getInpatientNo());
  95. p.setSid(o.getSid());
  96. p.setStaffId(o.getStaffId());
  97. p.setLedgerSn(o.getLedgerSn());
  98. p.setMdtrtId(siPatInfo.getMdtrtId());
  99. p.setPsnNo(siPatInfo.getPsnNo());
  100. p.setMedType(siPatInfo.getMedType());
  101. p.setAdmdvs(siPatInfo.getInsuplcAdmdvs());
  102. if (o.getMidSetl()) {
  103. List<Integer> notAllowedSns = zyDao.selectNotAllowedSnForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  104. o.getLedgerSn(), o.getEndtime());
  105. if (null != notAllowedSns && notAllowedSns.size() > 0) {
  106. List<Integer> tempSns = new ArrayList<>();
  107. for (int sn : notAllowedSns) {
  108. tempSns.add(sn);
  109. if (tempSns.size() == 100) {
  110. p.setDetailSns(tempSns);
  111. revokeUploadFees(p);
  112. tempSns.clear();
  113. }
  114. }
  115. if (tempSns.size() > 0) {
  116. p.setDetailSns(tempSns);
  117. revokeUploadFees(p);
  118. }
  119. }
  120. }
  121. Map<String, Queue<FeeDtle>> allFees = getAllFeesNotUploaded(o);
  122. Queue<FeeDtle> allPositiveFees = allFees.get("positive");
  123. Queue<FeeDtle> allNegativeFees = allFees.get("negative");
  124. if (allPositiveFees.size() == 0 && allNegativeFees.size() == 0) {
  125. return hospitalizationPreSettlement(p, o);
  126. }
  127. int index = 0;
  128. int feeSize = allPositiveFees.size() + allNegativeFees.size();
  129. int[] pstvres = prepareUploadFees(allPositiveFees, index, feeSize, p, o.getSid());
  130. index = pstvres[0];
  131. int[] ngtvres = prepareUploadFees(allNegativeFees, index, feeSize, p, o.getSid());
  132. index = ngtvres[0];
  133. if (pstvres[1] == 1 || ngtvres[1] == 1) {
  134. allFees = getAllFeesNotUploaded(o);
  135. allPositiveFees = allFees.get("positive");
  136. allNegativeFees = allFees.get("negative");
  137. log.info("医保中心数据有遗漏,继续上传遗漏部分。");
  138. index = prepareUploadFees(allPositiveFees, index, feeSize, p, o.getSid())[0];
  139. prepareUploadFees(allNegativeFees, index, feeSize, p, o.getSid());
  140. }
  141. return hospitalizationPreSettlement(p, o);
  142. }
  143. private Map<String, Queue<FeeDtle>> getAllFeesNotUploaded(Overview o) {
  144. Queue<FeeDtle> allPositiveFees, allNegativeFees;
  145. if (o.getMidSetl()) {
  146. allPositiveFees = zyDao.selectNotUploadedPositiveFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  147. o.getLedgerSn(), o.getBegntime(), o.getEndtime());
  148. allNegativeFees = zyDao.selectNotUploadedNegativeFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  149. o.getLedgerSn(), o.getBegntime(), o.getEndtime());
  150. } else {
  151. String today = getTodayEndTime();
  152. allPositiveFees = zyDao.selectNotUploadedPositiveFees(o.getInpatientNo(), o.getAdmissTimes(),
  153. o.getLedgerSn(), today);
  154. allPositiveFees.removeIf(item -> StringUtil.isBlank(item.getMedListCodg()));
  155. allNegativeFees = zyDao.selectNotUploadedNegativeFees(o.getInpatientNo(), o.getAdmissTimes(),
  156. o.getLedgerSn(), today);
  157. }
  158. Map<String, Queue<FeeDtle>> result = new HashMap<>();
  159. result.put("positive", allPositiveFees);
  160. result.put("negative", allNegativeFees);
  161. return result;
  162. }
  163. private String getTodayEndTime() {
  164. SimpleDateFormat smdate = new SimpleDateFormat("yyyy-MM-dd");
  165. String date = smdate.format(new Date());
  166. return date + " 23:59:59.999";
  167. }
  168. private int[] prepareUploadFees(Queue<FeeDtle> feeQueue, int index, int feeSize, ZyPatientInfo p, String sid) {
  169. int[] result = new int[] {0,0};
  170. if (feeQueue.size() == 0) {
  171. return result;
  172. }
  173. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS,
  174. p.getAdmdvs(), p.getStaffId());
  175. JSONObject socketMessage = new JSONObject();
  176. socketMessage.put("name", "updateProgress");
  177. socketMessage.put("percentage", 0);
  178. List<FeeDtle> tempList = new ArrayList<>();
  179. RestTemplate template = new RestTemplate();
  180. while (feeQueue.size() > 0) {
  181. FeeDtle feeDtle = feeQueue.poll();
  182. assert feeDtle != null;
  183. tempList.add(feeDtle);
  184. if (tempList.size() == 100) {
  185. int[] upldres = executeUploadFees(input, tempList, p);
  186. index += upldres[0];
  187. if (upldres[1] > 0) {
  188. result[1] = 1;
  189. }
  190. tempList.clear();
  191. socketMessage.replace("percentage", makePercentage(index, feeSize));
  192. template.postForObject(upldNotifyUrl + "/sendById",
  193. new PureCodeName(sid, socketMessage.toJSONString()), String.class);
  194. }
  195. }
  196. if (tempList.size() > 0) {
  197. int[] upldres = executeUploadFees(input, tempList, p);
  198. index += upldres[0];
  199. if (upldres[1] > 0) {
  200. result[1] = 1;
  201. }
  202. socketMessage.replace("percentage", makePercentage(index, feeSize));
  203. template.postForObject(upldNotifyUrl + "/sendById",
  204. new PureCodeName(sid, socketMessage.toJSONString()), String.class);
  205. }
  206. return result;
  207. }
  208. private int[] executeUploadFees(JSONObject input, List<FeeDtle> fees, ZyPatientInfo p) {
  209. String ref = JSONArray.toJSONString(fees);
  210. input.getJSONObject("input").put("feedetail", JSONArray.parse(ref));
  211. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS);
  212. log.info("【操作员:{}】,医保费用上传结果:{}", p.getStaffId(), result);
  213. if (null != result) {
  214. if (result.getIntValue(RESULT_CODE) == 0) {
  215. JSONArray array = result.getJSONObject(OUTPUT).getJSONArray("result");
  216. List<SiChargeTemp> tempList = new ArrayList<>();
  217. for (int i = 0; i < array.size(); i++) {
  218. JSONObject upldretrn = array.getJSONObject(i);
  219. SiChargeTemp chrgtemp = JSONObject.parseObject(upldretrn.toJSONString(), SiChargeTemp.class);
  220. chrgtemp.setPatNo(p.getInpatientNo());
  221. chrgtemp.setTimes(p.getAdmissTimes());
  222. chrgtemp.setLedgerSn(p.getLedgerSn());
  223. tempList.add(chrgtemp);
  224. }
  225. zyDao.updateTransFlag(p.getInpatientNo(), p.getAdmissTimes(), tempList);
  226. zyDao.insertSiChargeTempFeeBatch(tempList);
  227. return new int[] {tempList.size(), fees.size() - tempList.size()};
  228. } else {
  229. RestTemplate template = new RestTemplate();
  230. String message = result.getString(ERROR_MESSAGE);
  231. JSONObject socketMsg = new JSONObject();
  232. socketMsg.put("name", "uploadFeeResponse");
  233. socketMsg.put("patNo", p.getInpatientNo());
  234. socketMsg.put("patName", p.getName());
  235. socketMsg.put("times", p.getAdmissTimes());
  236. socketMsg.put("ledgerSn", p.getLedgerSn());
  237. socketMsg.put("message", message);
  238. socketMsg.put("title", String.format("住院号:【%s】,住院次数:【%d】,账页号:【%d】。",
  239. p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()));
  240. template.postForObject(upldNotifyUrl + "/sendById",
  241. new PureCodeName(p.getSid(), socketMsg.toJSONString()), String.class);
  242. return new int[] {fees.size(), 0};
  243. }
  244. }
  245. return new int[]{0, 0};
  246. }
  247. public ResultVo<String> hospitalizationPreSettlement(ZyPatientInfo p, Overview o) {
  248. ZyPreSetlmt zyPreSetlmt;
  249. if (o.getMidSetl()) {
  250. zyPreSetlmt = zyDao.selectPreSetlmtForMidSetl(p.getInpatientNo(), p.getAdmissTimes(),
  251. p.getLedgerSn(), o.getBegntime(), o.getEndtime());
  252. } else {
  253. zyPreSetlmt = zyDao.selectPreSetlmt(p.getInpatientNo(), p.getAdmissTimes(),
  254. p.getLedgerSn(), getTodayEndTime());
  255. }
  256. if (null == zyPreSetlmt || StringUtil.isBlank(zyPreSetlmt.getMdtrtId())) {
  257. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保在院信息!");
  258. }
  259. zyPreSetlmt.setMdtrtCertType(MdtrtCertType.RESIDENT_IDENTITY_CARD.getCode());
  260. zyPreSetlmt.setPsnSetlway(p.getDbg() ? PsnSetlWay.SETTLE_BY_QUOTA.getCode() : PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  261. zyPreSetlmt.setAcctUsedFlag(YesOrNo.NO.getCodeStr());
  262. zyPreSetlmt.setMidSetlFlag(YesOrNo.NO.getCodeStr());
  263. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.HOSPITALIZATION_PRE_SETTLEMENT,
  264. zyPreSetlmt.getInsuplcAdmdvs(), p.getStaffId());
  265. String ref = JSONObject.toJSONString(zyPreSetlmt);
  266. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  267. JSONObject result = exec.executeTrade(input, SiFunction.HOSPITALIZATION_PRE_SETTLEMENT);
  268. log.info("预结算:\n参数:{},\n结果:{}", input, result);
  269. if (null == result) {
  270. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  271. }
  272. Integer infcode = result.getInteger(RESULT_CODE);
  273. logDao.insert(new SiLog(input, result, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), infcode, zyPreSetlmt.getPsnNo()));
  274. if (null == infcode) {
  275. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  276. }
  277. if (infcode == 0) {
  278. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  279. String fundPay = setlinfo.getString("fund_pay_sumamt");
  280. zyDao.updateFundPay(fundPay, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
  281. String message = "患者【" + p.getName() + "】院内总费用与医保中心总费用一致,医保报销金额为:¥ " + fundPay + "。";
  282. return ResultVoUtil.success(message);
  283. }
  284. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  285. }
  286. private int makePercentage(int index, int size) {
  287. float per = (float)index / (float)size;
  288. return (int) (per * 100);
  289. }
  290. private void beforeUpload(Overview o) {
  291. Date disdate = zyDao.selectDscgDate(o.getInpatientNo(), o.getAdmissTimes());
  292. if (null != disdate) {
  293. int num = zyDao.updateChargedate(o.getInpatientNo(), o.getAdmissTimes(), disdate);
  294. log.info("修改费用时间大于出院医嘱时间的费用条目数:{}", num);
  295. }
  296. List<FeeCounteract> negative = zyDao.selectNegativeFeesWithOriDetlSn(
  297. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn());
  298. if (null == negative || negative.isEmpty()) {
  299. log.info("正负相抵完成,抵消费用总条目:0");
  300. return;
  301. }
  302. List<FeeCounteract> positive = new ArrayList<>();
  303. List<Integer> tempSn = new ArrayList<>();
  304. for (FeeCounteract feeCounteract : negative) {
  305. tempSn.add(feeCounteract.getOriDetailSn());
  306. if (tempSn.size() == 30) {
  307. positive.addAll(zyDao.selectPositiveFeesByDetlSn(
  308. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn));
  309. tempSn.clear();
  310. }
  311. }
  312. if (tempSn.size() > 0) {
  313. positive.addAll(zyDao.selectPositiveFeesByDetlSn(
  314. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn));
  315. }
  316. ConcurrentHashMap<Integer, FeeCounteract> posKeyVal = new ConcurrentHashMap<>();
  317. positive.forEach(itm -> {
  318. if (!posKeyVal.containsKey(itm.getDetailSn())) {
  319. posKeyVal.put(itm.getDetailSn(), itm);
  320. }
  321. });
  322. AtomicInteger count = new AtomicInteger();
  323. negative.forEach(itm -> {
  324. if (posKeyVal.containsKey(itm.getOriDetailSn())) {
  325. FeeCounteract pos = posKeyVal.get(itm.getOriDetailSn());
  326. if (itm.getChargeAmount() + pos.getChargeAmount() == 0d
  327. && itm.getChargeFee() + pos.getChargeFee() == 0d) {
  328. zyDao.updateYbTransFlagInPair(o.getInpatientNo(),
  329. o.getAdmissTimes(), itm.getDetailSn(), itm.getOriDetailSn());
  330. count.addAndGet(2);
  331. }
  332. }
  333. });
  334. log.info("正负相抵完成,抵消费用总条目:{}", count.get());
  335. }
  336. }