最新版宁夏武警公众号项目后端

This commit is contained in:
sangchengzhi
2026-01-07 10:36:02 +08:00
parent 364a48d4c7
commit f8bb9dc094
1512 changed files with 531911 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
package com.guahao.api.walkinto.mapper;
import com.guahao.api.walkinto.model.Bill;
import com.guahao.api.walkinto.model.param.BillParam;
import com.guahao.common.base.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface BillMapper extends BaseMapper<Bill> {
List<Map<String,Object>> getAll(BillParam param);
}

View File

@@ -0,0 +1,679 @@
package com.guahao.api.walkinto.controller;
// import CCBSign.RSASig;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.internal.org.apache.commons.lang3.StringUtils;
import com.guahao.WebLog;
import com.guahao.api.counts.model.InterfaceCount;
import com.guahao.api.counts.service.InterfaceCountService;
import com.guahao.api.walkinto.model.JhClientInfo;
import com.guahao.api.walkinto.model.JhNotifyInfo;
// import com.guahao.api.walkinto.service.IJhPayService;
import com.guahao.api.walkinto.model.PayQueryDTO;
import com.guahao.api.walkinto.service.WxPayService;
import com.guahao.common.config.WxPayConfig;
import com.guahao.common.response.ResponseResult;
import com.guahao.common.util.SoapUtil;
import com.guahao.common.util.XmlUtil;
import com.guahao.h5.hsjc.mapper.HsjcMapper;
import com.guahao.h5.hsjc.service.HsjcService;
import com.guahao.h5.hsjc.service.TXSendMsg;
import com.guahao.h5.hsjc.vo.HsjcVo;
import com.guahao.h5.message.service.MessageCenterService;
import com.guahao.h5.reserve.mapper.Reserve8Mapper;
import com.guahao.h5.reserve.vo.HisRefundVo;
import com.guahao.h5.reserve.vo.Reserve8Vo;
import com.guahao.h5.user.mapper.UserCardMapper;
import com.guahao.h5.user.mapper.UserOrderMapper;
import com.guahao.h5.user.model.UserCardVo;
import com.guahao.h5.user.model.UserOrder;
import com.guahao.h5.user.model.UserVo;
import com.guahao.h5.user.service.UserOrderService;
import com.guahao.h5.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import tk.mybatis.mapper.entity.Example;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @ClassName: ApiPayController
* @Description:
* @Author T.W
* @Date 2023/3/31
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("/pay")
public class ApiPayController {
// 获取application.yml中的配置
@Value("${jh.merchantId}")
private String merchantId;
@Value("${jh.posId}")
private String posId;
@Value("${jh.branchId}")
private String branchId;
@Value("${jh.subAppId}")
private String subAppId;
@Value("${jh.tradeType}")
private String tradeType;
@Value("${jh.pub}")
private String pub;
public static final String WX_APP_ID = "wx45acd2b4907cb8f4";
// joju微信AppSecret
// public static final String WX_SECRET="4c329fa399103dd27edd84617c620e8e";
public static final String WX_SECRET = "895b90585c4698485c07e113711eac85";
private static final Logger logger = LoggerFactory.getLogger(Object.class);
// @Resource
// IJhPayService iJhPayService;
@Autowired
TXSendMsg txSendMsg;
@Autowired
UserService userService;
@Autowired
MessageCenterService messageCenterService;
@Autowired
HsjcMapper hsjcMapper;
@Autowired
HsjcService hsjcService;
@Autowired
UserCardMapper userCardMapper;
@Autowired
UserOrderMapper userOrderMapper;
@Autowired
UserOrderService userOrderService;
@Autowired
WxPayConfig wxPayConfig;
@Autowired
WxPayService wxPayService;
@Autowired
Reserve8Mapper reserve8Mapper;
@Autowired
InterfaceCountService interfaceCountService;
/**
* 微信支付通知回调接口
*
* @return
*/
@PostMapping("/wxpay/notify")
@WebLog(description = "wxPayNotify")
public String wxPayNotify(@RequestBody String xmlStr, HttpServletResponse response, HttpServletRequest request) {
try {
String result = wxPayService.handleWxPayNotify(xmlStr);
return result;
} catch (Exception e) {
logger.error("微信支付回调处理异常", e);
// 返回失败,微信会重试
return wxPayService.buildFailResponse("处理异常");
}
}
/**
* 微信退款回调通知接口
*
* @return
*/
@PostMapping("/wxRefund/notify")
@WebLog(description = "wxRefundNotify")
public String wxRefundNotify(@RequestBody String xmlStr, HttpServletResponse response, HttpServletRequest request) {
try {
String result = wxPayService.handleWxRefundNotify(xmlStr);
return result;
} catch (Exception e) {
logger.error("微信支付回调处理异常", e);
// 返回失败,微信会重试
return wxPayService.buildFailResponse("处理异常");
}
}
/**
* 查询微信订单状态
* @param dto
* @return
*/
@PostMapping("/wxpay/query")
@WebLog(description = "WxPayQuery")
public Object wxPayQuery(PayQueryDTO dto) {
try {
if (StringUtils.isEmpty(dto.getOutTradeNo())) {
return ResponseResult.sysError("订单号不能为空");
}
log.info("查询微信支付订单状态参数[{}]", dto.getOutTradeNo());
// 调用 service 查询
Map<String, String> result = wxPayService.queryOrder(dto.getOutTradeNo());
return ResponseResult.success(result);
} catch (Exception e) {
log.error("查询微信支付订单状态失败", e);
return ResponseResult.sysError("查询失败:" + e.getMessage());
}
}
/**
* 微信退费
* @param
* @return
*/
@PostMapping("/wxpay/refundOrder")
@WebLog(description = "refundOrder")
public Object refundOrder(@RequestParam("powertranid") String powertranid,
@RequestParam("money") String money
) {
String paramTip = "";
try {
paramTip = String.format(" >>> requestObj:%s", JSONUtil.toJsonStr(powertranid));
Map map = wxPayService.refundOrder(powertranid,money);
return ResponseResult.success(map);
} catch (Exception e) {
e.printStackTrace();
log.error(">>>退费微信预支付订单结果失败>>>" + paramTip + " 原因" + e.getMessage());
return ResponseResult.sysError("退费微信预支付订单结果失败!原因:" + e.getMessage());
}
}
/**
* 手动关单接口
*/
@PostMapping("/wxpay/closeOrder")
@WebLog(description = "closeOrder")
public Map<String, Object> manualCloseOrder(PayQueryDTO dto) {
Map<String, Object> result = new HashMap<>();
String orderNo = dto.getOutTradeNo();
try {
boolean success = wxPayService.closeOrder(orderNo);
result.put("success", success);
result.put("message", success ? "关单成功" : "关单失败");
if (!success) {
result.put("code", "ORDER_CLOSE_FAILED");
}
} catch (Exception e) {
log.error("手动关单异常: {}, {}", orderNo, e.getMessage(), e);
result.put("success", false);
result.put("message", "关单异常: " + e.getMessage());
result.put("code", "ORDER_CLOSE_EXCEPTION");
}
return result;
}
/**
* 建行支付通知回调接口
*
* @return
*/
@RequestMapping("/jh/order")
@WebLog(description = "order")
public Object order(String openid, String price) {
log.info("建行下单参数:" + openid + ":" + price);
Map<String, Object> map = new HashMap<>();
JhClientInfo jhClientInfo = new JhClientInfo();
jhClientInfo.setOpenid(openid);
jhClientInfo.setPrice(price);
// map = iJhPayService.unifiedPlaceOrder(jhClientInfo);
return ResponseResult.success(map);
}
/**
* 建行支付通知回调接口
*
* @return
*/
@PostMapping("/jh/notify")
@WebLog(description = "notify")
public String pay(JhNotifyInfo jhNotifyInfo) {
log.info("建行回调通知参数[{}]", JSON.toJSONString(jhNotifyInfo));
// RSASig rsaSig = new RSASig();
// rsaSig.setPublicKey(pub);
String src = "POSID=" + jhNotifyInfo.getPOSID() + "&BRANCHID=" + jhNotifyInfo.getBRANCHID() + "&ORDERID=" + jhNotifyInfo.getORDERID() + "&PAYMENT=" + jhNotifyInfo.getPAYMENT() + "&CURCODE=" + jhNotifyInfo.getCURCODE() + "&REMARK1=" + jhNotifyInfo.getREMARK1() + "&REMARK2=" + jhNotifyInfo.getREMARK2() + "&ACC_TYPE=" + jhNotifyInfo.getACC_TYPE() + "&SUCCESS=" + jhNotifyInfo.getSUCCESS() + "&TYPE=" + jhNotifyInfo.getTYPE() + "&REFERER=" + jhNotifyInfo.getREFERER() + "&CLIENTIP=" + jhNotifyInfo.getCLIENTIP() + "&ACCDATE=" + jhNotifyInfo.getACCDATE();
// 校验签名
// boolean verifySigature = rsaSig.verifySigature(jhNotifyInfo.getSIGN(), src);
if (true) {
// 验签通过,业务逻辑自行处理
// 这里需要调用建行龙支付提供的查询订单接口以保证订单确实支付成功 待定
// 1、已经确定支付完成后首先要把订单信息推送给支付平台记录
// 2、支付平台记录后开始给对接his完成挂号、缴费、预存流程如果挂号失败调用支付平台完成退款再将退款订单推送给支付平台。
// 各个流程结束后,给公众号推送消息,提醒用户。
String orderid = jhNotifyInfo.getORDERID();
String type_s = orderid.substring(0, 2);
// Reserve8Vo reserve8Vo = new Reserve8Vo();
// reserve8Vo.setOrderno(orderid);
// List<Reserve8Vo> reserveList = reserve8Mapper.getReserveList(reserve8Vo);
// reserve8Vo = reserveList.get(0);
//
// =null;
// try {
// s =
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// log.info("打印支付平台获取的数据");
// log.info(s);
switch (type_s) {
case "TL":
log.info("挂号订单处理");
Reserve8Vo reserve8Vo = new Reserve8Vo();
reserve8Vo.setOrderno(orderid);
List<Reserve8Vo> reserveList = reserve8Mapper.getReserveList(reserve8Vo);
if (reserveList.size() >= 1) {
try {
reserve8Vo = reserveList.get(0);
if (reserve8Vo.getAppStatus() == 3) {// 重复订单,已经挂号完成的订单,不予处理,防止建行重复回调
return null;
}
// 先给支付平台发送消息,告知订单信息。
String callXML = XmlUtil.getCallXML(reserve8Vo, jhNotifyInfo.getORDERID());
String s = SoapUtil.zfSoapMethod(callXML);
log.info("打印支付平台获取的数据");
log.info(s);
// 做挂号确认操作
// 封装xml
String strConfirmXML = XmlUtil.confirmOpAppRegist(reserve8Vo);
log.debug("confirm req:" + strConfirmXML);
// 发送soap请求
String respConfirmXml = SoapUtil.soapMethod(strConfirmXML);
log.debug("confirm res:" + respConfirmXml);
// 解析报文
Map<String, Object> mapConfirm = XmlUtil.parse(respConfirmXml);
if (mapConfirm.get("returncode").toString().equals("1")) {// 如果his确认订单成功了,按照正常流程走。
if (mapConfirm.get("ReptNum") != null) {
reserve8Vo.setReptnum(mapConfirm.get("ReptNum").toString());
}
if (mapConfirm.get("SerialNo") != null) {
reserve8Vo.setSerialno(mapConfirm.get("SerialNo").toString());
}
if (mapConfirm.get("Location") != null) {
reserve8Vo.setLocation(mapConfirm.get("Location").toString());
}
if (mapConfirm.get("TiketNo") != null) {
reserve8Vo.setTicketno(mapConfirm.get("TiketNo").toString());
}
reserve8Vo.setPowertranid(reserve8Vo.getOrderno());
// 允许退号标志 N 不允许 Y 允许
reserve8Vo.setAppFlag("Y");
// 单据状态 1 已退费 0 正常 2 已消号 3 挂号成功
reserve8Vo.setAppStatus(3);
// 1 预约挂号 2 今日挂号 8医院不区分
reserve8Vo.setAppType(2);
reserve8Mapper.opConfirmAppoint(reserve8Vo);
// 推送消息给公众号
UserVo voUser = userService.queryUserInfoDetails(reserve8Vo.getUserId());
txSendMsg.SendNotifyGH("挂号成功", voUser.getOpenid(), reserve8Vo.getName(), reserve8Vo.getKsmc(), reserve8Vo.getYsmc(), reserve8Vo.getRegisterdate(), "Jaqf0Jl1SqcPrN3rnFx3Y1vxC8NXF8E--ZD7JzlVt1U");
// 挂号完成后,计入统计
log.info("统计收费挂号开始 userId is " + reserve8Vo.getUserId());
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(reserve8Vo.getUserId()));
interfaceCount.setInterfaceIdentification("TL");
interfaceCountService.updateInterfaceConut(interfaceCount);
} else {// 如果his确认订单失败了需要退款回去。将退款订单推送给支付平台。
// 调用支付平台的退款接口,完成退款
// String refundXML = XmlUtil.getRefundXML(reserve8Vo, jhNotifyInfo.getORDERID());
// String reR = SoapUtil.zfSoapMethod(refundXML);
// log.info("退款返回数据:" + reR);
// reserve8Mapper.opAppCancelAppoint(reserve8Vo);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
break;
case "YC":
log.info("住院预存数据处理!");
// 处理本地数据库的订单信息
try {
Example example = new Example(UserOrder.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("code", orderid);
List<UserOrder> list = userOrderMapper.selectByExample(example);
if (list != null && list.size() > 0) {
UserOrder uo = list.get(0);
if (uo.getType() == 0) {
uo.setType(1);
uo.setIcbcCode(orderid);
uo.setSuccesstime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
UserVo userVo = userService.queryUserInfoDetails(uo.getUser_id());
// UserVo userVo = userService.queryUserInfoDetails(userOrder.getUser_id());
String cYC = XmlUtil.getCallXML(uo, userVo.getPhone(), userVo.getName(), jhNotifyInfo.getORDERID());
String YC = SoapUtil.zfSoapMethod(cYC);
log.info("打印支付平台获取的数据");
log.info(YC);
// String strXML = yujiaoPay(uo);// 封装请求数据
String pay = userOrderService.yujiaoPay(uo);
log.debug("reqxml yujiao:" + pay);
String responseStr = SoapUtil.soapMethod(pay);// 发送请求
log.debug("resxml yujiao:" + responseStr);
Map<String, Object> map = XmlUtil.parse(responseStr); // 处理返回数据
if (map.get("returncode").toString().equals("1")) {// 正常缴费
uo.setHis_code(map.get("RcptNo").toString());
userOrderMapper.updateByPrimaryKey(uo);
txSendMsg.SendNotifyZY("预缴成功", userVo.getOpenid(), userVo.getName(), String.valueOf(uo.getMoney()), uo.getSuccesstime(), uo.getHosnum(), uo.getCode(), "OSFM2mQaDYtEp8cQ5iIFrKKY7lKT0mmfYmE7MugQ5AQ");
// SendNotifyJF(uo);
// 住院预存成功,计入统计
log.info("统计住院缴费开始 userId is " + uo.getUser_id());
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(uo.getUser_id()));
interfaceCount.setInterfaceIdentification("YC");
interfaceCountService.updateInterfaceConut(interfaceCount);
} else {// his请求失败,住院预缴信息写入失败,退费。
// log.info("his 提交信息失败!!");
// String refundXML = XmlUtil.getRefundXML(uo, userVo.getName(), jhNotifyInfo.getORDERID());
// String reR = SoapUtil.zfSoapMethod(refundXML);
// log.info("支付平台返回reR is :" + reR);
// uo.setType(1);
// uo.setIcbcCode(orderid);
// userOrderMapper.updateByPrimaryKey(uo);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// Calendar calendar = Calendar.getInstance();
// SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
// userOrder.setSuccesstime(formatter.format(calendar.getTime()));
// userOrder.setType(1);
//// int i = userOrderMapper.updateByPrimaryKey(userOrder);
// //给支付平台发送订单信息
// UserVo userVo = userService.queryUserInfoDetails(userOrder.getUser_id());
//
// String cYC = XmlUtil.getCallXML(userOrder, userVo.getPhone(), userVo.getName(), jhNotifyInfo.getORDERID());
// String YC = SoapUtil.zfSoapMethod(cYC);
// log.info("打印支付平台获取的数据");
// log.info(YC);
// //给his发消息通知支付完成
// String pay = userOrderService.yujiaoPay(userOrder);
// String responseStr = SoapUtil.soapMethod(pay);// 发送请求
// log.debug("resxml yujiao:" + responseStr);
// Map<String, Object> ycMap = XmlUtil.parse(responseStr); // 处理返回数据
// if (ycMap.get("returncode").toString().equals("1")) {
// userOrder.setHis_code(ycMap.get("RcptNo").toString());
//
// userOrderMapper.updateByPrimaryKey(userOrder);
//
// txSendMsg.SendNotifyZY("挂号成功", userVo.getOpenid(), reserve8Vo.getName(), reserve8Vo.getKsmc(), reserve8Vo.getYsmc(), reserve8Vo.getRegisterdate(), "Jaqf0Jl1SqcPrN3rnFx3Y1vxC8NXF8E--ZD7JzlVt1U");
//// SendNotifyJF(uo);
// }
break;
case "MZ":
log.info("门诊数据处理!");
try {
HsjcVo vo = new HsjcVo();
vo.setOrderno(orderid);
List<HsjcVo> list = hsjcMapper.getMzjfListByFlow(vo);
BigDecimal bdBillAmount = BigDecimal.valueOf(0);
BigDecimal bdBillAmountMid = BigDecimal.valueOf(0);
DecimalFormat formatAmt = new DecimalFormat("###.00");
String billMsg = "";
String updateDate = "";
log.debug("unpay order: " + orderid + " count:" + list.size());
for (int j = 0; j < list.size(); j++) {
if (j == (list.size() - 1)) {
billMsg += list.get(j).getFlowno();
if (list.get(j).getUpdatedate() == null || "".equals(list.get(j).getUpdatedate())) {
updateDate += list.get(j).getBilltime();
} else {
updateDate += list.get(j).getUpdatedate();
}
} else {
billMsg += list.get(j).getFlowno() + ",";
if (list.get(j).getUpdatedate() == null || "".equals(list.get(j).getUpdatedate())) {
updateDate += list.get(j).getBilltime() + ",";
} else {
updateDate += list.get(j).getUpdatedate() + ",";
}
}
bdBillAmountMid = new BigDecimal(list.get(j).getBillmoney());
bdBillAmount = bdBillAmount.add(bdBillAmountMid);
}
String billMoney = bdBillAmount.toPlainString();
// 单据集合用,分隔
vo.setBillsmsg(billMsg);
vo.setUserId(list.get(0).getUserId());
vo.setPatientid(list.get(0).getPatientid());
vo.setUpdatedate(updateDate);
vo.setPaynature("1");
vo.setPaytype("微信");
vo.setPowertranid(orderid);
vo.setPowertrancard("");
vo.setTerminalid("0001");
vo.setReferno("");
// 金额是总金额
vo.setZfamount(billMoney);
// vo.setYbzhamount();
// vo.setYbtcamount();
vo.setYboutmsg("医保结算信息");
vo.setHisopernum("WX");
// 给支付平台发送消息,告知支付信息
UserVo userInfo = userService.queryUserInfoDetails(vo.getUserId());
String callXML = XmlUtil.getCallXML(vo, jhNotifyInfo.getORDERID(), userInfo.getName(), userInfo.getPhone());
String s = SoapUtil.zfSoapMethod(callXML);
log.info("打印支付平台获取的数据");
log.info(s);
String respXml = hsjcService.MOP_OutpBillstoPayConfirm(vo);
// 解析报文
Map<String, Object> map = XmlUtil.parse(respXml);
if (map.get("returncode").toString().equals("1")) {
// 允许退号标志 N 不允许 Y 允许·
vo.setAppFlag("Y");
// 单据状态 1 已退费 0 正常 2 已消号 3 挂号成功 4 已缴费
vo.setAppStatus(4);
vo.setIcbcorderid(orderid);
Calendar c = Calendar.getInstance();
SimpleDateFormat f = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String time = f.format(c.getTime());
vo.setIcbcpaytime(time);
hsjcMapper.opHsjcConfirmAppoint(vo);
UserVo voUser = userService.queryUserInfoDetails(vo.getUserId());
log.debug("get hsjc userid:" + voUser.getName());
String cardNo = vo.getPatientid();
List<UserCardVo> UCList = userCardMapper.queryUserCardListByCardno(cardNo);
log.debug("real name:" + UCList.get(0).getName());
// 推送消息给公众号
// txSendMsg.SendNotifyMZ("缴费成功", voUser.getOpenid(), UCList.get(0).getName(), UCList.get(0).getCardNo(), time, billMoney, vo.getOrderno(), "nT84Plx_x5N-thR7Z37XfLPfVgsCFMsAG5NWu_pIqoY");
// 门诊缴费成功,计入统计
log.info("统计门诊缴费开始 userId is " + vo.getUserId());
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(vo.getUserId()));
interfaceCount.setInterfaceIdentification("MZ");
interfaceCountService.updateInterfaceConut(interfaceCount);
} else {// 写入his订单失败的话开始退款
// 需要判断本地数据是否缴费成功避免工行回调多次,导致误退费。
// String refundXML = XmlUtil.getRefundXML(vo, userInfo.getName(), jhNotifyInfo.getORDERID());
// String reR = SoapUtil.zfSoapMethod(refundXML);
// vo.setAppStatus(1);
// hsjcMapper.opHsjcCancelAppoint(vo);
// log.info("退款返回数据:" + reR);
// log.debug("errormsg:" + map.get("errormsg").toString());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
}
// 添加消息
// MessageCenterVo centerVo = new MessageCenterVo(vo.getUserId(), 1, "预约已成功", "您已预约成功请在当日提前30分钟到医院确认就诊。", "1");
// messageCenterService.insertMessageCenter(centerVo);
log.info("验签通过");
return "SUCCESS";
} else {
// 验签失败
log.info("验签失败");
return "FAIL";
}
}
@RequestMapping("/jh/sendMessage")
@WebLog(description = "sendMessage")
public Object sendMessage() {
// int i = txSendMsg.SendNotifyMZ("缴费成功", "oLDdW6N1UbN_69BUbCmL2CDZrtK8", "长川", "10130223", "2023-05-08 13:45:21", "13", "MZ20230508112050102334", "nT84Plx_x5N-thR7Z37XfLPfVgsCFMsAG5NWu_pIqoY");
int i = 0;
return ResponseResult.success(i);
}
//
// public int SendNotify(String Title, String userOpenid, String username, String keshiName, String ysmc, String jzTime, String templateId) {
// log.debug("in param:Title|" + Title + " userOpenid|" + userOpenid + " username|" + username + " keshiName|" +
// keshiName + " ysmc|" + ysmc + " jzTime|" + jzTime + " templateId|" + templateId);
//
// //第一步 获取token
// String accessUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&" +
// "&appid=" + WX_APP_ID + "&secret=" + WX_SECRET;
// String accessTokenStr = HttpClientUtil.doGet(accessUrl, null);
// log.debug("step 1 get accesstoken:" + accessTokenStr);
//
// JSONObject jsonObject = JSON.parseObject(accessTokenStr);
// String accessToken = jsonObject.get("access_token").toString();
//
// //第二步 获取消息模板ID
//// String templateUrl = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=" + accessToken;
//// JSONObject tpPara = new JSONObject();
//// tpPara.put("template_id_short", "OPENTM411040952");
//// String templateRes = HttpClientUtil.doPost(templateUrl, tpPara);
//// JSONObject jsonTemplate = JSON.parseObject(templateRes);
//
//// String templateId = jsonTemplate.get("template_id").toString();
// //第三步 发送模板消息
// String sendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
// JSONObject sendPara = new JSONObject();
// JSONObject dataPara = new JSONObject();
//
// JSONObject first = new JSONObject();
// first.put("value", Title);
// first.put("color", "#173177");
//
// JSONObject key1 = new JSONObject();
// key1.put("value", "海南武警总队医院");
// key1.put("color", "#173177");
//
// JSONObject key2 = new JSONObject();
// key2.put("value", keshiName);
// key2.put("color", "#173177");
// JSONObject key3 = new JSONObject();
// key3.put("value", ysmc);
// key3.put("color", "#173177");
//
// JSONObject key4 = new JSONObject();
// key4.put("value", username);
// key4.put("color", "#173177");
//
// JSONObject key5 = new JSONObject();
// key5.put("value", jzTime);
// key5.put("color", "#173177");
// JSONObject remark = new JSONObject();
// remark.put("value", "");
// remark.put("color", "#173177");
//
// dataPara.put("first", first);
// dataPara.put("keyword1", key1);
// dataPara.put("keyword2", key2);
// dataPara.put("keyword3", key3);
// dataPara.put("keyword4", key4);
// dataPara.put("keyword5", key5);
// dataPara.put("remark", remark);
//
// sendPara.put("touser", userOpenid);
// sendPara.put("template_id", templateId);
// sendPara.put("url", "http://hnwj.btlsoln.com/hnwj-gzh/#/Yylb");
// sendPara.put("data", dataPara);
// String sendRes = HttpClientUtil.doPost(sendUrl, sendPara);
// log.debug("step 2 send notify:" + sendRes);
//
// JSONObject jsonSend = JSON.parseObject(sendRes);
//
// return 0;
// }
@RequestMapping("/jh/refundMoney")
@WebLog(description = "refundMoney")
public Object refundMoney(String ddh, String money) {
HisRefundVo vo = new HisRefundVo();
vo.setPowertranid(ddh);
vo.setZfamount(money);
log.info("打印传参:" + vo);
try {
String refundXML = XmlUtil.getRefundXML(vo);
String reR = SoapUtil.zfSoapMethod(refundXML);
log.info("打印退款信息:" + reR);
} catch (Exception e) {
throw new RuntimeException(e);
}
// int i = txSendMsg.SendNotifyMZ("缴费成功", "oLDdW6N1UbN_69BUbCmL2CDZrtK8", "长川", "10130223", "2023-05-08 13:45:21", "13", "MZ20230508112050102334", "nT84Plx_x5N-thR7Z37XfLPfVgsCFMsAG5NWu_pIqoY");
return ResponseResult.success("ok");
}
}

View File

@@ -0,0 +1,58 @@
package com.guahao.api.walkinto.controller;
import com.guahao.api.walkinto.service.PayService;
import com.guahao.common.Exception.LogicException;
import com.guahao.common.response.ErrorCode;
import com.guahao.common.response.ResponseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/pay")
public class PayController {
private Logger log = LoggerFactory.getLogger(PayController.class);
@Autowired
private PayService payService;
/**
* 获取openid
* @param code
* @return
*/
@RequestMapping(value="/getopenid",method = RequestMethod.GET)
public Object getOpenid(String code){
try{
String openid=payService.getOpenid(code);
// String openid = "abcde";
return ResponseResult.success(openid);
}catch (Exception e){
e.printStackTrace();
log.error(e.getLocalizedMessage());
if(e instanceof LogicException){
return ResponseResult.failure(ErrorCode.EXCEPTION_SYS).appendMessage(e.getMessage());
}
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 支付回调
* @return
*/
@RequestMapping(value="/callback",method = RequestMethod.POST)
public void callback(HttpServletRequest request,HttpServletResponse response){
payService.callback(request,response);
}
}

View File

@@ -0,0 +1,177 @@
package com.guahao.api.walkinto.controller;
import cn.hutool.core.util.XmlUtil;
import com.guahao.api.walkinto.model.Response;
import org.apache.poi.xwpf.usermodel.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/temporary")
public class TemporaryController {
/**
* 2.1预约科室查询
* @return
*/
@RequestMapping(value = "/queryAppointDeptMark", produces = { "application/xml;charset=UTF-8" })
public Object test(HttpServletRequest request){
try{
System.out.println("======================================");
org.dom4j.Document d=new SAXReader().read(request.getInputStream());
Element root = d.getRootElement();
//获取根元素下所有节点
List<org.dom4j.Element> list = root.elements();
for(org.dom4j.Element e:list){
//获取属性值
System.out.println(e.getName()+"---------------------------"+e.getText());
}
}catch (Exception e){
e.printStackTrace();
}
Response temporary=new Response();
List list=new ArrayList<>();
Map<String,Object> map=new HashMap<String,Object>();
map.put("DEPT_CODE","4028818");
map.put("DEPT_NAME","高血压门诊");
map.put("IS_ONLINE","1");
list.add(map);
list.add(map);
list.add(map);
list.add(map);
Map<String,Object> lm=new HashMap<String,Object>();
lm.put("Record_Info",list);
temporary.Result_Data.put("Record_List",lm);
return temporary;
}
/**
* 2.3预约排班查询
* @return
*/
@RequestMapping(value = "/queryAppointSchedulesMark", produces = { "application/xml;charset=UTF-8" })
public Object queryAppointSchedulesMark(HttpServletRequest request){
try{
System.out.println("==============================================");
org.dom4j.Document d=new SAXReader().read(request.getInputStream());
Element root = d.getRootElement();
//获取根元素下所有节点
List<org.dom4j.Element> list = root.elements();
for(org.dom4j.Element e:list){
//获取属性值
System.out.println(e.getName()+"---------------------------"+e.getText());
}
}catch (Exception e){
e.printStackTrace();
}
Response temporary=new Response();
List list=new ArrayList<>();
Map<String,Object> map=new HashMap<String,Object>();
map.put("DEPT_CODE","00045101");
map.put("DEPT_NAME","皮肤科");
map.put("DOCTOR_CODE","7889");
map.put("DOCTOR_NAME","贾雨村");
map.put("MARK_TYPE","主任");
map.put("CLINIC_DATE","2014-05-07");
map.put("CLINIC_DURATION","4028818");
map.put("DEPT_CODE","下午");
map.put("FLAG_USED","0");
map.put("SUM_FEE","100.00");
map.put("CLINIC_POSITION","中清大厦4层");
map.put("MARK_DESC","贾雨村主治医生");
map.put("DOCTOR_CLINIC_TYPE","0");
map.put("DIAG_FEE","12.00");
map.put("APPOINT_COUNT","100");
map.put("PHARMACY_FEE","12.00");
map.put("IS_ONLINE_DOCTOR","1");
map.put("IS_ONLINE_SCHEDULE","0");
list.add(map);
list.add(map);
list.add(map);
list.add(map);
Map<String,Object> lm=new HashMap<String,Object>();
lm.put("Record_Info",list);
temporary.Result_Data.put("Record_List",lm);
return temporary;
}
/**
* 2.6 预约医生号源查询
* @return
*/
@RequestMapping(value = "/queryAppointHidsMark", produces = { "application/xml;charset=UTF-8" })
public Object querySchedulesMark(HttpServletRequest request){
try{
System.out.println("==============================================");
org.dom4j.Document d=new SAXReader().read(request.getInputStream());
Element root = d.getRootElement();
//获取根元素下所有节点
List<org.dom4j.Element> list = root.elements();
for(org.dom4j.Element e:list){
//获取属性值
System.out.println(e.getName()+"---------------------------"+e.getText());
}
}catch (Exception e){
e.printStackTrace();
}
Response temporary=new Response();
List list=new ArrayList<>();
Map<String,Object> map=new HashMap<String,Object>();
map.put("HID","330719196804253671");
map.put("DEPT_CODE","00045101");
map.put("DOCTOR_CODE","7889");
map.put("CLINIC_DATE","2014/05/04");
map.put("HB_TIME","14:37:02");
map.put("CLINIC_DURATION","上午");
map.put("REGISTERED_FEE","12.00");
map.put("PHARMACY_FEE","2.00");
map.put("DIAG_FEE","5.00");
map.put("IS_ONLINE","0");
map.put("HB_TYPE","特诊");
map.put("HB_NO","");
map.put("EXPENSE_DETAIL","[{\"feedesc\":\"就诊费\",\"fee\":\"10.5\"}," +
"{\"feedesc\":\"诊疗费\",\"fee\":\"5.5\"}," +
"{\"feedesc\":\"陪护费\",\"fee\":\"5.5\"}]");
list.add(map);
list.add(map);
list.add(map);
list.add(map);
Map<String,Object> lm=new HashMap<String,Object>();
lm.put("Record_Info",list);
temporary.Result_Data.put("Record_List",lm);
return temporary;
}
}

View File

@@ -0,0 +1,336 @@
package com.guahao.api.walkinto.controller;
import com.guahao.api.carousel.service.CarouselService;
import com.guahao.api.charge.service.ChargeService;
import com.guahao.api.charge.service.ChargeTypeService;
import com.guahao.api.guide.service.GuideLabelService;
import com.guahao.api.info.model.HospitalInfo;
import com.guahao.api.info.service.HospitalInfoService;
import com.guahao.api.information.service.InformationService;
import com.guahao.api.inspect.service.InspectService;
import com.guahao.api.inspect.service.InspectSubscribeService;
import com.guahao.api.inspect.service.InspectTypeService;
import com.guahao.api.medicine.service.MedicineDoctorService;
import com.guahao.api.medicine.service.MedicineService;
import com.guahao.api.medicine.service.MedicineTypeService;
import com.guahao.api.walkinto.service.BillService;
import com.guahao.common.base.PageBean;
import com.guahao.common.response.ErrorCode;
import com.guahao.common.response.ResponseResult;
import com.guahao.h5.token.service.TokenService;
import com.guahao.h5.token.vo.TokenVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/walkinto")
public class WalkintoController {
private Logger log = LoggerFactory.getLogger(WalkintoController.class);
@Autowired
private CarouselService carouselService;
@Autowired
private InformationService informationService;
@Autowired
private MedicineDoctorService doctorService;
@Autowired
private MedicineService medicineService;
@Autowired
private MedicineTypeService medicineTypeService;
@Autowired
private ChargeTypeService chargeTypeService;
@Autowired
private HospitalInfoService hospitalInfoService;
@Autowired
private ChargeService chargeService;
@Autowired
private GuideLabelService labelService;
@Autowired
private InspectService inspectService;
@Autowired
private InspectTypeService inspectTypeService;
@Autowired
private InspectSubscribeService subscribeService;
@Autowired
private BillService billService;
@Autowired
private TokenService tokenService;
/**
* 医疗服务接口
* @return
*/
@RequestMapping("/home")
public Object home(){
try{
Map<String,Object> map=new HashMap<String,Object>();
//轮播图
List<Map<String,Object>> clist=carouselService.getList(1,5,1);
map.put("carousel",clist);
//健康咨询
List<Map<String,Object>> jklist=informationService.getList(1,10,"",1).getData();
map.put("jiankang",jklist);
return ResponseResult.success(map);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 医疗服务查询医生和科室
* @param name
* @return
*/
@RequestMapping("/selysks")
public Object selYsAndKs(@RequestParam(value="name",required = false)String name){
try{
Map<String,Object> map=new HashMap<String,Object>();
List<Map<String,Object>> yslist = doctorService.getList(1,20,0,name);
map.put("ys",yslist);
List<Map<String,Object>> kslist = medicineService.getList(1,20,0,name);
map.put("ks",kslist);
return ResponseResult.success(map);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询科室分类
* @return
*/
@RequestMapping(value="/getksfl",method = RequestMethod.POST)
public Object getksfl(){
try{
List<Map<String,Object>> list = medicineTypeService.getList(1,99999,"");
return ResponseResult.success(list);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询科室详情
* @param id 科室id
* @return
*/
@RequestMapping(value="/getksinfo",method = RequestMethod.POST)
public Object getksinfo(@RequestParam("id") int id){
try{
Map<String,Object> medicine = medicineService.getinfo(id);
List<Map<String,Object>> yslist = doctorService.getList(1,20,id,"");
medicine.put("ys",yslist);
return ResponseResult.success(medicine);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询走进医院
* @return
*/
@RequestMapping(value="/getzjyy",method = RequestMethod.POST)
public Object getzjyy(){
try{
Map<String,Object> map=new HashMap<String,Object>();
//医院详情
HospitalInfo hi = hospitalInfoService.getinfo();
Map<String,Object> info=new HashMap<String,Object>();
info.put("name",hi.name);
info.put("img",hi.img);
info.put("logo",hi.logo);
info.put("address",hi.address);
info.put("label",hi.label);
info.put("tel",hi.tel);
map.put("info",info);
//医生
List<Map<String,Object>> yslist = doctorService.getList(1,8,0,"");
map.put("ys",yslist);
//科室
List<Map<String,Object>> kslist = medicineService.getList(1,8,0,"");
map.put("ks",kslist);
//医院动态
List<Map<String,Object>> dtlist=informationService.getList(1,10,"",3).getData();
map.put("dt",dtlist);
//收费项目
List<Map<String,Object>> xmlist = chargeService.getList(1,8,0,"");
map.put("xm",xmlist);
return ResponseResult.success(map);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询收费项目分类
* @return
*/
@RequestMapping(value="/getxmfl",method = RequestMethod.POST)
public Object getxmfl(){
try{
List<Map<String,Object>> list = chargeTypeService.getList(1,99999,"");
return ResponseResult.success(list);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询医院导视
* @return
*/
@RequestMapping(value="/getguide",method = RequestMethod.POST)
public Object getGuide(){
try{
List<Map<String,Object>> list = labelService.getGuide();
return ResponseResult.success(list);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 体检首页查询接口
* @return
*/
@RequestMapping("/inspecthome")
public Object inspecthome(){
try{
Map<String,Object> map=new HashMap<String,Object>();
//轮播图
List<Map<String,Object>> clist=carouselService.getList(1,5,2);
map.put("carousel",clist);
//健康咨询
List<Map<String,Object>> tjlist=inspectService.getList(1,10,0,"").getData();
map.put("tijian",tjlist);
return ResponseResult.success(map);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询体检分类
* @return
*/
@RequestMapping(value="/gettjfl",method = RequestMethod.POST)
public Object gettjfl(){
try{
List<Map<String,Object>> list = inspectTypeService.getList(1,99999,"");
return ResponseResult.success(list);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 查询体检套餐详情
*
* @return
*/
@RequestMapping(value="/gettjinfo",method = RequestMethod.POST)
public Object gettjinfo(@RequestParam("id") int id){
try{
Map<String,Object> map = inspectService.getinfo(id);
List<Map<String,Object>> list =subscribeService.getresource(id,new SimpleDateFormat("yyyy-MM").format(new Date()));
map.put("num",list);
return ResponseResult.success(map);
}catch (Exception e){
log.error(e.getLocalizedMessage());
return ResponseResult.sysError(e.getLocalizedMessage());
}
}
/**
* 分页查询账单记录
*
* @param page 当前页数
* @param pagesize 每页显示条数
* @param uid 用户id
* @param type 查询类型0、全部 1、当日 2、当月 3当年
* @return
*/
@RequestMapping(value="/getbill",method = RequestMethod.POST)
public Object getAdminList(@RequestParam("page") int page,
@RequestParam("pagesize") int pagesize,
@RequestParam("userId")Integer uid,
@RequestParam("token")String token,
@RequestParam(value = "time",required = false)Integer type){
try{
int retToken = getUserToken(uid, token);
if (retToken == 0) {
return ResponseResult.sysLoginError();
}
PageBean<Map<String,Object>> pageBean = billService.getlist(page,pagesize,uid,type);
return pageBean;
}catch (Exception e){
log.error(e.getLocalizedMessage());
return new PageBean<>(null, ErrorCode.EXCEPTION_SYS);
}
}
/**
* token验证
*/
private int getUserToken(Integer userId, String token) throws Exception {
TokenVo tokenVo = new TokenVo(userId, token);
int result = tokenService.getUserToken(tokenVo);
return result;
}
}

View File

@@ -0,0 +1,122 @@
package com.guahao.api.walkinto.model;
import javax.persistence.*;
import java.io.Serializable;
@Table(name="bill")
public class Bill implements Serializable {
/**
* 主键
*/
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
public int id;
/**
* 账单名称
*/
@Column(name="name")
public String name="";
/**
* 用户id
*/
@Column(name = "uid")
public int uid;
/**
* 账单类型(0、消费 1、退款)
*/
@Column(name="type")
public int type=0;
/**
* 账单金额
*/
@Column(name="money")
public Double money=0.0;
/**
* 账单单号
*/
@Column(name="out_trade_no")
public String outTradeNo="";
/**
* 删除状态1、删除
*/
@Column(name="flag")
public int flag=0;
/**
* 添加时间
*/
@Column(name="ctime")
public String ctime="";
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
public String getCtime() {
return ctime;
}
public void setCtime(String ctime) {
this.ctime = ctime;
}
}

View File

@@ -0,0 +1,26 @@
package com.guahao.api.walkinto.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @ClassName: JhClientInfo
* @Description:
* @Author T.W
* @Date 2023/4/3
* @Version 1.0
*/
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class JhClientInfo {
private String orderNo;
private String openid;
private String price;
}

View File

@@ -0,0 +1,190 @@
package com.guahao.api.walkinto.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
/**
* @ClassName: JhNotifyInfo
* @Description:
* @Author T.W
* @Date 2023/3/31
* @Version 1.0
*/
@Data
@ToString
public class JhNotifyInfo implements Serializable {
/**
* 商户柜台代码
*/
@JsonProperty("POSID")
private String POSID;
/**
* 分行代码
*/
@JsonProperty("BRANCHID")
private String BRANCHID;
/**
* 订单号最长30位
*/
@JsonProperty("ORDERID")
private String ORDERID;
/**
* 付款金额
*/
@JsonProperty("PAYMENT")
private String PAYMENT;
/**
* 币种
* 缺省为 01人民币
*/
@JsonProperty("CURCODE")
private String CURCODE;
/**
* 备注信息1
* 一般作为商户自定义备注信
* 息使用,可在对账单中显示
*/
@JsonProperty("REMARK1")
private String REMARK1;
/**
* 备注信息2
* 一般作为商户自定义备注信
* 息使用,可在对账单中显示
*/
@JsonProperty("REMARK2")
private String REMARK2;
/**
* 账户类型
* 服务器通知中有此字段返回且参与验签
* AL:代表支付宝支付
* WX:代表微信支付
* 其他:代表建行支付或跨行付
*/
@JsonProperty("ACC_TYPE")
private String ACC_TYPE;
/**
* 成功Y失败N
*/
@JsonProperty("SUCCESS")
private String SUCCESS;
/**
* 接口类型
* 分行业务人员在 P2 员工渠道后台设置防钓鱼的开关。
* 1- 防钓鱼接口
*/
@JsonProperty("TYPE")
private String TYPE;
/**
* Referer信息
* 分行业务人员在P2员工渠道后台设置防钓鱼开关。
* 1.开关关闭时,无此字段返回且不参与验签。
* 2.开关打开时,有此字段返回且参与验签。
*/
@JsonProperty("REFERER")
private String REFERER;
/**
* 客户端IP
* 客户在商户系统中的IP即客户登陆访问商户系统时使用的IP
* 分行业务人员在P2员工渠道后台设置防钓鱼开关。
* 1.开关关闭时,无此字段返回且不参与验签。
* 2.开关打开时,有此字段返回且参与验签。
*/
@JsonProperty("CLIENTIP")
private String CLIENTIP;
/**
* 系统记账日期
* 商户登陆商户后台设置返回记账日期的开关
* 1.开关关闭时,无此字段返回且不参与验签。
* 2.开关打开时有此字段返回且参与验签。参数值格式为YYYYMMDD如20100907
*/
@JsonProperty("ACCDATE")
private String ACCDATE;
/**
* 分期期数
* 从商户传送的信息中获得;
* 当分期期数为空或无此字段上送时,无此字段返回且不参与验签,否则有此字段返回且参与验签。
*/
// @JSONField(name="INSTALLNUM")
// private String INSTALLNUM;
/**
* 错误信息
* 该值默认返回为空商户无需处理仅需参与验签即可。当有分期期数返回时则有ERRMSG字段返回且参与验签否则无此字段返回且不参与验签。
*/
// @JSONField(name="ERRMSG")
// private String ERRMSG;
/**
* 支付账户信息
* 分行业务人员在P2员工渠道后台设置防钓鱼开关和返回账户信息的开关。
* 1.开关关闭时,无此字段返回且不参与验签。
* 2.开关打开但支付失败时,无此字段返回且不参与验签。
* 3.开关打开且支付成功时,有此字段返回且参与验签。参数值格式如下:“姓名|账号加密后的密文”。
* 解密方法请参考“商户通知验签包“文件夹下的《USERMSG》压缩包
*/
// @JSONField(name="USRMSG")
// private String USRMSG;
/**
* 客户加密信息
* 分行业务人员在P2员工渠道后台设置防钓鱼开关和客户信息加密返回的开关。
* 1.开关关闭时,无此字段返回且不参与验签
* 2.开关打开时,有此字段返回且参数验签。参数值格式如下:“证件号密文|手机号密文”。该字段不可解密。
*/
// @JSONField(name="USRINFO")
// private String USRINFO;
/**
* 实付金额
* 优惠之后的实际支付金额。
* 目前只针对白名单商户返回,无此字段返回且不参与验签,有此字段返回且参与验签。
*/
// @JSONField(name="DISCOUNT")
// private String DISCOUNT;
/**
* 返回客户的积分使用情况,格式如下:
* {“APnt_Hpn_Num”:”积分发生数量”,”APntCmpt_Amt”:”积分抵扣金额”}
* 当综合积分字段为空或无此字段上送时,无此字段返回且不参与验签,否则有此字段返回且参与验签。
*/
// @JSONField(name="ZHJF")
// private String ZHJF;
/**
* 客户识别号
* 提交建行的参数RETURN_FIELD打开对应开关才返回该字段。
* 客户识别码, 微信、支付宝、龙支付时返回。
* 有该字段返回时(无论返回值是空还是其他),需参与验签,否则无需参与验签。
*/
// @JSONField(name="OPENID")
// private String OPENID;
/**
* 用户子标识
* 提交建行的参数RETURN_FIELD打开对应开关才返回该字段。
* 微信支付专有字段。
* 子商户appid下用户唯一标识如需返回则请求时需要传sub_appid。
* 有该字段返回时(无论返回值是空还是其他),需参与验签,否则无需参与验签。
*/
// @JSONField(name="SUB_OPENID")
// private String SUB_OPENID;
/**
* 支付详细信息
* 支付详细信息。当RETURN_FIELD字段第四位上送1时返回。
* 字段说明见下方[支付详细信息字段说明]
* 格式如下:
* {“TYPE“:"ALIPAY",“PAY_CHANNEL“:"BANKCARD",“DEBIT_CREDIT_TYPE“:"DEBIT_CARD",“THIRD_TRADE_NO“:"2018010521001004890523646975"}
* 为防止特殊字符建行会将该参数值用utf-8编码进行urlencode因此商户需先decode之后才能拿到明文。
* 编码之后为:
* %7B%22TYPE%22%3A%22ALIPAY%22%2C%22PAY_CHANNEL%22%3A%22BANKCARD%22%2C%22DEBIT_CREDIT_TYPE%22%3A%22DEBIT_CARD%22%2C%22THIRD_TRADE_NO%22%3A%222018010521001004890523646975%22%7D
* 有该字段返回时(无论返回值是空还是其他)需参与验签否则无需参与验签参与签名的是encode之后的参数值。
*/
// @JSONField(name="PAYMENT_DETAILS")
// private String PAYMENT_DETAILS;
/**
* 数字签名
*/
@JsonProperty("SIGN")
private String SIGN;
}

View File

@@ -0,0 +1,210 @@
package com.guahao.api.walkinto.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
/**
* @ClassName: JhPlaceOrderInfo
* @Description:
* @Author T.W
* @Date 2023/3/31
* @Version 1.0
*/
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class JhPlaceOrderInfo {
/**
* 商户代码
* 必填
*/
@JSONField(name="MERCHANTID")
private String MERCHANTID;
/**
* 商户柜台代码
* 必填
*/
@JSONField(name="POSID")
private String POSID;
/**
* 分行代码
* 必填
*/
@JSONField(name="BRANCHID")
private String BRANCHID;
/**
* 订单号最长30位
* 必填
*/
@JSONField(name="ORDERID")
private String ORDERID;
/**
* 付款金额
* 必填
*/
@JSONField(name="PAYMENT")
private String PAYMENT;
/**
* 币种
* 必填
* 缺省为 01人民币
*/
@JSONField(name="CURCODE")
private String CURCODE;
/**
* 备注信息1
* 一般作为商户自定义备注信
* 息使用,可在对账单中显示
*/
@JSONField(name="REMARK1")
private String REMARK1;
/**
* 备注信息2
* 一般作为商户自定义备注信
* 息使用,可在对账单中显示
*/
@JSONField(name="REMARK2")
private String REMARK2;
/**
* 交易码
* 由建行统一分配为 530590
* 必填
*/
@JSONField(name="TXCODE")
private String TXCODE;
/**
* MAC 校验域
* 采用标准 MD5 算法,由商户实现
* 必填
*/
@JSONField(name="MAC")
private String MAC;
/**
* 接口类型
* 分行业务人员在 P2 员工渠道后台设置防钓鱼的开关。
* 1- 防钓鱼接口
* 必填
*/
@JSONField(name="TYPE")
private String TYPE;
/**
* 公钥后 30 位
* 商户从建行商户服务平台下载,截取后 30 位。
* 仅作为源串参加 MD5 摘要,不作为参数传递
* 必填
*/
@JSONField(name="PUB")
private String PUB;
/**
* 网关类型
* 默认送 0
* 必填
*/
@JSONField(name="GATEWAY")
private String GATEWAY;
/**
* 客户端 IP
* 客户在商户系统中的 IP即客户登陆访问商户系统时使用的 ip
*/
@JSONField(name="CLIENTIP")
private String CLIENTIP;
/**
* 客户注册信息
* 客户在商户系统中注册的信息,中文需使用 escape 编码
*/
@JSONField(name="REGINFO")
private String REGINFO;
/**
* 商品信息
* 客户购买的商品中文需使用 escape 编码
*/
@JSONField(name="PROINFO")
private String PROINFO;
/**
* 商户 URL
* 商户送空值即可;具体请看 REFERER 设置说明
*/
@JSONField(name="EFERER")
private String EFERER;
/**
* 订单超时时间
* 格式:
* YYYYMMDDHHMMSS如
* 20120214143005
* 银行系统时间> TIMEOUT
* 时拒绝交易,若送空值则不
* 判断超时。
* 当该字段有值时参与 MAC
* 校验,否则不参与 MAC 校
* 验。
*/
@JSONField(name="TIMEOUT")
private String TIMEOUT;
/**
* 交易类型
* JSAPI-- 公 众 号 支 付 、
* MINIPRO--小程序
* 必填
*/
@JSONField(name="TRADE_TYPE")
private String TRADE_TYPE;
/**
* 小程序/公众号的 APPID
* 当前调起支付的小程序/公众号 APPID
* 必填
*/
@JSONField(name="SUB_APPID")
private String SUB_APPID;
/**
* 用户子标识
* 用户在小程序/公众号 appid
* 下的唯一标识,小程序通过
* wx.login 获取,接口文档地
* 址
* https://developers.weixin.qq.com/miniprogram/dev/api/apilogin.html?t=20161122
* 必填
*/
@JSONField(name="SUB_OPENID")
private String SUB_OPENID;
/**
* 渠道商号
* 对于商户自定义的渠道商号当该字段有值时参与 MAC校验否则不参与 MAC 校验。
*/
@JSONField(name="WX_CHANNELID")
private String WX_CHANNELID;
/**
* 返回信息位图
* 共 20 位,商户通知是否返回某
* 个字段的位图0 或空-不返回,
* 1-返回。
* 第 1 位:是否返回 OPENID 和
* SUB_OPENID
* 第 2 位:保留位,默认送 0
* 第 3 位:保留位,默认送 0
* 第 4 位:是否返回支付详细信息
* 字段
* 示例10000000000000000000
*/
@JSONField(name="RETURN_FIELD")
private String RETURN_FIELD;
/**
* 实名支付
* 实名支付功能,包含类型、
* 证件号、姓名三个子域(如果本字段
* 出现,那么本字
* 段包含的三个子域均需出现。详见下
* 文说明5)USERPARAM字段说明
* 当该字段有值时参与MAC校验否则不
* 参与MAC校验。
* 暂未上线,请忽略
*/
@JSONField(name="USERPARAM")
private String USERPARAM;
}

View File

@@ -0,0 +1,19 @@
package com.guahao.api.walkinto.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author SangChengZhi
* @date 2025年09月06日 15:13
* @desc
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PayQueryDTO implements Serializable {
private String outTradeNo;
}

View File

@@ -0,0 +1,18 @@
package com.guahao.api.walkinto.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.HashMap;
import java.util.Map;
@XmlRootElement(name = "Response")
public class Response {
public Integer Result_Code=200;
public String Error_Msg="交易成功";
public Map<String,Object> Result_Data=new HashMap<String,Object>();
}

View File

@@ -0,0 +1,18 @@
package com.guahao.api.walkinto.model;
import lombok.Data;
/**
* @author Mr.zs
* @date 2025/3/17
*/
@Data
public class WxPay {
private String appid;
private String mchid;
private String wechartkey;
private String secret;
private String path;
private String domain;
}

View File

@@ -0,0 +1,46 @@
package com.guahao.api.walkinto.model.param;
import com.guahao.common.base.PageParams;
public class BillParam extends PageParams {
public BillParam(){}
public BillParam(int page,int pagesize,Integer uid,Integer type,String time){
this.currentPage=(page-1)*pagesize;
this.pageSize=pagesize;
this.uid=uid;
this.type=type;
this.time=time;
}
private Integer uid;
private Integer type;
private String time;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}

View File

@@ -0,0 +1,99 @@
package com.guahao.api.walkinto.service;
import com.guahao.api.walkinto.mapper.BillMapper;
import com.guahao.api.walkinto.model.Bill;
import com.guahao.api.walkinto.model.param.BillParam;
import com.guahao.common.base.BaseMapper;
import com.guahao.common.base.BaseService;
import com.guahao.common.base.PageBean;
import com.guahao.common.response.ErrorCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class BillService extends BaseService<Bill> {
@Override
public BaseMapper getMapper() {
return null;
}
@Autowired
private BillMapper billMapper;
/**
*
* 添加账单记录
*
* @param uid 用户id
* @param money 金额
* @param name 账单名称
* @param outTradeNo 账单单号
* @param type 账单类型0、支付 1、退款
* @return
*/
public int add(int uid,Double money,String name,String outTradeNo,int type){
Bill b=new Bill();
b.uid=uid;
b.money=money;
b.name=name;
b.outTradeNo=outTradeNo;
b.type=type;
b.ctime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
return billMapper.insert(b);
}
/**
* 分页查询账单记录
*
* @param page 当前页数
* @param pagesize 每页显示条数
* @param uid 用户id
* @param type 查询类型0、全部 1、当日 2、当月 3当年
* @return
*/
public PageBean<Map<String,Object>> getlist(int page, int pagesize, Integer uid, Integer type){
String time="";
if(type==null){
type=0;
}
switch (type){
case 1: //当日
time=new SimpleDateFormat("yyyy-MM-dd").format(new Date());
break;
case 2: //当月
time=new SimpleDateFormat("yyyy-MM").format(new Date());
break;
case 3: //当年
time=new SimpleDateFormat("yyyy").format(new Date());
break;
}
BillParam param=new BillParam(page,pagesize,uid,type,time);
List<Map<String,Object>> list=billMapper.getAll(param);
PageBean<Map<String,Object>> pageBean=new PageBean<Map<String,Object>>();
pageBean.setCode(ErrorCode.SUCCESS.code);
pageBean.setMessage(ErrorCode.SUCCESS.desc);
pageBean.setData(list);
pageBean.setPageIndex(page);
pageBean.setPageSize(pagesize);
pageBean.setTotalRecords(billMapper.getAll(new BillParam(1,999999,uid,type,time)).size());
double i=pageBean.getTotalRecords();
double j=i/pagesize;
double x=Math.ceil(j);
pageBean.setTotalPages((int) x);
return pageBean;
}
}

View File

@@ -0,0 +1,14 @@
package com.guahao.api.walkinto.service;
import com.guahao.api.walkinto.model.JhClientInfo;
import com.guahao.api.walkinto.model.JhPlaceOrderInfo;
import java.util.Map;
public interface IJhPayService {
/**
* 建行统一下单
// * @param jhPlaceOrderInfo
*/
public Map<String,Object> unifiedPlaceOrder(JhClientInfo jhClientInfo);
}

View File

@@ -0,0 +1,176 @@
package com.guahao.api.walkinto.service;
import com.alibaba.fastjson.JSON;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.guahao.api.walkinto.model.JhClientInfo;
import com.guahao.api.walkinto.model.JhPlaceOrderInfo;
import com.guahao.common.util.DateUtils;
import com.guahao.common.util.EscapeUtils;
import com.guahao.common.util.MD5Util;
import com.guahao.common.util.OrderNoUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @ClassName: JhPayServiceImpl
* @Description:
* @Author T.W
* @Date 2023/3/31
* @Version 1.0
*/
@Service
public class JhPayServiceImpl implements IJhPayService {
private Logger log = LoggerFactory.getLogger(PayService.class);
// 获取application.yml的配置信息
@Value("${jh.merchantId}")
private String merchantId;
@Value("${jh.posId}")
private String posId;
@Value("${jh.branchId}")
private String branchId;
@Value("${jh.subAppId}")
private String subAppId;
@Value("${jh.tradeType}")
private String tradeType;
@Value("${jh.pub}")
private String pub;
@Value("${jh.url}")
private String url;
@Value("${jh.operatorCode}")
private String operatorCode;
@Value("${jh.pwd}")
private String pwd;
@Value("${jh.wlptServerIp}")
private String wlptServerIp;
@Value("${jh.wlptPort}")
private String wlptPort;
/**
* 建行统一下单
*
* @param jhPlaceOrderInfo
*/
@Override
public Map<String, Object> unifiedPlaceOrder(JhClientInfo jhClientInfo) {
log.info("进入JhPayServiceImpl的unifiedPlaceOrder方法");
log.info("jhClientInfo:"+jhClientInfo);
Map<String, Object> map = new HashMap<>();
// -----------封装请求参数-----------
JhPlaceOrderInfo jhPlaceOrderInfo = new JhPlaceOrderInfo();
jhPlaceOrderInfo.setORDERID(jhClientInfo.getOrderNo());
jhPlaceOrderInfo.setPAYMENT(jhClientInfo.getPrice());
// jhPlaceOrderInfo.setPAYMENT("0.01");
jhPlaceOrderInfo.setSUB_OPENID(jhClientInfo.getOpenid()); //user openid
// 注意这里要对中文进行编码工具类参考下方2.4部分
// jhPlaceOrderInfo.setPROINFO(EscapeUtils.escape("挂号费") + jhPlaceOrderInfo.getPAYMENT());
// jhPlaceOrderInfo.setPAYMENT(jhClientInfo.getPrice());
// 1. 截取公钥后30位
String pubSub = pub.substring(pub.length() - 30);
jhPlaceOrderInfo.setMERCHANTID(merchantId);
jhPlaceOrderInfo.setPOSID(posId);
jhPlaceOrderInfo.setBRANCHID(branchId);
jhPlaceOrderInfo.setTRADE_TYPE(tradeType);
jhPlaceOrderInfo.setTIMEOUT(DateUtils.getAddTimes(15));
jhPlaceOrderInfo.setSUB_APPID(subAppId);
jhPlaceOrderInfo.setCURCODE("01");
jhPlaceOrderInfo.setTXCODE("530590");
jhPlaceOrderInfo.setTYPE("1");
jhPlaceOrderInfo.setGATEWAY("0");
jhPlaceOrderInfo.setPUB(pubSub);
jhPlaceOrderInfo.setREMARK1("jojubankinggzh");
// 2. 获取加密后的mac这里需要注意参与MAC的参数是固定排序格式需参考文档手动排序并MD5加密
String mac = getMac(jhPlaceOrderInfo);
jhPlaceOrderInfo.setMAC(mac);
// 3. 获取请求参数&连接
String paramsStr = getParamsStr(JSON.parseObject(JSON.toJSONString(jhPlaceOrderInfo), Map.class));
log.debug("url:" + url);
log.debug("para:" + paramsStr);
String result = HttpUtil.post(url, paramsStr);
log.debug("result:" + result);
if (StringUtils.isEmpty(result)) {
// 表示返回为空,自行处理
}
JSONObject jsonObject = JSON.parseObject(result);
if (!jsonObject.getString("SUCCESS").equals("true")) {
// SUCCESS返回状态码不为true时表示通信失败自行处理
}
// 获取接口返回的payUrl
String payUrl = jsonObject.getString("PAYURL");
if (StringUtils.isEmpty(payUrl)) {
// 如果PAYURL为空自行处理
}
// 返回结果参考{ "SUCCESS":"true", "PAYURL":"https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_08_EPAY?BRANCHID=120000000&TXCODE=530590&SUB_APPID=wx8b28b84282cce9fc&CCB_IBSVersion=V6&CURCODE=01&GATEWAY=0&PROINFO=%25u79DF%25u7528%25u8BBE%25u5907%25u62BC%25u91D11.00&MERCHANTID=105000789993067&ORDERID=575469756870557696&RETURN_FIELD=10000000000000000000&POSID=071114078&PAYMENT=1.00&TRADE_TYPE=MINIPRO&MAC=5e4a3586bfbeb6f1e86b1ba9ea12d19e&SUB_OPENID=oz46x5GAP3LnbSJVozyozYN-63Tw&TYPE=1&TIMEOUT=20221107164541&QRCODE=1&CHANNEL=1"}
// PAYURL不为空时对于小程序支付而言需手动发送一下get请求获取小程序支付所需的参数具体参数请参考相关文档
// 小程序https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=7_7&index=5
// 公众号https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=7_7&index=6
String payUrlResult = HttpUtil.get(payUrl);
if (StringUtils.isEmpty(payUrlResult)) {
// 请求异常,自行处理
}
log.debug("payUrlResult:" + payUrlResult);
JSONObject payUrlJson = JSON.parseObject(payUrlResult);
if (!payUrlJson.getString("ERRCODE").equals("000000")) {
// ERRCODE为错误码000000 表示交易成功,非 000000 表示交易失败,错误信息可以查看 ERRMSG 字段
}
map.put("appId", payUrlJson.getString("appId"));
map.put("timeStamp", payUrlJson.getString("timeStamp"));
map.put("nonceStr", payUrlJson.getString("nonceStr"));
map.put("package", payUrlJson.getString("package"));
map.put("signType", payUrlJson.getString("signType"));
map.put("paySign", payUrlJson.getString("paySign"));
return map;
}
/**
* 生成mac并md5加密
*
* @param jhPlaceOrderInfo
* @return
*/
private String getMac(JhPlaceOrderInfo jhPlaceOrderInfo) {
String postParams = "MERCHANTID=" + jhPlaceOrderInfo.getMERCHANTID() + "&POSID=" + jhPlaceOrderInfo.getPOSID() + "" +
"&BRANCHID=" + jhPlaceOrderInfo.getBRANCHID() + "&ORDERID=" + jhPlaceOrderInfo.getORDERID() + "&PAYMENT=" + jhPlaceOrderInfo.getPAYMENT() + "" +
"&CURCODE=01&TXCODE=530590&REMARK1=" + "jojubankinggzh" + "&REMARK2=&TYPE=1&PUB=" + jhPlaceOrderInfo.getPUB() + "&GATEWAY=0&CLIENTIP=&REGINFO=&PROINFO=" + "&REFERER=" +
"&TIMEOUT=" + jhPlaceOrderInfo.getTIMEOUT() + "&TRADE_TYPE=" + jhPlaceOrderInfo.getTRADE_TYPE() + "" +
"&SUB_APPID=" + jhPlaceOrderInfo.getSUB_APPID() + "&SUB_OPENID=" + jhPlaceOrderInfo.getSUB_OPENID() + "";
// return MD5Utils.string2MD5(postParams);
return MD5Util.MD5Encode(postParams, "UTF-8");
}
/**
* 生成提交参数
*
* @param params
* @return
*/
private String getParamsStr(Map params) {
StringBuffer toBeMacStr = new StringBuffer();
Set<Map.Entry<String, Object>> entries = params.entrySet();
Iterator iterator = entries.iterator();
while (iterator.hasNext()) {
Object itset = iterator.next();
Map.Entry entry = (Map.Entry) itset;
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if (StringUtils.isNotEmpty(value)) {
if (!key.equals("PUB")) {
toBeMacStr.append("&" + key.toUpperCase() + "=" + value);
}
}
}
return toBeMacStr.toString();
}
}

View File

@@ -0,0 +1,34 @@
package com.guahao.api.walkinto.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* @ClassName: LpayService
* @Description:
* @Author T.W
* @Date 2023/3/31
* @Version 1.0
*/
@Service
public class LpayService {
// private Logger log = LoggerFactory.getLogger(PayService.class);
String MERCHANTID = "105000180622409";
String POSID = "072160314";
String BRANCHID = "460000000";
String PUBLICKEY = "30819c300d06092a864886f70d010101050003818a003081860281807b07825e3370fb4f0eb10d2cb2e27d24c9803201cd50c4a76f5ff0ba8e655311c926c3a9e7fc2d1df76392ebc183ce65a9e3471067a8e1fea3347eba2e1dae760dc3cd149a99b2678e5d3f22cdcb4c1fa40942711c76c6fe56dd15f540f3445cef200ce7784293688f7ad618bb0c0d4a71762c6716e0d47c7860e1ebd7e675d7020111";
String MERFLAG = "1";
String CodePayUrl = "https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_00_BEPAY?";
String CodeCreateUrl = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6";
String WlCaozuoyuan = "001";
String WlPassword = "Aa123123";
String WlSHDM = "105000180622409";
//string WlAddr = "106.37.193.32";
//int WlPort = 443;
String WlAddr = "127.0.0.1";
int WlPort = 8080;
}

View File

@@ -0,0 +1,809 @@
package com.guahao.api.walkinto.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.guahao.common.util.HttpClientUtil;
import com.guahao.common.util.JedisUntils;
import com.guahao.common.util.VeDate;
// sang:注释icbc部分
// import com.icbc.api.DefaultIcbcClient;
// import com.icbc.api.IcbcApiException;
// import com.icbc.api.IcbcConstants;
// import com.icbc.api.UiIcbcClient;
// import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1;
// import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineOrderqryRequestV1;
// import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1;
// import com.icbc.api.request.CardbusinessEpayh5UiConsumptionRequestV1;
// import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineMerrefundResponseV1;
// import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineOrderqryResponseV1;
// import com.icbc.api.utils.IcbcSignature;
// import com.icbc.api.utils.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Service
public class PayService {
private Logger log = LoggerFactory.getLogger(PayService.class);
//商户编号
public static final String MER_ID="1726317574";
// public static final String MER_ID="060351010017004";
//线上协议编号
public static final String MER_PRTCL_NO="060351010017004";
//工行APPID
public static final String GH_APP_ID="10000000000003190784";
//微信APPID
public static final String WX_APP_ID="wx45acd2b4907cb8f4";
//微信AppSecret
public static final String WX_SECRET="4b5c37baebecfa9d5d0282c5d2867cd2";
// public static final String URL="http://gzh.btlsoln.com/WGZH";
public static final String URL="http://wx.btdbyy.cn:9081";
//工行网关公钥
public static final String APIGW_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIp\n" +
"iPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZER\n" +
"kx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4\n" +
"+EBpXo8gNiAFsNwIDAQAB";
//自己的私钥
// public static final String MY_PRIVATE_KEY="MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCWrJCh0z3q4w0yFyZSfYyPZPlbQYdz/dyGL6nodVlgELspDQ2XencoO1vg43T7OOEQDScp3IREDcha+9I/iGLSiPIlYUEfqQyCWIC28Jr0gr1f+zfb4pbejY46Fc2SntGmwlN/JPLPHWhKLpig/i6aqZN3IvXPM9Lu5tW0JSa6uEPsYIMPZY/2+8okuvPuBU2Zlzdf+pvtP+BUVc/GjbFI26F+uo95eLBufuBnZ9z++ttP4UrAZJ7VNU2iztHheBgV9S3nupdL1SJN6Ga+ZROdfXEo8KKVSQmjPh9U3eaz+o3iLnuAnoj3UP31SuDeiOGLdRW0YY5MzFmvCHBA1b4vAgMBAAECggEALDFVAoHIyVnrBuQPU2aLkYtWL9PafMTap2jXdtzkZ+7AVlwDvogm5t/yJNXR+9VE/cY91GNfT+6S80yk8Al6orGUBC6wQS7+AkUfC4kqicjG7p3qVk3xXjk6nALFFtoKN9ULVGFr7h979TYRgjbLSIWwQOM6IZnbpkKCL6It59mrp5ns6EQthEVvijpD7yqj7xCOAB1EF8tBG9TyM+jc5exbslbQKtapAaGTEBVPLNC66rOkaDIlBQY6tQwzugCBzVo31//Jrx0pule7MNBdP1iCqP5XvLIgJ+P/al9d32vgbN+Ce1VUD9ghAJ44VzdDhNMsfXVVx/xPKdB2Luw2wQKBgQDgVcY3Pb+0lFIRhT81OpFne1JnVxmXCDkoqWWNnVOY7rFsd71Xf4tnYfr9fdIZHy/esun2OFhkGr/gK5K6HJW+LtZHCwXTO10TR5h+mWbJBSNCpOGVf/ZeRuaKrRLcPeeKllIZN3MYkL5ytLrBccskvCUZxNZL4E2P2U7TRop/8QKBgQCr8Rdfa6uWLcA7MqaS3Y6MCemLAvLqdRwe8r+zRfrS0kbz3bJB/wDdb1qrx7m72uSkFQjQvOnFzoaVuPy95WCOTEjWel7QtFmTYuFEN+kx2qBQiW0KU3C0H7CHLDDk6593og5qSsU3tA3wHQOatFFYY+7TGBYmhKcuHklyy1RAHwKBgQC8gZcECFE0zoV/z3XjpolUaV4/FAOe0/wj3ORG8XKzya8xNBTYl4ZuovijVbzb+0bgXXsXuRUdWRTuq+6pkSeLHhRUskB81R9K+hh8GS8zr6uHbsFYPKSrZ+yFjxWQGDyeSd5G7j863zYJcTCVKKfJAIg0dSCVta+3NqV0B4yOIQKBgQCL1Ow/K99FqTt2aUDSm+B7vuvxo5pOVqNh/+UrNLRBk8UkOp3n0iyv6QmCPlGslt3vGzQqHhi4R7doOCNDhDG8SAnMc4R8ks9ub7HnutipNLXACaNmDGnR8xurMqMo6P6tWlwC0YAGRyY2qkHuJMsq6Uqm3iXVeXhEp1jwRK/l3QKBgQCjaN6BNFHq3PM9JYHlQgJNG0ACOVW4bqEp7dy7WFaLHXuJwlpN4zoI/FYS+zVVEwX3A//d+iW29w7VR543CB0QjZNUB+swYA8KYrtDqXC2o9bF+LKSq10Ga/BHNWDHZZTm2XiFxzzpVQAcuaumoj0+5qQpQ5ZvR6HZVOEo8uq0EQ==";
public static final String MY_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCJFkZeWd97TiE3LmhTHOL0dM5Oa2cMf9oKX9xiuALskTHX+2JpvNysLobqXmqgXjyeVTXP1bRldQRM5FEYfZA9oSZhRrw943ik/2UUeJJ2sq8wMa3XTrw9wWjJw9eP1lnc5IseBT1Tn/QTJhLm6ydjqXjl/KyBF3HMZy7rKiqt9vH6zDaSwYGHC+UeVbQvcvLdwJDVsiv7Ah5SgIVZydfUXKwKx4BbkHLbn0zMEWAIzFlu92xpDQ8+mX6lMZS9jefcSDmrwpLFIUmkfb6ZM4lqWV1Z01QXws8vu4ONEqT7mxJ9oNQmIVk9Ys4YiSn6bCN8zTCdNzsVmXN+iL/jcNQRAgMBAAECggEAZ06uAPRhgh7C0T7bx6aBMg/EWTx/D+BZhG/xOUPKkFRq54S+CUkWU3tMmNpGKExcCkXUo6c8pyij8P4uTvJw/MCwl6YivdDqXg1JM0AZv/GwK/WEODlRiohyW3qGvBKg7eIdJKZ2LMrhuHx8yiB0MprITSk5Jp9wVsV7iiTgvO+8ywz6SW0mANvuxSh/5/mR/ybQK+40IuVHTyScvL03jK1woiLM1zNqc9Rv/kb2oAvO7NbogmPxbM44TR8L8YDgnAcDugONqE3dZfR8fmgUJQRixaAijx2Q/xoqoxhGkfVrhfUdKBsiHL+uuji5CgZbYDgTGTue0jiYmNkk+rGnAQKBgQDMQdIvdsFfuhFM4TQEy7FivEcFxvWlQ4IshwFhAxJAQpcqxuKq8i5qjsZ5RGrg8Le3KaFbmfS99QRoL8xM22cfLAz/p6z1BP52wY4No+/MSsMZGuBDivBX9ASUVNPHOWzAoq8qCMZ69nb+mVCU/O+T4ePxilRZATpcKanPUG7DuQKBgQCr0HApc+ooPQ5Akho3JupgqtpFERvG4dSxWiU9qx0/kMAbfDsCL63zciceMuq0t31yzs/5KmzJtJIOC0iUaLBSJhA53ZCXCJUULZbAWSgw6nbbIsx1F5JrJFoZrQtqxzLU/+i2TMA5ZxHmtXvzK2TwG4aOn11A7VUvv5luPhbvGQKBgQCZLyvwyMFRh3v+Ck824YSRJd6l6IbFgJGZz04rcWA4rTgtrqbDyYkiBR24SKVXOXCufxwyVI4GAEFj2aUAZvM5n5HIEfpWb35fld1xQWdP8SnMJCnYvdRuQeVFUTDakqiK9/ciMR6ZjUnEuzqB4gfTAnAu760+avtXry9Y+Vt4kQKBgF3w7LKtjzULFRTXDYBkRbgvEoK69P4MEhgaWsxaF/bedTtR9I2gdjLqklrfqha/UNcKHwp0WOD8WvNU1g1XJDj2WN7atyjtZ12OA6QN23zLZcsxPqszBTqRuLXbOKfcXH27ooiydFOueEo1ppzxeBIUasDmf711RqOB1ilBx5ZZAoGAFnZLJdV8SM6xm7FlXwjWN5I/4CB/hmyD5a4KNGq9clX7IUIsn9ywA+J5Cm4utpiMEyTOf0yA/iiup4YQWu+akhyded4uawd2yeyoLMu1o/ZYbiruH29/VST6iSpe6r0H7UU7B+R+0WFoXj3G6PMoMtl4LsZhdT3zUtVb2XCwbCY=";
public String getOpenid(String code){
String accessUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+WX_APP_ID+"&secret="+WX_SECRET+"&code="+code+"&grant_type=authorization_code";
String accessTokenStr = HttpClientUtil.doGet(accessUrl,null);
JSONObject jsonObject = JSON.parseObject(accessTokenStr);
System.out.println(jsonObject.toString());
log.info(jsonObject.toString());
if (jsonObject.get("errcode") != null) {
System.out.println(jsonObject.get("errcode").toString() + ":" + jsonObject.get("errmsg"));
}
String openId = jsonObject.getString("openid");
return openId;
}
/**
* 调起支付接口
*
* @param money 支付金额
* @param out_trade_no 订单号
* @param notify_url 回调地址
* @param body 商品名称
* @return 返回自动提交的form表单
*/
public String pay(Double money,String out_trade_no,String notify_url,String body){
// sang:注释icbc部分,添加String返回值
String ret = null;
return ret;
//需传入appid私钥字符集
// UiIcbcClient client = new UiIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8);
// CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1 request = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1();
// //根据测试环境和生产环境替换相应ip和端口
// request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/aggregatepay/b2c/online/ui/consumepurchaseshowpay/V1");
// CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz();
// request.setBizContent(bizContent);
// //请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
// bizContent.setExpireTime("120");
// bizContent.setIcbc_appid(GH_APP_ID);
// bizContent.setMer_id(MER_ID);
// bizContent.setMer_prtcl_no(MER_PRTCL_NO);
// bizContent.setNotify_type("HS");
// bizContent.setNotify_url(URL+notify_url);
//
// bizContent.setResult_type("0");
// // bizContent.setReturn_url(URL+"/dist/index.html#/Yygh?type=1");
// bizContent.setReturn_url("http://gzh.btlsoln.com/jojugongzhonghao/#/Yylb");
//
// //订单金额
// int m= (int) Math.round(money*100);
// bizContent.setOrder_amt(""+m);
// bizContent.setOut_trade_no(out_trade_no);
// bizContent.setSaledepname("包头第八医院");
// String str="就医缴费";
// if(body!=null||!body.trim().equals("")){
// str=body.trim();
// if(body.trim().equals("挂号费")){
// //支付成功跳转地址
// bizContent.setReturn_url("http://wx.btdbyy.cn:9081/jojugongzhonghao/#/Yylb");
// }else if(body.trim().equals("住院预交支付")){
// bizContent.setReturn_url("http://wx.btdbyy.cn:9081/jojugongzhonghao/index.html#/ZYCharge_list?inHosNum=2020111990437&HosDate=");
// }
// }
// bizContent.setBody(str);
// try {
// String ret=client.buildPostForm(request);
// System.out.println(ret);
// log.debug("payment info:" + ret);
// JedisUntils.getJedis().set(bizContent.getOut_trade_no(),ret);
// return ret;
// } catch (IcbcApiException e) {
// e.printStackTrace();
// return null;
// }
}
/**
* 支付回调
* @param request
* @param response
*/
public void callback(HttpServletRequest request, HttpServletResponse response){
PrintWriter out = null;
try {
Map<String, String> params=new HashMap<String, String>();
String from=request.getParameter("from");
String api=request.getParameter("api");
String app_id=request.getParameter("app_id");
String charset=request.getParameter("charset");
String format=request.getParameter("format");
String encrypt_type=request.getParameter("encrypt_type");
String timestamp=request.getParameter("timestamp");
String biz_content=request.getParameter("biz_content");
String sign_type=request.getParameter("sign_type");
String sign=request.getParameter("sign");
params.put("from", from);
params.put("api", api);
params.put("app_id", app_id);
params.put("charset", charset);
params.put("format", format);
params.put("encrypt_type", encrypt_type);
params.put("timestamp", timestamp);
params.put("biz_content", biz_content);
params.put("sign_type", sign_type);//目前上行网关签名暂时仅支持RSA
/**********验证工行上行网关RSA签名**********/
log.info("==================================");
log.info(params.toString());
//回调接口
String path="/pay/callback";
// sang:注释icbc部分,改为null
// WebUtils.buildOrderedSignStr(path, params)
String signStr= null;
String results = null;
String responseBizContent= null;
// sang:注释icbc部分,改为true
// IcbcSignature.verify(signStr, sign_type, APIGW_PUBLIC_KEY, charset, sign);
boolean flag=true;
log.info("---------------------"+flag);
//验证签名
if (!flag) {
responseBizContent= "{\"return_code\":-12345,\"return_msg\":\"icbc sign not pass.\"}";
}
else
{
System.out.println("-----------------支付成功-------------------");
/**********合作方/分行 业务逻辑处理**********/
@SuppressWarnings("unchecked")
Map<String, Object> respMap = (Map<String, Object>) JSON.parse(biz_content);
log.info("return_code:"+respMap.get("return_code")+",return_msg:"+respMap.get("return_msg"));
if(!respMap.get("return_code").toString().equals("0")){
responseBizContent= "{\"return_code\":-12345,\"return_msg\":\""+respMap.get("return_msg")+"\"}";
}else{
String msg_id=respMap.get("msg_id").toString();
//业务请求字段获取
String outTradeNo=(String)respMap.get("out_trade_no");
String order_id=(String)respMap.get("order_id");
//业务处理逻辑......
System.out.print(outTradeNo);
//业务返回参数设置
int return_code=0;
String return_msg="success.";
responseBizContent="{\"return_code\":"+return_code+",\"return_msg\":\""+return_msg+"\",\"msg_id\":\""+msg_id+"\","
+"\"busi_param_rp\":\"thisisresponseparameter\"}";
}
}
//2、商户以RSA签名为例如下其中priKey为商户私钥
signStr="\"response_biz_content\":"+responseBizContent+","+"\"sign_type\":"+"\"RSA2\"";
// sang:注释icbc部分,改为null
// IcbcSignature.sign(signStr, "RSA2", MY_PRIVATE_KEY,
// charset);
sign=null;
results="{"+signStr+",\"sign\":\""+sign+"\"}";
response.setContentType("application/json; charset=utf-8");
out = response.getWriter();
out.write(results);
}catch (Throwable e) {
e.printStackTrace();
out.write(e.getMessage());
} finally {
out.flush();
out.close();
}
}
/**
* 查询
* @param out_trade_no 订单号
* @return
*/
public String inq(String out_trade_no){
String ret = "";
//签名类型为RSA2时需传入appid私钥和网关公钥签名类型使用定值cbcConstants.SIGN_TYPE_RSA2其他参数使用缺省值
// sang:注释icbc部分
// DefaultIcbcClient client = new DefaultIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,
// MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
// CardbusinessAggregatepayB2cOnlineOrderqryRequestV1 request = new
// CardbusinessAggregatepayB2cOnlineOrderqryRequestV1();
// //根据测试环境和生产环境替换相应ip和端口
// request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/orderqry/V1");
//
// //请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
// CardbusinessAggregatepayB2cOnlineOrderqryRequestV1.CardbusinessAggregatepayB2cOnlineOrderqryRequestV1Biz bizContent = new
// CardbusinessAggregatepayB2cOnlineOrderqryRequestV1.CardbusinessAggregatepayB2cOnlineOrderqryRequestV1Biz();
// request.setBizContent(bizContent);
//
// bizContent.setMer_id(MER_ID);//商户编号‐必输项
//
// //商户订单号
// bizContent.setOut_trade_no(out_trade_no);
//
// //bizContent.setOrder_id("020001030558000611912230005002");
// bizContent.setDeal_flag("0");
// bizContent.setIcbc_appid(GH_APP_ID);
//
// CardbusinessAggregatepayB2cOnlineOrderqryResponseV1 response;
log.debug("------------------------------查询单号:"+out_trade_no);
// sang:注释icbc部分
// try{
// response=client.execute(request,"bdby" + System.currentTimeMillis());
// //msgId消息通讯唯一编号要求每次调用独立生成APP级唯一
//
// if(response.getReturnCode()==0){
// //6、业务成功处理请根据接口文档用response.getxxx()获取同步返回的业务数据
// log.debug("查询ReturnCode:"+response.getReturnCode());
// log.debug("查询response:"+JSON.toJSONString(response));
// ret=JSON.toJSONString(response);
// }else{
// //失败
// log.debug("查询response:"+JSON.toJSONString(response));
// log.debug("查询ReturnCode:"+response.getReturnCode());
// log.debug("查询ReturnMsg:"+response.getReturnMsg());
// ret=JSON.toJSONString(response);
// }
// }catch(IcbcApiException e){
// e.printStackTrace();
// }
return ret;
}
/**
* 退款
* @param money 退款金额
* @param out_trade_no 订单号
* @return
*/
public String refundHis(Double money,String out_trade_no){
String ret = "";
//签名类型为RSA2时需传入appid私钥和网关公钥签名类型使用定值cbcConstants.SIGN_TYPE_RSA2其他参数使用缺省值
// sang:注释icbc部分
// DefaultIcbcClient client = new DefaultIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,
// MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1 request = new
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1();
// //根据测试环境和生产环境替换相应ip和端口
// request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/merrefund/V1");
// //请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz bizContent = new
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz();
// request.setBizContent(bizContent);
//
// bizContent.setMer_id(MER_ID);//商户编号‐必输项
//
// //商户订单号
// bizContent.setOut_trade_no(out_trade_no);
log.debug("------------------------------退款单号:"+out_trade_no);
//工行订单号
//bizContent.setOrder_id("060551080009000532107130007355");
// sang:注释icbc部分
// bizContent.setOuttrx_serial_no(VeDate.getNo(4));//外部退货流水号‐必输项
// //退货总金额‐必输项
// int m= (int) Math.round(money*100);
// bizContent.setRet_total_amt(""+m);
// bizContent.setTrnsc_ccy("001");//交易币种‐必输项
// bizContent.setOrder_apd_inf("");
// bizContent.setIcbc_appid(GH_APP_ID);
// bizContent.setMer_acct("");
// bizContent.setMer_prtcl_no(MER_PRTCL_NO);
//
// CardbusinessAggregatepayB2cOnlineMerrefundResponseV1 response;
// try {
// //msgId消息通讯唯一编号要求每次调用独立生成APP级唯一
// response = client.execute(request);
//
// if (response.isSuccess()) {
// // 业务成功处理请根据接口文档用response.getxxx()获取同步返回的业务数据
// // ret=response.getReturnCode();
// ret = JSON.toJSONString(response);
// log.debug("退费ICBC success return:" + ret);
// } else {
// // 失败
// ret = JSON.toJSONString(response);
// log.debug("退费ICBC failed return:" + ret);
// log.error("退费ReturnMsg:"+response.getReturnMsg());
// }
// } catch (IcbcApiException e) {
// e.printStackTrace();
// }
return ret;
}
/**
* 退款
* @param money 退款金额
* @param out_trade_no 订单号
* @return
*/
public int refund(Double money,String out_trade_no){
int ret = -1;
// sang:注释icbc部分
//签名类型为RSA2时需传入appid私钥和网关公钥签名类型使用定值cbcConstants.SIGN_TYPE_RSA2其他参数使用缺省值
// DefaultIcbcClient client = new DefaultIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,
// MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1 request = new
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1();
// //根据测试环境和生产环境替换相应ip和端口
// request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/merrefund/V1");
// //请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz bizContent = new
// CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz();
// request.setBizContent(bizContent);
//
// bizContent.setMer_id(MER_ID);//商户编号‐必输项
//
// //商户订单号
// bizContent.setOut_trade_no(out_trade_no);
System.out.println("------------------------------退款单号:"+out_trade_no);
//工行订单号
//bizContent.setOrder_id("060551080009000532107130007355");
// sang:注释icbc部分
// bizContent.setOuttrx_serial_no(VeDate.getNo(4));//外部退货流水号‐必输项
// //退货总金额‐必输项
// int m= (int) Math.round(money*100);
// bizContent.setRet_total_amt(""+m);
// bizContent.setTrnsc_ccy("001");//交易币种‐必输项
// bizContent.setOrder_apd_inf("");
// bizContent.setIcbc_appid(GH_APP_ID);
// bizContent.setMer_acct("");
// bizContent.setMer_prtcl_no(MER_PRTCL_NO);
//
// CardbusinessAggregatepayB2cOnlineMerrefundResponseV1 response;
// try {
// //msgId消息通讯唯一编号要求每次调用独立生成APP级唯一
// response = client.execute(request);
//
// if (response.isSuccess()) {
// // 业务成功处理请根据接口文档用response.getxxx()获取同步返回的业务数据
// ret=response.getReturnCode();
// } else {
// // 失败
// ret=response.getReturnCode();
// log.error("ReturnMsg:"+response.getReturnMsg());
// }
// } catch (IcbcApiException e) {
// e.printStackTrace();
// }
return ret;
}
/**
* 退款
* @param args
*/
/*public static void main(String[] args) {
//签名类型为RSA2时需传入appid私钥和网关公钥签名类型使用定值cbcConstants.SIGN_TYPE_RSA2其他参数使用缺省值
DefaultIcbcClient client = new DefaultIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,
MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
CardbusinessAggregatepayB2cOnlineMerrefundRequestV1 request = new
CardbusinessAggregatepayB2cOnlineMerrefundRequestV1();
//根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/merrefund/V1");
//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz bizContent = new
CardbusinessAggregatepayB2cOnlineMerrefundRequestV1.CardbusinessAggregatepayB2cOnlineMerrefundRequestV1Biz();
request.setBizContent(bizContent);
bizContent.setMer_id(MER_ID);//商户编号‐必输项
//商户订单号
//bizContent.setOut_trade_no("TJ202108061635073884");
//工行订单号
bizContent.setOrder_id("060551080009000512108060014521");
bizContent.setOuttrx_serial_no(VeDate.getNo(4));//外部退货流水号‐必输项
bizContent.setRet_total_amt("1");//退货总金额‐必输项
bizContent.setTrnsc_ccy("001");//交易币种‐必输项
bizContent.setOrder_apd_inf("");
bizContent.setIcbc_appid(GH_APP_ID);
bizContent.setMer_acct("");
CardbusinessAggregatepayB2cOnlineMerrefundResponseV1 response;
try {
//msgId消息通讯唯一编号要求每次调用独立生成APP级唯一
response = client.execute(request);
if (response.isSuccess()) {
// 业务成功处理请根据接口文档用response.getxxx()获取同步返回的业务数据
System.out.println("ReturnCode:"+response.getReturnCode());
System.out.println("response:" + response);
} else {
// 失败
System.out.println("ReturnCode:"+response.getReturnCode());
System.out.println("ReturnMsg:"+response.getReturnMsg());
}
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
/*public static void main(String[] args) {
//需传入appid私钥字符集
UiIcbcClient client = new UiIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8);
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1 request = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1();
//根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/aggregatepay/b2c/online/ui/consumepurchaseshowpay/V1");
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz();
request.setBizContent(bizContent);
//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
bizContent.setExpireTime("120");
bizContent.setIcbc_appid(GH_APP_ID);
bizContent.setMer_id(MER_ID);
bizContent.setMer_prtcl_no(MER_PRTCL_NO);
bizContent.setNotify_type("HS");
bizContent.setNotify_url("http://http://122.51.116.79:9081//inspect/subscribe/callback");
bizContent.setResult_type("0");
bizContent.setReturn_url("http://http://122.51.116.79:9081//dist/index.html#/Yygh?type=1");
//订单金额
bizContent.setOrder_amt("1");
String out="TJ"+VeDate.getNo(4);
System.out.println("-----------------"+out);
bizContent.setOut_trade_no(out);
bizContent.setSaledepname("赤峰市元宝山区妇幼保健计划生育服务中心");
String str="就医缴费";
bizContent.setBody(str);
try {
String ret=client.buildPostForm(request);
System.out.println(ret);
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
/**
* PC支付
* @param args
*//*
public static void main(String[] args) {
// 4、需传入appid私钥字符集
UiIcbcClient client = new UiIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,MY_PRIVATE_KEY,IcbcConstants.CHARSET_UTF8);
CardbusinessEpaypcConsumptionRequestV1 request = new
CardbusinessEpaypcConsumptionRequestV1();
// 5、根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/epaypc/consumption/V1");
CardbusinessEpaypcConsumptionRequestV1.CardbusinessEpaypcConsumptionRequestV1Biz bizContent = new
CardbusinessEpaypcConsumptionRequestV1.CardbusinessEpaypcConsumptionRequestV1Biz();
request.setBizContent(bizContent);
// 6、请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
//埋名或非埋名标志字典1-埋名2-非埋名,默认非埋名
bizContent.setIcbc_flag("1");
//工行API平台的APPID
bizContent.setIcbc_appid(GH_APP_ID);
SimpleDateFormat sf=new SimpleDateFormat("yyyyMMddHHmmss");
Date date=new Date();
//交易日期时间格式为yyyyMMddHHmmss要求在银行系统当前时间的前1小时和后12小时范围内否则判定交易时间非法
bizContent.setOrder_date(sf.format(date));
//订单有效日期,对订单的有效日期进
//行限定,输入类
//似”20110802152230”的时间串代表8
//月2日15:22:30之前支付订单有效。
bizContent.setExpire_time(sf.format(new Date(date.getTime()+300000)));
//商户订单号若该笔订单为招投标订单icbc_flag送2且order_flag_ztb上送1则该字段上送约定的招投标缴纳编号长度MAX(20)
bizContent.setOut_trade_no(VeDate.getNo(4));
//订单金额,单位分
bizContent.setAmount("1");
//分期付款期数1、3、6、9、12、
//18、241代表全额付款必须为以上
//述值,否则订单校验不通过
bizContent.setInstallment_times("1");
//交易币种,目前工行只支持使用人民
//币001支付
bizContent.setCur_type("001");
//商户编号
bizContent.setMer_id(MER_ID);
//收单协议编号
bizContent.setMer_prtcl_no(MER_PRTCL_NO);
//商户账号,商户入账账号,只能交易时指定。
bizContent.setMer_acct("0605024309200001696");
//商品名称
bizContent.setGoods_name("挂号");
//商户reference上送商户网站域名
//(支持通配符,例如“*.某B2C商
//城.com”如果上送工行会在客户
//支付订单时,校验商户上送域名与客
//户跳转工行支付页面之前网站域名的
//一致性
//bizContent.setMer_reference("xxx");
//商户获取用户的请求ip上送。当商户
//reference项送空时该项必输
bizContent.setMer_custom_ip("192.168.0.119");
//返回商户变量, 工行给商户发送商户通
//知时会原样返回,可参考响应报文中
//attach字段
bizContent.setMer_var(bizContent.getOut_trade_no());
//通知商户URL必须合法的URL交易
//结束银行使用HTTP协议POST方式
//向此地址发送通知信息;目前只支持
//80端口
bizContent.setMer_url("http://guahao.hzyqtkj.com/pay/callback");
//支付成功回显页面,支付成功后,跳
//转至该页面显示
bizContent.setReturn_url("xxx");
//当商户返回的商城取货地址为正常可
//达时,如该参数非空,则倒计时结束
//后自动跳转回商城取货地址对应链
//接,如不上送则默认不自动跳转。 单
//位(秒)
//bizContent.setAuto_refer_sec("xxx");
//联名校验标志。取值“1”客户支付
//时,网银判断该客户是否与商户联
//名,是则按上送金额扣帐,否则展现
//未联名错误我行联名商户可送“1”
//取值“0”不检验客户是否与商户联
//名,按上送金额扣帐。非联名商户请
//送“0”
bizContent.setVerify_join_flag("0");
//通知类型,表示在交易处理完成后把交易结果通知商户的处理模式。 取值“HS”在交易完成后将通知信息主动发送给商户发送地址为mer_url指定地址 取值“AG”在交易完成后不通知商户
bizContent.setNotify_type("HS");
//指定支付卡标志仅icbc_flag送1时使
//用。0-否1-是,不送或上送其他值按
//0-否处理如上送1则快捷支付及工
//行卡网银支付方式下,限定仅可使用
//指定卡完成交易。其他支付方式不作
//限制。
//bizContent.setE_fixedACFlag("xxx");
//默认“2”。有效取值0-仅借记卡1-仅信用卡2-All
bizContent.setCredit_type("2");
//订单有效间隔,单位为秒,若不输或
//输入值大于86400则按系统默认间隔
//处理
bizContent.setOrder_interval("600");
//订单附加信息
bizContent.setOrder_apd_inf("");
try {
boolean testFlag = true;
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"========================================");
System.out.println(client.buildPostForm(request));
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
/**
* H5支付
* @param args
*//*
public static void main(String[] args) {
// 4、需传入appid私钥字符集
UiIcbcClient client = new UiIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,MY_PRIVATE_KEY,IcbcConstants.CHARSET_UTF8);
CardbusinessEpayh5UiConsumptionRequestV1 request = new
CardbusinessEpayh5UiConsumptionRequestV1();
// 5、根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/aggregatepay/b2c/online/ui/consumepurchaseshowpay/V1");
CardbusinessEpayh5UiConsumptionRequestV1.CardbusinessEpayh5UiConsumptionRequestV1Biz bizContent = new CardbusinessEpayh5UiConsumptionRequestV1.CardbusinessEpayh5UiConsumptionRequestV1Biz();
request.setBizContent(bizContent);
// 6、请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
//工行API平台的APPID
bizContent.setIcbc_appid(GH_APP_ID);
SimpleDateFormat sf=new SimpleDateFormat("yyyyMMddHHmmss");
Date date=new Date();
//交易日期时间格式为YYYYMMDDHHmmss要求在银行系统当前时间的前1小时和后12小时范围内否则判定交易时间非法
bizContent.setOrder_date(sf.format(date));
//商户订单号
bizContent.setOrder_id(VeDate.getNo(4));
//订单金额,单位分
bizContent.setAmount("1");
//分期付款期数1、3、6、9、12、18、241代表全额付款必须为以上述值否则订单校验不通过
bizContent.setInstallment_times("1");
//交易币种目前工行只支持使用人民币001支付
bizContent.setCur_type("001");
//商户编号
bizContent.setMer_id(MER_ID);
//收单协议编号
bizContent.setMer_prtcl_no(MER_PRTCL_NO);
//商户账号,商户入账账号,只能交易时指定。(商户付给银行手续费的账户,可以在开户的时候指定,也可以用交易指定方式;用交易指定方式则使用此商户账号)
//bizContent.setMer_acct("xxx");
//通知商户URL必须合法的URL交易结束银行使用HTTP协议POST方式向此地址发送通知信息目前只支持80端口
bizContent.setMerURL("http://guahao.hzyqtkj.com/pay/callback");
//支付成功回显页面,支付成功后,跳转至该页面显示
bizContent.setReturn_url("http://www.baidu.com");
bizContent.setNotify_type("HS");
//选输收单接入方式4-H55-APP7-微信公众号8-支付宝生活号默认4
bizContent.setAccess_type("7");
//订单有效间隔单位为秒若不输或输入值大于86400则按系统默认间隔处理
bizContent.setOrder_interval("300");
try {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"========================================");
System.out.println(client.buildPostForm(request));
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
/**
* 聚合支付 埋名
* @param args
*/
/*public static void main(String[] args) {
//签名类型为RSA时需传入appid私钥和网关公钥签名类型使用定值IcbcConstants.SIGN_TYPE_RSA其他参数使用缺省值
DefaultIcbcClient client = new DefaultIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2,MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1();
//根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1");
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz();
//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
//商户编号
bizContent.setMer_id(MER_ID);
//商户订单号,只能是数字、大小写字母,且在同一个商户号下唯一
bizContent.setOut_trade_no(VeDate.getNo(4));
//支付方式9-微信10-支付宝
bizContent.setPay_mode("9");
//收单接入方式5-APP7-微信公众号8-支付宝生活号9-微信小程序
bizContent.setAccess_type("7");
//收单产品协议编号
bizContent.setMer_prtcl_no(MER_PRTCL_NO);
//交易日期时间格式为yyyyMM-dd'T'HH:mm:ss
bizContent.setOrig_date_time(new SimpleDateFormat("yyyy-MM-dd").format(new Date())+"T"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
//设备号
bizContent.setDecive_info("013467007042135");
*//*商品描述,商品描述交易字段格式根据不同的应用场景按照以下格式:
1PC网站传入浏览器打开的网站主页title名-实际商品名称
2公众号传入公众号名称-实际商品名称;
3H5传入浏览器打开的移动网页的主页title名-实际商品名称;
4线下门店门店品牌名-城市分店名实际商品名称;
5APP传入应用市场上的APP名字-实际商品名称*//*
bizContent.setBody("赤峰市元宝山区妇幼保健计划生育服务中心-挂号收费");
//交易币种目前工行只支持使用人民币001支付
bizContent.setFee_type("001");
//用户端IP
bizContent.setSpbill_create_ip("192.168.0.119");
//订单金额,单位为分
bizContent.setTotal_fee("1");
//异步通知商户URL端口必须为443或80
bizContent.setMer_url("http://guahao.hzyqtkj.com/pay/callback");
//商户在微信开放平台注册的APPID支付方式为微信时不能为空
bizContent.setShop_appid(WX_APP_ID);
//商户在工行API平台的APPID
bizContent.setIcbc_appid(GH_APP_ID);
//第三方用户标识商户在微信公众号内或微信小程序内接入时必送即access_type为7或9时上送用户在商户APPID下的唯一标识商户通过支付宝生活号接入时不送
bizContent.setOpen_id("o2RHm57mWjZDEINy1l0zAcpqC5fw");
//订单失效时间单位为秒建议大于60秒
bizContent.setExpire_time("120");
//通知类型,表示在交易处理完成后把交易结果通知商户的处理模式。 取值“HS”在交易完成后将通知信息主动发送给商户发送地址为mer_url指定地址 取值“AG”在交易完成后不通知商户
bizContent.setNotify_type("HS");
request.setBizContent(bizContent);
CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response;
try {
response = client.execute(request, System.currentTimeMillis()+"");
//msgId消息通讯唯一编号要求每次调用独立生成APP级唯一
if (response.getReturnCode() == 0) {
// 6、业务成功处理请根据接口文档用response.getxxx()获取同步返回的业务数据
System.out.println("ReturnCode:"+response.getReturnCode());
System.out.println("response:" + JSON.toJSONString(response));
} else {
// 失败
System.out.println("response:" + JSON.toJSONString(response));
System.out.println("ReturnCode:"+response.getReturnCode());
System.out.println("ReturnMsg:"+response.getReturnMsg());
}
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
/*public static void main(String[] args) {
//需传入appid私钥字符集
UiIcbcClient client = new UiIcbcClient(GH_APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8);
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1 request = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1();
//根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl("https://gw.open.icbc.com.cn/ui/cardbusiness/aggregatepay/b2c/online/ui/consumepurchaseshowpay/V1");
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz();
request.setBizContent(bizContent);
//请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值
bizContent.setExpireTime("120");
bizContent.setIcbc_appid(GH_APP_ID);
bizContent.setMer_id(MER_ID);
bizContent.setMer_prtcl_no(MER_PRTCL_NO);
bizContent.setNotify_type("HS");
bizContent.setNotify_url("http://guahao.hzyqtkj.com/pay/callback");
bizContent.setOrder_amt("1");
bizContent.setOut_trade_no(VeDate.getNo(4));
bizContent.setSaledepname("赤峰市元宝山区妇幼保健计划生育服务中心");
bizContent.setBody("挂号缴费");
bizContent.setSubject("");
try {
System.out.println(client.buildPostForm(request));
} catch (IcbcApiException e) {
e.printStackTrace();
}
}*/
}

View File

@@ -0,0 +1,906 @@
package com.guahao.api.walkinto.service;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.github.wxpay.sdk.WXPayUtil;
import com.guahao.api.counts.model.InterfaceCount;
import com.guahao.api.counts.service.InterfaceCountService;
import com.guahao.api.task.mapper.UserMzjfMapper;
import com.guahao.api.task.mapper.UserReserve8Mapper;
import com.guahao.api.walkinto.model.PayQueryDTO;
import com.guahao.api.walkinto.model.WxPay;
import com.guahao.h5.hsjc.mapper.HsjcMapper;
import com.guahao.h5.hsjc.service.TXSendMsg;
import com.guahao.h5.hsjc.vo.HsjcVo;
import com.guahao.h5.reserve.mapper.BinganMapper;
import com.guahao.h5.reserve.vo.BingAnVO;
import com.guahao.h5.reserve.vo.WxPayVo;
import com.guahao.h5.user.mapper.UserCardMapper;
import com.guahao.h5.user.mapper.UserOrderMapper;
import com.guahao.h5.user.model.UserCardVo;
import com.guahao.h5.user.model.UserOrder;
import com.guahao.h5.user.model.UserVo;
import com.guahao.h5.user.service.UserOrderService;
import com.guahao.h5.user.service.UserService;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import com.guahao.common.Exception.CustomException;
import com.guahao.common.config.WxPayConfig;
import com.guahao.common.util.*;
import com.guahao.h5.reserve.domain.WxResult;
import com.guahao.h5.reserve.mapper.Reserve8Mapper;
import com.guahao.h5.reserve.vo.HisRefundVo;
import com.guahao.h5.reserve.vo.Reserve8Vo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import tk.mybatis.mapper.entity.Example;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author SangChengZhi
* @date 2025年09月06日 9:30
* @desc
*/
@Service
@Slf4j
public class WxPayService {
@Autowired
private WxPayConfig wxPayConfig;
@Autowired
Reserve8Mapper reserve8Mapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
InterfaceCountService interfaceCountService;
@Autowired
private WxPayUtil wxPayUtil;
@Autowired
TXSendMsg txSendMsg;
@Autowired
private UserService userService;
@Autowired
private HsjcMapper hsjcMapper;
@Autowired
private UserCardMapper userCardMapper;
@Autowired
private UserOrderMapper userOrderMapper;
@Autowired
private UserMzjfMapper userMzjfMapper;
@Autowired
private BinganMapper binganMapper;
/**
* 处理微信支付回调
*/
public String handleWxPayNotify(String xmlStr) {
String paramTip = "";
Map<String, String> resultMap = new HashMap<>();
try {
paramTip = String.format(" >>> xmlStr:%s", xmlStr);
// 1. XML 转 Map
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
if (map.isEmpty()) {
throw new CustomException("400", "微信异步回调结果失败, xml转map为空");
}
// 2. 验签
boolean isValid = WXPayUtil.isSignatureValid(map, wxPayConfig.getApiKey());
if (!isValid) {
throw new CustomException("400", "微信支付回调验签失败");
}
log.info("微信支付回调签名验证成功");
// 3. 转换为对象
WxResult wxResult = JSON.parseObject(JSON.toJSONString(map), WxResult.class);
// 4. 检查支付结果
if ("SUCCESS".equals(wxResult.getReturn_code()) && "SUCCESS".equals(wxResult.getResult_code())) {
// 新增:关键!查询本地订单状态
if (wxResult.getOut_trade_no().startsWith("TL")){
List<Reserve8Vo> vos = reserve8Mapper.getReserveListByhisorderno(wxResult.getOut_trade_no());
log.info("挂号订单查询");
Reserve8Vo reserve8Vo = vos.get(0);
// 新增如果订单已被系统关闭app_status=4则拒绝支付回调
if (reserve8Vo.getAppStatus() == 4 ){
log.warn("收到已关闭订单的支付回调,拒绝处理: {}", wxResult.getOut_trade_no());
// 不调用 processRegistrationAfterPayment
// 返回 SUCCESS 是为了让微信不再重试通知
resultMap.put("return_code", "SUCCESS");
resultMap.put("return_msg", "");
return WXPayUtil.mapToXml(resultMap);
}
// 5. 处理挂号业务
processRegistrationAfterPayment(wxResult.getOut_trade_no(),wxResult.getTransaction_id());
}else if (wxResult.getOut_trade_no().startsWith("MZ")){
List<HsjcVo> mzvos = hsjcMapper.getMzjfListByOrderno(wxResult.getOut_trade_no());
log.info("缴费订单查询");
// List<HsjcVo> mzvos = hsjcMapper.getMzjfListByOrderno(wxResult.getOut_trade_no());
HsjcVo hsjcVo = mzvos.get(0);
log.info("查询结果hsjcvo{}",hsjcVo);
if (hsjcVo.getAppStatus() == 4){
log.warn("收到已关闭订单的支付回调,拒绝处理: {}", wxResult.getOut_trade_no());
resultMap.put("return_code", "SUCCESS");
resultMap.put("return_msg", "");
return WXPayUtil.mapToXml(resultMap);
}
// 处理缴费业务
MzconfirmAppoint(hsjcVo,wxResult.getOut_trade_no(),wxResult.getTransaction_id());
} else if (wxResult.getOut_trade_no().startsWith("YC")){
log.info("住院预交单订单查询");
// String msg_id = wxResult.get("msg_id").toString();
//业务请求字段获取
String outTradeNo = wxResult.getOut_trade_no();
//业务处理逻辑......
Example example = new Example(UserOrder.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("code", outTradeNo);
List<UserOrder> list = userOrderMapper.selectByExample(example);
UserOrder uo = list.get(0);
if (uo.getType() == 0) {
uo.setType(1);
uo.setIcbcCode(wxResult.getTransaction_id());
uo.setSuccesstime(DateUtils.getHisDateTime());
String strXML = UserOrderService.yujiaoPay(uo);// 封装请求数据
log.debug("reqxml 预交:" + strXML);
String responseStr = SoapUtil.soapMethod(strXML);// 发送请求
log.debug("resxml 预交:" + responseStr);
Map<String, Object> mapresult = XmlUtil.parse(responseStr); // 处理返回数据
if (mapresult.get("returncode").toString().equals("1")) {
uo.setHis_code(wxResult.getTransaction_id());
userOrderMapper.updateByPrimaryKey(uo);
UserVo userVo = userService.queryUserInfoDetails(uo.getUser_id());
String openid = userVo.getOpenid();
txSendMsg.SendNotifyYJJ(uo,openid);
}
}
}else if (wxResult.getOut_trade_no().startsWith("BA")){
// 病案缴费
log.info("病案缴费订单查询");
BingAnVO vo = binganMapper.selectByOrderNo(wxResult.getOut_trade_no());
if (vo.getStatus() == 2){
log.warn("收到已关闭订单的支付回调,拒绝处理: {}", wxResult.getOut_trade_no());
resultMap.put("return_code", "SUCCESS");
resultMap.put("return_msg", "");
return WXPayUtil.mapToXml(resultMap);
}
BAconfirmAppoint(vo,wxResult.getOut_trade_no(),wxResult.getTransaction_id());
}
}
// 6. 构建成功响应
resultMap.put("return_code", "SUCCESS");
resultMap.put("return_msg", "");
} catch (Exception e) {
log.error(">>> 微信支付回调失败 >>> " + paramTip + " 原因: " + ThrowableUtil.getStackTrace(e));
resultMap.put("return_code", "FAIL");
resultMap.put("return_msg", e.getMessage());
}
// 7. 返回 XML 响应
try {
return WXPayUtil.mapToXml(resultMap);
} catch (Exception e) {
log.error("返回微信支付回调通知组数据失败", e);
return buildFailResponse("系统异常");
}
}
/**
* 微信支付成功后处理病案业务
* @param vo
* @param outTradeNo
* @param transactionId
*/
private void BAconfirmAppoint(BingAnVO vo, String outTradeNo, String transactionId) {
try {
String jfXML = XmlUtil.OutpBAPayedConfirm(vo);
log.info("病案缴费确认支付resxml"+jfXML);
String respJfXml = SoapUtil.soapMethod(jfXML);
log.info("病案缴费确认支付reqxml"+respJfXml);
Map<String, Object> Jfmap = XmlUtil.parse(respJfXml);
if (Jfmap.get("ReturnCode").equals("1")){
String code = RandomUtil.randomNumbers(4);
binganMapper.updateReptnoByOrderNo(outTradeNo,Jfmap.get("RcptNo").toString(),code);
// UserVo userVo = userService.queryUserInfoDetails(Integer.valueOf(vo.getUserId()));
// String openid = userVo.getOpenid();
// //微信推送
// txSendMsg.SendNotifyBAYJ(openid,vo.getHosNumber(),vo.getPages(),vo.getAmount(),DateUtils.getHisDateTimeChineseFormat());
// 记录统计
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(vo.getUserId());
interfaceCount.setInterfaceIdentification("BA");
interfaceCountService.updateInterfaceConut(interfaceCount);
}else {
log.error("his病案缴费失败: " + Jfmap.get("ErrorMsg"));
throw new CustomException("400", "his病案缴费失败: " + Jfmap.get("ErrorMsg"));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 微信支付成功后处理门诊缴费业务
* @param outTradeNo MZXXXX
* @param transactionId 4200002868202509263849320128 powertraidId
*/
private void MzconfirmAppoint(HsjcVo hsjcVo,String outTradeNo, String transactionId) {
try {
// 记录统计
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(hsjcVo.getUserId()));
interfaceCount.setInterfaceIdentification("MZ");
interfaceCountService.updateInterfaceConut(interfaceCount);
// 下一步搞相关的数据,然后确认缴费
Reserve8Vo reserve8Vo = new Reserve8Vo();
reserve8Vo.setPatientid(hsjcVo.getPatientid());
reserve8Vo.setBillsMsg(hsjcVo.getFlowno());
reserve8Vo.setPaynature(Integer.valueOf(hsjcVo.getPaynature()));
reserve8Vo.setPaytype(hsjcVo.getPaytype());
reserve8Vo.setPowertranid(outTradeNo);
reserve8Vo.setTerminalid(hsjcVo.getTerminalid());
reserve8Vo.setZfamount(WxPayDUtil.parseToBigDecimal(hsjcVo.getBillmoney()));
if (hsjcVo.getYbzhamount() == null ){
reserve8Vo.setYbzhamount(BigDecimal.ZERO);
}else {
reserve8Vo.setYbzhamount(WxPayDUtil.parseToBigDecimal(hsjcVo.getYbzhamount()));
}
// reserve8Vo.setYbtcamount(WxPayDUtil.parseToBigDecimal(hsjcVo.getYbtcamount()));
reserve8Vo.setHisopernum(hsjcVo.getHisopernum());
reserve8Vo.setRootObject(null);
// // 做缴费确认支付操作,此处无用
String jfXML = XmlUtil.confirmOpAppPayed(reserve8Vo);
log.info("缴费确认支付resxml"+jfXML);
String respJfXml = SoapUtil.soapMethod(jfXML);
log.info("缴费确认支付reqxml"+respJfXml);
Map<String, Object> Jfmap = XmlUtil.parse(respJfXml);
// log.info("缴费确认支付map"+Jfmap);
if (Jfmap.get("ReturnCode").equals("-1")){
log.error("his挂号缴费失败: " + Jfmap.get("ErrorMsg"));
throw new CustomException("400", "his挂号缴费失败: " + Jfmap.get("ErrorMsg"));
}
hsjcMapper.opUpdateReptNobyOrder(outTradeNo,Jfmap.get("RcptNo").toString(),transactionId);
if (Jfmap.get("ReturnCode").equals("1")) {
log.info("his挂号缴费成功,收据/发票号:"+Jfmap.get("RcptNo"));
//推送微信消息
UserVo userVo = userService.queryUserInfoDetails(hsjcVo.getUserId());
hsjcMapper.opUpdateOrderByHis(4,outTradeNo);
// UserCardVo userCardVo = new UserCardVo();
// userCardVo.setCardNo(hsjcVo.getPatientid());
String cardNo = hsjcVo.getPatientid();
List<UserCardVo> userCardVos = userCardMapper.queryUserCardListByCardno(cardNo);
String name = userCardVos.get(0).getName();
txSendMsg.SendNotifyMZ("缴费成功", userVo.getOpenid(), name, hsjcVo.getBillmoney(), DateUtils.getTimes(),Jfmap.get("RcptNo").toString(), "on3VOL4p5sf6RfvP9ttnV8EuVm39javFnSlJnsW_yPE");
}else {
log.error("his挂号缴费失败: " + Jfmap.get("ErrorMsg"));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 微信支付成功后处理挂号逻辑
* @param outTradeNo 商户订单号
*/
private void processRegistrationAfterPayment(String outTradeNo,String transactionId) {
log.info("transactionId:"+transactionId);
String lockKey = "wxpay_notify:" + outTradeNo;
try {
// 1. 尝试获取分布式锁30秒过期
Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 30, TimeUnit.SECONDS);
if (Boolean.FALSE.equals(isLocked)) {
log.warn("重复回调,已加锁: {}", outTradeNo);
return;
}
// 根据订单号查询挂号信息
Reserve8Vo vo = new Reserve8Vo();
vo.setOrderno(outTradeNo);
List<Reserve8Vo> list = reserve8Mapper.getReserveList(vo);
if (list != null && !list.isEmpty()) {
Reserve8Vo reserveVo = list.get(0);
// 检查是否已经处理过(避免重复处理)
if (reserveVo.getAppStatus() == 3) {
log.info("订单已处理,无需重复处理: " + outTradeNo);
return;
}
// // 移除Redis中的临时订单数据
// String redisKey = "order:temp:" + reserveVo.getOrderno();
// redisTemplate.delete(redisKey);
//
// // 从过期订单集合中移除
// redisTemplate.opsForZSet().remove("order:expiring", reserveVo.getOrderno());
// 覆盖为微信订单号
// reserveVo.setPowertranid(transactionId);
// 做挂号确认操作
String strConfirmXML = XmlUtil.confirmOpAppRegist(reserveVo);
String respConfirmXml = SoapUtil.soapMethod(strConfirmXML);
log.debug("OutpReserveConfirm req:" + strConfirmXML);
log.debug("OutpReserveConfirm res:" + respConfirmXml);
// 解析报文
Map<String, Object> mapConfirm = XmlUtil.parse(respConfirmXml);
if (mapConfirm.get("returncode").toString().equals("1")) {
// 更新挂号信息
if (mapConfirm.get("ReptNum") != null) {
reserveVo.setReptnum(mapConfirm.get("ReptNum").toString());
}
if (mapConfirm.get("SerialNo") != null) {
reserveVo.setSerialno(mapConfirm.get("SerialNo").toString());
}
if (mapConfirm.get("Location") != null) {
reserveVo.setLocation(mapConfirm.get("Location").toString());
}
if (mapConfirm.get("TiketNo") != null) {
reserveVo.setTicketno(mapConfirm.get("TiketNo").toString());
}
reserveVo.setPowertranid(transactionId);
// 允许退号标志 N 不允许 Y 允许
// reserveVo.setAppFlag("Y");
// 单据状态 1 已退费 0 正常 2 已消号 3 挂号成功(抢号成功) 4 已缴费
reserveVo.setAppStatus(4);
// 1 预约挂号 2 今日挂号 8医院不区分
// reserveVo.setAppType(2);
reserve8Mapper.opConfirmAppoint(reserveVo);
UserVo voUser = userService.queryUserInfoDetails(reserveVo.getUserId());
try {
log.info("推送消息给公众号openid:{}", voUser.getOpenid());
//推送消息给公众号
txSendMsg.SendNotifyGH("挂号成功", voUser.getOpenid(), reserveVo.getName(), reserveVo.getKsmc(), reserveVo.getYsmc(), reserveVo.getRegisterdate()+" "+reserveVo.getTimeinterval(), "XQQAg3l56vhHDYj1grFNxF5lgL6yz8_zXuQdRBk_nMc");
} catch (Exception e) {
log.error("挂号推送消息失败");
throw new RuntimeException(e);
}
// 记录统计
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(reserveVo.getUserId()));
interfaceCount.setInterfaceIdentification("TL");
interfaceCountService.updateInterfaceConut(interfaceCount);
// // 做缴费确认支付操作,此处无用
// String jfXML = XmlUtil.confirmOpAppPayed(reserveVo);
// log.info("缴费确认支付resxml"+jfXML);
// String respJfXml = SoapUtil.soapMethod(jfXML);
// log.info("缴费确认支付reqxml"+respJfXml);
// // 解析报文
// Map<String, Object> Jfmap = XmlUtil.parse(respJfXml);
// if (Jfmap.get("returncode").toString().equals("1")) {
// log.info("his挂号缴费成功,收据/发票号:"+Jfmap.get("RcptNo"));
// }else {
// log.error("his挂号缴费失败: " + Jfmap.get("errormsg"));
// }
log.info("挂号处理成功: " + outTradeNo);
} else {
log.error("挂号确认失败,将自动退款: " + mapConfirm.get("errormsg"));
// 可以考虑发起退款
refundOrder(outTradeNo, String.valueOf(reserveVo.getZfamount()));
}
} else {
log.warn("未找到对应订单: " + outTradeNo);
}
} catch (Exception e) {
log.error("处理挂号逻辑异常: " + outTradeNo, e);
// 根据业务需求决定是否需要发起退款或其他补偿措施
} finally {
// 3. 释放锁
redisTemplate.delete(lockKey);
}
}
public String buildFailResponse(String message) {
Map<String, String> result = new HashMap<>();
result.put("return_code", "FAIL");
result.put("return_msg", message);
try {
return WXPayUtil.mapToXml(result);
} catch (Exception e) {
log.error("构建失败响应失败", e);
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[系统错误]]></return_msg></xml>";
}
}
public Map<String, String> queryOrder(String outTradeNo) {
Map<String, String> data = new HashMap<>();
data.put("appid", wxPayConfig.getAppId());
data.put("mch_id", wxPayConfig.getMchId());
data.put("out_trade_no", outTradeNo);
data.put("nonce_str", RandomUtil.randomString(32));
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
// 1. 生成签名
String sign = WxPayDUtil.generateSignature(data, wxPayConfig.getApiKey());
data.put("sign", sign);
// 2. 转 XML
WxPayUtil wxPayUtil = new WxPayUtil();
String xmlParam = wxPayUtil.mapToXml(data);
log.info("Query_xmlParam" + xmlParam);
// 3. 创建 HttpClient 和 HttpPost
client = HttpClients.createDefault();
httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/orderquery");
httpPost.setHeader("Content-Type", "text/xml; charset=utf-8");
// 4. 设置请求体
StringEntity entity = new StringEntity(xmlParam, "UTF-8");
httpPost.setEntity(entity);
// 5. 执行请求
response = client.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
throw new CustomException("500", "HTTP请求失败状态码" + statusCode);
}
// 6. 获取响应
HttpEntity responseEntity = response.getEntity();
if (responseEntity == null) {
throw new CustomException("500", "微信支付接口返回空响应");
}
String responseXml = EntityUtils.toString(responseEntity, "UTF-8");
log.info("Query_responseXml: " + responseXml);
// 7. 解析 XML
Map<String, String> resultMap = wxPayUtil.xmlToMap(responseXml);
if (resultMap == null) {
throw new CustomException("500", "微信支付查询接口返回空");
}
// 8. 校验通信状态
String returnCode = resultMap.get("return_code");
if (!"SUCCESS".equals(returnCode)) {
String returnMsg = resultMap.get("return_msg");
throw new CustomException("500", "通信失败:" + returnMsg);
}
// 9. 校验业务结果
String resultCode = resultMap.get("result_code");
if (!"SUCCESS".equals(resultCode)) {
String errCode = resultMap.get("err_code");
String errCodeDes = resultMap.get("err_code_des");
throw new CustomException(errCode, "查询失败:" + errCodeDes);
}
return resultMap;
} catch (Exception e) {
log.error("查询微信支付订单状态失败", e);
throw new RuntimeException(e);
} finally {
// 释放资源
try {
if (response != null) {
response.close();
}
if (httpPost != null) {
httpPost.releaseConnection();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
log.warn("关闭 HTTP 连接时发生异常", e);
}
}
}
public Map<String, String> refundOrder(String powertranid,String amount) {
Map<String, String> data = new HashMap<>();
data.put("appid", wxPayConfig.getAppId());
data.put("mch_id", wxPayConfig.getMchId());
data.put("nonce_str", RandomUtil.randomString(32));
data.put("out_trade_no", powertranid);
data.put("out_refund_no", WxPayDUtil.makeNo("TF"));
// 此处暂时修改为1分
// String money ="1";
String money = WxPayDUtil.yuanToFee(amount);
data.put("total_fee", money);
data.put("refund_fee", money);
data.put("notify_url", "https://nxwj.btlsoln.com/nxgzh/pay/wxRefund/notify");
data.put("op_user_id", wxPayConfig.getMchId()); // 操作员 = 商户号
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
// 1. 生成签名
String sign = WxPayDUtil.generateSignature(data, wxPayConfig.getApiKey());
data.put("sign", sign);
// 2. 转为 XML
WxPayUtil wxPayUtil = new WxPayUtil();
String xmlParam = wxPayUtil.mapToXml(data);
log.info("Refund Request XML: " + xmlParam);
// 3. 加载 p12 证书(关键:退款必须用证书)
KeyStore keyStore = KeyStore.getInstance("PKCS12");
String certPath = wxPayConfig.getCertPath(); // 例如: /cert/apiclient_cert.p12
try (FileInputStream instream = new FileInputStream(certPath)) {
keyStore.load(instream, wxPayConfig.getMchId().toCharArray()); // 证书密码 = 商户号
}
// 4. 创建 SSL 上下文
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, wxPayConfig.getMchId().toCharArray()) // 加载密钥
.build();
// 5. 创建支持双向认证的 HttpClient
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, // 支持的协议
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
);
client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
// 6. 创建请求
httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
httpPost.setHeader("Content-Type", "text/xml; charset=utf-8");
// 7. 设置请求体
StringEntity entity = new StringEntity(xmlParam, "UTF-8");
httpPost.setEntity(entity);
// 8. 执行请求
response = client.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
throw new CustomException("500", "HTTP请求失败状态码" + statusCode);
}
// 9. 获取响应
HttpEntity responseEntity = response.getEntity();
if (responseEntity == null) {
throw new CustomException("500", "微信退款接口返回空响应");
}
String responseXml = EntityUtils.toString(responseEntity, "UTF-8");
log.info("Refund Response XML: " + responseXml);
// 10. 解析 XML
Map<String, String> resultMap = wxPayUtil.xmlToMap(responseXml);
if (resultMap == null || resultMap.isEmpty()) {
throw new CustomException("500", "微信退款接口返回空");
}
// 11. 校验通信状态
String returnCode = resultMap.get("return_code");
if (!"SUCCESS".equals(returnCode)) {
String returnMsg = resultMap.get("return_msg");
log.error("微信退款通信失败: {}", returnMsg);
throw new CustomException("500", "通信失败:" + returnMsg);
}
// 12. 校验业务结果
String resultCode = resultMap.get("result_code");
String errCodeDes = resultMap.get("err_code_des");
if (!"SUCCESS".equals(resultCode) && "订单已全额退款".equals(errCodeDes)) {
log.info("订单已全额退款");
return resultMap;
}else if (!"SUCCESS".equals(resultCode) && !"订单已全额退款".equals(errCodeDes)){
String errCode = resultMap.get("err_code");
// String errCodeDes = resultMap.get("err_code_des");
log.error("微信退款业务失败: {} - {}", errCode, errCodeDes);
throw new CustomException(errCode, "退款失败:" + errCodeDes);
}
// ✅ 退款成功,返回结果
return resultMap;
} catch (Exception e) {
log.error("微信退款请求失败", e);
throw new RuntimeException("微信退款失败: " + e.getMessage(), e);
} finally {
// 释放资源
try {
if (response != null) {
response.close();
}
if (httpPost != null) {
httpPost.releaseConnection();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
log.warn("关闭 HTTP 连接时发生异常", e);
}
}
}
public String handleWxRefundNotify(String xmlData) {
log.info("进入退款回调");
try {
// 1. 解析外层 XML
log.info("微信退款回调通知 XML: " + xmlData);
WxPayUtil wxPayUtil = new WxPayUtil();
Map<String, String> notifyMap = wxPayUtil.xmlToMap(xmlData);
String returnCode = notifyMap.get("return_code");
if (!"SUCCESS".equals(returnCode)) {
log.warn("微信通知失败: return_code={}", returnCode);
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[处理失败]]></return_msg></xml>";
}
String reqInfo = notifyMap.get("req_info");
if (reqInfo == null || reqInfo.isEmpty()) {
log.warn("req_info 为空");
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[参数缺失]]></return_msg></xml>";
}
// 2. 解密 req_info使用 APIv2 key
String apiKey = wxPayConfig.getApiKey(); // 确保这是 32 位的 API 密钥
String decryptData;
try {
decryptData = decryptReqInfo(reqInfo,apiKey);
} catch (Exception e) {
log.error("解密 req_info 失败", e);
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[解密失败]]></return_msg></xml>";
}
log.info("解密后的退款数据: " + decryptData);
// 3. 解析明文 XML
Map<String, String> refundResult = wxPayUtil.xmlToMap(decryptData);
String outTradeNo = refundResult.get("out_trade_no");
String outRefundNo = refundResult.get("out_refund_no");
String refundStatus = refundResult.get("refund_status"); // SUCCESS / FAIL / PROCESSING
log.info("退款结果: out_trade_no={}, out_refund_no={}, status={}", outTradeNo, outRefundNo, refundStatus);
//
// if (refundService.isAlreadyProcessed(outRefundNo)) {
// log.info("退款单 {} 已处理,跳过", outRefundNo);
// return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
// }
// 5. 处理业务逻辑
if ("SUCCESS".equals(refundStatus)) {
Reserve8Vo vo = new Reserve8Vo();
vo.setOrderno(outTradeNo);
List<Reserve8Vo> reserveList = reserve8Mapper.getReserveList(vo);
if (reserveList.isEmpty()){
if (outTradeNo.substring(0, 2).equals("YC")){
//业务处理逻辑......
Example example = new Example(UserOrder.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("code", outTradeNo);
List<UserOrder> list = userOrderMapper.selectByExample(example);
UserOrder uo = list.get(0);
userOrderMapper.SelectUserOrderByCode(outTradeNo,3);
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(uo.getUser_id()));
interfaceCount.setInterfaceIdentification("YCTF");
interfaceCountService.updateInterfaceConut(interfaceCount);
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}else if (outTradeNo.substring(0, 2).equals("MZ")){
HsjcVo hsjcvo = new HsjcVo();
hsjcvo.setOrderno(outTradeNo);
List<HsjcVo> list = hsjcMapper.getMzjfListByFlow(hsjcvo);
hsjcvo = list.get(0);
hsjcMapper.updateByOutTradeNo(outTradeNo,5);
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(hsjcvo.getUserId()));
interfaceCount.setInterfaceIdentification("MZTF");
interfaceCountService.updateInterfaceConut(interfaceCount);
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}else if (outTradeNo.substring(0, 2).equals("BA")){
// 手动病案退款
binganMapper.updateByOrderNoAndStatus(outTradeNo);
// InterfaceCount interfaceCount = new InterfaceCount();
// interfaceCount.setUserId(Integer.toString(hsjcvo.getUserId()));
// interfaceCount.setInterfaceIdentification("BATF");
// interfaceCountService.updateInterfaceConut(interfaceCount);
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}
}
Reserve8Vo reserveVo = reserveList.get(0);
// 4. 冪等处理
if (reserveVo.getAppStatus() != null && reserveVo.getAppStatus().intValue() == 1) {
// 处理逻辑
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
}
if (!reserveList.isEmpty()) {
// 更新状态1 已退费
reserve8Mapper.opAppPayAppoint(outTradeNo, "Y", 1,"");
// 统计
InterfaceCount interfaceCount = new InterfaceCount();
interfaceCount.setUserId(Integer.toString(reserveVo.getUserId()));
interfaceCount.setInterfaceIdentification("TH");
interfaceCountService.updateInterfaceConut(interfaceCount);
log.info("退款成功,订单 {} 已更新", outTradeNo);
} else {
log.warn("未找到订单: {}", outTradeNo);
}
} else {
log.warn("退款未成功: {}", refundStatus);
}
// 6. 返回成功
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
} catch (Exception e) {
log.error("处理退款回调异常", e);
// ❗❗❗ 重要:返回 FAIL让微信重试
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[处理异常]]></return_msg></xml>";
}
}
/**
* 解密微信退款通知中的 req_infoV2 版本AES-256-CBC
* @param
* @param apiKey APIv2 密钥32位字符串
* @return 明文 XML 字符串
*/
public static String decryptReqInfo(String reqInfo, String apiKey) throws Exception {
// 1. 对 API Key 进行 MD5 哈希,得到 32 位小写十六进制字符串
String md5Key = DigestUtils.md5DigestAsHex(apiKey.getBytes(StandardCharsets.UTF_8)).toLowerCase();
// 2. 将 MD5 字符串转换为字节数组作为 AES 密钥
byte[] keyBytes = md5Key.getBytes(StandardCharsets.UTF_8);
// 3. Base64 解码加密数据
byte[] encryptedData = Base64.getDecoder().decode(reqInfo);
// 4. 使用 AES/ECB/PKCS5Padding 模式解密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decrypted = cipher.doFinal(encryptedData);
return new String(decrypted, StandardCharsets.UTF_8);
}
/**
* 关单方法
*/
@Transactional(rollbackFor = Exception.class)
public boolean closeOrder(String orderNo) {
// log.info("关单方法: {}", orderNo);
// 获取分布式锁,防止重复处理
String lockKey = "order:lock:" + orderNo;
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.MINUTES);
if (!locked) {
log.info("订单{}正在被其他进程处理", orderNo);
return false;
}
try {
// 1. 检查订单是否已支付
// 这里应该先查数据库确认订单状态
List<Reserve8Vo> vos = reserve8Mapper.getReserveListByhisorderno(orderNo);
Reserve8Vo order = vos.get(0);
if (order != null && "3".equals(order.getAppStatus())) {
log.info("订单{}已支付,无需关单", orderNo);
return false;
}
// 2. 调用微信关单API
boolean wxCloseSuccess = closeWxOrder(orderNo);
if (!wxCloseSuccess) {
log.error("微信关单失败: {}", orderNo);
// 可以考虑重试机制
}else {
// 3. 更新数据库订单状态为已关闭
reserve8Mapper.opAppPayAppoint(orderNo,"Y", 2, ""); // 2表示已关闭
// 4. 清理Redis数据
String tempKey = "order:temp:" + orderNo;
redisTemplate.delete(tempKey);
redisTemplate.opsForZSet().remove("order:expiring", orderNo);
log.info("订单关单成功: {}", orderNo);
return true;
}
return false;
} finally {
// 释放分布式锁
redisTemplate.delete(lockKey);
}
}
/**
* 调用微信关单API
*/
public boolean closeWxOrder(String orderNo) {
try {
WxPayVo wxPayVo = new WxPayVo();
wxPayVo.setOutTradeNo(orderNo);
Map<String, String> result = wxPayUtil.closeOrder(wxPayVo);
// 必须同时判断
if ("SUCCESS".equals(result.get("return_code"))
&& "SUCCESS".equals(result.get("result_code"))) {
return true;
} else {
// 关单失败,不要更新本地状态为“已关闭”
log.warn("关单未成功,不更新本地状态: {}", wxPayVo.getOutTradeNo());
return false;
// TODO: 可加入重试队列如5秒后重试
}
} catch (Exception e) {
// 关键:打印异常类型 + 消息 + 堆栈
log.error(" 调用微信关单API异常 | 订单号: {} | 异常类型: {} | 消息: {}",
orderNo,
e.getClass().getSimpleName(),
e.getMessage() == null ? "null" : e.getMessage(),
e); // e 必须放最后,才能输出堆栈
return false;
}
}
}