SiMzFeeService.java 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. package thyyxxk.simzfeeoprnsystm.service;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.alibaba.fastjson2.JSON;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.web.client.RestTemplate;
  7. import thyyxxk.simzfeeoprnsystm.dao.*;
  8. import thyyxxk.simzfeeoprnsystm.dicts.*;
  9. import thyyxxk.simzfeeoprnsystm.external.WebHisService;
  10. import thyyxxk.simzfeeoprnsystm.pojo.*;
  11. import thyyxxk.simzfeeoprnsystm.pojo.ResultVo;
  12. import thyyxxk.simzfeeoprnsystm.pojo.SiPatInfo;
  13. import thyyxxk.simzfeeoprnsystm.utils.*;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.stereotype.Service;
  17. import java.math.BigDecimal;
  18. import java.math.RoundingMode;
  19. import java.util.*;
  20. import java.util.concurrent.TimeUnit;
  21. @Slf4j
  22. @Service
  23. public class SiMzFeeService {
  24. private final SiMzDao mzDao;
  25. private final SiSetlinfoDao setlinfoDao;
  26. private final SiSetldetailDao setldetailDao;
  27. private final ScheduledDao scheduledDao;
  28. private final ExecService exec;
  29. private final WebHisService webHisService;
  30. private final MariadbService mariadbService;
  31. private static final String RESULT_CODE = "infcode";
  32. private static final String ERROR_MESSAGE = "err_msg";
  33. private static final String OUTPUT = "output";
  34. private final SiLogDao logDao;
  35. @Value("${web-his-url}")
  36. private String webHisUrl;
  37. @Value("${thmz-url}")
  38. private String thmzUrl;
  39. @Autowired
  40. public SiMzFeeService(SiMzDao mzDao, SiSetlinfoDao setlinfoDao,
  41. SiSetldetailDao setldetailDao, ScheduledDao scheduledDao, ExecService exec,
  42. WebHisService webHisService, MariadbService mariadbService,
  43. SiLogDao logDao) {
  44. this.mzDao = mzDao;
  45. this.setlinfoDao = setlinfoDao;
  46. this.setldetailDao = setldetailDao;
  47. this.scheduledDao = scheduledDao;
  48. this.exec = exec;
  49. this.webHisService = webHisService;
  50. this.mariadbService = mariadbService;
  51. this.logDao = logDao;
  52. }
  53. private boolean mipSettled(String hisOrdNum) {
  54. int count = mzDao.getMipSettleCount(hisOrdNum);
  55. return count > 0;
  56. }
  57. private boolean inMipSettleProcess(String hisOrdNum) {
  58. Integer lockFlag = mzDao.getLockFlag(hisOrdNum);
  59. return null != lockFlag && lockFlag == 1;
  60. }
  61. public ResultVo<String> outpatientRegistration(MzPatientInfo p) {
  62. Regstrtn regstrtn;
  63. if (null != p.getVisitDate() && StringUtil.notBlank(p.getDeptCode())
  64. && StringUtil.notBlank(p.getDoctorCode())) {
  65. regstrtn = mzDao.selectRegstrtn2(p);
  66. if (null != regstrtn) {
  67. regstrtn.setBegntime(p.getVisitDate());
  68. regstrtn.setDeptCode(p.getDeptCode());
  69. }
  70. } else {
  71. regstrtn = mzDao.selectRegstrtn(p.getPatNo(), p.getTimes());
  72. }
  73. if (null == regstrtn) {
  74. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
  75. "mz_visit_table或t_si_pat_info 信息为空,请联系医生重开处方。");
  76. }
  77. if (StringUtil.notBlank(regstrtn.getMdtrtId())) {
  78. return ResultVoUtil.success("本次就诊已有医保登记[mdtrtId:" + regstrtn.getMdtrtId() + "],请勿重复办理。");
  79. }
  80. String hisOrdNum = p.getPatNo() + "_" + p.getTimes() + "_1";
  81. if (mipSettled(hisOrdNum)) {
  82. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
  83. "患者已完成移动医保支付,请勿重复办理。");
  84. }
  85. if (inMipSettleProcess(hisOrdNum)) {
  86. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
  87. "患者已进入移动医保支付流程,无法办理。");
  88. }
  89. if (!p.abortBeforeUploadFees()) {
  90. List<String> chargeCodeList = mzDao.selectHisChargeCodes(p.getPatNo(), p.getTimes());
  91. if (chargeCodeList.isEmpty()) {
  92. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未找到收费明细,请先生成医保处方。");
  93. }
  94. // 查询处方是否有折扣
  95. String discount = queryDiscount(p.getPatNo(), p.getTimes(), chargeCodeList);
  96. if (!discount.equals("OK")) {
  97. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, discount);
  98. }
  99. }
  100. if (null == p.getInsutype()) {
  101. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(p.getPatNo(), p.getTimes());
  102. p.setInsuplcAdmdvs(siPatInfo.getInsuplcAdmdvs());
  103. p.setInsutype(siPatInfo.getInsutype());
  104. p.setPsnType(siPatInfo.getPsnType());
  105. p.setName(siPatInfo.getPsnName());
  106. p.setSocialNo(siPatInfo.getCertno());
  107. }
  108. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  109. if (readCardBizType != ReadCardBizType.REGISTRATION && !p.getInsuplcAdmdvs().startsWith("43")) {
  110. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "省外异地的患者请读社保卡或医保电子凭证登记!");
  111. }
  112. if (existSettledButNotPay(p.getPatNo(), p.getTimes())) {
  113. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
  114. "有HIS未缴费的医保结算,无法办理医保登记。请先完成门诊缴费再重新办理。");
  115. }
  116. if (StringUtil.notBlank(p.getMedType())) {
  117. mzDao.updateMedtype(p.getMedType(), p.getPatNo(), p.getTimes());
  118. }
  119. if (readCardBizType == ReadCardBizType.REGISTRATION) {
  120. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  121. regstrtn.setMdtrtCertType(mdtrtCertType.getCode());
  122. if (mdtrtCertType.getCode().equals(MdtrtCertType.SOCIAL_SECURITY_CARD.getCode())) {
  123. String[] out = p.getReadCardResult().split("\\|");
  124. regstrtn.setMdtrtCertNo(out[2]);
  125. regstrtn.setCardSn(out[3]);
  126. } else if (mdtrtCertType.getCode().equals(MdtrtCertType.ELECTRONIC_VOUCHER.getCode())) {
  127. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  128. JSONObject qrdata = qrinfo.getJSONObject("data");
  129. if (null != qrdata) {
  130. qrinfo = qrdata;
  131. }
  132. regstrtn.setMdtrtCertNo(qrinfo.getString("ecToken"));
  133. }
  134. }
  135. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_REGISTRATION,
  136. p.getInsuplcAdmdvs(), p.getStaffId());
  137. regstrtn.setInsutype(p.getInsutype());
  138. regstrtn.setPsnType(p.getPsnType());
  139. regstrtn.setIptOtpNo(p.getPatNo());
  140. String ref = JSONObject.toJSONStringWithDateFormat(regstrtn, "yyyy-MM-dd HH:mm:ss");
  141. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  142. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_REGISTRATION);
  143. log.info("【操作员:{}】,门诊挂号:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  144. Integer infcode = result.getInteger(RESULT_CODE);
  145. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, regstrtn.getPsnNo()));
  146. if (infcode == 0) {
  147. setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  148. JSONObject output = result.getJSONObject(OUTPUT).getJSONObject("data");
  149. p.setMdtrtId(output.getString("mdtrt_id"));
  150. p.setVisitDate(regstrtn.getBegntime());
  151. mzDao.afterRegistrtn(p);
  152. return ResultVoUtil.success(p.getMdtrtId());
  153. }
  154. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  155. }
  156. public ResultVo<String> revokeOutpatientRegistration(MzPatientInfo p) {
  157. if (null == p.getTimes()) {
  158. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  159. }
  160. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(p.getPatNo(), p.getTimes());
  161. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  162. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保挂号信息。");
  163. }
  164. MzgjUtil.finishProcessing(p.getPatNo());
  165. RevokeRegRequest request = new RevokeRegRequest();
  166. request.setInsuplcAdmdvs(siPatInfo.getInsuplcAdmdvs()); ;
  167. request.setStaffId(p.getStaffId());
  168. request.setPsnNo(siPatInfo.getPsnNo());
  169. request.setMdtrtId(siPatInfo.getMdtrtId());
  170. request.setPatNo(p.getPatNo());
  171. request.setTimes(p.getTimes());
  172. return executeOutpatientRegRevoke(request);
  173. }
  174. public ResultVo<String> executeOutpatientRegRevoke(RevokeRegRequest request) {
  175. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_REGISTRATION,
  176. request.getInsuplcAdmdvs(), request.getStaffId());
  177. JSONObject data = new JSONObject();
  178. data.put("psn_no", request.getPsnNo());
  179. data.put("mdtrt_id", request.getMdtrtId());
  180. data.put("ipt_otp_no", request.getPatNo());
  181. input.getJSONObject("input").put("data", data);
  182. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_REGISTRATION);
  183. log.info("【操作员:{}】,取消门诊挂号:\n参数:{},\n结果:{}", request.getStaffId(), input, result);
  184. Integer infcode = result.getInteger(RESULT_CODE);
  185. logDao.insert(new SiLog(input, result, request.getPatNo(), request.getTimes(), infcode, request.getPsnNo()));
  186. String errMsg = result.getString(ERROR_MESSAGE);
  187. if (infcode == 0 || (null != errMsg && errMsg.contains("不存在该就诊信息"))) {
  188. mzDao.clearMdtrtIdForMz(request.getPatNo(), request.getTimes(), null);
  189. setlinfoDao.deletePreSettleInfo(request.getPatNo(), request.getTimes());
  190. return ResultVoUtil.success("取消门诊挂号成功。");
  191. }
  192. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, errMsg);
  193. }
  194. public ResultVo<String> uploadOutpatientInfo(MzPatientInfo mzptnt, SpcChrDiseAcct spcChrDiseAcct, SiPatInfo siPatInfo) {
  195. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_OUTPATIENT_INFO,
  196. siPatInfo.getInsuplcAdmdvs(), spcChrDiseAcct.getStaffId());
  197. JSONObject mdtrtinfo = new JSONObject();
  198. List<Diagnoses> diagnosesList = new ArrayList<>();
  199. String icdCodeNew = mzDao.selectIcdCodeNew(siPatInfo.getPatNo(), siPatInfo.getTimes());
  200. if (StringUtil.isBlank(icdCodeNew) && null != mzptnt) {
  201. icdCodeNew = mzptnt.getIcdCodeNew();
  202. }
  203. if (StringUtil.notBlank(icdCodeNew)) {
  204. Diagnoses base = mzDao.selectDiseinfo(siPatInfo.getPatNo(), siPatInfo.getTimes());
  205. if (null == base && null != mzptnt) {
  206. CodeName dor = mzDao.getDorCodeAndName(mzptnt.getDoctorCode());
  207. base = new Diagnoses();
  208. base.setDiagDept(mzptnt.getDeptCode());
  209. base.setDiagTime(mzptnt.getVisitDate());
  210. base.setDiseDorNo(dor.getCode());
  211. base.setDiseDorName(dor.getName());
  212. }
  213. String[] icds = icdCodeNew.split(",");
  214. for (int i = 0; i < icds.length; i++) {
  215. String icd = icds[i];
  216. String icdTextNew = mzDao.selectIcdTextNew(icd);
  217. Diagnoses diag = new Diagnoses();
  218. diag.setDiagCode(icd);
  219. diag.setDiagName(icdTextNew);
  220. diag.setDiagSrtNo(i + 1);
  221. diag.setDiagType("1");
  222. diag.setValiFlag("1");
  223. diag.setDiagDept(base.getDiagDept());
  224. diag.setDiagTime(base.getDiagTime());
  225. diag.setDiseDorNo(base.getDiseDorNo());
  226. diag.setDiseDorName(base.getDiseDorName());
  227. diagnosesList.add(diag);
  228. }
  229. } else {
  230. diagnosesList = mzDao.selectMzDiags(siPatInfo.getPatNo(), siPatInfo.getTimes());
  231. if (null == diagnosesList || diagnosesList.isEmpty()) {
  232. log.info("【{}】 上传就诊信息失败,门诊诊断为空。", siPatInfo.getPatNo());
  233. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者的门诊诊断为空,请联系医生填写。");
  234. }
  235. }
  236. if (siPatInfo.getMedType().equals("14") || siPatInfo.getMedType().equals("51")) {
  237. if (StringUtil.isBlank(spcChrDiseAcct.getOpspDiseCode())) {
  238. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "生育门诊与慢特病门诊的病种不能为空 !");
  239. }
  240. }
  241. mdtrtinfo.put("mdtrt_id", siPatInfo.getMdtrtId());
  242. mdtrtinfo.put("psn_no", siPatInfo.getPsnNo());
  243. mdtrtinfo.put("med_type", siPatInfo.getMedType());
  244. mdtrtinfo.put("begntime", DateUtil.formatDatetime(siPatInfo.getVisitDatetime()));
  245. mdtrtinfo.put("main_cond_dscr", spcChrDiseAcct.getOpspDiseName());
  246. mdtrtinfo.put("dise_codg", spcChrDiseAcct.getOpspDiseCode());
  247. mdtrtinfo.put("dise_name", spcChrDiseAcct.getOpspDiseName());
  248. mdtrtinfo.put("birctrl_type", "");
  249. mdtrtinfo.put("birctrl_matn_date", "");
  250. mdtrtinfo.put("exp_content", spcChrDiseAcct.getExpContent());
  251. String ref = JSONObject.toJSONString(diagnosesList);
  252. input.getJSONObject("input").put("mdtrtinfo", mdtrtinfo);
  253. input.getJSONObject("input").put("diseinfo", JSONArray.parse(ref));
  254. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_OUTPATIENT_INFO);
  255. log.info("【操作员:{}】门诊就诊信息上传:\n参数:{},\n结果:{}", spcChrDiseAcct.getStaffId(), input, result);
  256. Integer infcode = result.getInteger(RESULT_CODE);
  257. logDao.insert(new SiLog(input, result, siPatInfo.getPatNo(), siPatInfo.getTimes(), infcode, siPatInfo.getPsnNo()));
  258. if (result.getIntValue(RESULT_CODE) == 0) {
  259. Diagnoses main = diagnosesList.get(0);
  260. mzDao.updatePatDiseinfo(siPatInfo.getPatNo(), siPatInfo.getTimes(), main.getDiagCode(), main.getDiagName());
  261. return ResultVoUtil.success("门诊就诊信息上传成功。");
  262. }
  263. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  264. }
  265. public ResultVo<SiPatInfo> uploadOutpatientFeeDetails(SpcChrDiseAcct p) {
  266. String patNo = p.getPatNo();
  267. if (null == p.getTimes()) {
  268. p.setTimes(mzDao.selectMaxTimes(patNo));
  269. }
  270. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(patNo, p.getTimes());
  271. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  272. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "【门诊号:" + patNo +
  273. "】未找到此患者的医保挂号信息,请核实。");
  274. }
  275. if (!p.getFromDirectReg()) {
  276. ResultVo<String> uplRes = uploadOutpatientInfo(null, p, siPatInfo);
  277. if (null != uplRes && uplRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  278. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, uplRes.getMessage());
  279. }
  280. }
  281. List<FeeDetail> feeDetails = mzDao.selectOutpatientFees(patNo, p.getTimes());
  282. if (null == feeDetails || feeDetails.isEmpty()) {
  283. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有需要上传的费用。");
  284. }
  285. MzVisit mzVisit = mzDao.selectMzVisitInfo(patNo, p.getTimes());
  286. if (null == mzVisit || StringUtil.isBlank(mzVisit.getVisitDeptCode())) {
  287. log.info("【{},{}】就诊科室没有匹配医保码,无法使用门诊统筹。", patNo, p.getTimes());
  288. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "就诊科室没有匹配医保码,无法使用门诊统筹。");
  289. }
  290. String batchNo = patNo + "_" + p.getTimes();
  291. feeDetails.forEach(item -> {
  292. item.setMdtrtId(siPatInfo.getMdtrtId());
  293. item.setPsnNo(siPatInfo.getPsnNo());
  294. item.setChrgBchno(batchNo);
  295. item.setRxCircFlag(YesOrNo.NO.getCodeStr());
  296. item.setBilgDeptCodg(mzVisit.getVisitDeptCode());
  297. item.setBilgDeptName(mzVisit.getVisitDeptName());
  298. if (siPatInfo.getMedType().equals("51")) {
  299. item.setMatnFeeFlag("1");
  300. }
  301. });
  302. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_OUTPATIENT_FEE_DETAILS,
  303. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  304. String ref = JSONArray.toJSONStringWithDateFormat(feeDetails, "yyyy-MM-dd HH:mm:ss");
  305. JSONArray feedetail = JSONArray.parseArray(ref);
  306. input.getJSONObject("input").put("feedetail", feedetail);
  307. JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_OUTPATIENT_FEE_DETAILS);
  308. log.info("【操作员:{}】门诊费用明细信息上传:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  309. Integer infcode = result.getInteger(RESULT_CODE);
  310. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, siPatInfo.getPsnNo()));
  311. if (infcode == 0) {
  312. JSONArray feeRes = result.getJSONObject(OUTPUT).getJSONArray("result");
  313. double fulamtOwnpayAmt = 0d;
  314. double overlmtAmt = 0d;
  315. double preselfpayAmt = 0d;
  316. double inscpScpAmt = 0d;
  317. for (int i = 0; i < feeRes.size(); i++) {
  318. JSONObject fee = feeRes.getJSONObject(i);
  319. fulamtOwnpayAmt += fee.getDoubleValue("fulamt_ownpay_amt");
  320. overlmtAmt += fee.getDoubleValue("overlmt_amt");
  321. preselfpayAmt += fee.getDoubleValue("preselfpay_amt");
  322. inscpScpAmt += fee.getDoubleValue("inscp_scp_amt");
  323. String detlSn = fee.getString("feedetl_sn");
  324. String chrgLv = fee.getString("chrgitm_lv");
  325. String chrgType = fee.getString("med_chrgitm_type");
  326. String[] sns = detlSn.split("_");
  327. int times = Integer.parseInt(sns[1]);
  328. int recNo = Integer.parseInt(sns[2]);
  329. int odrNo = Integer.parseInt(sns[3]);
  330. int itmNo = Integer.parseInt(sns[4]);
  331. mzDao.afterUploadFees(patNo, times, recNo, odrNo, itmNo, chrgLv, chrgType);
  332. }
  333. siPatInfo.setFulamtOwnpayAmt(fulamtOwnpayAmt);
  334. siPatInfo.setOverlmtAmt(overlmtAmt);
  335. siPatInfo.setPreselfpayAmt(preselfpayAmt);
  336. siPatInfo.setInscpScpAmt(inscpScpAmt);
  337. mzDao.updateSortOfAmt(siPatInfo);
  338. setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  339. return ResultVoUtil.success(siPatInfo);
  340. }
  341. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  342. }
  343. public ResultVo<String> revokeOutpatientFeeDetails(MzPatientInfo p) {
  344. if (null == p.getTimes()) {
  345. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  346. }
  347. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(p.getPatNo(), p.getTimes());
  348. if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) {
  349. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有此患者的医保挂号信息!");
  350. }
  351. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_FEE_DETAILS,
  352. siPatInfo.getInsuplcAdmdvs(), p.getStaffId());
  353. JSONObject data = new JSONObject();
  354. data.put("mdtrt_id", siPatInfo.getMdtrtId());
  355. data.put("psn_no", siPatInfo.getPsnNo());
  356. data.put("chrg_bchno", "0000");
  357. input.getJSONObject("input").put("data", data);
  358. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_FEE_DETAILS);
  359. log.info("【操作员:{}】门诊费用明细信息撤销,参数:{},结果:{}", p.getStaffId(), input, result);
  360. Integer infcode = result.getInteger(RESULT_CODE);
  361. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, siPatInfo.getPsnNo()));
  362. if (infcode == 0) {
  363. mzDao.afterRevokeFees(p.getPatNo(), p.getTimes());
  364. setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  365. return ResultVoUtil.success("门诊费用明细信息撤销成功。");
  366. }
  367. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  368. }
  369. public ResultVo<FundDetail> outpatientPreSettlement(MzPatientInfo p) {
  370. if (null == p.getTimes()) {
  371. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  372. }
  373. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(p.getPatNo(), p.getTimes(), false);
  374. if (setlfund != null) {
  375. return setlfund;
  376. }
  377. MzPreSetlmt mzPreSetlmt = mzDao.selectPreSetlmt(p.getPatNo(), p.getTimes());
  378. if (null == mzPreSetlmt || null == mzPreSetlmt.getMedfeeSumamt()) {
  379. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者没有已上传的费用。");
  380. }
  381. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  382. if (readCardBizType == ReadCardBizType.SETTLEMENT) {
  383. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  384. mzPreSetlmt.setMdtrtCertType(mdtrtCertType.getCode());
  385. if (mdtrtCertType.getCode().equals(MdtrtCertType.SOCIAL_SECURITY_CARD.getCode())) {
  386. String[] out = p.getReadCardResult().split("\\|");
  387. mzPreSetlmt.setMdtrtCertNo(out[2]);
  388. mzPreSetlmt.setCardSn(out[3]);
  389. } else if (mdtrtCertType.getCode().equals(MdtrtCertType.ELECTRONIC_VOUCHER.getCode())) {
  390. String socialNo = mzDao.selectSocialNo(p.getPatNo());
  391. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  392. JSONObject qrdata = qrinfo.getJSONObject("data");
  393. if (null != qrdata) {
  394. qrinfo = qrdata;
  395. }
  396. if (!Objects.equals(socialNo, qrinfo.getString("idNo").trim())) {
  397. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "电子医保凭证身份证与HIS身份证不一致,请确认是否人证相符。");
  398. }
  399. mzPreSetlmt.setMdtrtCertNo(qrinfo.getString("ecToken"));
  400. }
  401. }
  402. mzPreSetlmt.setMedfeeSumamt(mzPreSetlmt.getMedfeeSumamt().setScale(2, RoundingMode.HALF_UP));
  403. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_PRE_SETTLEMENT,
  404. mzPreSetlmt.getInsuplcAdmdvs(), p.getStaffId());
  405. mzPreSetlmt.setPsnSetlway(PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  406. mzPreSetlmt.setAcctUsedFlag(p.getAcctUsedFlag());
  407. mzPreSetlmt.setChrgBchno(p.getPatNo() + "_" + p.getTimes());
  408. mzPreSetlmt.setExpContent(p.getExpContent());
  409. String ref = JSONObject.toJSONString(mzPreSetlmt);
  410. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  411. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_PRE_SETTLEMENT);
  412. log.info("【操作员:{}】门诊预结算:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  413. Integer infcode = result.getInteger(RESULT_CODE);
  414. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, mzPreSetlmt.getPsnNo()));
  415. if (infcode == 0) {
  416. setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  417. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  418. FundDetail fundDetail = new FundDetail();
  419. fundDetail.setTotalCost(setlinfo.getString("medfee_sumamt"));
  420. fundDetail.setFundPay(setlinfo.getString("fund_pay_sumamt"));
  421. fundDetail.setCashPay(setlinfo.getString("psn_cash_pay"));
  422. fundDetail.setAcctPay(setlinfo.getString("acct_pay"));
  423. fundDetail.setSelfPay(setlinfo.getString("psn_part_amt"));
  424. fundDetail.setCardType(getCardType(mzPreSetlmt.getInsuplcAdmdvs()));
  425. SiSetlinfo setlEntity = JSONObject.parseObject(setlinfo.toJSONString(), SiSetlinfo.class);
  426. setlEntity.setPatNo(p.getPatNo());
  427. setlEntity.setTimes(p.getTimes());
  428. setlEntity.setLedgerSn(0);
  429. setlEntity.setStaffId(p.getStaffId());
  430. setlEntity.setSetlType(ClrType.OUTPATIENT.getCode());
  431. setlEntity.setInsuplcAdmdvs(mzPreSetlmt.getInsuplcAdmdvs());
  432. log.info("开始插入预结算临时信息:{}_{}", p.getPatNo(), p.getTimes());
  433. setlinfoDao.insertPreSettleInfo(setlEntity);
  434. log.info("插入预结算临时信息成功:{}_{}", p.getPatNo(), p.getTimes());
  435. return ResultVoUtil.success(fundDetail);
  436. }
  437. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  438. }
  439. private ResultVo<FundDetail> getFundDetailByPatientInfo(String patNo, int times, boolean realSettle) {
  440. SiSetlinfo sisetlinfo = mzDao.selectSettledInfo(patNo, times, 0);
  441. if (!realSettle && null == sisetlinfo) {
  442. sisetlinfo = setlinfoDao.selectPresettleInfo(patNo, times);
  443. }
  444. if (null != sisetlinfo) {
  445. return getFundDetailFromSetlinfo(sisetlinfo);
  446. }
  447. return null;
  448. }
  449. private ResultVo<FundDetail> getFundDetailFromSetlinfo(SiSetlinfo setlinfo) {
  450. FundDetail fundDetail = new FundDetail();
  451. fundDetail.setCardType(getCardType(setlinfo.getInsuplcAdmdvs()));
  452. fundDetail.setTotalCost(String.valueOf(setlinfo.getMedfeeSumamt()));
  453. fundDetail.setFundPay(String.valueOf(setlinfo.getFundPaySumamt()));
  454. fundDetail.setAcctPay(String.valueOf(setlinfo.getAcctPay()));
  455. fundDetail.setCashPay(String.valueOf(setlinfo.getPsnCashPay()));
  456. fundDetail.setSelfPay(String.valueOf(setlinfo.getPsnCashPay()));
  457. if (setlinfo.getRevoked() == 1) {
  458. fundDetail.reverseAll();
  459. }
  460. fundDetail.setSetlinfo(setlinfo);
  461. return ResultVoUtil.success(fundDetail);
  462. }
  463. private Integer getCardType(String insplc) {
  464. if (insplc.startsWith("4301")) {
  465. return 1;
  466. } else if (insplc.equals("439900")) {
  467. return 2;
  468. }
  469. return 3;
  470. }
  471. public ResultVo<FundDetail> outpatientSettlement(MzPatientInfo p) {
  472. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(p.getPatNo(), p.getTimes(), true);
  473. if (setlfund != null) {
  474. return setlfund;
  475. }
  476. Setlmt setlmt = mzDao.selectSetlmt(p.getPatNo(), p.getTimes());
  477. if (null == setlmt) {
  478. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有此患者的医保就诊信息。");
  479. }
  480. p.setInsuplcAdmdvs(setlmt.getInsuplcAdmdvs());
  481. p.setPsnNo(setlmt.getPsnNo());
  482. p.setMdtrtId(setlmt.getMdtrtId());
  483. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.OUTPATIENT_SETTLEMENT,
  484. setlmt.getInsuplcAdmdvs(), p.getStaffId());
  485. ReadCardBizType readCardBizType = ReadCardBizType.get(p.getReadCardBizType());
  486. if (readCardBizType == ReadCardBizType.SETTLEMENT) {
  487. MdtrtCertType mdtrtCertType = MdtrtCertType.getByLabel(p.getMdtrtCertType());
  488. setlmt.setMdtrtCertType(mdtrtCertType.getCode());
  489. if (mdtrtCertType.getCode().equals(MdtrtCertType.SOCIAL_SECURITY_CARD.getCode())) {
  490. String[] out = p.getReadCardResult().split("\\|");
  491. setlmt.setMdtrtCertNo(out[2]);
  492. setlmt.setCardSn(out[3]);
  493. } else if (mdtrtCertType.getCode().equals(MdtrtCertType.ELECTRONIC_VOUCHER.getCode())) {
  494. String socialNo = mzDao.selectSocialNo(p.getPatNo());
  495. JSONObject qrinfo = JSONObject.parseObject(p.getReadCardResult());
  496. if (!Objects.equals(socialNo, qrinfo.getString("idNo").trim())) {
  497. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "电子医保凭证身份证与HIS身份证不一致,请确认是否人证相符。");
  498. }
  499. setlmt.setMdtrtCertNo(qrinfo.getString("ecToken"));
  500. }
  501. }
  502. setlmt.setMedfeeSumamt(setlmt.getMedfeeSumamt().setScale(2, RoundingMode.HALF_UP));
  503. setlmt.setPsnSetlway(PsnSetlWay.SETTLE_BY_ITEMS.getCode());
  504. setlmt.setChrgBchno(p.getPatNo() + "_" + p.getTimes());
  505. Integer acctUsedFlag = p.getRealAcctUsedFlag();
  506. if (null == acctUsedFlag) {
  507. Double acctPay = mzDao.selectAcctPayInPreSettle(setlmt.getMdtrtId());
  508. if (null != acctPay && acctPay > 0) {
  509. acctUsedFlag = 1;
  510. } else {
  511. acctUsedFlag = 0;
  512. }
  513. }
  514. setlmt.setAcctUsedFlag(String.valueOf(acctUsedFlag));
  515. setlmt.setInvono(SnowFlakeId.getInstance().nextId());
  516. setlmt.setExpContent(p.getExpContent());
  517. String ref = JSONObject.toJSONString(setlmt);
  518. input.getJSONObject("input").put("data", JSONObject.parseObject(ref));
  519. JSONObject result = exec.executeTrade(input, SiFunction.OUTPATIENT_SETTLEMENT);
  520. log.info("【操作员:{}】门诊结算:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  521. Integer infcode = result.getInteger(RESULT_CODE);
  522. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, setlmt.getPsnNo()));
  523. if (infcode == 0) {
  524. JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo");
  525. SiSetlinfo setlEntity = JSONObject.parseObject(setlinfo.toJSONString(), SiSetlinfo.class);
  526. List<SiSetldetail> fundList = new ArrayList<>();
  527. JSONArray setldetail = result.getJSONObject(OUTPUT).getJSONArray("setldetail");
  528. for (int i = 0; i < setldetail.size(); i++) {
  529. SiSetldetail setldetailEntity = JSONObject.parseObject(setldetail.getJSONObject(i).toJSONString(),
  530. SiSetldetail.class);
  531. fundList.add(setldetailEntity);
  532. }
  533. setlEntity.setSetldetail(fundList);
  534. return dealSetlEntity(p, setlEntity);
  535. }
  536. String errMsg = result.getString(ERROR_MESSAGE);
  537. if (errMsg.contains("服务提供者后端服务响应超时")) {
  538. return timeoutSetl(p);
  539. }
  540. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, errMsg);
  541. }
  542. public ResultVo<FundDetail> timeoutSetl(MzPatientInfo p) {
  543. if (StringUtil.isBlank(p.getMdtrtId())) {
  544. p.setMdtrtId(mzDao.getMdtrtId(p.getPatNo(), p.getTimes()));
  545. }
  546. if (StringUtil.isBlank(p.getMdtrtId())) {
  547. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有找到患者的医保就诊信息!");
  548. }
  549. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(p.getPatNo(), p.getTimes(), true);
  550. if (setlfund != null) {
  551. return setlfund;
  552. }
  553. SiSetlinfo setlEntity = querySettlementInfo(p);
  554. if (null != setlEntity) {
  555. return dealSetlEntity(p, setlEntity);
  556. }
  557. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "超时结算失败。");
  558. }
  559. private ResultVo<FundDetail> dealSetlEntity(MzPatientInfo p, SiSetlinfo setlEntity) {
  560. saveSetlinfoToDatabase(setlEntity, p);
  561. if (!p.getStraitSettle() && BigDecimal.ZERO.compareTo(setlEntity.getPsnCashPay()) == 0) {
  562. ResultVo<String> mzChargeResponse = mzHisChargeProcess(p.getPatNo(), p.getTimes(),
  563. String.valueOf(setlEntity.getMedfeeSumamt()));
  564. if (mzChargeResponse.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  565. revokeOutpatientSettlementForTask(setlEntity);
  566. return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, mzChargeResponse.getMessage());
  567. }
  568. }
  569. setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  570. return getFundDetailFromSetlinfo(setlEntity);
  571. }
  572. private SiSetlinfo querySettlementInfo(MzPatientInfo p) {
  573. String url = "http://172.16.32.167:8077/siQuery/querySettlementInfo";
  574. JSONObject params = new JSONObject();
  575. params.put("psnNo", p.getPsnNo());
  576. params.put("mdtrtId", p.getMdtrtId());
  577. ResultVo<LinkedHashMap> vo = new RestTemplate().postForObject(url, params, ResultVo.class);
  578. if (null == vo || vo.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  579. return null;
  580. }
  581. LinkedHashMap resMap = vo.getData();
  582. SiSetlinfo entity = JSONObject.parseObject(JSON.toJSONString(resMap), SiSetlinfo.class);
  583. entity.setInsuplcAdmdvs(resMap.get("insuOptins").toString());
  584. if (null == entity.getPsnPartAmt()) {
  585. entity.setPsnPartAmt(new BigDecimal(resMap.get("psnPay").toString()));
  586. }
  587. if (null == entity.getPsnCashPay()) {
  588. entity.setPsnCashPay(new BigDecimal(resMap.get("cashPayamt").toString()));
  589. }
  590. return entity;
  591. }
  592. private void saveSetlinfoToDatabase(SiSetlinfo setlEntity, MzPatientInfo p) {
  593. setlEntity.setPatNo(p.getPatNo());
  594. setlEntity.setTimes(p.getTimes());
  595. setlEntity.setLedgerSn(0);
  596. setlEntity.setStaffId(p.getStaffId());
  597. setlEntity.setRevoked(YesOrNo.NO.getCode());
  598. setlEntity.setInsuplcAdmdvsName(mzDao.getInsuplcAdmdvsName(setlEntity.getMdtrtId()));
  599. setlEntity.setSetlType(ClrType.OUTPATIENT.getCode());
  600. if (StringUtil.isBlank(setlEntity.getInsuplcAdmdvs())) {
  601. setlEntity.setInsuplcAdmdvs(p.getInsuplcAdmdvs());
  602. }
  603. setlEntity.setBegntime(mzDao.selectBegntime(p.getPatNo(), p.getTimes()));
  604. setlEntity.setEndtime(setlEntity.getSetlTime());
  605. setlEntity.setMzSaved(p.getSaved());
  606. BigDecimal hospitalPart = BigDecimal.ZERO;
  607. List<SiSetldetail> fundList = setlEntity.getSetldetail();
  608. fundList = null == fundList ? new ArrayList<>() : fundList;
  609. for (int i = 0; i < fundList.size(); i++) {
  610. SiSetldetail detail = fundList.get(i);
  611. detail.setPatNo(p.getPatNo());
  612. detail.setTimes(p.getTimes());
  613. detail.setSetlId(setlEntity.getSetlId());
  614. detail.setSortNo(i + 1);
  615. detail.setLedgerSn(0);
  616. if (detail.getFundPayType().equals("999996") || detail.getSetlProcInfo().equals("999996")) {
  617. hospitalPart = hospitalPart.add(BigDecimal.valueOf(detail.getFundPayamt()));
  618. }
  619. setldetailDao.insert(detail);
  620. }
  621. setlEntity.setHospPartAmt(hospitalPart);
  622. setlinfoDao.insert(setlEntity);
  623. setlinfoDao.updateSiZyInfoSetlId(p.getPatNo(), p.getTimes(), 0, setlEntity.getSetlId(),
  624. setlEntity.getMedinsSetlId(), setlEntity.getMedinsSetlId());
  625. webHisService.saveCumInfo(webHisUrl, setlEntity);
  626. }
  627. public ResultVo<FundDetail> revokeOutpatientSettlement(MzPatientInfo p) {
  628. log.info("请求撤销门诊医保结算:{}", JSONObject.toJSON(p));
  629. if (null == p.getTimes()) {
  630. p.setTimes(mzDao.selectMaxTimes(p.getPatNo()));
  631. }
  632. SiSetlinfo setlinfo = mzDao.selectSettledInfo(p.getPatNo(), p.getTimes(), 0);
  633. if (null == setlinfo) {
  634. if (p.needRevokeRegistration()) {
  635. deletePresettleInfoAndRevokeYb(p);
  636. }
  637. setlinfo = mzDao.selectSettledInfo(p.getPatNo(), p.getTimes(), 1);
  638. if (null == setlinfo) {
  639. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有此患者的已结算数据。");
  640. }
  641. return getFundDetailFromSetlinfo(setlinfo);
  642. }
  643. String staffDept = mzDao.selectStaffDepartment(p.getStaffId());
  644. if (!Objects.equals(staffDept, "3020100") &&
  645. !Objects.equals(staffDept, "3060000") &&
  646. !Objects.equals(staffDept, "3100000")) {
  647. if (!Objects.equals(p.getStaffId(), setlinfo.getStaffId())) {
  648. return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "您没有权限撤销本条医保业务,请到收费窗口退处方,或者联系医保科处理。");
  649. }
  650. }
  651. if (BigDecimal.ZERO.compareTo(setlinfo.getPsnCashPay()) == 0
  652. && !Objects.equals(staffDept, "3060000")) {
  653. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "本次结算【个人现金支付为0】,请到收费窗口做退费操作。");
  654. }
  655. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_SETTLEMENT,
  656. mzDao.selectAdmdvs(setlinfo.getPatNo(), setlinfo.getTimes(), setlinfo.getLedgerSn()), p.getStaffId());
  657. JSONObject data = new JSONObject();
  658. data.put("setl_id", setlinfo.getSetlId());
  659. data.put("mdtrt_id", setlinfo.getMdtrtId());
  660. data.put("psn_no", setlinfo.getPsnNo());
  661. input.getJSONObject("input").put("data", data);
  662. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_SETTLEMENT);
  663. log.info("【操作员:{}】门诊结算撤销:\n参数:{},\n结果:{}", p.getStaffId(), input, result);
  664. Integer infcode = result.getInteger(RESULT_CODE);
  665. logDao.insert(new SiLog(input, result, p.getPatNo(), p.getTimes(), infcode, setlinfo.getPsnNo()));
  666. if (p.needRevokeRegistration()) {
  667. deletePresettleInfoAndRevokeYb(p);
  668. }
  669. if (infcode == 0) {
  670. afterRevokeSetl(p.getPatNo(), p.getTimes(), input.getString("msgid"));
  671. return getFundDetailFromSetlinfo(setlinfo);
  672. }
  673. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
  674. }
  675. public void revokeOutpatientSettlementForTask(SiSetlinfo setlinfo) {
  676. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_SETTLEMENT,
  677. mzDao.selectAdmdvs(setlinfo.getPatNo(), setlinfo.getTimes(), setlinfo.getLedgerSn()), "99999");
  678. JSONObject data = new JSONObject();
  679. data.put("setl_id", setlinfo.getSetlId());
  680. data.put("mdtrt_id", setlinfo.getMdtrtId());
  681. data.put("psn_no", setlinfo.getPsnNo());
  682. input.getJSONObject("input").put("data", data);
  683. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_SETTLEMENT);
  684. log.info("【操作员:99999】门诊结算撤销:\n参数:{},\n结果:{}", input, result);
  685. Integer infcode = result.getInteger(RESULT_CODE);
  686. logDao.insert(new SiLog(input, result, setlinfo.getPatNo(), setlinfo.getTimes(), infcode, setlinfo.getPsnNo()));
  687. if (null != infcode && infcode == 0) {
  688. afterRevokeSetl(setlinfo.getPatNo(), setlinfo.getTimes(), input.getString("msgid"));
  689. MzPatientInfo mzPatientInfo = new MzPatientInfo();
  690. mzPatientInfo.setPatNo(setlinfo.getPatNo());
  691. mzPatientInfo.setTimes(setlinfo.getTimes());
  692. mzPatientInfo.setStaffId("99999");
  693. revokeOutpatientFeeDetails(mzPatientInfo);
  694. revokeOutpatientRegistration(mzPatientInfo);
  695. }
  696. }
  697. public void afterRevokeSetl(String patNo, int times, String msgId) {
  698. MzgjUtil.finishProcessing(patNo);
  699. try {
  700. mzDao.deleteSetlInfo(patNo, times);
  701. mzDao.deleteSetlDetail(patNo, times);
  702. mzDao.updateRvkSetlMsgid(patNo, times, msgId);
  703. setlinfoDao.deletePreSettleInfo(patNo, times);
  704. } catch (Exception e) {
  705. String sql1 = String.format("update t_si_setlinfo set revoked=1,mz_saved=0 where pat_no='%s' and times=%d;\n", patNo, times);
  706. String sql2 = String.format("delete from t_si_setldetail where pat_no='%s' and times=%d;\n", patNo, times);
  707. String sql3 = String.format("update t_si_pat_info set rvk_setl_msgid='%s' where pat_no='%s' and times=%d;",
  708. msgId, patNo, times);
  709. String sql = sql1 + sql2 + sql3;
  710. mariadbService.insertNewRecord(sql);
  711. }
  712. }
  713. public ResultVo<FundDetail> directRegistration(DirectionRegParam param) {
  714. log.info("门诊共济:{}", param);
  715. if (MzgjUtil.inProcessing(param.getPatientId())) {
  716. log.info("【{}】此患者上一次的共济流程尚未结束,请稍后再试。", param.getPatientId());
  717. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者上一次的共济流程尚未结束,请稍后再试。");
  718. }
  719. ResultVo<FundDetail> setlfund = getFundDetailByPatientInfo(param.getPatientId(), param.getTimes(), false);
  720. if (setlfund != null) {
  721. return setlfund;
  722. }
  723. MzgjUtil.addProcess(param.getPatientId());
  724. ResultVo<FundDetail> response;
  725. try {
  726. response = executeMzgj(param);
  727. } catch (Exception e) {
  728. response = ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, e.getMessage());
  729. } finally {
  730. MzgjUtil.finishProcessing(param.getPatientId());
  731. }
  732. return response;
  733. }
  734. private ResultVo<FundDetail> executeMzgj(DirectionRegParam param) {
  735. if (mzDao.selectExistCount(param.getPatientId(), param.getTimes()) == 0) {
  736. if (mzDao.updateMzTimes(param.getPatientId(), param.getTimes()) == 0) {
  737. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
  738. "[t_si_pat_info]不存在患者[" + param.getPatientId()
  739. + "]第[" + param.getTimes() + "]次的就诊信息,请重新查询。");
  740. }
  741. }
  742. mzDao.deleteTempPatinfo(param.getPatientId(), param.getTimes());
  743. MzPatientInfo mzptnt = new MzPatientInfo();
  744. mzptnt.setStaffId(param.getStaffId());
  745. mzptnt.setPatNo(param.getPatientId());
  746. mzptnt.setTimes(param.getTimes());
  747. mzptnt.setMedType(param.getMedType());
  748. mzptnt.setAcctUsedFlag(param.getAcctUsedFlag());
  749. mzptnt.setStraitSettle(param.getStraitSettle());
  750. mzptnt.setAbortBeforeUploadFees(param.abortBeforeUploadFees());
  751. mzptnt.setVisitDate(param.getVisitDate());
  752. mzptnt.setDeptCode(param.getVisitDeptCode());
  753. mzptnt.setDoctorCode(param.getDoctorCode());
  754. mzptnt.setIcdCodeNew(param.getIcdCodeNew());
  755. mzptnt.setIcdTextNew(param.getIcdTextNew());
  756. if (!param.abortBeforeUploadFees()) {
  757. // 生成医保费用
  758. String mzReceipts = generateSiMzFees(mzptnt);
  759. if (!mzReceipts.equals("SUCCESS")) {
  760. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, mzReceipts);
  761. }
  762. }
  763. // 填充医保基本信息
  764. SiPatInfo siPatInfo = mzDao.selectSiPatInfoForMz(mzptnt.getPatNo(), mzptnt.getTimes());
  765. mzptnt.setInsuplcAdmdvs(siPatInfo.getInsuplcAdmdvs());
  766. mzptnt.setInsutype(siPatInfo.getInsutype());
  767. mzptnt.setPsnType(siPatInfo.getPsnType());
  768. mzptnt.setName(siPatInfo.getPsnName());
  769. mzptnt.setSocialNo(siPatInfo.getCertno());
  770. // 解析读卡信息
  771. if (StringUtil.notBlank(param.getReadCardResult())) {
  772. MdtrtCertType mdtrtCertType = MdtrtCertType.get(param.getReadCardType());
  773. mzptnt.setMdtrtCertType(mdtrtCertType.getLabel());
  774. mzptnt.setReadCardBizType(ReadCardBizType.REGISTRATION.getCode());
  775. mzptnt.setReadCardResult(param.getReadCardResult());
  776. if (mdtrtCertType.getCode().equals(MdtrtCertType.ELECTRONIC_VOUCHER.getCode())) {
  777. JSONObject obj = JSONObject.parseObject(param.getReadCardResult());
  778. JSONObject qrdata = obj.getJSONObject("data");
  779. if (null != qrdata) {
  780. obj = qrdata;
  781. }
  782. String admdvs = obj.getString("insuOrg");
  783. if (StringUtil.isBlank(mzptnt.getInsuplcAdmdvs())) {
  784. mzptnt.setInsuplcAdmdvs(admdvs);
  785. }
  786. }
  787. }
  788. // 挂号登记
  789. ResultVo<String> regres = outpatientRegistration(mzptnt);
  790. if (regres.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  791. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, regres.getMessage());
  792. }
  793. // 上传就诊信息
  794. siPatInfo = mzDao.selectSiPatInfoForMz(mzptnt.getPatNo(), mzptnt.getTimes());
  795. siPatInfo.setFromDirectReg(true);
  796. SpcChrDiseAcct spcChrDiseAcct = new SpcChrDiseAcct();
  797. spcChrDiseAcct.setStaffId(param.getStaffId());
  798. spcChrDiseAcct.setOpspDiseCode(param.getOpspDiseCode());
  799. spcChrDiseAcct.setOpspDiseName(param.getOpspDiseName());
  800. spcChrDiseAcct.setExpContent(param.getExpContent());
  801. ResultVo<String> upldMdtrtRes = uploadOutpatientInfo(mzptnt, spcChrDiseAcct, siPatInfo);
  802. if (upldMdtrtRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  803. revokeOutpatientRegistration(mzptnt);
  804. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, upldMdtrtRes.getMessage());
  805. }
  806. if (param.abortBeforeUploadFees()) {
  807. return ResultVoUtil.success();
  808. }
  809. // 上传费用明细
  810. spcChrDiseAcct.setStaffId(param.getStaffId());
  811. spcChrDiseAcct.setPatNo(mzptnt.getPatNo());
  812. spcChrDiseAcct.setTimes(mzptnt.getTimes());
  813. spcChrDiseAcct.setFromDirectReg(true);
  814. ResultVo<SiPatInfo> upldFeeRes = uploadOutpatientFeeDetails(spcChrDiseAcct);
  815. if (upldFeeRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  816. revokeOutpatientRegistration(mzptnt);
  817. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, upldFeeRes.getMessage());
  818. }
  819. // 如果是退费重收,直接结算
  820. if (param.getStraitSettle()) {
  821. return outpatientSettlement(mzptnt);
  822. }
  823. // 如果试算个人现金支付为0,直接结算
  824. mzptnt.setReadCardBizType(ReadCardBizType.SETTLEMENT.getCode());
  825. ResultVo<FundDetail> presetlResponse = outpatientPreSettlement(mzptnt);
  826. if (presetlResponse.getCode() == ExceptionEnum.SUCCESS.getCode()) {
  827. FundDetail fundDetail = presetlResponse.getData();
  828. BigDecimal cashpay = new BigDecimal(fundDetail.getCashPay());
  829. if (cashpay.compareTo(BigDecimal.ZERO) == 0) {
  830. return outpatientSettlement(mzptnt);
  831. }
  832. }
  833. return presetlResponse;
  834. }
  835. public String generateSiMzFees(MzPatientInfo mzptnt) {
  836. ResultVo<List<Map<String, Object>>> getMzRcptRes = webHisService.getMzReceipts(webHisUrl, mzptnt);
  837. if (null == getMzRcptRes) {
  838. return ExceptionEnum.NETWORK_ERROR.getMessage();
  839. }
  840. if (getMzRcptRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  841. return getMzRcptRes.getMessage();
  842. }
  843. List<MzReceipt> mzReceipts = new ArrayList<>();
  844. for (Map<String, Object> item : getMzRcptRes.getData()) {
  845. int times = (int) item.get("times");
  846. if (times != mzptnt.getTimes()) {
  847. continue;
  848. }
  849. mzDao.deleteAllReceipts(mzptnt.getPatNo(), times);
  850. Map<Integer, List<MzReceipt>> orderReceiptsMap = FilterUtil.cast(item.get("mzReceipts"));
  851. for (Map.Entry<Integer, List<MzReceipt>> entry : orderReceiptsMap.entrySet()) {
  852. mzReceipts.addAll(entry.getValue());
  853. }
  854. }
  855. if (mzReceipts.isEmpty()) {
  856. return "没有可以上传到医保的费用。";
  857. }
  858. ResultVo<String> insertSiMzFeeRes = webHisService.insertSiMzFees(webHisUrl, mzReceipts);
  859. if (insertSiMzFeeRes.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  860. return insertSiMzFeeRes.getMessage();
  861. }
  862. return "SUCCESS";
  863. }
  864. private String queryDiscount(String patNo, int times, List<String> mzReceipts) {
  865. JSONObject params = new JSONObject();
  866. params.put("patientId", patNo);
  867. params.put("times", times);
  868. params.put("chargeCodes", mzReceipts);
  869. JSONObject response = webHisService.checkDiscount(thmzUrl, params);
  870. int code = response.getIntValue("code");
  871. if (code == 0) {
  872. return "OK";
  873. }
  874. if (code == -2) {
  875. return "患者本次就诊有折扣优惠,无法进行医保统筹。";
  876. }
  877. return response.getString("message");
  878. }
  879. private ResultVo<String> mzHisChargeProcess(String patientId, int times, String totalFee) {
  880. JSONObject params = new JSONObject();
  881. params.put("patientId", patientId);
  882. params.put("times", times);
  883. params.put("totalFee", totalFee);
  884. int tryTimes = 1;
  885. JSONObject response = webHisService.mzChargeFee(thmzUrl, params);
  886. log.info("第{}次保存处方:\n参数:{}\n结果:{}", tryTimes, params, response);
  887. while (0 != response.getInteger("code") && tryTimes < 5
  888. && !response.getString("message").contains("已经收费")) {
  889. try {
  890. tryTimes += 1;
  891. response = webHisService.mzChargeFee(thmzUrl, params);
  892. log.info("第{}次保存处方:\n参数:{}\n结果:{}", tryTimes, params, response);
  893. TimeUnit.SECONDS.sleep(Math.min(tryTimes, 3));
  894. } catch (Exception e) {
  895. log.error("TIMEUNIT SLEEP ERROR", e);
  896. }
  897. }
  898. if (0 != response.getInteger("code") && !response.getString("message").contains("已经收费")) {
  899. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR, "自动保存处方失败,将为您撤销门诊医保业务。");
  900. }
  901. return ResultVoUtil.success();
  902. }
  903. public ResultVo<Integer> isPatientDuringSiSettle(String patientId) {
  904. int result = MzgjUtil.inProcessing(patientId) ? 1 : 0;
  905. return ResultVoUtil.success(result);
  906. }
  907. public void deletePresettleInfoAndRevokeYb(MzPatientInfo p) {
  908. int res = setlinfoDao.deletePreSettleInfo(p.getPatNo(), p.getTimes());
  909. if (res == 1) {
  910. revokeOutpatientFeeDetails(p);
  911. revokeOutpatientRegistration(p);
  912. }
  913. }
  914. private boolean existSettledButNotPay(String patNo, int times) {
  915. List<SiSetlinfo> setlinfos = scheduledDao.selectSettleInfosByPatient(patNo, times);
  916. for (SiSetlinfo item : setlinfos) {
  917. if (null != item.getPayCount() && item.getPayCount() > 0) {
  918. scheduledDao.updateMzSaved(item.getSetlId());
  919. } else {
  920. return true;
  921. }
  922. }
  923. return false;
  924. }
  925. public void test() {
  926. JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_OUTPATIENT_SETTLEMENT, "430105", "01897");
  927. JSONObject data = new JSONObject();
  928. data.put("setl_id", "421253439");
  929. data.put("mdtrt_id", "758032270");
  930. data.put("psn_no", "43000020100034025147");
  931. input.getJSONObject("input").put("data", data);
  932. JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_OUTPATIENT_SETTLEMENT);
  933. log.info("【操作员:01897】门诊结算撤销:\n参数:{},\n结果:{}",input, result);
  934. }
  935. }