diff --git a/src/main/java/com/saye/hospitalgd/controller/MedicalInsuranceReconciliationController.java b/src/main/java/com/saye/hospitalgd/controller/MedicalInsuranceReconciliationController.java new file mode 100644 index 0000000..8cd8de3 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/controller/MedicalInsuranceReconciliationController.java @@ -0,0 +1,150 @@ +package com.saye.hospitalgd.controller; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.saye.hospitalgd.commons.date.DateDUtil; +import com.saye.hospitalgd.commons.log.LogUtil; +import com.saye.hospitalgd.scheduler.jobMethod.MedicalInsuranceReconciliationMethod; +import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; + +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +/** + * @author thuang + * @version 1.0 + * @description: 医保对账Controller + * @date 2025/10/24 + */ +@Api(value = "医保对账相关接口") +@Controller +@RequestMapping("/medicalInsuranceReconciliation") +public class MedicalInsuranceReconciliationController { + + @Autowired + private MedicalInsuranceReconciliationService medicalInsuranceReconciliationService; + + /** + * 跳转到医保对账页面 + */ + @RequestMapping("/toMedicalInsuranceReconciliation") + public String toMedicalInsuranceReconciliation(ModelMap modelMap) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.add(Calendar.DATE, -1); + Date startDate = calendar.getTime(); + + String startTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, startDate); + String endTime = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd); + + modelMap.addAttribute("startTime", startTime); + modelMap.addAttribute("endTime", endTime); + + return "financialReconciliation/medicalInsuranceReconciliation"; + } + + /** + * 跳转到医保对账结果页面 + */ + @RequestMapping("/toMedicalInsuranceReconciliationResult") + public String toMedicalInsuranceReconciliationResult(ModelMap modelMap) { + return "financialReconciliation/medicalInsuranceReconciliationResult"; + } + + /** + * 执行医保对账 + */ + @ApiOperation(value = "执行医保对账", notes = "") + @PostMapping("/executeMedicalInsuranceReconciliation") + @ResponseBody + public HashMap executeMedicalInsuranceReconciliation( + @ApiParam(value = "对账日期") @RequestParam String trade_date) { + + HashMap responseMap = new HashMap<>(); + + try { + LogUtil.info(this.getClass(), "开始执行医保对账,日期:" + trade_date); + + MedicalInsuranceReconciliationMethod reconciliationMethod = new MedicalInsuranceReconciliationMethod(); + HashMap result = reconciliationMethod.executeMedicalInsuranceReconciliation(trade_date); + + responseMap.put("code", "0".equals(result.get("errCode")) ? 0 : 1); + responseMap.put("msg", result.get("errMsg")); + responseMap.put("data", result.get("reconciliationResults")); + + } catch (Exception e) { + e.printStackTrace(); + LogUtil.error(this.getClass(), "医保对账失败:" + e.getMessage()); + responseMap.put("code", 1); + responseMap.put("msg", "医保对账失败:" + e.getMessage()); + } + + return responseMap; + } + + /** + * 查询医保对账结果 + */ + @ApiOperation(value = "查询医保对账结果", notes = "") + @GetMapping("/findMedicalInsuranceReconciliationResult") + @ResponseBody + public HashMap findMedicalInsuranceReconciliationResult( + @ApiParam(value = "开始日期") String startDate, + @ApiParam(value = "结束日期") String endDate, + @ApiParam(value = "险种类型") String insutype, + @ApiParam(value = "清算类别") String clrType, + @ApiParam(value = "对账结果") String stmtRslt, + @ApiParam(value = "页码") int page, + @ApiParam(value = "每页数量") int limit) { + + HashMap responseMap = new HashMap<>(); + + try { + HashMap queryMap = new HashMap<>(); + if (startDate != null && !"".equals(startDate)) { + queryMap.put("startDate", startDate); + } + if (endDate != null && !"".equals(endDate)) { + queryMap.put("endDate", endDate); + } + if (insutype != null && !"".equals(insutype)) { + queryMap.put("insutype", insutype); + } + if (clrType != null && !"".equals(clrType)) { + queryMap.put("clr_type", clrType); + } + if (stmtRslt != null && !"".equals(stmtRslt)) { + queryMap.put("stmt_rslt", stmtRslt); + } + + PageHelper.startPage(page, limit); + PageInfo> pageInfo = new PageInfo<>( + medicalInsuranceReconciliationService.findMedicalInsuranceReconciliationResult(queryMap) + ); + + responseMap.put("code", 0); + responseMap.put("msg", "OK"); + responseMap.put("count", pageInfo.getTotal()); + responseMap.put("data", pageInfo.getList()); + + } catch (Exception e) { + e.printStackTrace(); + LogUtil.error(this.getClass(), "查询医保对账结果失败:" + e.getMessage()); + responseMap.put("code", 1); + responseMap.put("msg", "查询失败:" + e.getMessage()); + } + + return responseMap; + } +} + + diff --git a/src/main/java/com/saye/hospitalgd/controller/MilitaryInsuranceController.java b/src/main/java/com/saye/hospitalgd/controller/MilitaryInsuranceController.java index 5a84a42..16c6d78 100644 --- a/src/main/java/com/saye/hospitalgd/controller/MilitaryInsuranceController.java +++ b/src/main/java/com/saye/hospitalgd/controller/MilitaryInsuranceController.java @@ -141,13 +141,7 @@ public class MilitaryInsuranceController { map.put("endTime", endTime.substring(0, 10)); // 提取日期部分 } - // 添加调试信息 - System.out.println("军保统计查询参数: " + map.toString()); - List> hisDetailCount = hisDetailService.findHisDetailCountData(map); - - // 添加调试信息 - System.out.println("军保统计查询结果: " + (hisDetailCount != null ? hisDetailCount.toString() : "null")); if (hisDetailCount != null && hisDetailCount.size() > 0) { responseMap.put("money", hisDetailCount.get(0).get("MONEY")); @@ -236,8 +230,8 @@ public class MilitaryInsuranceController { if (list.size() > 0) { // 定义标题头和文件名 - String[] DISTANCE_HEADERNAME = {"交易状态", "业务类型", "支付方式", "交易时间", "交易日期", "操作员", "总金额", "平台交易号", "his订单号", "HIS交易ID", "患者id", "患者姓名", "来源"}; - String[] sqlKey = {"TRADINGSTATUS", "BIZTYPE", "PAYTYPE", "TRADETIME", "TRADE_DATE", "HISOPERCODE", "AMOUNT", "PLATFORMTRANSID", "HISTRANSID", "HISTRANSID", "PATIENTID", "PATIENTNAME", "SOURCE"}; + String[] DISTANCE_HEADERNAME = {"交易状态", "业务类型", "支付方式", "交易时间", "交易日期", "操作员", "总金额", "平台交易号", "his订单号", "HIS交易ID", "患者id", "患者姓名", "来源", "清算类别", "险种类型"}; + String[] sqlKey = {"TRADINGSTATUS", "BIZTYPE", "PAYTYPE", "TRADETIME", "TRADE_DATE", "HISOPERCODE", "AMOUNT", "PLATFORMTRANSID", "HISTRANSID", "HISTRANSID", "PATIENTID", "PATIENTNAME", "SOURCE", "CLR_TYPE", "INSUTYPE"}; List rulList = new ArrayList(list); @@ -263,6 +257,9 @@ public class MilitaryInsuranceController { exportXLS.modifyWidthOfHeader("5000", 9); exportXLS.modifyWidthOfHeader("5000", 10); exportXLS.modifyWidthOfHeader("10000", 11); + exportXLS.modifyWidthOfHeader("5000", 12); // 来源 + exportXLS.modifyWidthOfHeader("5000", 13); // 清算类别 + exportXLS.modifyWidthOfHeader("5000", 14); // 险种类型 // 文件名称 // 产生4位长度的随机码(由字母和数字组成) diff --git a/src/main/java/com/saye/hospitalgd/controller/PaymentStatisticsController.java b/src/main/java/com/saye/hospitalgd/controller/PaymentStatisticsController.java index d3eea9d..6abfc15 100644 --- a/src/main/java/com/saye/hospitalgd/controller/PaymentStatisticsController.java +++ b/src/main/java/com/saye/hospitalgd/controller/PaymentStatisticsController.java @@ -144,6 +144,10 @@ public class PaymentStatisticsController { LinkedHashMap zffsMap = numMap.get(str_zffs); if (zffsMap != null) { String countNum = zffsMap.get(c_jyrq); + // 安全处理countNum,如果为null或空字符串则默认为"0" + if (countNum == null || countNum.isEmpty()) { + countNum = "0"; + } countNum = new BigDecimal(countNum).add(new BigDecimal(num1)).toString(); zffsMap.put(c_jyrq, countNum); } @@ -181,6 +185,10 @@ public class PaymentStatisticsController { LinkedHashMap zffsMap = moneyMap.get(str_zffs); if (zffsMap != null) { String countNum = zffsMap.get(c_jyrq); + // 安全处理countNum,如果为null或空字符串则默认为"0" + if (countNum == null || countNum.isEmpty()) { + countNum = "0"; + } countNum = new BigDecimal(countNum).add(new BigDecimal(money)).toString(); zffsMap.put(c_jyrq, countNum); } @@ -316,32 +324,86 @@ public class PaymentStatisticsController { String amount = StringDUtil.changeNullToEmpty(hashMap.get("AMOUNT")).trim(); String paytype = StringDUtil.changeNullToEmpty(hashMap.get("PAYTYPE")).trim(); + + // 数据核准:确保PayType在预定义范围内 + if (!hisMoneyData.containsKey(paytype)) { + log.warn("发现未预定义的PayType: [{}], 数据: {}, 已归类为其他支付方式", paytype, hashMap); + paytype = "4"; // 归类为其他支付方式 + } + + // 数据核准:确保I_JYQD在预定义范围内 + if (!thirdMoneyData.containsKey(i_zffs)) { + log.warn("发现未预定义的I_JYQD: [{}], 数据: {}, 已归类为其他支付方式", i_zffs, hashMap); + i_zffs = "5"; // 归类为其他支付方式 + } // 如果银行端金额不为空 if (StrUtil.isNotBlank(i_jyje)) { - log.info("hashMap is :" + hashMap); - log.info("aaa is : " + thirdMoneyData.get(i_zffs)); - BigDecimal money = Convert.toBigDecimal(thirdMoneyData.get(i_zffs)); - money = money.add(new BigDecimal(i_jyje)); - thirdMoneyData.put(i_zffs, money.toString()); + try { + log.info("处理银行端数据: i_zffs={}, i_jyje={}", i_zffs, i_jyje); + + // 验证金额格式 + BigDecimal transAmount = new BigDecimal(i_jyje); + if (transAmount.compareTo(BigDecimal.ZERO) < 0) { + log.warn("发现负数金额: i_jyje={}, 数据: {}", i_jyje, hashMap); + } + + // 安全获取当前金额,如果为null则默认为BigDecimal.ZERO + BigDecimal money = Convert.toBigDecimal(thirdMoneyData.get(i_zffs), BigDecimal.ZERO); + money = money.add(transAmount); + thirdMoneyData.put(i_zffs, money.toString()); - int num = Integer.parseInt(StringDUtil.changeNullToEmpty(thirdNumData.get(i_zffs))); - num++; - thirdNumData.put(i_zffs, num + ""); + // 安全获取当前数量,如果为null或空字符串则默认为"0" + String currentNumStr = StringDUtil.changeNullToEmpty(thirdNumData.get(i_zffs)); + if (currentNumStr.isEmpty()) { + currentNumStr = "0"; + } + + int num = Integer.parseInt(currentNumStr); + num++; + thirdNumData.put(i_zffs, num + ""); + + } catch (NumberFormatException e) { + log.error("银行端金额格式错误: i_jyje=[{}], 数据: {}, 错误: {}", i_jyje, hashMap, e.getMessage()); + } } // 如果his端金额不为空 if (StrUtil.isNotBlank(amount)) { - log.info("hashMap is :" + hashMap); - BigDecimal money = new BigDecimal(StringDUtil.changeNullToEmpty(hisMoneyData.get(paytype))); - money = money.add(new BigDecimal(amount)); - hisMoneyData.put(paytype, money.toString()); + try { + log.info("处理HIS端数据: paytype={}, amount={}", paytype, amount); + + // 验证金额格式 + BigDecimal transAmount = new BigDecimal(amount); + if (transAmount.compareTo(BigDecimal.ZERO) < 0) { + log.warn("发现负数金额: amount={}, 数据: {}", amount, hashMap); + } + + // 安全获取当前金额,如果为null或空字符串则默认为"0" + String currentMoneyStr = StringDUtil.changeNullToEmpty(hisMoneyData.get(paytype)); + if (currentMoneyStr.isEmpty()) { + currentMoneyStr = "0"; + } + + BigDecimal money = new BigDecimal(currentMoneyStr); + money = money.add(transAmount); + hisMoneyData.put(paytype, money.toString()); - int num = Integer.parseInt(StringDUtil.changeNullToEmpty(hisNumData.get(paytype))); - num++; - hisNumData.put(paytype, num + ""); + // 安全获取当前数量,如果为null或空字符串则默认为"0" + String currentNumStr = StringDUtil.changeNullToEmpty(hisNumData.get(paytype)); + if (currentNumStr.isEmpty()) { + currentNumStr = "0"; + } + + int num = Integer.parseInt(currentNumStr); + num++; + hisNumData.put(paytype, num + ""); + + } catch (NumberFormatException e) { + log.error("HIS端金额格式错误: amount=[{}], 数据: {}, 错误: {}", amount, hashMap, e.getMessage()); + } } } diff --git a/src/main/java/com/saye/hospitalgd/controller/quartz/BaseQuartzConfigController.java b/src/main/java/com/saye/hospitalgd/controller/quartz/BaseQuartzConfigController.java index 38b54ef..2567653 100644 --- a/src/main/java/com/saye/hospitalgd/controller/quartz/BaseQuartzConfigController.java +++ b/src/main/java/com/saye/hospitalgd/controller/quartz/BaseQuartzConfigController.java @@ -48,6 +48,17 @@ public class BaseQuartzConfigController{ @Autowired private DicinfoService dicinfoService; + /** + * @description 跳转到定时任务管理页面 + * @author thuang + * @created 2025/10/24 + * @return + */ + @RequestMapping("/toQuartzManage") + public String toQuartzManage() { + return "system/quartzManage"; + } + /** * @description 查询所有的定时任务 * @author thuang diff --git a/src/main/java/com/saye/hospitalgd/entity/HisbillsHistory.java b/src/main/java/com/saye/hospitalgd/entity/HisbillsHistory.java index 0034a9a..8d673a5 100644 --- a/src/main/java/com/saye/hospitalgd/entity/HisbillsHistory.java +++ b/src/main/java/com/saye/hospitalgd/entity/HisbillsHistory.java @@ -23,4 +23,8 @@ public class HisbillsHistory { private String PatientName; private String source; private String trade_date; + private String clrType; // 清算类别 + private String insutype; // 险种类型 + private String ybzhAmount; // 医保账户金额 + private String ybtcAmount; // 医保统筹金额 } diff --git a/src/main/java/com/saye/hospitalgd/entity/MedicalInsuranceReconciliationResult.java b/src/main/java/com/saye/hospitalgd/entity/MedicalInsuranceReconciliationResult.java new file mode 100644 index 0000000..abddce4 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/entity/MedicalInsuranceReconciliationResult.java @@ -0,0 +1,29 @@ +package com.saye.hospitalgd.entity; + +import lombok.Data; + +/** + * @author thuang + * @version 1.0 + * @description: 医保对账结果实体类 + * @date 2025/10/24 + */ +@Data +public class MedicalInsuranceReconciliationResult { + + private String id; // 主键ID + private String tradeDate; // 对账日期 + private String insutype; // 险种类型 + private String clrType; // 清算类别 + private String medfee_sumamt; // 医疗费用总额 + private String fund_pay_sumamt; // 基金支付总额(医保统筹) + private String acct_pay; // 账户支付金额(医保账户) + private String fixmedins_setl_cnt; // 定点医药机构结算笔数 + private String stmt_rslt; // 对账结果(0-成功,1-失败) + private String stmt_rslt_dscr; // 对账结果描述 + private String apiResult; // 接口调用结果 + private String createTime; // 创建时间 + private String modifyTime; // 修改时间 +} + + diff --git a/src/main/java/com/saye/hospitalgd/mapper/HisDetailMapper.java b/src/main/java/com/saye/hospitalgd/mapper/HisDetailMapper.java index eba6709..2f4a65d 100644 --- a/src/main/java/com/saye/hospitalgd/mapper/HisDetailMapper.java +++ b/src/main/java/com/saye/hospitalgd/mapper/HisDetailMapper.java @@ -41,4 +41,6 @@ public interface HisDetailMapper { void deleteHisBillOriginalHYByParam(HashMap deleteMap) throws Exception; void insertAllHisBillOriginalHY(List> addList) throws Exception; + + List> findMedicalInsuranceGroupData(HashMap map) throws Exception; } diff --git a/src/main/java/com/saye/hospitalgd/mapper/MedicalInsuranceReconciliationMapper.java b/src/main/java/com/saye/hospitalgd/mapper/MedicalInsuranceReconciliationMapper.java new file mode 100644 index 0000000..d084218 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/mapper/MedicalInsuranceReconciliationMapper.java @@ -0,0 +1,38 @@ +package com.saye.hospitalgd.mapper; + +import org.apache.ibatis.annotations.Mapper; + +import java.util.HashMap; +import java.util.List; + +/** + * @author thuang + * @version 1.0 + * @description: 医保对账Mapper + * @date 2025/10/24 + */ +@Mapper +public interface MedicalInsuranceReconciliationMapper { + + /** + * 插入医保对账结果 + */ + void insertMedicalInsuranceReconciliationResult(HashMap map) throws Exception; + + /** + * 批量插入医保对账结果 + */ + void insertMedicalInsuranceReconciliationResultBatch(List> list) throws Exception; + + /** + * 查询医保对账结果 + */ + List> findMedicalInsuranceReconciliationResult(HashMap map) throws Exception; + + /** + * 删除医保对账结果 + */ + void deleteMedicalInsuranceReconciliationResult(HashMap map) throws Exception; +} + + diff --git a/src/main/java/com/saye/hospitalgd/mapper/system/FinanceUserMapper.java b/src/main/java/com/saye/hospitalgd/mapper/system/FinanceUserMapper.java index 0e4cad0..d609085 100644 --- a/src/main/java/com/saye/hospitalgd/mapper/system/FinanceUserMapper.java +++ b/src/main/java/com/saye/hospitalgd/mapper/system/FinanceUserMapper.java @@ -72,4 +72,5 @@ public interface FinanceUserMapper { + diff --git a/src/main/java/com/saye/hospitalgd/model/BaseQuartzConfigEntity.java b/src/main/java/com/saye/hospitalgd/model/BaseQuartzConfigEntity.java index 010ff8b..0fe499e 100644 --- a/src/main/java/com/saye/hospitalgd/model/BaseQuartzConfigEntity.java +++ b/src/main/java/com/saye/hospitalgd/model/BaseQuartzConfigEntity.java @@ -6,6 +6,7 @@ public class BaseQuartzConfigEntity { private String quartzGroup; private String status; private String quartzClass; + private String quartzType; private String remark; private String createUserId; private String expression; @@ -41,6 +42,12 @@ public class BaseQuartzConfigEntity { public void setQuartzClass(String quartzClass) { this.quartzClass = quartzClass; } + public String getQuartzType() { + return quartzType; + } + public void setQuartzType(String quartzType) { + this.quartzType = quartzType; + } public String getRemark() { return remark; } diff --git a/src/main/java/com/saye/hospitalgd/model/FinanceUser.java b/src/main/java/com/saye/hospitalgd/model/FinanceUser.java index 9a05f8d..eef5940 100644 --- a/src/main/java/com/saye/hospitalgd/model/FinanceUser.java +++ b/src/main/java/com/saye/hospitalgd/model/FinanceUser.java @@ -40,4 +40,5 @@ public class FinanceUser { + diff --git a/src/main/java/com/saye/hospitalgd/scheduler/job/MedicalInsuranceReconciliationJob.java b/src/main/java/com/saye/hospitalgd/scheduler/job/MedicalInsuranceReconciliationJob.java new file mode 100644 index 0000000..1dc28e3 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/scheduler/job/MedicalInsuranceReconciliationJob.java @@ -0,0 +1,58 @@ +package com.saye.hospitalgd.scheduler.job; + +import com.saye.hospitalgd.commons.log.LogUtil; +import com.saye.hospitalgd.scheduler.jobMethod.MedicalInsuranceReconciliationMethod; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.util.HashMap; + +/** + * @author yuan + * @version 1.0 + * @description: 医保对账定时任务 + * @date 2025/10/24 + */ +public class MedicalInsuranceReconciliationJob implements Job { + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + + JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap(); + String id = jobDataMap.getString("id"); + String name = jobDataMap.getString("name"); + String trade_date = jobDataMap.getString("trade_date"); + + // 如果没有指定对账日期,使用前一天的日期(医保对账通常对前一天的数据) + if (trade_date == null || trade_date.trim().isEmpty()) { + java.util.Calendar calendar = java.util.Calendar.getInstance(); + calendar.add(java.util.Calendar.DATE, -1); // 前一天 + java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); + trade_date = sdf.format(calendar.getTime()); + LogUtil.info(this.getClass(), "未指定对账日期,自动使用前一天日期:" + trade_date); + } + + LogUtil.info(this.getClass(), "医保对账定时任务【" + name + "】开始执行,日期:" + trade_date); + + try { + MedicalInsuranceReconciliationMethod method = new MedicalInsuranceReconciliationMethod(); + HashMap result = method.executeMedicalInsuranceReconciliation(trade_date); + + String errCode = (String) result.get("errCode"); + if ("0".equals(errCode)) { + LogUtil.info(this.getClass(), "医保对账定时任务【" + name + "】执行成功"); + } else { + LogUtil.error(this.getClass(), "医保对账定时任务【" + name + "】执行失败:" + result.get("errMsg")); + } + + } catch (Exception e) { + e.printStackTrace(); + LogUtil.error(this.getClass(), "医保对账定时任务【" + name + "】执行异常:" + e.getMessage()); + throw new JobExecutionException(e); + } + } +} + + diff --git a/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/HISGetDataMethodByJH.java b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/HISGetDataMethodByJH.java index f4523f0..3e14fe9 100644 --- a/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/HISGetDataMethodByJH.java +++ b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/HISGetDataMethodByJH.java @@ -158,6 +158,12 @@ public class HISGetDataMethodByJH { String amount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("amount")); String tradeTime = StringDUtil.changeNullToEmpty(hisBillHashMap.get("tradeTime")); + // 提取新增字段:清算类别、险种类型、医保账户金额、医保统筹金额 + String clrType = StringDUtil.changeNullToEmpty(hisBillHashMap.get("clrType")); + String insutype = StringDUtil.changeNullToEmpty(hisBillHashMap.get("insutype")); + String ybzhAmount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("ybzhAmount")); + String ybtcAmount = StringDUtil.changeNullToEmpty(hisBillHashMap.get("ybtcAmount")); + // 只有当缺少关键业务信息时才跳过(患者ID、金额、交易时间都为空) if ("".equals(patientId) && "".equals(amount) && "".equals(tradeTime)){ log.warn("跳过缺少关键业务信息的记录: powerTranID={}, receiptNO={}, hisTransId={}", @@ -222,6 +228,10 @@ public class HISGetDataMethodByJH { addMap.put("patientName",patientName); addMap.put("trade_date",thistrade_date); addMap.put("his_wsdl_id",his_wsdl_id); + addMap.put("clrType",clrType); // 清算类别 + addMap.put("insutype",insutype); // 险种类型 + addMap.put("ybzhAmount",ybzhAmount); // 医保账户金额 + addMap.put("ybtcAmount",ybtcAmount); // 医保统筹金额 //如果是现金记录先放进现金集合内 if (cash_code.equals(payType)){ @@ -259,6 +269,10 @@ public class HISGetDataMethodByJH { addMap.put("patientName",""); addMap.put("trade_date",trade_date); addMap.put("his_wsdl_id",his_wsdl_id); + addMap.put("clrType",""); // 现金记录没有清算类别 + addMap.put("insutype",""); // 现金记录没有险种类型 + addMap.put("ybzhAmount","0"); // 现金记录没有医保账户金额 + addMap.put("ybtcAmount","0"); // 现金记录没有医保统筹金额 cashMap.put(hisOperCode+"_"+payMethod,addMap); }else { @@ -300,6 +314,10 @@ public class HISGetDataMethodByJH { addMap.put("patientName",""); addMap.put("trade_date",trade_date); addMap.put("his_wsdl_id",his_wsdl_id); + addMap.put("clrType",""); // 支票记录没有清算类别 + addMap.put("insutype",""); // 支票记录没有险种类型 + addMap.put("ybzhAmount","0"); // 支票记录没有医保账户金额 + addMap.put("ybtcAmount","0"); // 支票记录没有医保统筹金额 zhipiaoMap.put(hisOperCode+"_"+payMethod,addMap); }else { diff --git a/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/MedicalInsuranceReconciliationMethod.java b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/MedicalInsuranceReconciliationMethod.java new file mode 100644 index 0000000..77a3a4c --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/MedicalInsuranceReconciliationMethod.java @@ -0,0 +1,355 @@ +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 executeMedicalInsuranceReconciliation(String trade_date) { + HashMap 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 queryMap = new HashMap<>(); + queryMap.put("trade_date", trade_date); + + // 查询所有有险种和清算类别的记录(不限制PayType) + List> 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 deleteMap = new HashMap<>(); + deleteMap.put("trade_date", trade_date); + reconciliationService.deleteMedicalInsuranceReconciliationResult(deleteMap); + + // 2. 遍历每个险种和清算类别的组合,调用医保局接口 + List> reconciliationResults = new ArrayList<>(); + + for (HashMap 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 callResult = callMedicalInsuranceAPI( + trade_date, insutype, clrType, medfee_sumamt, + fund_pay_sumamt, acct_pay, fixmedins_setl_cnt + ); + + // 4. 记录对账结果 + HashMap 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 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 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 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; + } +} + diff --git a/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/ReconciliationMethod.java b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/ReconciliationMethod.java index e1449e6..8247328 100644 --- a/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/ReconciliationMethod.java +++ b/src/main/java/com/saye/hospitalgd/scheduler/jobMethod/ReconciliationMethod.java @@ -79,6 +79,17 @@ public class ReconciliationMethod { military_code = StringDUtil.changeNullToEmpty(militaryPayTypeList.get(0).get("DICVALUE")); } searchMap.put("military_code", military_code); + + // 查询医保支付方式的dicvalue(需要从常规对账中过滤掉) + String medical_insurance_code = ""; // 默认为空,表示不过滤 + HashMap medicalSearchMap = new HashMap<>(); + medicalSearchMap.put("parentCode", "PAY_TYPE"); + medicalSearchMap.put("dicname", "医保"); + List> medicalPayTypeList = dicinfoService.selectDicinfoListByCondition(medicalSearchMap); + if (medicalPayTypeList != null && medicalPayTypeList.size() > 0) { + medical_insurance_code = StringDUtil.changeNullToEmpty(medicalPayTypeList.get(0).get("DICVALUE")); + } + searchMap.put("medical_insurance_code", medical_insurance_code); //查询his和三方记录 List> hisbillsList = hisbillsHistoryService.findHisBillsByDate(searchMap); diff --git a/src/main/java/com/saye/hospitalgd/service/HisDetailService.java b/src/main/java/com/saye/hospitalgd/service/HisDetailService.java index 5ed4e8f..b62062a 100644 --- a/src/main/java/com/saye/hospitalgd/service/HisDetailService.java +++ b/src/main/java/com/saye/hospitalgd/service/HisDetailService.java @@ -30,4 +30,6 @@ public interface HisDetailService { List> findHisCashDetail(HashMap map) throws Exception; List> findHisDetailCountData(HashMap map) throws Exception; + + List> findMedicalInsuranceGroupData(HashMap map) throws Exception; } diff --git a/src/main/java/com/saye/hospitalgd/service/MedicalInsuranceReconciliationService.java b/src/main/java/com/saye/hospitalgd/service/MedicalInsuranceReconciliationService.java new file mode 100644 index 0000000..f96ad84 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/service/MedicalInsuranceReconciliationService.java @@ -0,0 +1,35 @@ +package com.saye.hospitalgd.service; + +import java.util.HashMap; +import java.util.List; + +/** + * @author thuang + * @version 1.0 + * @description: 医保对账Service + * @date 2025/10/24 + */ +public interface MedicalInsuranceReconciliationService { + + /** + * 插入医保对账结果 + */ + void insertMedicalInsuranceReconciliationResult(HashMap map) throws Exception; + + /** + * 批量插入医保对账结果 + */ + void insertMedicalInsuranceReconciliationResultBatch(List> list) throws Exception; + + /** + * 查询医保对账结果 + */ + List> findMedicalInsuranceReconciliationResult(HashMap map) throws Exception; + + /** + * 删除医保对账结果 + */ + void deleteMedicalInsuranceReconciliationResult(HashMap map) throws Exception; +} + + diff --git a/src/main/java/com/saye/hospitalgd/service/impl/HisDetailServiceImpl.java b/src/main/java/com/saye/hospitalgd/service/impl/HisDetailServiceImpl.java index 2cb75d7..91ca88b 100644 --- a/src/main/java/com/saye/hospitalgd/service/impl/HisDetailServiceImpl.java +++ b/src/main/java/com/saye/hospitalgd/service/impl/HisDetailServiceImpl.java @@ -179,5 +179,9 @@ public class HisDetailServiceImpl implements HisDetailService { return hisDetailMapper.findHisDetailCountData(map); } + @Override + public List> findMedicalInsuranceGroupData(HashMap map) throws Exception { + return hisDetailMapper.findMedicalInsuranceGroupData(map); + } } diff --git a/src/main/java/com/saye/hospitalgd/service/impl/MedicalInsuranceReconciliationServiceImpl.java b/src/main/java/com/saye/hospitalgd/service/impl/MedicalInsuranceReconciliationServiceImpl.java new file mode 100644 index 0000000..175c094 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/service/impl/MedicalInsuranceReconciliationServiceImpl.java @@ -0,0 +1,46 @@ +package com.saye.hospitalgd.service.impl; + +import com.saye.hospitalgd.mapper.MedicalInsuranceReconciliationMapper; +import com.saye.hospitalgd.service.MedicalInsuranceReconciliationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashMap; +import java.util.List; + +/** + * @author thuang + * @version 1.0 + * @description: 医保对账ServiceImpl + * @date 2025/10/24 + */ +@Service +@Transactional +public class MedicalInsuranceReconciliationServiceImpl implements MedicalInsuranceReconciliationService { + + @Autowired + private MedicalInsuranceReconciliationMapper medicalInsuranceReconciliationMapper; + + @Override + public void insertMedicalInsuranceReconciliationResult(HashMap map) throws Exception { + medicalInsuranceReconciliationMapper.insertMedicalInsuranceReconciliationResult(map); + } + + @Override + public void insertMedicalInsuranceReconciliationResultBatch(List> list) throws Exception { + medicalInsuranceReconciliationMapper.insertMedicalInsuranceReconciliationResultBatch(list); + } + + @Override + public List> findMedicalInsuranceReconciliationResult(HashMap map) throws Exception { + return medicalInsuranceReconciliationMapper.findMedicalInsuranceReconciliationResult(map); + } + + @Override + public void deleteMedicalInsuranceReconciliationResult(HashMap map) throws Exception { + medicalInsuranceReconciliationMapper.deleteMedicalInsuranceReconciliationResult(map); + } +} + + diff --git a/src/main/java/com/saye/hospitalgd/service/system/FinanceUserService.java b/src/main/java/com/saye/hospitalgd/service/system/FinanceUserService.java index ff7fd73..e783b5b 100644 --- a/src/main/java/com/saye/hospitalgd/service/system/FinanceUserService.java +++ b/src/main/java/com/saye/hospitalgd/service/system/FinanceUserService.java @@ -76,4 +76,5 @@ public interface FinanceUserService { + diff --git a/src/main/java/com/saye/hospitalgd/service/system/impl/FinanceUserServiceImpl.java b/src/main/java/com/saye/hospitalgd/service/system/impl/FinanceUserServiceImpl.java index 91eb84f..86d48df 100644 --- a/src/main/java/com/saye/hospitalgd/service/system/impl/FinanceUserServiceImpl.java +++ b/src/main/java/com/saye/hospitalgd/service/system/impl/FinanceUserServiceImpl.java @@ -106,4 +106,5 @@ public class FinanceUserServiceImpl implements FinanceUserService { + diff --git a/src/main/java/com/saye/hospitalgd/util/HisUtil.java b/src/main/java/com/saye/hospitalgd/util/HisUtil.java index d1866b4..a8aeca8 100644 --- a/src/main/java/com/saye/hospitalgd/util/HisUtil.java +++ b/src/main/java/com/saye/hospitalgd/util/HisUtil.java @@ -764,6 +764,20 @@ public class HisUtil { if (powerTranIDElm != null) { powerTranID = powerTranIDElm.getText(); } + + //清算类别(医保记录才有) + Element clrTypeElm = item.element("clr_type"); + String clrType = ""; + if (clrTypeElm != null) { + clrType = clrTypeElm.getText(); + } + + //险种类型(医保记录才有) + Element insutypeElm = item.element("insutype"); + String insutype = ""; + if (insutypeElm != null) { + insutype = insutypeElm.getText(); + } addMap.put("visitzOrg", visitzOrg); addMap.put("bizType", bizType); @@ -782,7 +796,9 @@ public class HisUtil { addMap.put("hisTime", hisTime); addMap.put("hisOperCode", hisOperNum); // 修改字段名以匹配HISGetDataMethodByJH中的使用 addMap.put("powerTranID", powerTranID); - addMap.put("hisTransId", receiptNO); // 新增HisTransId字段,使用ReceiptNO的值 + addMap.put("hisTransId", receiptNO); + addMap.put("clrType", clrType); // 清算类别 + addMap.put("insutype", insutype); // 险种类型 // 新增HisTransId字段,使用ReceiptNO的值 addList.add(addMap); } diff --git a/src/main/java/com/saye/hospitalgd/util/HttpClientUtil.java b/src/main/java/com/saye/hospitalgd/util/HttpClientUtil.java index 2d4fdee..2d90eb9 100644 --- a/src/main/java/com/saye/hospitalgd/util/HttpClientUtil.java +++ b/src/main/java/com/saye/hospitalgd/util/HttpClientUtil.java @@ -208,4 +208,5 @@ public class HttpClientUtil { + diff --git a/src/main/java/com/saye/hospitalgd/util/SSLUtil.java b/src/main/java/com/saye/hospitalgd/util/SSLUtil.java new file mode 100644 index 0000000..64ebae9 --- /dev/null +++ b/src/main/java/com/saye/hospitalgd/util/SSLUtil.java @@ -0,0 +1,114 @@ +package com.saye.hospitalgd.util; + +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; + +import javax.net.ssl.*; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * SSL证书工具类 + * 用于处理HTTPS请求时的SSL证书验证问题 + * + * @author thuang + * @date 2025/10/24 + */ +public class SSLUtil { + + /** + * 创建一个信任所有证书的HttpClient + * 注意:此方法会跳过SSL证书验证,仅用于开发/测试环境 + * 生产环境建议导入正确的SSL证书到JVM信任库 + * + * @return CloseableHttpClient + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + * @throws KeyManagementException + */ + public static CloseableHttpClient createSSLClientDefault() + throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { + + // 创建信任所有证书的策略 + TrustStrategy acceptingTrustStrategy = new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + return true; + } + }; + + // 构建SSL上下文 + SSLContext sslContext = SSLContextBuilder + .create() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); + + // 创建SSL连接工厂(不验证主机名) + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + sslContext, + new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "SSLv3"}, + null, + SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER + ); + + // 创建HttpClient + return HttpClients.custom() + .setSSLSocketFactory(sslSocketFactory) + .build(); + } + + /** + * 全局禁用SSL证书验证(针对HttpsURLConnection) + * 注意:此方法会影响整个JVM,请谨慎使用 + */ + public static void disableSSLVerification() { + try { + // 创建信任所有证书的TrustManager + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } + }; + + // 安装信任所有证书的TrustManager + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + // 创建不进行主机名验证的HostnameVerifier + HostnameVerifier allHostsValid = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + // 安装不进行主机名验证的HostnameVerifier + HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); + + } catch (NoSuchAlgorithmException | KeyManagementException e) { + e.printStackTrace(); + } + } +} + + + diff --git a/src/main/resources/mapper/BaseQuartzConfigMapper.xml b/src/main/resources/mapper/BaseQuartzConfigMapper.xml index ac0d566..39df42e 100644 --- a/src/main/resources/mapper/BaseQuartzConfigMapper.xml +++ b/src/main/resources/mapper/BaseQuartzConfigMapper.xml @@ -7,6 +7,7 @@ + @@ -16,12 +17,15 @@ - select CONFIGID,QUARTZ_NAME,QUARTZ_GROUP,STATUS,QUARTZ_CLASS,REMARK,CREATEUSERID,EXPRESSION,CREATE_TIME from base_quartz_config + select CONFIGID,QUARTZ_NAME,QUARTZ_GROUP,STATUS,QUARTZ_CLASS,QUARTZ_TYPE,REMARK,CREATEUSERID,EXPRESSION,CREATE_TIME from base_quartz_config where CONFIGID=#{id} update base_quartz_config set QUARTZ_NAME=#{quartzName},QUARTZ_GROUP=#{quartzGroup},STATUS=#{status},QUARTZ_CLASS=#{quartzClass} - ,REMARK=#{remark},CREATEUSERID=#{createUserId},EXPRESSION=#{expression} + ,QUARTZ_TYPE=#{quartzType},REMARK=#{remark},CREATEUSERID=#{createUserId},EXPRESSION=#{expression} where CONFIGID=#{configId} @@ -53,14 +57,14 @@ - insert into base_quartz_config(configid, quartz_name, status, quartz_class, remark, createuserid, expression, create_time) - values(#{id},#{quartzName},#{status}, #{quartz_class}, #{remark}, #{createuserid}, #{expression}, #{create_time} ) + insert into base_quartz_config(configid, quartz_name, status, quartz_class, quartz_type, remark, createuserid, expression, create_time) + values(#{id},#{quartzName},#{status}, #{quartz_class}, #{quartz_type}, #{remark}, #{createuserid}, #{expression}, #{create_time} ) update base_quartz_config set QUARTZ_NAME=#{quartzName},QUARTZ_GROUP=#{quartzGroup},QUARTZ_CLASS=#{quartzClass} - ,REMARK=#{remark},EXPRESSION=#{expression} + ,QUARTZ_TYPE=#{quartzType},REMARK=#{remark},EXPRESSION=#{expression} where CONFIGID=#{configId} diff --git a/src/main/resources/mapper/HisDetailMapper.xml b/src/main/resources/mapper/HisDetailMapper.xml index 34f77a3..e372934 100644 --- a/src/main/resources/mapper/HisDetailMapper.xml +++ b/src/main/resources/mapper/HisDetailMapper.xml @@ -17,6 +17,10 @@ ,trade_date ,his_wsdl_id ,HisTransId + ,clr_type + ,insutype + ,ybzhAmount + ,ybtcAmount from hisbill_history @@ -97,24 +101,25 @@ insert into - hisbill_original_hy(VisitzOrg,BizType,PayType,Amount,ZFAmount,YBZHAmount,YBTCAmount,Receipt_no,PatientID,PatientName,TradeTime,HisTime,HisOperNum,PowerTranID,trade_date) + hisbill_original_hy(VisitzOrg,BizType,PayType,Amount,ZFAmount,YBZHAmount,YBTCAmount,Receipt_no,PatientID,PatientName,TradeTime,HisTime,HisOperNum,PowerTranID,trade_date,clr_type,insutype) values ( #{itm.visitzOrg},#{itm.bizType},#{itm.payType},#{itm.amount},#{itm.zfAmount},#{itm.ybzhAmount},#{itm.ybtcAmount}, - #{itm.receiptNO},#{itm.patientID},#{itm.patientName},#{itm.tradeTime},#{itm.hisTime},#{itm.hisOperNum},#{itm.powerTranID},#{itm.trade_date} + #{itm.receiptNO},#{itm.patientID},#{itm.patientName},#{itm.tradeTime},#{itm.hisTime},#{itm.hisOperNum},#{itm.powerTranID},#{itm.trade_date}, + #{itm.clrType},#{itm.insutype} ) insert into - hisbill_history(PayMethod,TradingStatus,BizType,PayType,TradeTime,HisOperCode,Amount,remarks,PlatformTransId,PatientId,PatientName,trade_date,his_wsdl_id,HisTransId) + hisbill_history(PayMethod,TradingStatus,BizType,PayType,TradeTime,HisOperCode,Amount,remarks,PlatformTransId,PatientId,PatientName,trade_date,his_wsdl_id,HisTransId,clr_type,insutype,ybzhAmount,ybtcAmount) values ( #{itm.payMethod},#{itm.tradingStatus},#{itm.bizType},#{itm.payType},#{itm.tradeTime},#{itm.hisOperCode},#{itm.amount},#{itm.remarks},#{itm.platformTransId},#{itm.patientId} - ,#{itm.patientName},#{itm.trade_date},#{itm.his_wsdl_id},#{itm.hisTransId} + ,#{itm.patientName},#{itm.trade_date},#{itm.his_wsdl_id},#{itm.hisTransId},#{itm.clrType},#{itm.insutype},#{itm.ybzhAmount},#{itm.ybtcAmount} ) @@ -147,6 +152,10 @@ ,trade_date ,his_wsdl_id ,HisTransId + ,clr_type + ,insutype + ,ybzhAmount + ,ybtcAmount from hisbill_history where trade_date=#{trade_date} @@ -162,7 +171,7 @@ @@ -200,4 +209,23 @@ + + + \ No newline at end of file diff --git a/src/main/resources/mapper/HisbillsHistoryMapper.xml b/src/main/resources/mapper/HisbillsHistoryMapper.xml index 5151c62..93128a4 100644 --- a/src/main/resources/mapper/HisbillsHistoryMapper.xml +++ b/src/main/resources/mapper/HisbillsHistoryMapper.xml @@ -27,6 +27,9 @@ and PayType != #{military_code} + + and PayType != #{medical_insurance_code} + + select + id, + trade_date, + insutype, + clr_type, + medfee_sumamt, + fund_pay_sumamt, + acct_pay, + fixmedins_setl_cnt, + stmt_rslt, + stmt_rslt_dscr, + api_result, + DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') as create_time, + DATE_FORMAT(modify_time, '%Y-%m-%d %H:%i:%s') as modify_time + from medical_insurance_reconciliation_result + + + and trade_date = #{trade_date} + + + and trade_date >= #{startDate} + + + and trade_date <= #{endDate} + + + and insutype = #{insutype} + + + and clr_type = #{clr_type} + + + and clr_type = #{clrType} + + + and stmt_rslt = #{stmt_rslt} + + + and stmt_rslt = #{stmtRslt} + + + order by create_time desc, trade_date desc, insutype, clr_type + + + + + delete from medical_insurance_reconciliation_result + where trade_date = #{trade_date} + + + + + diff --git a/src/main/resources/mapper/system/FinanceUserMapper.xml b/src/main/resources/mapper/system/FinanceUserMapper.xml index cab7fa7..cc015d3 100644 --- a/src/main/resources/mapper/system/FinanceUserMapper.xml +++ b/src/main/resources/mapper/system/FinanceUserMapper.xml @@ -128,4 +128,5 @@ + diff --git a/src/main/resources/templates/financialReconciliation/medicalInsuranceReconciliationResult.html b/src/main/resources/templates/financialReconciliation/medicalInsuranceReconciliationResult.html new file mode 100644 index 0000000..ad0c2b7 --- /dev/null +++ b/src/main/resources/templates/financialReconciliation/medicalInsuranceReconciliationResult.html @@ -0,0 +1,476 @@ + + + + + 医保对账结果查询 + + + + + + + + + + +
+
+
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+ + + +
+
+
+
+ 医保对账结果 +   +
+
+
+ +
+ + + + + + + + + + diff --git a/src/main/resources/templates/system/financeUser_test.html b/src/main/resources/templates/system/financeUser_test.html index b680f40..4532038 100644 --- a/src/main/resources/templates/system/financeUser_test.html +++ b/src/main/resources/templates/system/financeUser_test.html @@ -73,4 +73,5 @@ + diff --git a/src/main/resources/templates/system/quartzManage.html b/src/main/resources/templates/system/quartzManage.html new file mode 100644 index 0000000..88811e0 --- /dev/null +++ b/src/main/resources/templates/system/quartzManage.html @@ -0,0 +1,510 @@ + + + + + 定时任务管理 + + + + + + + + + + +
+
+
+ 任务名称: + +
+ +
+ 任务类型: + +
+ +
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ + + +