bugfix:移动医保对账

This commit is contained in:
Yuan
2025-12-23 09:24:28 +08:00
parent f084043a4b
commit ae385398fc
13 changed files with 502 additions and 9 deletions

View File

@@ -0,0 +1,68 @@
package com.saye.hospitalgd.controller;
import com.saye.hospitalgd.commons.date.DateDUtil;
import com.saye.hospitalgd.commons.string.StringDUtil;
import com.saye.hospitalgd.service.FinancialReconciliation.MobileYbReconciliationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
@Controller
@RequestMapping("/mobileYbReconciliation")
@Api(tags = "微信移动医保对账")
public class MobileYbReconciliationController {
@Autowired
private MobileYbReconciliationService mobileYbReconciliationService;
@RequestMapping("/toMobileYb")
public String toMobileYb(ModelMap modelMap) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, -1);
String startTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, calendar.getTime());
String endTime = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd);
modelMap.addAttribute("startTime", startTime);
modelMap.addAttribute("endTime", endTime);
return "paymentStatistics/mobileYbReconciliation";
}
@RequestMapping("/findData")
@ResponseBody
@ApiOperation("查询微信移动医保对账数据")
public HashMap<Object, Object> findData(@RequestBody HashMap<Object, Object> map) {
HashMap<Object, Object> resp = new HashMap<>();
String errCode = "0";
String errMsg = "";
try {
String tradeDate = StringDUtil.changeNullToEmpty(map.get("trade_date"));
if ("".equals(tradeDate)) {
errCode = "1";
errMsg = "trade_date不能为空";
} else {
resp = mobileYbReconciliationService.reconcile(tradeDate);
}
} catch (Exception e) {
errCode = "999";
errMsg = e.getMessage();
}
resp.put("errCode", errCode);
resp.put("errMsg", errMsg);
return resp;
}
}

View File

@@ -452,6 +452,16 @@ public class PaymentStatisticsController {
public HashMap<Object, Object> findTenpaySummary(String startTime, String endTime) {
HashMap<Object, Object> response = new HashMap<>();
try {
// 如果未选择日期,则默认查询昨日到今日,避免无条件查全量
if ((startTime == null || "".equals(startTime.trim())) && (endTime == null || "".equals(endTime.trim()))) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, -1);
Date startDate = calendar.getTime();
startTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, startDate);
endTime = DateDUtil.getCurrentDate(DateDUtil.yyyy_MM_dd);
}
HashMap<Object, Object> map = new HashMap<>();
map.put("startTime", startTime);
map.put("endTime", endTime);

View File

@@ -0,0 +1,36 @@
package com.saye.hospitalgd.entity;
import lombok.Data;
/**
* 微信移动医保对账结果
*/
@Data
public class MobileYbReconciliationResult {
private String id;
private String tradeDate;
private String bankMedfee;
private String bankAcctPay;
private String bankFundPay;
private String hisMedfee;
private String hisAcctPay;
private String hisFundPay;
private String diffMedfee;
private String diffAcctPay;
private String diffFundPay;
/** 0-平1-不平 */
private String stmtRslt;
private String stmtRsltDscr;
private String createTime;
private String modifyTime;
}

View File

@@ -0,0 +1,22 @@
package com.saye.hospitalgd.mapper.FinancialReconciliation;
import java.util.HashMap;
public interface MobileYbReconciliationMapper {
HashMap<Object, Object> sumBankMobileYb(HashMap<Object, Object> map);
HashMap<Object, Object> sumHisMobileYb(HashMap<Object, Object> map);
void insertResult(HashMap<Object, Object> map);
void deleteResultByDate(HashMap<Object, Object> map);
HashMap<Object, Object> findResultByDate(HashMap<Object, Object> map);
}

View File

@@ -0,0 +1,24 @@
package com.saye.hospitalgd.scheduler.job;
import com.saye.hospitalgd.scheduler.jobMethod.MobileYbReconciliationMethod;
import java.util.HashMap;
/**
* Quartz 调度入口:微信移动医保对账
* 方法名executeMobileYbReconciliation
* 参数trade_dateyyyy-MM-dd为空则默认昨日
*/
public class MobileYbReconciliationJob {
public HashMap<Object, Object> executeMobileYbReconciliation(String trade_date) {
MobileYbReconciliationMethod method = new MobileYbReconciliationMethod();
return method.executeMobileYbReconciliation(trade_date);
}
}

