SiMzFeeService.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. package thyyxxk.simzfeeoprnsystm.service;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import thyyxxk.simzfeeoprnsystm.dao.SiLogDao;
  6. import thyyxxk.simzfeeoprnsystm.dao.SiMzDao;
  7. import thyyxxk.simzfeeoprnsystm.dao.SiSetldetailDao;
  8. import thyyxxk.simzfeeoprnsystm.dao.SiSetlinfoDao;
  9. import thyyxxk.simzfeeoprnsystm.dicts.*;
  10. import thyyxxk.simzfeeoprnsystm.external.WebHisSrvc;
  11. import thyyxxk.simzfeeoprnsystm.pojo.*;
  12. import thyyxxk.simzfeeoprnsystm.pojo.ResultVo;
  13. import thyyxxk.simzfeeoprnsystm.pojo.SiPatInfo;
  14. import thyyxxk.simzfeeoprnsystm.utils.*;
  15. import lombok.extern.slf4j.Slf4j;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.stereotype.Service;
  18. import java.math.BigDecimal;
  19. import java.math.RoundingMode;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.concurrent.TimeUnit;
  24. @Slf4j
  25. @Service
  26. public class SiMzFeeService {
  27. private final SiMzDao mzDao;
  28. private final SiSetlinfoDao setlinfoDao;
  29. private final SiSetldetailDao setldetailDao;
  30. private final ExecService exec;
  31. private final WebHisSrvc webHisSrvc;
  32. private static final String RESULT_CODE = "infcode";
  33. private static final String ERROR_MESSAGE = "err_msg";
  34. private static final String OUTPUT = "output";
  35. private final SiLogDao logDao;
  36. @Value("${web-his-url}")
  37. private String webHisUrl;
  38. @Autowired
  39. public SiMzFeeService(SiMzDao mzDao, SiSetlinfoDao setlinfoDao,
  40. SiSetldetailDao setldetailDao, ExecService exec, WebHisSrvc webHisSrvc, SiLogDao logDao) {
  41. this.mzDao = mzDao;
  42. this.setlinfoDao = setlinfoDao;
  43. this.setldetailDao = setldetailDao;
  44. this.exec = exec;
  45. this.webHisSrvc = webHisSrvc;
  46. this.logDao = logDao;
  47. }
  48. public ResultVo<String> outpatientRegistration(MzPatientInfo p) {
  49. Regstrtn regstrtn = mzDao.selectRegstrtn(p.getPatNo(), p.getTimes());
  50. if (null == regstrtn) {
  51. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "mz_visit_table患者信息为空,请联系医生重开处方。");
  52. }
  53. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  54. if (readCardBizType != ReadCardBizType.REGISTRATION && !p.getInsuplcAdmdvs().startsWith("43")) {
  55. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "省外异地的患者请读社保卡或医保电子凭证登记!");
  56. }
  57. if (readCardBizType == ReadCardBizType.REGISTRATION) {
  58. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  59. regstrtn.setMdtrtCertType(mdtrtCertType.getCode());
  60. if (mdtrtCertType == MdtrtCertType.SOCIAL_SECURITY_CARD) {
  61. String[] out = p.getReadCardResult().split("\\|");
  62. regstrtn.setMdtrtCertNo(out[2]);
  63. regstrtn.setCardSn(out[3]);
  64. } else if (mdtrtCertType == MdtrtCertType.MEDICAL_INSURANCE_ELECTRONIC_VOUCHER) {
  65. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  66. regstrtn.setMdtrtCertNo(qrinfo.getString("ecToken"));
  67. }
  68. }
  69. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_REGISTRATION,
  70. p.getInsuplcAdmdvs(), p.getStaffId());
  71. regstrtn.setInsutype(p.getInsutype());
  72. regstrtn.setPsnType(p.getPsnType());
  73. regstrtn.setIptOtpNo(p.getPatNo());
  74. String ref = JSONObject.toJSONStringWithDateFormat(regstrtn, "yyyy-MM-dd HH:mm:ss");
  75. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  76. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_REGISTRATION);
  77. log.info("【操作员:{}】,门诊挂号:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  78. if (null == result) {
  79. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  80. }
  81. Integer infcode = result.getInteger(RESULT_CODE);
  82. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, regstrtn.getPsnNo()));
  83. if (null == infcode) {
  84. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  85. }
  86. if (infcode == 0) {
  87. JSONObject output = result.getJSONObject(OUTPUT).getJSONObject("data");
  88. p.setMdtrtId(output.getString("mdtrt_id"));
  89. p.setVisitDate(regstrtn.getBegntime());
  90. mzDao.afterRegistrtn(p);
  91. return ResultVoUtil.success("挂号成功。");
  92. }
  93. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  94. }
  95. public ResultVo<String> revokeOutpatientRegistration(MzPatientInfo p) {
  96. if (null == p.getTimes()) {
  97. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  98. }
  99. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(p.getPatNo(), p.getTimes());
  100. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  101. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保挂号信息。");
  102. }
  103. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_REGISTRATION,
  104. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  105. JSONObject data = new JSONObject();
  106. data.put("psn_no", siPatInfo.getPsnNo());
  107. data.put("mdtrt_id", siPatInfo.getMdtrtId());
  108. data.put("ipt_otp_no", p.getPatNo());
  109. input.getJSONObject("input").put("data", data);
  110. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_REGISTRATION);
  111. log.info("【操作员:{}】,取消门诊挂号:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  112. if (null == result) {
  113. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  114. }
  115. Integer infcode = result.getInteger(RESULT_CODE);
  116. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, siPatInfo.getPsnNo()));
  117. if (null == infcode) {
  118. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  119. }
  120. if (infcode == 0) {
  121. mzDao.clearMdtrtIdForMz(p.getPatNo(), p.getTimes(), null);
  122. return ResultVoUtil.success("取消门诊挂号成功。");
  123. }
  124. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  125. }
  126. private ResultVo<String> uploadOutpatientInfo(SpcChrDiseAcct diseInfo, SiPatInfo siPatInfo, String staffId) {
  127. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_OUTPATIENT_INFO,
  128. siPatInfo.getInsuplcAdmdvs(), staffId);
  129. JSONObject mdtrtinfo = new JSONObject();
  130. List<Diagnoses> diagnosesList = new ArrayList<>();
  131. String icdCodeNew = mzDao.selectIcdCodeNew(siPatInfo.getPatNo(), siPatInfo.getTimes());
  132. if (StringUtil.isBlank(icdCodeNew)) {
  133. diagnosesList = mzDao.selectMzDiags(siPatInfo.getPatNo(), siPatInfo.getTimes());
  134. if (null == diagnosesList || diagnosesList.isEmpty()) {
  135. log.info("【{}】 上传就诊信息失败,门诊诊断为空。", siPatInfo.getPatNo());
  136. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者的门诊诊断为空,请联系医生填写。");
  137. }
  138. } else {
  139. Diagnoses base = mzDao.selectDiseinfo(siPatInfo.getPatNo(), siPatInfo.getTimes());
  140. String[] icds = icdCodeNew.split(",");
  141. for (int i = 0; i < icds.length; i++) {
  142. String icd = icds[i];
  143. String icdTextNew = mzDao.selectIcdTextNew(icd);
  144. Diagnoses diag = new Diagnoses();
  145. diag.setDiagCode(icd);
  146. diag.setDiagName(icdTextNew);
  147. diag.setDiagSrtNo(i + 1);
  148. diag.setDiagType("1");
  149. diag.setValiFlag("1");
  150. diag.setDiagDept(base.getDiagDept());
  151. diag.setDiagTime(base.getDiagTime());
  152. diag.setDiseDorNo(base.getDiseDorNo());
  153. diag.setDiseDorName(base.getDiseDorName());
  154. diagnosesList.add(diag);
  155. }
  156. }
  157. if (siPatInfo.getMedType().equals("14") || siPatInfo.getMedType().equals("51")) {
  158. if (StringUtil.isBlank(diseInfo.getOpspDiseCode())) {
  159. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "生育门诊与慢特病门诊的病种不能为空 !");
  160. }
  161. }
  162. mdtrtinfo.put("mdtrt_id", siPatInfo.getMdtrtId());
  163. mdtrtinfo.put("psn_no", siPatInfo.getPsnNo());
  164. mdtrtinfo.put("med_type", siPatInfo.getMedType());
  165. mdtrtinfo.put("begntime", DateUtil.formatDatetime(siPatInfo.getVisitDatetime()));
  166. mdtrtinfo.put("main_cond_dscr", diseInfo.getOpspDiseName());
  167. mdtrtinfo.put("dise_codg", diseInfo.getOpspDiseCode());
  168. mdtrtinfo.put("dise_name", diseInfo.getOpspDiseName());
  169. mdtrtinfo.put("birctrl_type", "");
  170. mdtrtinfo.put("birctrl_matn_date", "");
  171. String ref = JSONObject.toJSONString(diagnosesList);
  172. input.getJSONObject("input").put("mdtrtinfo", mdtrtinfo);
  173. input.getJSONObject("input").put("diseinfo", JSONArray.parse(ref));
  174. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_OUTPATIENT_INFO);
  175. log.info("【操作员:{}】门诊就诊信息上传:\n参数:{},\n结果:{}", staffId, input, result);
  176. Integer infcode = result.getInteger(RESULT_CODE);
  177. logDao.insert(new SiLog(input, result, siPatInfo.getPatNo(), siPatInfo.getTimes(), infcode, siPatInfo.getPsnNo()));
  178. if (result.getIntValue(RESULT_CODE) == 0) {
  179. Diagnoses main = diagnosesList.get(0);
  180. mzDao.updatePatDiseinfo(siPatInfo.getPatNo(), siPatInfo.getTimes(), main.getDiagCode(), main.getDiagName());
  181. return ResultVoUtil.success("门诊就诊信息上传成功。");
  182. }
  183. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  184. }
  185. public ResultVo<SiPatInfo> uploadOutpatientFeeDetails(SpcChrDiseAcct p) {
  186. String patNo = p.getPatNo();
  187. if (null == p.getTimes()) {
  188. p.setTimes(mzDao.selectMaxTimes(patNo));
  189. }
  190. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(patNo, p.getTimes());
  191. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  192. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【门诊号:" + patNo +
  193. "】未找到此患者的医保挂号信息,请核实。");
  194. }
  195. if (!p.getFromDirectReg()) {
  196. ResultVo<String> uplRes = uploadOutpatientInfo(p, siPatInfo, p.getStaffId());
  197. if (null != uplRes && uplRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  198. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, uplRes.getMessage());
  199. }
  200. }
  201. List<FeeDetail> feeDetails = mzDao.selectOutpatientFees(patNo, p.getTimes());
  202. if (null == feeDetails || feeDetails.isEmpty()) {
  203. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有需要上传的费用。");
  204. }
  205. MzVisit mzVisit = mzDao.selectMzVisitInfo(patNo, p.getTimes());
  206. if (null == mzVisit || StringUtil.isBlank(mzVisit.getVisitDeptCode())) {
  207. log.info("【{},{}】就诊科室没有匹配医保码,无法使用门诊统筹。", patNo, p.getTimes());
  208. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "就诊科室没有匹配医保码,无法使用门诊统筹。");
  209. }
  210. String batchNo = patNo + "_" + p.getTimes();
  211. feeDetails.forEach(item -> {
  212. item.setMdtrtId(siPatInfo.getMdtrtId());
  213. item.setPsnNo(siPatInfo.getPsnNo());
  214. item.setChrgBchno(batchNo);
  215. item.setRxCircFlag(YesOrNo.NO.getCodeStr());
  216. item.setHospApprFlag(YesOrNo.YES.getCodeStr());
  217. item.setBilgDeptCodg(mzVisit.getVisitDeptCode());
  218. item.setBilgDeptName(mzVisit.getVisitDeptName());
  219. if (siPatInfo.getMedType().equals("51")) {
  220. item.setMatnFeeFlag("1");
  221. }
  222. });
  223. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_OUTPATIENT_FEE_DETAILS,
  224. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  225. String ref = JSONArray.toJSONStringWithDateFormat(feeDetails, "yyyy-MM-dd HH:mm:ss");
  226. JSONArray feedetail = JSONArray.parseArray(ref);
  227. input.getJSONObject("input").put("feedetail", feedetail);
  228. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_OUTPATIENT_FEE_DETAILS);
  229. log.info("【操作员:{}】门诊费用明细信息上传:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  230. if (null == result) {
  231. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  232. }
  233. Integer infcode = result.getInteger(RESULT_CODE);
  234. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, siPatInfo.getPsnNo()));
  235. if (null == infcode) {
  236. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  237. }
  238. if (infcode == 0) {
  239. JSONArray feeRes = result.getJSONObject(OUTPUT).getJSONArray("result");
  240. double fulamtOwnpayAmt = 0d;
  241. double overlmtAmt = 0d;
  242. double preselfpayAmt = 0d;
  243. double inscpScpAmt = 0d;
  244. for (int i = 0; i < feeRes.size(); i++) {
  245. JSONObject fee = feeRes.getJSONObject(i);
  246. fulamtOwnpayAmt += fee.getDoubleValue("fulamt_ownpay_amt");
  247. overlmtAmt += fee.getDoubleValue("overlmt_amt");
  248. preselfpayAmt += fee.getDoubleValue("preselfpay_amt");
  249. inscpScpAmt += fee.getDoubleValue("inscp_scp_amt");
  250. String detlSn = fee.getString("feedetl_sn");
  251. String chrgLv = fee.getString("chrgitm_lv");
  252. String chrgType = fee.getString("med_chrgitm_type");
  253. String[] sns = detlSn.split("_");
  254. int times = Integer.parseInt(sns[1]);
  255. int recNo = Integer.parseInt(sns[2]);
  256. int odrNo = Integer.parseInt(sns[3]);
  257. int itmNo = Integer.parseInt(sns[4]);
  258. mzDao.afterUploadFees(patNo, times, recNo, odrNo, itmNo, chrgLv, chrgType);
  259. }
  260. siPatInfo.setFulamtOwnpayAmt(fulamtOwnpayAmt);
  261. siPatInfo.setOverlmtAmt(overlmtAmt);
  262. siPatInfo.setPreselfpayAmt(preselfpayAmt);
  263. siPatInfo.setInscpScpAmt(inscpScpAmt);
  264. mzDao.updateSortOfAmt(siPatInfo);
  265. return ResultVoUtil.success(siPatInfo);
  266. }
  267. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  268. }
  269. public ResultVo<String> revokeOutpatientFeeDetails(MzPatientInfo p) {
  270. if (null == p.getTimes()) {
  271. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  272. }
  273. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(p.getPatNo(), p.getTimes());
  274. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  275. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有此患者的医保挂号信息!");
  276. }
  277. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_FEE_DETAILS,
  278. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  279. JSONObject data = new JSONObject();
  280. data.put("mdtrt_id", siPatInfo.getMdtrtId());
  281. data.put("psn_no", siPatInfo.getPsnNo());
  282. data.put("chrg_bchno", "0000");
  283. input.getJSONObject("input").put("data", data);
  284. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_FEE_DETAILS);
  285. log.info("【操作员:{}】门诊费用明细信息撤销,参数:{},结果:{}", p.getStaffId(), input, result);
  286. if (null == result) {
  287. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  288. }
  289. Integer infcode = result.getInteger(RESULT_CODE);
  290. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, siPatInfo.getPsnNo()));
  291. if (null == infcode) {
  292. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  293. }
  294. if (infcode == 0) {
  295. mzDao.afterRevokeFees(p.getPatNo(), p.getTimes());
  296. return ResultVoUtil.success("门诊费用明细信息撤销成功。");
  297. }
  298. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  299. }
  300. public ResultVo<FundDetail> outpatientPreSettlement(MzPatientInfo p) {
  301. while (MzgjUtil.inProcessing(p.getPatNo())) {
  302. try {
  303. TimeUnit.SECONDS.sleep(1);
  304. } catch (InterruptedException e) {
  305. throw new RuntimeException(e);
  306. }
  307. }
  308. if (null == p.getTimes()) {
  309. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  310. }
  311. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(p.getPatNo(), p.getTimes());
  312. if (setlfund != null) {
  313. return setlfund;
  314. }
  315. MzPreSetlmt mzPreSetlmt = mzDao.selectPreSetlmt(p.getPatNo(), p.getTimes());
  316. if (null == mzPreSetlmt || null == mzPreSetlmt.getMedfeeSumamt()) {
  317. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者没有已上传的费用。");
  318. }
  319. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  320. if (readCardBizType == ReadCardBizType.SETTLEMENT) {
  321. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  322. mzPreSetlmt.setMdtrtCertType(mdtrtCertType.getCode());
  323. if (mdtrtCertType == MdtrtCertType.SOCIAL_SECURITY_CARD) {
  324. String[] out = p.getReadCardResult().split("\\|");
  325. mzPreSetlmt.setMdtrtCertNo(out[2]);
  326. mzPreSetlmt.setCardSn(out[3]);
  327. } else if (mdtrtCertType == MdtrtCertType.MEDICAL_INSURANCE_ELECTRONIC_VOUCHER) {
  328. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  329. if (!p.getSocialNo().trim().equals(qrinfo.getString("idNo").trim())) {
  330. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "电子医保凭证身份证与HIS身份证不一致,请确认是否人证相符。");
  331. }
  332. mzPreSetlmt.setMdtrtCertNo(qrinfo.getString("ecToken"));
  333. }
  334. }
  335. mzPreSetlmt.setMedfeeSumamt(mzPreSetlmt.getMedfeeSumamt().setScale(2, RoundingMode.HALF_UP));
  336. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_PRE_SETTLEMENT,
  337. mzPreSetlmt.getInsuplcAdmdvs(), p.getStaffId());
  338. mzPreSetlmt.setPsnSetlway(PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  339. mzPreSetlmt.setAcctUsedFlag(p.getAcctUsedFlag());
  340. mzPreSetlmt.setChrgBchno(p.getPatNo() + "_" + p.getTimes());
  341. String ref = JSONObject.toJSONString(mzPreSetlmt);
  342. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  343. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_PRE_SETTLEMENT);
  344. log.info("【操作员:{}】门诊预结算:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  345. if (null == result) {
  346. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  347. }
  348. Integer infcode = result.getInteger(RESULT_CODE);
  349. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, mzPreSetlmt.getPsnNo()));
  350. if (null == infcode) {
  351. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  352. }
  353. if (infcode == 0) {
  354. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  355. FundDetail fundDetail = new FundDetail();
  356. fundDetail.setTotalCost(setlinfo.getString("medfee_sumamt"));
  357. fundDetail.setFundPay(setlinfo.getString("fund_pay_sumamt"));
  358. fundDetail.setCashPay(setlinfo.getString("psn_cash_pay"));
  359. fundDetail.setAcctPay(setlinfo.getString("acct_pay"));
  360. fundDetail.setSelfPay(setlinfo.getString("psn_part_amt"));
  361. fundDetail.setCardType(getCardType(mzPreSetlmt.getInsuplcAdmdvs()));
  362. return ResultVoUtil.success(fundDetail);
  363. }
  364. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  365. }
  366. private ResultVo<FundDetail> getFundDetailByPatientInfo(String patientId, int times) {
  367. SiSetlinfo sisetlinfo = mzDao.selectSettledInfo(patientId, times, 0);
  368. if (null != sisetlinfo && null != sisetlinfo.getSetlId()) {
  369. return getFundDetailFromSetlinfo(sisetlinfo);
  370. }
  371. return null;
  372. }
  373. private ResultVo<FundDetail> getFundDetailFromSetlinfo(SiSetlinfo sisetl) {
  374. FundDetail fundDetail = new FundDetail();
  375. fundDetail.setCardType(getCardType(sisetl.getInsuplcAdmdvs()));
  376. fundDetail.setTotalCost(String.valueOf(sisetl.getMedfeeSumamt()));
  377. fundDetail.setFundPay(String.valueOf(sisetl.getFundPaySumamt()));
  378. fundDetail.setCashPay(String.valueOf(sisetl.getPsnCashPay()));
  379. fundDetail.setAcctPay(String.valueOf(sisetl.getAcctPay()));
  380. fundDetail.setSelfPay(String.valueOf(sisetl.getPsnPartAmt()));
  381. if (sisetl.getRevoked() == 1) {
  382. fundDetail.reverseAll();
  383. }
  384. return ResultVoUtil.success(fundDetail);
  385. }
  386. private Integer getCardType(String insplc) {
  387. if (insplc.startsWith("4301")) {
  388. return 1;
  389. } else if (insplc.equals("439900")) {
  390. return 2;
  391. }
  392. return 3;
  393. }
  394. public ResultVo<FundDetail> outpatientSettlement(MzPatientInfo p) {
  395. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(p.getPatNo(), p.getTimes());
  396. if (setlfund != null) {
  397. return setlfund;
  398. }
  399. Setlmt setlmt = mzDao.selectSetlmt(p.getPatNo(), p.getTimes());
  400. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_SETTLEMENT,
  401. setlmt.getInsuplcAdmdvs(), p.getStaffId());
  402. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  403. if (readCardBizType == ReadCardBizType.SETTLEMENT) {
  404. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  405. setlmt.setMdtrtCertType(mdtrtCertType.getCode());
  406. if (mdtrtCertType == MdtrtCertType.SOCIAL_SECURITY_CARD) {
  407. String[] out = p.getReadCardResult().split("\\|");
  408. setlmt.setMdtrtCertNo(out[2]);
  409. setlmt.setCardSn(out[3]);
  410. } else if (mdtrtCertType == MdtrtCertType.MEDICAL_INSURANCE_ELECTRONIC_VOUCHER) {
  411. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  412. if (!p.getSocialNo().trim().equals(qrinfo.getString("idNo").trim())) {
  413. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "电子医保凭证身份证与HIS身份证不一致,请确认是否人证相符。");
  414. }
  415. setlmt.setMdtrtCertNo(qrinfo.getString("ecToken"));
  416. }
  417. }
  418. setlmt.setMedfeeSumamt(setlmt.getMedfeeSumamt().setScale(2, RoundingMode.HALF_UP));
  419. setlmt.setPsnSetlway(PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  420. setlmt.setChrgBchno(p.getPatNo() + "_" + p.getTimes());
  421. setlmt.setAcctUsedFlag(p.getAcctUsedFlag());
  422. setlmt.setInvono(SnowFlakeId.getInstance().nextId());
  423. String ref = JSONObject.toJSONString(setlmt);
  424. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  425. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_SETTLEMENT);
  426. log.info("【操作员:{}】门诊结算:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  427. if (null == result) {
  428. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR, "与医保中心的连接出现网络异常!");
  429. }
  430. Integer infcode = result.getInteger(RESULT_CODE);
  431. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, setlmt.getPsnNo()));
  432. if (null == infcode) {
  433. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  434. }
  435. if (infcode == 0) {
  436. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  437. SiSetlinfo setlEntity = JSONObject.parseObject(setlinfo.toJSONString(), SiSetlinfo.class);
  438. setlEntity.setPatNo(p.getPatNo());
  439. setlEntity.setTimes(p.getTimes());
  440. setlEntity.setLedgerSn(0);
  441. setlEntity.setStaffId(p.getStaffId());
  442. setlEntity.setRevoked(YesOrNo.NO.getCode());
  443. setlEntity.setSetlType(ClrType.OUTPATIENT.getCode());
  444. setlEntity.setInsuplcAdmdvs(setlmt.getInsuplcAdmdvs());
  445. setlEntity.setBegntime(mzDao.selectBegntime(p.getPatNo(), p.getTimes()));
  446. setlEntity.setEndtime(setlEntity.getSetlTime());
  447. setlEntity.setMzSaved(p.getSaved());
  448. BigDecimal hospitalPart = BigDecimal.ZERO;
  449. JSONArray setldetail = result.getJSONObject(OUTPUT).getJSONArray("setldetail");
  450. for (int i = 0; i < setldetail.size(); i++) {
  451. SiSetldetail setldetailEntity = JSONObject.parseObject(setldetail.getJSONObject(i).toJSONString(),
  452. SiSetldetail.class);
  453. setldetailEntity.setPatNo(p.getPatNo());
  454. setldetailEntity.setTimes(p.getTimes());
  455. setldetailEntity.setLedgerSn(0);
  456. if (setldetailEntity.getFundPayType().equals("999996") || setldetailEntity.getSetlProcInfo().equals("999996")) {
  457. hospitalPart = hospitalPart.add(BigDecimal.valueOf(setldetailEntity.getFundPayamt()));
  458. }
  459. setldetailDao.insert(setldetailEntity);
  460. }
  461. setlEntity.setHospPartAmt(hospitalPart.doubleValue());
  462. setlinfoDao.insert(setlEntity);
  463. setlinfoDao.updateSiZyInfoSetlId(p.getPatNo(), p.getTimes(), 0, setlEntity.getSetlId(),
  464. setlEntity.getMedinsSetlId(), input.getString("msgid"));
  465. webHisSrvc.saveCumInfo(webHisUrl, setlEntity);
  466. return getFundDetailFromSetlinfo(setlEntity);
  467. }
  468. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  469. }
  470. public ResultVo<FundDetail> revokeOutpatientSettlement(MzPatientInfo p) {
  471. if (null == p.getTimes()) {
  472. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  473. }
  474. SiSetlinfo setlinfo = mzDao.selectSettledInfo(p.getPatNo(), p.getTimes(), 0);
  475. if (null == setlinfo) {
  476. setlinfo = mzDao.selectSettledInfo(p.getPatNo(), p.getTimes(), 1);
  477. if (null == setlinfo) {
  478. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有此患者的已结算数据。");
  479. }
  480. return getFundDetailFromSetlinfo(setlinfo);
  481. }
  482. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_SETTLEMENT,
  483. mzDao.selectAdmdvs(setlinfo.getPatNo(), setlinfo.getTimes(), setlinfo.getLedgerSn()), p.getStaffId());
  484. JSONObject data = new JSONObject();
  485. data.put("setl_id", setlinfo.getSetlId());
  486. data.put("mdtrt_id", setlinfo.getMdtrtId());
  487. data.put("psn_no", setlinfo.getPsnNo());
  488. input.getJSONObject("input").put("data", data);
  489. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_SETTLEMENT);
  490. log.info("【操作员:{}】门诊结算撤销:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  491. if (null == result) {
  492. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  493. }
  494. Integer infcode = result.getInteger(RESULT_CODE);
  495. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, setlinfo.getPsnNo()));
  496. if (null == infcode) {
  497. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message"));
  498. }
  499. if (infcode == 0) {
  500. mzDao.deleteSetlInfo(p.getPatNo(), p.getTimes());
  501. mzDao.deleteSetlDetail(p.getPatNo(), p.getTimes());
  502. mzDao.updateRvkSetlMsgid(p.getPatNo(), p.getTimes(), input.getString("msgid"));
  503. if (null != p.getNeedRevokeRegistration() && p.getNeedRevokeRegistration() == 1) {
  504. revokeOutpatientFeeDetails(p);
  505. revokeOutpatientRegistration(p);
  506. }
  507. return getFundDetailFromSetlinfo(setlinfo);
  508. }
  509. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  510. }
  511. public void revokeOutpatientSettlementForTask(SiSetlinfo setlinfo) {
  512. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_SETTLEMENT,
  513. mzDao.selectAdmdvs(setlinfo.getPatNo(), setlinfo.getTimes(), setlinfo.getLedgerSn()), "99999");
  514. JSONObject data = new JSONObject();
  515. data.put("setl_id", setlinfo.getSetlId());
  516. data.put("mdtrt_id", setlinfo.getMdtrtId());
  517. data.put("psn_no", setlinfo.getPsnNo());
  518. input.getJSONObject("input").put("data", data);
  519. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_SETTLEMENT);
  520. log.info("【操作员:99999】门诊结算撤销:\n参数:{},\n结果:{}", input, result);
  521. Integer infcode = result.getInteger(RESULT_CODE);
  522. logDao.insert(new SiLog(input, result, setlinfo.getPatNo(), setlinfo.getTimes(), infcode, setlinfo.getPsnNo()));
  523. if (null != infcode && infcode == 0) {
  524. mzDao.deleteSetlInfo(setlinfo.getPatNo(), setlinfo.getTimes());
  525. mzDao.deleteSetlDetail(setlinfo.getPatNo(), setlinfo.getTimes());
  526. mzDao.updateRvkSetlMsgid(setlinfo.getPatNo(), setlinfo.getTimes(), input.getString("msgid"));
  527. MzPatientInfo mzPatientInfo = new MzPatientInfo();
  528. mzPatientInfo.setPatNo(setlinfo.getPatNo());
  529. mzPatientInfo.setTimes(setlinfo.getTimes());
  530. mzPatientInfo.setStaffId("99999");
  531. revokeOutpatientFeeDetails(mzPatientInfo);
  532. revokeOutpatientRegistration(mzPatientInfo);
  533. }
  534. }
  535. public ResultVo<FundDetail> directRegistration(DirectionRegParam param) {
  536. log.info("门诊共济:{}", param);
  537. if (MzgjUtil.inProcessing(param.getPatientId())) {
  538. log.info("【{}】此患者上一次的共济流程尚未结束,请稍后再试。", param.getPatientId());
  539. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者上一次的共济流程尚未结束,请稍后再试。");
  540. }
  541. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(param.getPatientId(), param.getTimes());
  542. if (setlfund != null) {
  543. return setlfund;
  544. }
  545. MzgjUtil.addProcess(param.getPatientId());
  546. try {
  547. return executeMzgj(param);
  548. } catch (Exception e) {
  549. log.error("门诊共济出错:", e);
  550. return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, e.getMessage());
  551. } finally {
  552. MzgjUtil.finishProcessing(param.getPatientId());
  553. }
  554. }
  555. private ResultVo<FundDetail> executeMzgj(DirectionRegParam param) {
  556. if (mzDao.selectExistCount(param.getPatientId(), param.getTimes()) == 0) {
  557. mzDao.updateMzTimes(param.getPatientId(), param.getTimes());
  558. }
  559. mzDao.deleteTempPatinfo(param.getPatientId(), param.getTimes());
  560. MzPatientInfo mzptnt = new MzPatientInfo();
  561. mzptnt.setStaffId(param.getStaffId());
  562. mzptnt.setPatNo(param.getPatientId());
  563. mzptnt.setTimes(param.getTimes());
  564. mzptnt.setAcctUsedFlag(String.valueOf(param.getAcctUsedFlag()));
  565. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(mzptnt.getPatNo(), mzptnt.getTimes());
  566. mzptnt.setInsuplcAdmdvs(siPatInfo.getInsuplcAdmdvs());
  567. mzptnt.setInsutype(siPatInfo.getInsutype());
  568. mzptnt.setPsnType(siPatInfo.getPsnType());
  569. mzptnt.setName(siPatInfo.getPsnName());
  570. mzptnt.setSocialNo(siPatInfo.getCertno());
  571. if (StringUtil.notBlank(param.getReadCardResult())) {
  572. MdtrtCertType mdtrtCertType = MdtrtCertType.get(param.getReadCardType());
  573. mzptnt.setMdtrtCertType(mdtrtCertType.getLabel());
  574. mzptnt.setReadCardBizType(ReadCardBizType.REGISTRATION.getCode());
  575. mzptnt.setReadCardResult(param.getReadCardResult());
  576. }
  577. ResultVo<String> regres = outpatientRegistration(mzptnt);
  578. if (null == regres) {
  579. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  580. }
  581. if (regres.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  582. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, regres.getMessage());
  583. }
  584. // 挂号登记成功后上传就诊信息
  585. siPatInfo = mzDao.selectSiPatInfoForMz(mzptnt.getPatNo(), mzptnt.getTimes());
  586. siPatInfo.setFromDirectReg(true);
  587. SpcChrDiseAcct spcChrDiseAcct = new SpcChrDiseAcct();
  588. ResultVo<String> upldMdtrtRes = uploadOutpatientInfo(spcChrDiseAcct, siPatInfo, param.getStaffId());
  589. if (null == upldMdtrtRes) {
  590. revokeOutpatientRegistration(mzptnt);
  591. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  592. }
  593. if (upldMdtrtRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  594. revokeOutpatientRegistration(mzptnt);
  595. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, upldMdtrtRes.getMessage());
  596. }
  597. // 上传就诊信息成功后生成门诊医保费用
  598. ResultVo<List<Map<String, Object>>> getMzRcptRes = webHisSrvc.getMzReceipts(webHisUrl, mzptnt);
  599. if (null == getMzRcptRes) {
  600. revokeOutpatientRegistration(mzptnt);
  601. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  602. }
  603. if (getMzRcptRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  604. revokeOutpatientRegistration(mzptnt);
  605. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, getMzRcptRes.getMessage());
  606. }
  607. List<MzReceipt> mzReceipts = new ArrayList<>();
  608. for (Map<String, Object> item : getMzRcptRes.getData()) {
  609. int times = (int) item.get("times");
  610. mzDao.deleteAllReceipts(param.getPatientId(), times);
  611. Map<Integer, List<MzReceipt>> orderReceiptsMap = FilterUtil.cast(item.get("mzReceipts"));
  612. for (Map.Entry<Integer, List<MzReceipt>> entry : orderReceiptsMap.entrySet()) {
  613. mzReceipts.addAll(entry.getValue());
  614. }
  615. }
  616. if (mzReceipts.isEmpty()) {
  617. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有可以上传到医保的费用。");
  618. }
  619. ResultVo<String> insertSiMzFeeRes = webHisSrvc.insertSiMzFees(webHisUrl, mzReceipts);
  620. if (null == insertSiMzFeeRes) {
  621. revokeOutpatientRegistration(mzptnt);
  622. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  623. }
  624. if (insertSiMzFeeRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  625. revokeOutpatientRegistration(mzptnt);
  626. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, insertSiMzFeeRes.getMessage());
  627. }
  628. // 生成费用成功后上传到医保
  629. spcChrDiseAcct.setStaffId(param.getStaffId());
  630. spcChrDiseAcct.setPatNo(mzptnt.getPatNo());
  631. spcChrDiseAcct.setTimes(mzptnt.getTimes());
  632. spcChrDiseAcct.setFromDirectReg(true);
  633. ResultVo<SiPatInfo> upldFeeRes = uploadOutpatientFeeDetails(spcChrDiseAcct);
  634. if (null == upldFeeRes) {
  635. revokeOutpatientRegistration(mzptnt);
  636. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
  637. }
  638. if (upldFeeRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  639. revokeOutpatientRegistration(mzptnt);
  640. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, upldFeeRes.getMessage());
  641. }
  642. // 上传完成之后结算并返回结算结果
  643. return outpatientSettlement(mzptnt);
  644. }
  645. public ResultVo<Integer> isPatientDuringSiSettle(String patientId) {
  646. int result = MzgjUtil.inProcessing(patientId) ? 1 : 0;
  647. return ResultVoUtil.success(result);
  648. }
  649. // public ResultVo<String> payOnline(EcTokenParams params) {
  650. //
  651. //
  652. // }
  653. // private ResultVo<EcTokenUpldRslt> ecTokenUploadFees(EcTokenParams params) {
  654. // EcTokenUpldDetl upldDetl = mzDao.selectEcTokenUpldDetl(params.getPatientId(), params.getTimes());
  655. // if (null == upldDetl || StringUtil.isBlank(upldDetl.getMdtrtId())) {
  656. // return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者有没有效的医保登记信息,请核实。");
  657. // }
  658. // upldDetl.setIdNo(params.getIdNo());
  659. // upldDetl.setUserName(params.getUserName());
  660. // upldDetl.setIdType(params.getIdType());
  661. // upldDetl.setEcToken(params.getEcToken());
  662. // upldDetl.setInsuCode(params.getInsuOrg());
  663. // upldDetl.setIptOtpNo(params.getPatientId());
  664. //
  665. // upldDetl.setDiseinfoList(null);
  666. // upldDetl.setFeedetailList(null);
  667. //
  668. // JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.ECTOKEN_UPLOAD_FEE_DETAIL,
  669. // params.getInsuOrg(), params.getStaffId());
  670. // }
  671. }