init:微信医保数据入库

This commit is contained in:
Yuan
2025-11-17 17:27:12 +08:00
parent 62676cf59b
commit 3dbb92d616
2 changed files with 331 additions and 0 deletions

View File

@@ -1,8 +1,16 @@
package com.saye.hgddmz.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.saye.hgddmz.commons.date.DateDUtil;
import com.saye.hgddmz.commons.string.StringDUtil;
import com.saye.hgddmz.entity.BankbillHistory;
@@ -19,6 +27,7 @@ import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.*;
@@ -28,6 +37,8 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
@@ -46,6 +57,8 @@ public class GetDateController {
private static String appid = "wx45acd2b4907cb8f4";
private static String secret = "895b90585c4698485c07e113711eac85";
private static String key = "Nxwj20250903Jojubanking12091209x";
private static String key_yb = "086831b6021364d2e96e523771087a02";
// 微信消息推送相关常量
private static String WX_APP_ID = "wx45acd2b4907cb8f4";
@@ -1550,4 +1563,306 @@ public class GetDateController {
// Spring会在响应完成后自动处理资源清理
}
}
@PostMapping("/getBankDataByMedicalInsuranceAPI")
@ResponseBody
public HashMap<Object, Object> getBankDataByMedicalInsuranceAPI(@RequestBody HashMap<Object, Object> map) {
List<BankbillHistory> list = new ArrayList<>();
log.info("开始获取微信医保账单");
HashMap<Object, Object> responseMap = new HashMap<>();
String errCode = "0";
String errMsg = "";
try {
String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH"));
String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID"));
String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date"));
log.info("开始获取微信账单,参数: mch_id={}, trade_date={}", mch_id, trade_date);
HashMap<String, Object> reqMap = new HashMap<>();
reqMap.put("grant_type", grant_type);
reqMap.put("appid", appid);
reqMap.put("secret", secret);
String randomStr = RandomUtil.randomString(32);
// String signString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+ key;
// String sign = SecureUtil.md5(signString).toUpperCase();
// String reqXml = "<xml>\n" +
// " <appid>" + appid + "</appid>\n" +
// " <bill_date>" + trade_date + "</bill_date>\n" +
// " <bill_type>ALL</bill_type>\n" +
// " <mch_id>" + mch_id + "</mch_id>\n" +
// " <nonce_str>" + randomStr + "</nonce_str>\n" +
// " <sign>" + sign + "</sign>\n" +
// "</xml>";
// // 获取access_token
// log.info("开始调用微信账单接口,参数: mch_id={}, trade_date={}", mch_id, trade_date);
// String body1 = HttpUtil.createPost("https://api.mch.weixin.qq.com/pay/downloadbill")
// .header("Content-Type", "text/xml")
// .timeout(30000) // 设置30秒超时
// .body(reqXml)
// .execute()
// .body();
// log.info("微信账单接口返回数据长度: {}", body1 != null ? body1.length() : 0);
// log.info("微信账单接口返回数据: {}", body1);
//
// // 检查微信接口返回状态
//
// if (body1.contains("<return_msg><![CDATA[Bill Creating]]></return_msg>")) {
// log.info("账单正在生成中,请稍后重试");
// errCode = "999";
// errMsg = "微信账单正在生成中,请稍后重试";
// responseMap.put("errCode", errCode);
// responseMap.put("errMsg", errMsg);
// return responseMap;
// }
//
// // 检查是否无账单数据
// if (body1.contains("<return_msg><![CDATA[No Bill Exist]]></return_msg>")) {
// log.info("该日期无账单数据");
// errCode = "999";
// errMsg = "该日期无账单数据";
// responseMap.put("errCode", errCode);
// responseMap.put("errMsg", errMsg);
// return responseMap;
// }
//
// String[] split = body1.split("\n");
// for (int i = 1; i < split.length - 2; i++) {
// String[] split1 = split[i].split(",");
// if (Arrays.toString(split1).equals("[<return_msg><![CDATA[No Bill Exist]]></return_msg>]")) {
// break;
// }
// // 检查是否是账单正在生成状态
// if (Arrays.toString(split1).contains("Bill Creating")) {
// log.info("账单正在生成中,跳过处理");
// break;
// }
//
// BankbillHistory bankbillHistory = new BankbillHistory();
// int flag = 0;
//
// // 解析CSV数据到BankbillHistory实体
// for (int j = 0; j < split1.length; j++) {
// String value = split1[j].replaceAll("`", "").trim();
//
// switch (j) {
// case 0: // 交易时间
// if (value.contains(" ")) {
// String[] timeSplit = value.split(" ");
// bankbillHistory.setCQsrq(timeSplit[0]); // 清算日期
// bankbillHistory.setCJyrq(timeSplit[0]); // 交易日期
// bankbillHistory.setCJysj(timeSplit[1]); // 交易时间
// }
// break;
// case 4: // 设备号
// bankbillHistory.setCZdh(value);
// break;
// case 5: // 微信订单号
// bankbillHistory.setCYsddh(value);
// break;
// case 6: // 商户订单号
// bankbillHistory.setCShddh(value);
// break;
// case 7: // 用户标识
// bankbillHistory.setCCard(value);
// break;
// case 8: // 交易类型
// bankbillHistory.setCJylx(value);
// break;
// case 9: // 交易状态
// if ("REFUND".equals(value)) {
// flag = -1;
// }
// break;
// case 10: // 付款银行
// bankbillHistory.setCFkh(value);
// break;
// case 12: // 应结订单金额
// bankbillHistory.setCQsje(value);
// break;
// case 24: // 订单金额
// // 只有在非退款状态时才设置订单金额
// if (flag >= 0) {
// bankbillHistory.setCJyje(value);
// }
// break;
// case 20: // 商品名称
// bankbillHistory.setCBzzd(value);
// break;
// case 22: // 手续费
// bankbillHistory.setCSxf(value);
// break;
// case 14: // 微信退款单号
// bankbillHistory.setCThddh(value);
// break;
// case 15: // 商户退款单号
// bankbillHistory.setCYjylsh(value);
// break;
// case 25: // 申请退款金额
// if (!"0.00".equals(value) && !value.isEmpty()) {
// bankbillHistory.setCJyje("-" + value);
// }
// break;
// }
// }
//
// // 设置支付方式
// bankbillHistory.setCZffs("微信支付");
//
// // 设置表名
// bankbillHistory.setBillTableName("微信支付账单");
//
// list.add(bankbillHistory);
// }
// 获取access_token
String body = HttpUtil.createPost("https://api.weixin.qq.com/cgi-bin/stable_token").body(JSONUtil.toJsonStr(reqMap)).execute().body();
String access_token = JSONUtil.parseObj(body).getStr("access_token");
// 获取医保账单下载地址
// https://api.weixin.qq.com/payinsurance/billdownload?access_token=ACCESS_TOKEN
String signYBString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+key_yb;
log.info("微信账单签名:" + signYBString);
String signYB = SecureUtil.md5(signYBString).toUpperCase();
log.info("微信账单签名结果:" + signYB);
String reqYbXml = "<xml>\n" +
" <appid>" + appid + "</appid>\n" +
" <bill_date>" + trade_date + "</bill_date>\n" +
" <bill_type>ALL</bill_type>\n" +
" <mch_id>" + mch_id + "</mch_id>\n" +
" <nonce_str>" + randomStr + "</nonce_str>\n" +
" <sign>" + signYB + "</sign>\n" +
"</xml>";
log.info("微信账单请求参数:" + reqYbXml);
String resBody = HttpUtil.createPost("https://api.weixin.qq.com/payinsurance/billdownload?access_token=" + access_token).header("Content-Type", "text/xml").body(reqYbXml).execute().body();
log.info("微信账单下载返回结果:" + resBody);
Document document = XmlUtil.parseXml(resBody);
Element elementG = XmlUtil.getRootElement(document);
Element returnCode = XmlUtil.getElement(elementG, "return_code");
if (returnCode.getTextContent().equals("SUCCESS")) {// 响应成功
// 下载文件
Element downloadUrl = XmlUtil.getElement(elementG, "download_url");
String dwUrl = downloadUrl.getTextContent();
log.info("开始下载文件");
HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".csv");
HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".txt");
// HttpUtil.downloadFileFromUrl(dwUrl, localPath);
log.info("下载文件成功");
CsvReader reader = CsvUtil.getReader();
try {
CsvData read = reader.read(FileUtil.file(localPath + File.separator + trade_date + ".csv"));
List<CsvRow> rows = read.getRows();
if (rows.size() > 1) {
for (int i = 1; i < rows.size(); i++) {
CsvRow row = rows.get(i);
BankbillHistory bankbillHistory = new BankbillHistory();
String s = row.get(0).replaceAll("`", "");
String[] s1 = s.split(" ");
log.info("s1 is :" + Arrays.toString(s1));
bankbillHistory.setCJyrq(s1[0]);
bankbillHistory.setCQsrq(s1[0]);
bankbillHistory.setCJysj(s1[1]);
bankbillHistory.setCZdh(row.get(1).replaceAll("`", ""));
bankbillHistory.setCCkh(row.get(2).replaceAll("`", ""));
bankbillHistory.setCLsh(row.get(5).replaceAll("`", ""));
bankbillHistory.setCShddh(row.get(6).replaceAll("`", ""));
bankbillHistory.setCCard(row.get(7).replaceAll("`", ""));
bankbillHistory.setCYsddh(row.get(25).replaceAll("`", ""));
// 处理交易金额不跳过0.00的记录
String amount = row.get(46).replaceAll("`", "");
if (row.get(45).replaceAll("`", "").equals("REFUND")) {
// 退款记录,金额为负数
if (!"0.00".equals(amount) && !amount.isEmpty()) {
bankbillHistory.setCJyje("-" + amount);
} else {
bankbillHistory.setCJyje("0.00");
}
} else {
// 普通交易记录
bankbillHistory.setCJyje(amount);
}
// 医保账户金额医保个账金额第53列索引52
if (row.size() > 52) {
String acctPay = row.get(52).replaceAll("`", "");
bankbillHistory.setAcctPay(acctPay);
}
// 医保统筹金额第54列索引53
if (row.size() > 53) {
String fundPaySumamt = row.get(53).replaceAll("`", "");
bankbillHistory.setFundPaySumamt(fundPaySumamt);
}
// 医疗总费用订单总金额第49列索引48
if (row.size() > 48) {
String medfeeSumamt = row.get(48).replaceAll("`", "");
bankbillHistory.setMedfeeSumamt(medfeeSumamt);
}
bankbillHistory.setBillTableName("微信医保账单");
list.add(bankbillHistory);
// 打印第一条记录的完整实体类信息
if (i == 1) {
log.info("========== 微信账单解析实体类示例 ==========");
log.info("实体类完整信息JSON格式:");
log.info(JSONUtil.toJsonStr(bankbillHistory));
log.info("");
log.info("实体类字段详情:");
log.info(" 交易日期(cJyrq): {}", bankbillHistory.getCJyrq());
log.info(" 清算日期(cQsrq): {}", bankbillHistory.getCQsrq());
log.info(" 交易时间(cJysj): {}", bankbillHistory.getCJysj());
log.info(" 终端号(cZdh): {}", bankbillHistory.getCZdh());
log.info(" 参考号(cCkh): {}", bankbillHistory.getCCkh());
log.info(" 流水号(cLsh): {}", bankbillHistory.getCLsh());
log.info(" 商户订单号(cShddh): {}", bankbillHistory.getCShddh());
log.info(" 用户标识(cCard): {}", bankbillHistory.getCCard());
log.info(" 微信订单号(cYsddh): {}", bankbillHistory.getCYsddh());
log.info(" 交易金额(cJyje): {}", bankbillHistory.getCJyje());
log.info(" 医疗总费用(medfeeSumamt): {}", bankbillHistory.getMedfeeSumamt());
log.info(" 医保账户金额(acctPay): {}", bankbillHistory.getAcctPay());
log.info(" 医保统筹金额(fundPaySumamt): {}", bankbillHistory.getFundPaySumamt());
log.info(" 表名(billTableName): {}", bankbillHistory.getBillTableName());
log.info("==========================================");
}
}
}
responseMap.put("list", list);
} catch (IORuntimeException e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
if (list.size() > 0) {
log.info("集合大小为"+ list.size());
responseMap.put("list", list);
} else {
errCode = "999";
errMsg = "账单数据为空,或未获取到账单!";
}
responseMap.put("errCode", errCode);
responseMap.put("errMsg", errMsg);
return responseMap;
} catch (Exception e) {
log.error("微信账单获取异常", e);
errCode = "999";
errMsg = "微信账单获取异常: " + e.getMessage();
responseMap.put("errCode", errCode);
responseMap.put("errMsg", errMsg);
return responseMap;
}
}
}

View File

@@ -1,5 +1,6 @@
package com.saye.hgddmz.entity;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Getter;
import lombok.Setter;
@@ -139,5 +140,20 @@ public class BankbillHistory implements Serializable {
* 对账表名
*/
private String billTableName;
/**
* 医保账户金额(医保个账金额)
*/
@JSONField(name = "acct_pay")
private String acctPay;
/**
* 医保统筹金额
*/
@JSONField(name = "fund_pay_sumamt")
private String fundPaySumamt;
/**
* 医疗总费用(订单总金额)
*/
@JSONField(name = "medfee_sumamt")
private String medfeeSumamt;
}