View File

@@ -0,0 +1,47 @@
package com.saye.hospitalgd.scheduler.jobMethod;
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.service.FinancialReconciliation.MobileYbReconciliationService;
import com.saye.hospitalgd.service.impl.FinancialReconciliation.MobileYbReconciliationServiceImpl;
import lombok.extern.slf4j.Slf4j;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
/**
* 微信移动医保对账方法
* 被调度任务调用,传入 trade_dateyyyy-MM-dd为空则默认昨日
*/
@Slf4j
public class MobileYbReconciliationMethod {
public HashMap<Object, Object> executeMobileYbReconciliation(String trade_date) {
HashMap<Object, Object> resp = new HashMap<>();
String errCode = "0";
String errMsg = "";
try {
String targetDate = trade_date;
if (targetDate == null || "".equals(targetDate.trim())) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, -1);
targetDate = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, calendar.getTime());
}
LogUtil.info(this.getClass(), "开始执行微信移动医保对账,日期:" + targetDate);
MobileYbReconciliationService svc = GetBeanUtil.getBean(MobileYbReconciliationServiceImpl.class);
resp = svc.reconcile(targetDate);
LogUtil.info(this.getClass(), "微信移动医保对账结束,结果:" + resp);
} catch (Exception e) {
errCode = "999";
errMsg = e.getMessage();
log.error("微信移动医保对账失败:{}", errMsg, e);
}
resp.put("errCode", errCode);
resp.put("errMsg", errMsg);
return resp;
}
}

View File

@@ -0,0 +1,16 @@
package com.saye.hospitalgd.service.FinancialReconciliation;
import java.util.HashMap;
public interface MobileYbReconciliationService {
HashMap<Object, Object> reconcile(String tradeDate) throws Exception;
HashMap<Object, Object> findResult(String tradeDate);
}

View File

@@ -0,0 +1,95 @@
package com.saye.hospitalgd.service.impl.FinancialReconciliation;
import com.saye.hospitalgd.mapper.FinancialReconciliation.MobileYbReconciliationMapper;
import com.saye.hospitalgd.service.FinancialReconciliation.MobileYbReconciliationService;
import com.saye.hospitalgd.commons.uuid.UUIDGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.HashMap;
@Service
public class MobileYbReconciliationServiceImpl implements MobileYbReconciliationService {
@Autowired
private MobileYbReconciliationMapper mobileYbReconciliationMapper;
@Override
public HashMap<Object, Object> reconcile(String tradeDate) throws Exception {
HashMap<Object, Object> resp = new HashMap<>();
String errCode = "0";
String errMsg = "";
try {
HashMap<Object, Object> param = new HashMap<>();
param.put("trade_date", tradeDate);
HashMap<Object, Object> bank = mobileYbReconciliationMapper.sumBankMobileYb(param);
HashMap<Object, Object> his = mobileYbReconciliationMapper.sumHisMobileYb(param);
BigDecimal bankMedfee = getDecimal(bank.get("bank_medfee"));
BigDecimal bankAcct = getDecimal(bank.get("bank_acct_pay"));
BigDecimal bankFund = getDecimal(bank.get("bank_fund_pay"));
BigDecimal hisMedfee = getDecimal(his.get("his_medfee"));
BigDecimal hisAcct = getDecimal(his.get("his_acct_pay"));
BigDecimal hisFund = getDecimal(his.get("his_fund_pay"));
BigDecimal diffMedfee = bankMedfee.subtract(hisMedfee);
BigDecimal diffAcct = bankAcct.subtract(hisAcct);
BigDecimal diffFund = bankFund.subtract(hisFund);
String stmtRslt = (diffMedfee.compareTo(BigDecimal.ZERO) == 0
&& diffAcct.compareTo(BigDecimal.ZERO) == 0
&& diffFund.compareTo(BigDecimal.ZERO) == 0) ? "0" : "1";
// 覆盖写结果
mobileYbReconciliationMapper.deleteResultByDate(param);
HashMap<Object, Object> insert = new HashMap<>();
insert.put("id", UUIDGenerator.getUUID());
insert.put("trade_date", tradeDate);
insert.put("bank_medfee", bankMedfee);
insert.put("bank_acct_pay", bankAcct);
insert.put("bank_fund_pay", bankFund);
insert.put("his_medfee", hisMedfee);
insert.put("his_acct_pay", hisAcct);
insert.put("his_fund_pay", hisFund);
insert.put("diff_medfee", diffMedfee);
insert.put("diff_acct_pay", diffAcct);
insert.put("diff_fund_pay", diffFund);
insert.put("stmt_rslt", stmtRslt);
insert.put("stmt_rslt_dscr", stmtRslt.equals("0") ? "" : "不平");
mobileYbReconciliationMapper.insertResult(insert);
resp.putAll(insert);
} catch (Exception e) {
errCode = "999";
errMsg = e.getMessage();
}
resp.put("errCode", errCode);
resp.put("errMsg", errMsg);
return resp;
}
@Override
public HashMap<Object, Object> findResult(String tradeDate) {
HashMap<Object, Object> param = new HashMap<>();
param.put("trade_date", tradeDate);
return mobileYbReconciliationMapper.findResultByDate(param);
}
private BigDecimal getDecimal(Object obj) {
if (obj == null || "".equals(obj.toString().trim())) {
return BigDecimal.ZERO;
}
return new BigDecimal(obj.toString());
}
}

