package thyyxxk.sizyfeeoprnsystm.service; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.client.RestTemplate; import thyyxxk.sizyfeeoprnsystm.dao.SiLogDao; import thyyxxk.sizyfeeoprnsystm.dao.SiZyDao; import thyyxxk.sizyfeeoprnsystm.dicts.MdtrtCertType; import thyyxxk.sizyfeeoprnsystm.dicts.PsnSetlWay; import thyyxxk.sizyfeeoprnsystm.dicts.SiFunction; import thyyxxk.sizyfeeoprnsystm.dicts.YesOrNo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import thyyxxk.sizyfeeoprnsystm.pojo.*; import thyyxxk.sizyfeeoprnsystm.utils.*; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; /** * @author dj */ @Slf4j @Service public class SiZyFeeService { private static final String RESULT_CODE = "infcode"; private static final String ERROR_MESSAGE = "err_msg"; private static final String OUTPUT = "output"; private final SiZyDao zyDao; private final SiLogDao logDao; private final ExecService exec; @Value("${upld-notify-url}") private String upldNotifyUrl; @Autowired public SiZyFeeService(SiZyDao zyDao, SiLogDao logDao, ExecService exec) { this.zyDao = zyDao; this.logDao = logDao; this.exec = exec; } private void revokeUploadFees(ZyPatientInfo p) { if (null == p.getDetailSns() || p.getDetailSns().isEmpty()) { return; } SiPatInfo siPatInfo = zyDao.selectSiPatInfoForZy(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()); if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) { return; } JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.REVOKE_HOSPITALIZATION_FEE_DETAILS, siPatInfo.getInsuplcAdmdvs(), p.getStaffId()); JSONArray data = new JSONArray(); p.getDetailSns().forEach(detailSn -> { JSONObject item = new JSONObject(); item.put("feedetl_sn", detailSn); item.put("mdtrt_id", siPatInfo.getMdtrtId()); item.put("psn_no", siPatInfo.getPsnNo()); data.add(item); }); input.getJSONObject("input").put("data", data); JSONObject result = exec.executeTrade(input, SiFunction.REVOKE_HOSPITALIZATION_FEE_DETAILS); log.info("【操作员:{}】撤销已上传的费用:\n参数:{},\n结果:{}", p.getStaffId(), input, result); if (null == result || null == result.getInteger(RESULT_CODE)) { ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR); return; } if (result.getIntValue(RESULT_CODE) == 0) { if (null == p.getDetailSns() || p.getDetailSns().isEmpty()) { zyDao.revokeAllUploadFee(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()); zyDao.deleteSiChrmTemp(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()); } else { zyDao.revokePartUploadFee(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), p.getDetailSns()); zyDao.deletePartSiChrmTemp(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), p.getDetailSns()); } ResultVoUtil.success("撤销费用上传成功。"); } } public ResultVo uploadFeeDetail(Overview o) { if (null == o.getLedgerSn()) { Integer ledger = zyDao.selectMaxLedgerSn(o.getInpatientNo(), o.getAdmissTimes()); if (null == ledger) { ledger = 1; } o.setLedgerSn(ledger); } if (null == o.getMidSetl()) { o.setMidSetl(false); } SiPatInfo siPatInfo = zyDao.selectSiPatInfoForZy(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn()); if (null == siPatInfo || StringUtil.isBlank(siPatInfo.getMdtrtId())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保在院信息!"); } beforeUpload(o); zyDao.hisRecount(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn()); ZyPatientInfo p = zyDao.selectPatientInfo(o.getInpatientNo()); p.setSid(o.getSid()); p.setStaffId(o.getStaffId()); p.setLedgerSn(o.getLedgerSn()); p.setMdtrtId(siPatInfo.getMdtrtId()); p.setPsnNo(siPatInfo.getPsnNo()); p.setMedType(siPatInfo.getMedType()); p.setAdmdvs(siPatInfo.getInsuplcAdmdvs()); Queue allPositiveFees, allNegativeFees; if (o.getMidSetl()) { List notAllowedSns = zyDao.selectNotAllowedSnForMidSetl(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), o.getEndtime()); if (null != notAllowedSns && notAllowedSns.size() > 0) { List tempSns = new ArrayList<>(); for (int sn : notAllowedSns) { tempSns.add(sn); if (tempSns.size() == 100) { p.setDetailSns(tempSns); revokeUploadFees(p); tempSns.clear(); } } if (tempSns.size() > 0) { p.setDetailSns(tempSns); revokeUploadFees(p); } } allPositiveFees = zyDao.selectNotUploadedPositiveFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), o.getBegntime(), o.getEndtime()); allNegativeFees = zyDao.selectNotUploadedNegativeFeesForMidSetl(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), o.getBegntime(), o.getEndtime()); } else { String today = getTodayEndTime(); allPositiveFees = zyDao.selectNotUploadedPositiveFees(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), today); allPositiveFees.removeIf(item -> StringUtil.isBlank(item.getMedListCodg())); allNegativeFees = zyDao.selectNotUploadedNegativeFees(o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), today); } if (allPositiveFees.size() == 0 && allNegativeFees.size() == 0) { return hospitalizationPreSettlement(p, o); } int index = 0; int feeSize = allPositiveFees.size() + allNegativeFees.size(); index = prepareUploadFees(allPositiveFees, index, feeSize, p, o.getSid()); prepareUploadFees(allNegativeFees, index, feeSize, p, o.getSid()); return hospitalizationPreSettlement(p, o); } private String getTodayEndTime() { SimpleDateFormat smdate = new SimpleDateFormat("yyyy-MM-dd"); String date = smdate.format(new Date()); return date + " 23:59:59.999"; } private int prepareUploadFees(Queue feeQueue, int index, int feeSize, ZyPatientInfo p, String sid) { JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS, p.getAdmdvs(), p.getStaffId()); JSONObject socketMessage = new JSONObject(); socketMessage.put("name", "updateProgress"); socketMessage.put("percentage", 0); List tempList = new ArrayList<>(); RestTemplate template = new RestTemplate(); while (feeQueue.size() > 0) { FeeDtle feeDtle = feeQueue.poll(); assert feeDtle != null; tempList.add(feeDtle); if (tempList.size() == 100) { executeUploadFees(input, tempList, p); tempList.clear(); index += 100; socketMessage.replace("percentage", makePercentage(index, feeSize)); template.postForObject(upldNotifyUrl + "/sendById", new PureCodeName(sid, socketMessage.toJSONString()), String.class); } } if (tempList.size() > 0) { executeUploadFees(input, tempList, p); index += tempList.size(); socketMessage.replace("percentage", makePercentage(index, feeSize)); template.postForObject(upldNotifyUrl + "/sendById", new PureCodeName(sid, socketMessage.toJSONString()), String.class); } return index; } private void executeUploadFees(JSONObject input, List fees, ZyPatientInfo p) { String ref = JSONArray.toJSONString(fees); input.getJSONObject("input").put("feedetail", JSONArray.parse(ref)); JSONObject result = exec.executeTrade(input, SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS); log.info("【操作员:{}】,医保费用上传结果:{}", p.getStaffId(), result); RestTemplate template = new RestTemplate(); if (null != result) { if (result.getIntValue(RESULT_CODE) == 0) { zyDao.updateTransFlag(p.getInpatientNo(), p.getAdmissTimes(), fees); JSONArray array = result.getJSONObject(OUTPUT).getJSONArray("result"); List tempList = new ArrayList<>(); for (int i = 0; i < array.size(); i++) { JSONObject upldretrn = array.getJSONObject(i); SiChargeTemp chrgtemp = JSONObject.parseObject(upldretrn.toJSONString(), SiChargeTemp.class); chrgtemp.setPatNo(p.getInpatientNo()); chrgtemp.setTimes(p.getAdmissTimes()); chrgtemp.setLedgerSn(p.getLedgerSn()); tempList.add(chrgtemp); } zyDao.insertSiChargeTempFeeBatch(tempList); } else { String message = result.getString(ERROR_MESSAGE); JSONObject socketMsg = new JSONObject(); socketMsg.put("name", "uploadFeeResponse"); socketMsg.put("patNo", p.getInpatientNo()); socketMsg.put("times", p.getAdmissTimes()); socketMsg.put("ledgerSn", p.getLedgerSn()); socketMsg.put("message", message); socketMsg.put("title", String.format("住院号:【%s】,住院次数:【%d】,账页号:【%d】。", p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn())); template.postForObject(upldNotifyUrl + "/sendById", new PureCodeName(p.getSid(), socketMsg.toJSONString()), String.class); } } } public ResultVo hospitalizationPreSettlement(ZyPatientInfo p, Overview o) { ZyPreSetlmt zyPreSetlmt; if (o.getMidSetl()) { zyPreSetlmt = zyDao.selectPreSetlmtForMidSetl(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), o.getBegntime(), o.getEndtime()); } else { zyPreSetlmt = zyDao.selectPreSetlmt(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), getTodayEndTime()); } if (null == zyPreSetlmt || StringUtil.isBlank(zyPreSetlmt.getMdtrtId())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者没有有效的医保在院信息!"); } zyPreSetlmt.setMdtrtCertType(MdtrtCertType.RESIDENT_IDENTITY_CARD.getCode()); zyPreSetlmt.setPsnSetlway(p.getDbg() ? PsnSetlWay.SETTLE_BY_QUOTA.getCode() : PsnSetlWay.SETTLE_BY_ITEMS.getCode()); zyPreSetlmt.setAcctUsedFlag(YesOrNo.NO.getCodeStr()); zyPreSetlmt.setMidSetlFlag(YesOrNo.NO.getCodeStr()); JSONObject input = exec.makeTradeHeaderWithInsureArea(SiFunction.HOSPITALIZATION_PRE_SETTLEMENT, zyPreSetlmt.getInsuplcAdmdvs(), p.getStaffId()); String ref = JSONObject.toJSONString(zyPreSetlmt); input.getJSONObject("input").put("data", JSONObject.parseObject(ref)); JSONObject result = exec.executeTrade(input, SiFunction.HOSPITALIZATION_PRE_SETTLEMENT); log.info("预结算:\n参数:{},\n结果:{}", input, result); if (null == result) { return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR); } Integer infcode = result.getInteger(RESULT_CODE); logDao.insert(new SiLog(input, result, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), infcode)); if (null == infcode) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "医保中心报错:" + result.getString("message")); } if (infcode == 0) { JSONObject setlinfo = result.getJSONObject(OUTPUT).getJSONObject("setlinfo"); String fundPay = setlinfo.getString("fund_pay_sumamt"); zyDao.updateFundPay(fundPay, p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn()); String message = "患者【" + p.getName() + "】院内总费用与医保中心总费用一致,医保报销金额为:¥ " + fundPay + "。"; return ResultVoUtil.success(message); } return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE)); } private int makePercentage(int index, int size) { float per = (float)index / (float)size; return (int) (per * 100); } private void beforeUpload(Overview o) { Date disdate = zyDao.selectDscgDate(o.getInpatientNo(), o.getAdmissTimes()); if (null != disdate) { int num = zyDao.updateChargedate(o.getInpatientNo(), o.getAdmissTimes(), disdate); log.info("修改费用时间大于出院医嘱时间的费用条目数:{}", num); } List negative = zyDao.selectNegativeFeesWithOriDetlSn( o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn()); if (null == negative || negative.isEmpty()) { log.info("正负相抵完成,抵消费用总条目:0"); return; } List positive = new ArrayList<>(); List tempSn = new ArrayList<>(); for (FeeCounteract feeCounteract : negative) { tempSn.add(feeCounteract.getOriDetailSn()); if (tempSn.size() == 30) { positive.addAll(zyDao.selectPositiveFeesByDetlSn( o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn)); tempSn.clear(); } } if (tempSn.size() > 0) { positive.addAll(zyDao.selectPositiveFeesByDetlSn( o.getInpatientNo(), o.getAdmissTimes(), o.getLedgerSn(), tempSn)); } ConcurrentHashMap posKeyVal = new ConcurrentHashMap<>(); positive.forEach(itm -> { if (!posKeyVal.containsKey(itm.getDetailSn())) { posKeyVal.put(itm.getDetailSn(), itm); } }); AtomicInteger count = new AtomicInteger(); negative.forEach(itm -> { if (posKeyVal.containsKey(itm.getOriDetailSn())) { FeeCounteract pos = posKeyVal.get(itm.getOriDetailSn()); if (itm.getChargeAmount() + pos.getChargeAmount() == 0d && itm.getChargeFee() + pos.getChargeFee() == 0d) { zyDao.updateYbTransFlagInPair(o.getInpatientNo(), o.getAdmissTimes(), itm.getDetailSn(), itm.getOriDetailSn()); count.addAndGet(2); } } }); log.info("正负相抵完成,抵消费用总条目:{}", count.get()); } }