Files
dzpt/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/MedicalInsuranceReconciliationMethod.java
2025-10-27 08:49:28 +08:00

356 lines
17 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.saye.hospitalgd.scheduler.jobMethod;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.saye.hospitalgd.commons.date.DateDUtil;
import com.saye.hospitalgd.commons.getBean.GetBeanUtil;
import com.saye.hospitalgd.commons.log.LogUtil;
import com.saye.hospitalgd.commons.string.StringDUtil;
import com.saye.hospitalgd.commons.uuid.UUIDGenerator;
import com.saye.hospitalgd.service.HisDetailService;
import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService;
import com.saye.hospitalgd.service.impl.HisDetailServiceImpl;
import com.saye.hospitalgd.service.impl.MedicalInsuranceReconciliationServiceImpl;
import com.saye.hospitalgd.service.system.DicinfoService;
import com.saye.hospitalgd.service.system.impl.DicinfoServiceImpl;
import com.saye.hospitalgd.util.SSLUtil;
import com.saye.hospitalgd.util.pojo.HttpResult;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @author thuang
* @version 1.0
* @description: 医保对账方法
* @date 2025/10/24
*/
public class MedicalInsuranceReconciliationMethod {
// 普通医保局对账接口地址
private static final String MEDICAL_INSURANCE_URL = "https://10.134.97.159/fsi/api/ybSettlementStmtService/stmtTotal";
// 工商医保对账接口地址险种99410专用
private static final String GONGSHANG_INSURANCE_URL = "http://10.150.4.74:8111/gssetl/api/hisbiz";
// 工商医保险种代码
private static final String GONGSHANG_INSUTYPE = "99410";
// 固定参数
private static final String SETL_OPTINS = "640104";
private static final String INFNO = "3201";
private static final String INFVER = "1.0";
private static final String FIXMEDINS_CODE = "H64010400022";
private static final String FIXMEDINS_NAME = "中国人民武装警察部队宁夏回族自治区总队医院";
private static final String INSUPLC_ADMDVS = "410000";
private static final String MDTRTAREA_ADMVS = "411302";
private static final String OPTER = "ADMIN";
private static final String OPTER_NAME = "系统管理员";
private static final String OPTER_TYPE = "1";
private static final String RECER_SYS_CODE = "HIS";
private static final String SIGNTYPE = "SM3";
/**
* 执行医保对账
* @param trade_date 对账日期
* @return 对账结果
*/
public HashMap<Object, Object> executeMedicalInsuranceReconciliation(String trade_date) {
HashMap<Object, Object> responseMap = new HashMap<>();
String errCode = "0";
String errMsg = "";
try {
LogUtil.info(this.getClass(), "开始执行医保对账,日期:" + trade_date);
LogUtil.info(this.getClass(), "开始查询医保数据不限制PayType");
// 1. 从数据库查询医保数据按险种和清算类别分组统计不限制PayType
HisDetailService hisDetailService = GetBeanUtil.getBean(HisDetailServiceImpl.class);
HashMap<Object, Object> queryMap = new HashMap<>();
queryMap.put("trade_date", trade_date);
// 查询所有有险种和清算类别的记录不限制PayType
List<HashMap<Object, Object>> medicalRecords = hisDetailService.findMedicalInsuranceGroupData(queryMap);
if (medicalRecords == null || medicalRecords.size() == 0) {
LogUtil.info(this.getClass(), "医保对账:当日没有医保数据,日期:" + trade_date);
errMsg = "当日没有医保数据";
responseMap.put("errCode", errCode);
responseMap.put("errMsg", errMsg);
responseMap.put("reconciliationResults", new ArrayList<>());
return responseMap;
}
LogUtil.info(this.getClass(), "查询到医保分组数据:" + medicalRecords.size() + "");
// 删除当天旧的对账结果
MedicalInsuranceReconciliationService reconciliationService =
GetBeanUtil.getBean(MedicalInsuranceReconciliationServiceImpl.class);
HashMap<Object, Object> deleteMap = new HashMap<>();
deleteMap.put("trade_date", trade_date);
reconciliationService.deleteMedicalInsuranceReconciliationResult(deleteMap);
// 2. 遍历每个险种和清算类别的组合,调用医保局接口
List<HashMap<Object, Object>> reconciliationResults = new ArrayList<>();
for (HashMap<Object, Object> record : medicalRecords) {
String insutype = StringDUtil.changeNullToEmpty(record.get("INSUTYPE"));
String clrType = StringDUtil.changeNullToEmpty(record.get("CLR_TYPE"));
String medfee_sumamt = StringDUtil.changeNullToEmpty(record.get("MEDFEE_SUMAMT"));
String fund_pay_sumamt = StringDUtil.changeNullToEmpty(record.get("FUND_PAY_SUMAMT"));
String acct_pay = StringDUtil.changeNullToEmpty(record.get("ACCT_PAY"));
String fixmedins_setl_cnt = StringDUtil.changeNullToEmpty(record.get("FIXMEDINS_SETL_CNT"));
// 跳过空的险种或清算类别
if ("".equals(insutype) || "".equals(clrType)) {
LogUtil.info(this.getClass(), "跳过险种或清算类别为空的记录");
continue;
}
LogUtil.info(this.getClass(), String.format("处理险种:%s清算类别%s交易笔数%s总金额%s",
insutype, clrType, fixmedins_setl_cnt, medfee_sumamt));
try {
// 3. 调用医保局对账接口
HashMap<Object, Object> callResult = callMedicalInsuranceAPI(
trade_date, insutype, clrType, medfee_sumamt,
fund_pay_sumamt, acct_pay, fixmedins_setl_cnt
);
// 4. 记录对账结果
HashMap<Object, Object> resultMap = new HashMap<>();
resultMap.put("id", UUIDGenerator.getUUID());
resultMap.put("trade_date", trade_date);
resultMap.put("insutype", insutype);
resultMap.put("clr_type", clrType);
resultMap.put("medfee_sumamt", medfee_sumamt);
resultMap.put("fund_pay_sumamt", fund_pay_sumamt);
resultMap.put("acct_pay", acct_pay);
resultMap.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
resultMap.put("setl_optins", callResult.get("setl_optins"));
resultMap.put("stmt_rslt", callResult.get("stmt_rslt"));
resultMap.put("stmt_rslt_dscr", callResult.get("stmt_rslt_dscr"));
resultMap.put("infcode", callResult.get("infcode"));
resultMap.put("err_msg", callResult.get("err_msg"));
resultMap.put("warn_msg", callResult.get("warn_msg"));
resultMap.put("refmsg_time", callResult.get("refmsg_time"));
resultMap.put("respond_time", callResult.get("respond_time"));
resultMap.put("inf_refmsgid", callResult.get("inf_refmsgid"));
resultMap.put("api_result", callResult.get("api_result"));
resultMap.put("create_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
resultMap.put("modify_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
reconciliationResults.add(resultMap);
} catch (Exception e) {
LogUtil.error(this.getClass(), String.format("医保对账失败,险种:%s清算类别%s错误%s",
insutype, clrType, e.getMessage()));
// 记录失败结果
HashMap<Object, Object> resultMap = new HashMap<>();
resultMap.put("id", UUIDGenerator.getUUID());
resultMap.put("trade_date", trade_date);
resultMap.put("insutype", insutype);
resultMap.put("clr_type", clrType);
resultMap.put("medfee_sumamt", medfee_sumamt);
resultMap.put("fund_pay_sumamt", fund_pay_sumamt);
resultMap.put("acct_pay", acct_pay);
resultMap.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
resultMap.put("stmt_rslt", "9");
resultMap.put("stmt_rslt_dscr", "调用医保局接口失败:" + e.getMessage());
resultMap.put("api_result", "ERROR");
resultMap.put("create_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
resultMap.put("modify_time", DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss));
reconciliationResults.add(resultMap);
}
}
// 5. 批量保存对账结果到数据库
if (reconciliationResults.size() > 0) {
reconciliationService.insertMedicalInsuranceReconciliationResultBatch(reconciliationResults);
}
responseMap.put("reconciliationResults", reconciliationResults);
LogUtil.info(this.getClass(), "医保对账完成,共处理 " + reconciliationResults.size() + " 组数据");
} catch (Exception e) {
e.printStackTrace();
errCode = "999";
errMsg = "医保对账失败:" + e.getMessage();
LogUtil.error(this.getClass(), errMsg);
}
responseMap.put("errCode", errCode);
responseMap.put("errMsg", errMsg);
return responseMap;
}
/**
* 调用医保局对账接口
*/
private HashMap<Object, Object> callMedicalInsuranceAPI(
String trade_date, String insutype, String clr_type,
String medfee_sumamt, String fund_pay_sumamt, String acct_pay,
String fixmedins_setl_cnt) throws Exception {
HashMap<Object, Object> result = new HashMap<>();
// 计算日期范围(当日到当日)
String stmt_begndate = trade_date;
String stmt_enddate = trade_date;
// 生成当前时间
String inf_time = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd_HH_mm_ss);
// 生成消息ID机构编码+时间戳+序号)
String msgid = FIXMEDINS_CODE + DateDUtil.DateToStr("yyyyMMddHHmmss", new Date()) + "0001";
// 构建请求JSON
JSONObject requestJson = new JSONObject();
requestJson.put("cainfo", "");
requestJson.put("dev_no", "");
requestJson.put("dev_safe_info", "");
requestJson.put("fixmedins_code", FIXMEDINS_CODE);
requestJson.put("fixmedins_name", FIXMEDINS_NAME);
requestJson.put("inf_time", inf_time);
requestJson.put("infno", INFNO);
requestJson.put("infver", INFVER);
requestJson.put("insuplc_admdvs", INSUPLC_ADMDVS);
requestJson.put("mdtrtarea_admvs", MDTRTAREA_ADMVS);
requestJson.put("msgid", msgid);
requestJson.put("opter", OPTER);
requestJson.put("opter_name", OPTER_NAME);
requestJson.put("opter_type", OPTER_TYPE);
requestJson.put("recer_sys_code", RECER_SYS_CODE);
requestJson.put("sign_no", "");
requestJson.put("signtype", SIGNTYPE);
// 构建input.data
JSONObject inputData = new JSONObject();
inputData.put("acct_pay", acct_pay);
inputData.put("clr_type", clr_type);
inputData.put("fixmedins_setl_cnt", fixmedins_setl_cnt);
inputData.put("fund_pay_sumamt", fund_pay_sumamt);
inputData.put("insutype", insutype);
inputData.put("medfee_sumamt", medfee_sumamt);
inputData.put("setl_optins", SETL_OPTINS);
inputData.put("stmt_begndate", stmt_begndate);
inputData.put("stmt_enddate", stmt_enddate);
JSONObject input = new JSONObject();
input.put("data", inputData);
requestJson.put("input", input);
LogUtil.info(this.getClass(), "医保对账请求(日期范围:" + stmt_begndate + "" + stmt_enddate + "" + requestJson.toJSONString());
// 根据险种选择接口地址
String apiUrl;
boolean isGongshang = GONGSHANG_INSUTYPE.equals(insutype);
if (isGongshang) {
apiUrl = GONGSHANG_INSURANCE_URL;
LogUtil.info(this.getClass(), "险种99410使用工商医保接口当日到当日" + apiUrl);
} else {
apiUrl = MEDICAL_INSURANCE_URL;
LogUtil.info(this.getClass(), "使用普通医保接口(当日到当日):" + apiUrl);
}
// 发送HTTP请求使用信任所有SSL证书的HttpClient
CloseableHttpClient httpClient = null;
try {
httpClient = SSLUtil.createSSLClientDefault();
} catch (Exception e) {
LogUtil.error(this.getClass(), "创建SSL HttpClient失败" + e.getMessage());
// 如果创建SSL HttpClient失败使用默认的HttpClient
httpClient = HttpClients.createDefault();
}
HttpPost httpPost = new HttpPost(apiUrl);
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setEntity(new StringEntity(requestJson.toJSONString(), StandardCharsets.UTF_8));
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpPost);
String responseStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
LogUtil.info(this.getClass(), "医保对账响应:" + responseStr);
// 解析响应
JSONObject responseJson = JSON.parseObject(responseStr);
// 存储基础响应信息
result.put("infcode", responseJson.getInteger("infcode"));
result.put("err_msg", responseJson.getString("err_msg"));
result.put("warn_msg", responseJson.getString("warn_msg"));
result.put("refmsg_time", responseJson.getString("refmsg_time"));
result.put("respond_time", responseJson.getString("respond_time"));
result.put("inf_refmsgid", responseJson.getString("inf_refmsgid"));
Integer infcode = responseJson.getInteger("infcode");
if (infcode != null && infcode == 0) {
// 请求成功
JSONObject output = responseJson.getJSONObject("output");
if (output != null && output.containsKey("stmtinfo")) {
JSONObject stmtinfo = output.getJSONObject("stmtinfo");
result.put("setl_optins", stmtinfo.getString("setl_optins"));
String stmt_rslt = stmtinfo.getString("stmt_rslt");
String stmt_rslt_dscr = stmtinfo.getString("stmt_rslt_dscr");
// 工商医保的对账结果处理99410险种
if (isGongshang) {
// 工商医保返回格式:
// stmt_rslt: "101" 表示有差异(对应普通医保的"1"失败)
// stmt_rslt: "0" 表示一致(对应普通医保的"0"成功)
if ("101".equals(stmt_rslt)) {
result.put("stmt_rslt", "1"); // 转换为标准的失败标识
LogUtil.info(this.getClass(), "工商医保对账结果:有差异 - " + stmt_rslt_dscr);
} else if ("0".equals(stmt_rslt)) {
result.put("stmt_rslt", "0"); // 成功
LogUtil.info(this.getClass(), "工商医保对账结果:一致");
} else {
result.put("stmt_rslt", stmt_rslt); // 保持原值
LogUtil.info(this.getClass(), "工商医保对账结果:" + stmt_rslt);
}
} else {
// 普通医保直接使用返回值
result.put("stmt_rslt", stmt_rslt);
}
result.put("stmt_rslt_dscr", stmt_rslt_dscr);
result.put("api_result", "SUCCESS");
} else {
result.put("stmt_rslt", "9");
result.put("stmt_rslt_dscr", "返回数据格式错误");
result.put("api_result", "ERROR");
}
} else {
// 请求失败
String err_msg = responseJson.getString("err_msg");
result.put("stmt_rslt", "9");
result.put("stmt_rslt_dscr", "医保局返回错误:" + err_msg);
result.put("api_result", "ERROR");
}
} finally {
if (response != null) {
response.close();
}
httpClient.close();
}
return result;
}
}