View File

@@ -41,7 +41,6 @@
from bankbill_history
where C_JYRQ = #{trade_date}
and (is_inpatient is null or is_inpatient = '0') <!-- 排除住院订单(终端号10091548和10091549) -->
and (bill_table_name is null or bill_table_name != '微信医保账单') <!-- 排除微信医保账单 -->
</select>
<insert id="saveOriginalData" parameterType="java.util.List">
insert into bankbills_original (

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.saye.hospitalgd.mapper.FinancialReconciliation.MobileYbReconciliationMapper">
<!-- 银行侧汇总:微信医保账单 -->
<select id="sumBankMobileYb" parameterType="HashMap" resultType="HashMap">
SELECT
CAST(IFNULL(SUM(CAST(MEDFEE_SUMAMT AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS bank_medfee,
CAST(IFNULL(SUM(CAST(ACCT_PAY AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS bank_acct_pay,
CAST(IFNULL(SUM(CAST(FUND_PAY_SUMAMT AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS bank_fund_pay
FROM bankbill_history
<where>
<if test="trade_date!=null and trade_date!=''">
AND C_JYRQ = #{trade_date}
</if>
AND (
bill_table_name = '微信医保账单'
OR bill_table_name = '微信移动医保账单'
OR bill_table_name LIKE '%医保%'
OR bill_table_name IS NULL
)
</where>
</select>
<!-- HIS 侧汇总HisOperCode='yb'(微信移动医保) -->
<select id="sumHisMobileYb" parameterType="HashMap" resultType="HashMap">
SELECT
CAST(IFNULL(SUM(CAST(MEDFEE_SUMAMT AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS his_medfee,
CAST(IFNULL(SUM(CAST(ACCT_PAY AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS his_acct_pay,
CAST(IFNULL(SUM(CAST(FUND_PAY_SUMAMT AS DECIMAL(19,2))),0) AS DECIMAL(19,2)) AS his_fund_pay
FROM hisbill_history
<where>
<if test="trade_date!=null and trade_date!=''">
AND trade_date = #{trade_date}
</if>
AND HisOperCode = 'yb'
</where>
</select>
<!-- 结果表mobile_yb_reconciliation_result -->
<insert id="insertResult" parameterType="HashMap">
INSERT INTO mobile_yb_reconciliation_result
(id, trade_date,
bank_medfee, bank_acct_pay, bank_fund_pay,
his_medfee, his_acct_pay, his_fund_pay,
diff_medfee, diff_acct_pay, diff_fund_pay,
stmt_rslt, stmt_rslt_dscr, create_time, modify_time)
VALUES
(#{id}, #{trade_date},
#{bank_medfee}, #{bank_acct_pay}, #{bank_fund_pay},
#{his_medfee}, #{his_acct_pay}, #{his_fund_pay},
#{diff_medfee}, #{diff_acct_pay}, #{diff_fund_pay},
#{stmt_rslt}, #{stmt_rslt_dscr}, now(), now())
</insert>
<delete id="deleteResultByDate" parameterType="HashMap">
DELETE FROM mobile_yb_reconciliation_result
WHERE trade_date = #{trade_date}
</delete>
<select id="findResultByDate" parameterType="HashMap" resultType="HashMap">
SELECT *
FROM mobile_yb_reconciliation_result
WHERE trade_date = #{trade_date}
LIMIT 1
</select>
</mapper>

View File

@@ -69,8 +69,9 @@
<if test="endTime != null and endTime != ''">
AND trade_date &lt;= #{endTime}
</if>
AND LOWER(HisOperCode) = 'wx'
AND LOWER(HisOperCode) in ('wx' , 'yb')
AND TradingStatus = '1'
AND PayType in ('2','1')
</where>
UNION ALL
SELECT '支付宝支付' AS PAY_NAME,
@@ -92,8 +93,9 @@
<if test="endTime != null and endTime != ''">
AND trade_date &lt;= #{endTime}
</if>
AND LOWER(HisOperCode) = 'wx'
AND LOWER(HisOperCode) in ('wx' , 'yb')
AND TradingStatus = '2'
AND PayType in ('2','1')
</where>
UNION ALL
SELECT '合计' AS PAY_NAME,
@@ -107,8 +109,9 @@
<if test="endTime != null and endTime != ''">
AND trade_date &lt;= #{endTime}
</if>
AND LOWER(HisOperCode) = 'wx'
AND LOWER(HisOperCode) in ('wx' , 'yb')
AND TradingStatus IN ('1','2')
AND PayType in ('2','1')
</where>
</select>

View File

@@ -82,7 +82,6 @@
and b.C_JYRQ &lt;= #{endTime}
and a.PayMethod != '2' -- 排除不参与对账的记录
and (b.is_inpatient is null or b.is_inpatient = '0') -- 排除住院订单
and (b.bill_table_name is null or b.bill_table_name != '微信医保账单') -- 排除微信医保账单
<if test="prepayment_code != null and prepayment_code != ''">
and a.PayType != #{prepayment_code}
</if>
@@ -140,7 +139,7 @@
</if>
) a
inner join
(select * from bankbill_history where C_JYRQ = #{trade_date} and (is_inpatient is null or is_inpatient = '0') and (bill_table_name is null or bill_table_name != '微信医保账单')) b -- 排除住院订单与微信医保账单
(select * from bankbill_history where C_JYRQ = #{trade_date} and (is_inpatient is null or is_inpatient = '0')) b -- 排除住院订单
on a.PlatformTransId = b.C_SHDDH and a.TradingStatus = b.C_JYLX and ROUND(CAST(a.Amount AS DECIMAL(18,2)), 2) = ROUND(CAST(b.C_JYJE AS DECIMAL(18,2)), 2)
</insert>
@@ -186,7 +185,7 @@
</if>
) a
left join
(select * from bankbill_history where C_JYRQ = #{trade_date} and (is_inpatient is null or is_inpatient = '0') and (bill_table_name is null or bill_table_name != '微信医保账单')) b -- 排除住院订单与微信医保账单
(select * from bankbill_history where C_JYRQ = #{trade_date} and (is_inpatient is null or is_inpatient = '0')) b -- 排除住院订单
on a.PlatformTransId = b.C_SHDDH and a.TradingStatus = b.C_JYLX and ROUND(CAST(a.Amount AS DECIMAL(18,2)), 2) = ROUND(CAST(b.C_JYJE AS DECIMAL(18,2)), 2)
where b.C_SHDDH is null
</insert>
@@ -237,13 +236,11 @@
select * from bankbill_history
where C_JYRQ = #{trade_date}
and (is_inpatient is null or is_inpatient = '0')
and (bill_table_name is null or bill_table_name != '微信医保账单')
and C_SHDDH in (
select C_SHDDH
from bankbill_history
where C_JYRQ = #{trade_date}
and (is_inpatient is null or is_inpatient = '0')
and (bill_table_name is null or bill_table_name != '微信医保账单')
group by C_SHDDH
having ROUND(SUM(CAST(C_JYJE AS DECIMAL(18,2))), 2) != 0
)

View File

@@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>微信移动医保对账</title>
<link rel="stylesheet" th:href="@{/layui/css/layui.css}">
<link rel="stylesheet" th:href="@{/css/common.css}">
<script th:src="@{/layui/jquery-3.4.1.min.js}"></script>
<script th:src="@{/layui/layui.js}"></script>
<style>
.panel {padding:16px;background:#fff;margin-top:10px;border:1px solid #e6e6e6;box-shadow:0 1px 3px rgba(0,0,0,0.08);border-radius:6px;}
.panel-title {font-size:16px;font-weight:600;margin-bottom:8px;}
.result-ok {color:#16b777;font-weight:bold;}
.result-bad {color:#ff5722;font-weight:bold;}
.data-row {margin-top:12px;display:flex;flex-wrap:wrap;gap:16px;}
.data-box {padding:12px;border:1px solid #f0f0f0;border-radius:6px;min-width:260px;background:#fafafa;}
.data-box span {display:block;line-height:1.8;}
</style>
</head>
<body class="layui-layout-body">
<div style="left:8px;right:8px;bottom:8px;top:8px;position:absolute;overflow-y:auto;">
<div class="toolbar" id="titleDiv">
<div style="display:inline-block;">
<form class="layui-form">
<div class="layui-inline">
<label class="layui-form-label">对账日期</label>
<div class="layui-input-inline">
<input type="text" class="layui-input formWidthTwo" id="tradeDate" placeholder="yyyy-MM-dd" th:value="${endTime}">
</div>
</div>
<div class="layui-inline">
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="search()"><i class="layui-icon layui-icon-search"></i>查询</button>
</div>
</form>
</div>
</div>
<div class="panel">
<div class="panel-title">微信移动医保对账结果</div>
<div class="data-row">
<div class="data-box">
<span>银行-医疗总费用:<span id="bank_medfee">0.00</span></span>
<span>HIS-医疗总费用:<span id="his_medfee">0.00</span></span>
<span>差额:<span id="diff_medfee">0.00</span></span>
</div>
<div class="data-box">
<span>银行-账户支付:<span id="bank_acct_pay">0.00</span></span>
<span>HIS-账户支付:<span id="his_acct_pay">0.00</span></span>
<span>差额:<span id="diff_acct_pay">0.00</span></span>
</div>
<div class="data-box">
<span>银行-统筹支付:<span id="bank_fund_pay">0.00</span></span>
<span>HIS-统筹支付:<span id="his_fund_pay">0.00</span></span>
<span>差额:<span id="diff_fund_pay">0.00</span></span>
</div>
<div class="data-box">
<span>结果:<span id="stmt_rslt" class="result-ok"></span></span>
<span id="stmt_rslt_dscr"></span>
</div>
</div>
</div>
</div>
<script th:inline="javascript">
let layer, laydate;
layui.use(['laydate','layer'], function(){
laydate = layui.laydate; layer = layui.layer;
laydate.render({elem:'#tradeDate',type:'date'});
});
function fmt(v){return (v===null||v===undefined||v==='')?'0.00':parseFloat(v).toFixed(2);}
function search(){
let tradeDate = $("#tradeDate").val();
if(!tradeDate){layer.msg("请选择对账日期");return;}
let param = {trade_date: tradeDate};
$.ajax({
url:'/mobileYbReconciliation/findData',
method:'post',
contentType:'application/json;charset=UTF-8',
data:JSON.stringify(param),
success:function(res){
if(res.errCode==='0'){
$("#bank_medfee").text(fmt(res.bank_medfee));
$("#bank_acct_pay").text(fmt(res.bank_acct_pay));
$("#bank_fund_pay").text(fmt(res.bank_fund_pay));
$("#his_medfee").text(fmt(res.his_medfee));
$("#his_acct_pay").text(fmt(res.his_acct_pay));
$("#his_fund_pay").text(fmt(res.his_fund_pay));
$("#diff_medfee").text(fmt(res.diff_medfee));
$("#diff_acct_pay").text(fmt(res.diff_acct_pay));
$("#diff_fund_pay").text(fmt(res.diff_fund_pay));
const ok = res.stmt_rslt === '0';
$("#stmt_rslt").text(ok?'平':'不平').attr('class', ok?'result-ok':'result-bad');
$("#stmt_rslt_dscr").text(res.stmt_rslt_dscr||'');
}else{
layer.alert(res.errMsg||'查询失败');
}
},
error:function(){
layer.alert('请求失败');
}
});
}
</script>
</body>
</html>