SiZyFeeService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. Queue<FeeDtle> allPositiveFees, allNegativeFees;
  103. if (o.getMidSetl()) {
  104. List<Integer> notAllowedSns = zyDao.selectNotAllowedSnForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  105. o.getLedgerSn(), o.getEndtime());
  106. if (null != notAllowedSns && notAllowedSns.size() > 0) {
  107. List<Integer> tempSns = new ArrayList<>();
  108. for (int sn : notAllowedSns) {
  109. tempSns.add(sn);
  110. if (tempSns.size() == 100) {
  111. p.setDetailSns(tempSns);
  112. revokeUploadFees(p);
  113. tempSns.clear();
  114. }
  115. }
  116. if (tempSns.size() > 0) {
  117. p.setDetailSns(tempSns);
  118. revokeUploadFees(p);
  119. }
  120. }
  121. allPositiveFees = zyDao.selectNotUploadedPositiveFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  122. o.getLedgerSn(), o.getBegntime(), o.getEndtime());
  123. allNegativeFees = zyDao.selectNotUploadedNegativeFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(),
  124. o.getLedgerSn(), o.getBegntime(), o.getEndtime());
  125. } else {
  126. String today = getTodayEndTime();
  127. allPositiveFees = zyDao.selectNotUploadedPositiveFees(o.getInpatientNo(), o.getAdmissTimes(),
  128. o.getLedgerSn(), today);
  129. allPositiveFees.removeIf(item -> StringUtil.isBlank(item.getMedListCodg()));
  130. allNegativeFees = zyDao.selectNotUploadedNegativeFees(o.getInpatientNo(), o.getAdmissTimes(),
  131. o.getLedgerSn(), today);
  132. }
  133. if (allPositiveFees.size() == 0 && allNegativeFees.size() == 0) {
  134. return hospitalizationPreSettlement(p, o);
  135. }
  136. int index = 0;
  137. int feeSize = allPositiveFees.size() + allNegativeFees.size();
  138. index = prepareUploadFees(allPositiveFees, index, feeSize, p, o.getSid());
  139. prepareUploadFees(allNegativeFees, index, feeSize, p, o.getSid());
  140. return hospitalizationPreSettlement(p, o);
  141. }
  142. private String getTodayEndTime() {
  143. SimpleDateFormat smdate = new SimpleDateFormat("yyyy-MM-dd");
  144. String date = smdate.format(new Date());
  145. return date + " 23:59:59.999";
  146. }
  147. private int prepareUploadFees(Queue<FeeDtle> feeQueue, int index, int feeSize, ZyPatientInfo p, String sid) {
  148. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS,
  149. p.getAdmdvs(), p.getStaffId());
  150. JSONObject socketMessage = new JSONObject();
  151. socketMessage.put("name", "updateProgress");
  152. socketMessage.put("percentage", 0);
  153. List<FeeDtle> tempList = new ArrayList<>();
  154. RestTemplate template = new RestTemplate();
  155. while (feeQueue.size() > 0) {
  156. FeeDtle feeDtle = feeQueue.poll();
  157. assert feeDtle != null;
  158. tempList.add(feeDtle);
  159. if (tempList.size() == 100) {
  160. executeUploadFees(input, tempList, p);
  161. tempList.clear();
  162. index += 100;
  163. socketMessage.replace("percentage", makePercentage(index, feeSize));
  164. template.postForObject(upldNotifyUrl + "/sendById",
  165. new PureCodeName(sid, socketMessage.toJSONString()), String.class);
  166. }
  167. }
  168. if (tempList.size() > 0) {
  169. executeUploadFees(input, tempList, p);
  170. index += tempList.size();
  171. socketMessage.replace("percentage", makePercentage(index, feeSize));
  172. template.postForObject(upldNotifyUrl + "/sendById",
  173. new PureCodeName(sid, socketMessage.toJSONString()), String.class);
  174. }
  175. return index;
  176. }
  177. private void executeUploadFees(JSONObject input, List<FeeDtle> fees, ZyPatientInfo p) {
  178. String ref = JSONArray.toJSONString(fees);
  179. input.getJSONObject("input").put("feedetail", JSONArray.parse(ref));
  180. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS);
  181. log.info("【操作员:{}】,医保费用上传结果:{}", p.getStaffId(), result);
  182. RestTemplate template = new RestTemplate();
  183. if (null != result) {
  184. if (result.getIntValue(RESULT_CODE) == 0) {
  185. zyDao.updateTransFlag(p.getInpatientNo(), p.getAdmissTimes(), fees);
  186. JSONArray array = result.getJSONObject(OUTPUT).getJSONArray("result");
  187. List<SiChargeTemp> tempList = new ArrayList<>();
  188. for (int i = 0; i < array.size(); i++) {
  189. JSONObject upldretrn = array.getJSONObject(i);
  190. SiChargeTemp chrgtemp = JSONObject.parseObject(upldretrn.toJSONString(), SiChargeTemp.class);
  191. chrgtemp.setPatNo(p.getInpatientNo());
  192. chrgtemp.setTimes(p.getAdmissTimes());
  193. chrgtemp.setLedgerSn(p.getLedgerSn());
  194. tempList.add(chrgtemp);
  195. }
  196. zyDao.insertSiChargeTempFeeBatch(tempList);
  197. } else {
  198. String message = result.getString(ERROR_MESSAGE);
  199. JSONObject socketMsg = new JSONObject();
  200. socketMsg.put("name", "uploadFeeResponse");
  201. socketMsg.put("patNo", p.getInpatientNo());
  202. socketMsg.put("times", p.getAdmissTimes());
  203. socketMsg.put("ledgerSn", p.getLedgerSn());
  204. socketMsg.put("message", message);
  205. socketMsg.put("title", String.format("住院号:【%s】,住院次数:【%d】,账页号:【%d】。",
  206. p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()));
  207. template.postForObject(upldNotifyUrl + "/sendById",
  208. new PureCodeName(p.getSid(), socketMsg.toJSONString()), String.class);
  209. }
  210. }
  211. }
  212. public ResultVo<String> hospitalizationPreSettlement(ZyPatientInfo p, Overview o) {
  213. ZyPreSetlmt zyPreSetlmt;
  214. if (o.getMidSetl()) {
  215. zyPreSetlmt = zyDao.selectPreSetlmtForMidSetl(p.getInpatientNo(), p.getAdmissTimes(),
  216. p.getLedgerSn(), o.getBegntime(), o.getEndtime());
  217. } else {
  218. zyPreSetlmt = zyDao.selectPreSetlmt(p.getInpatientNo(), p.getAdmissTimes(),
  219. p.getLedgerSn(), getTodayEndTime());
  220. }
  221. if (null == zyPreSetlmt || StringUtil.isBlank(zyPreSetlmt.getMdtrtId())) {
  222. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保在院信息!");
  223. }
  224. zyPreSetlmt.setMdtrtCertType(MdtrtCertType.RESIDENT_IDENTITY_CARD.getCode());
  225. zyPreSetlmt.setPsnSetlway(p.getDbg() ? PsnSetlWay.SETTLE_BY_QUOTA.getCode() : PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  226. zyPreSetlmt.setAcctUsedFlag(YesOrNo.NO.getCodeStr());
  227. zyPreSetlmt.setMidSetlFlag(YesOrNo.NO.getCodeStr());
  228. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.HOSPITALIZATION_PRE_SETTLEMENT,
  229. zyPreSetlmt.getInsuplcAdmdvs(), p.getStaffId());
  230. String ref = JSONObject.toJSONString(zyPreSetlmt);
  231. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  232. JSONObject result = exec.executeTrade(input, SiFunction.HOSPITALIZATION_PRE_SETTLEMENT);
  233. log.info("预结算:\n参数:{},\n结果:{}", input, result);
  234. if (null == result) {
  235. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  236. }
  237. Integer infcode = result.getInteger(RESULT_CODE);
  238. logDao.insert(new SiLog(input, result, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), infcode));
  239. if (null == infcode) {
  240. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  241. }
  242. if (infcode == 0) {
  243. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  244. String fundPay = setlinfo.getString("fund_pay_sumamt");
  245. zyDao.updateFundPay(fundPay, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
  246. String message = "患者【" + p.getName() + "】院内总费用与医保中心总费用一致,医保报销金额为:¥ " + fundPay + "。";
  247. return ResultVoUtil.success(message);
  248. }
  249. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  250. }
  251. private int makePercentage(int index, int size) {
  252. float per = (float)index / (float)size;
  253. return (int) (per * 100);
  254. }
  255. private void beforeUpload(Overview o) {
  256. Date disdate = zyDao.selectDscgDate(o.getInpatientNo(), o.getAdmissTimes());
  257. if (null != disdate) {
  258. int num = zyDao.updateChargedate(o.getInpatientNo(), o.getAdmissTimes(), disdate);
  259. log.info("修改费用时间大于出院医嘱时间的费用条目数:{}", num);
  260. }
  261. List<FeeCounteract> negative = zyDao.selectNegativeFeesWithOriDetlSn(
  262. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn());
  263. if (null == negative || negative.isEmpty()) {
  264. log.info("正负相抵完成,抵消费用总条目:0");
  265. return;
  266. }
  267. List<FeeCounteract> positive = new ArrayList<>();
  268. List<Integer> tempSn = new ArrayList<>();
  269. for (FeeCounteract feeCounteract : negative) {
  270. tempSn.add(feeCounteract.getOriDetailSn());
  271. if (tempSn.size() == 30) {
  272. positive.addAll(zyDao.selectPositiveFeesByDetlSn(
  273. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn));
  274. tempSn.clear();
  275. }
  276. }
  277. if (tempSn.size() > 0) {
  278. positive.addAll(zyDao.selectPositiveFeesByDetlSn(
  279. o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn));
  280. }
  281. ConcurrentHashMap<Integer, FeeCounteract> posKeyVal = new ConcurrentHashMap<>();
  282. positive.forEach(itm -> {
  283. if (!posKeyVal.containsKey(itm.getDetailSn())) {
  284. posKeyVal.put(itm.getDetailSn(), itm);
  285. }
  286. });
  287. AtomicInteger count = new AtomicInteger();
  288. negative.forEach(itm -> {
  289. if (posKeyVal.containsKey(itm.getOriDetailSn())) {
  290. FeeCounteract pos = posKeyVal.get(itm.getOriDetailSn());
  291. if (itm.getChargeAmount() + pos.getChargeAmount() == 0d
  292. && itm.getChargeFee() + pos.getChargeFee() == 0d) {
  293. zyDao.updateYbTransFlagInPair(o.getInpatientNo(),
  294. o.getAdmissTimes(), itm.getDetailSn(), itm.getOriDetailSn());
  295. count.addAndGet(2);
  296. }
  297. }
  298. });
  299. log.info("正负相抵完成,抵消费用总条目:{}", count.get());
  300. }
  301. }