微信后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
11 KiB

package com.ynxbd.wx.wxfactory;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.helper.common.*;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException;
import com.ynxbd.wx.config.WeChatConfig;
import com.ynxbd.wx.wxfactory.base.auth.models.RespAccessToken;
import com.ynxbd.wx.wxfactory.bean.*;
import com.ynxbd.wx.wxfactory.medical.MdConfig;
import com.ynxbd.wx.wxfactory.utils.WxSignHelper;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.Cache;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class WxMedicalHelper {
private static final RepeatKeyHelper KEYS = new RepeatKeyHelper(60);
/**
* [医保]获取用户信息
*
* @param openid openid
* @param qrCode 授权
*/
public static MedicalUserInfo getUserInfo(String openid, String qrCode, String cardNo, String realName) throws ServiceException {
log.info("[医保]获取用户信息 openid={}, qrCode={}", openid, qrCode);
MedicalUserInfo info = WxFactory.Medical.Common().getUserInfo(MdConfig.PARTNER_URL, openid, qrCode);
if (info == null || !info.isSuccess()) {
String message = info == null ? "授权失败" : info.getMessage();
log.info("[医保授权]失败 {}", message);
throw new ServiceException(message);
}
if (cardNo != null) {
String meCardNo = info.getCardNo();
if (meCardNo != null && !cardNo.equals(meCardNo)) {
String tip = null;
if (realName != null) {
String userName = info.getUserName();
userName = ParamHelper.nameFilter(userName);
realName = ParamHelper.nameFilter(realName);
if (userName.length() < 3 && realName.length() < 3) {
userName += ParamHelper.idCardNoFilter(meCardNo);
realName += ParamHelper.idCardNoFilter(cardNo);
}
tip = String.format("医保卡绑定人是:【%s】,当前支付的订单属于患者:【%s】,该订单不属于医保卡本人,禁止支付", userName, realName);
}
log.info("【医保】不是本人禁止支付");
throw new ServiceException(ResultEnum.PAY_NO_SELF_NO_PAY, tip);
}
}
return info;
}
/**
* 医保支付回调
*
* @param request 请求
* @return 支付信息
*/
public static MedicalNotify medicalPayNotify(HttpServletRequest request) throws ServiceException {
try {
// 转换数据对象
Map<String, Object> paramsMap = WxSignHelper.getReqXmlParamsMap(request);
if (paramsMap == null) {
throw new ServiceException("【医保】回调通知下单信息返回错误");
}
// 签名验证
if (!WxSignHelper.validateSign(paramsMap, MdConfig.PAY_KEY)) { // 验证未通过,通知支付失败
throw new ServiceException("【医保】回调通知签名验证未通过!");
}
String json = JsonHelper.toJsonString(paramsMap);
if ("".equals(json)) {
throw new ServiceException("【医保】回调通知下单信息为空");
}
MedicalNotify notifyInfo = JsonHelper.parseObject(json, MedicalNotify.class);
if (notifyInfo == null) {
throw new ServiceException("【医保】回调通知下单信息转换失败");
}
String openid = notifyInfo.getOpenid();
String outTradeNo = notifyInfo.getHospOutTradeNo();
String medTransId = notifyInfo.getMedTransId();
BigDecimal totalFee = notifyInfo.getTotalFee();// 金额
BigDecimal cashFee = notifyInfo.getCashFee();
BigDecimal insuranceFee = notifyInfo.getInsuranceFee();
String timeEnd = notifyInfo.getTimeEnd();
if (openid == null || outTradeNo == null || medTransId == null || totalFee == null || cashFee == null || insuranceFee == null || timeEnd == null) {
throw new ServiceException(String.format("【医保】下单信息返回错误 outTradeNo={%s}", outTradeNo));
}
// 已处理 去重
if (KEYS.isContainsKey(medTransId)) {
throw new ServiceException(ResultEnum.PAY_NOTIFY_REPEAT, String.format("【医保】[重复请求]下单信息去重 outTradeNo={%s}", outTradeNo));
}
String info = WxSignHelper.getMapInfo(paramsMap, "response_content");
Map<String, String> dateMap = WxSignHelper.getDateMap(timeEnd);
notifyInfo.setPayDate(dateMap.get(WxSignHelper.DATE_KEY));
notifyInfo.setPayTime(dateMap.get(WxSignHelper.TIME_KEY));
//
notifyInfo.setInfo(info);
notifyInfo.setCashFee(cashFee.movePointLeft(2));
notifyInfo.setInsuranceFee(insuranceFee.movePointLeft(2));
notifyInfo.setTotalFee(totalFee.movePointLeft(2));
return notifyInfo;
} catch (Exception e) {
if (e instanceof ServiceException) {
throw e;
}
ErrorHelper.println(e);
throw new ServiceException(String.format("【医保】支付通知异常:[%s]", e.getMessage()));
}
}
/**
* [医保]创建订单
*
* @param outTradeNo 订单号
* @param openid openid
* @param cardNo 卡号
* @param realName 真实姓名
* @param payOrdId 医保订单号
* @param payAuthNo 用户授权码
* @param totalFee 支付总金额
* @param insuranceFee 个账 + 统筹支付金额
* @param cashFee 现金支付金额
* @param notifyUrl 回调地址
* @param callbackUrl 跳转地址
* @param body 说明
* @param attach 额外字段(通知类型)
*/
public static Map<String, Object> createOrder(OrderTypeEnum orderTypeEnum, String outTradeNo, String serialNo, String openid, String cardNo, String realName, String ip, String payOrdId, String payAuthNo,
BigDecimal totalFee, BigDecimal insuranceFee, BigDecimal cashFee, String notifyUrl, String callbackUrl, String body, String attach) throws ServiceException {
Map<String, Object> map = new HashMap<>();
log.info("[微信医保]下单 outTradeNo={}, openid={}, cardNo={}, realName={}, payOrdId={}, payAuthNo={}, totalFee={}, insuranceFee={}, cashFee={}"
, outTradeNo, openid, cardNo, realName, payOrdId, payAuthNo, totalFee, insuranceFee, cashFee);
MedicalPayOrder order = WxFactory.Medical.Common().createOrder(orderTypeEnum, WxCacheHelper.getAccessToken(),
MdConfig.MD_APP_ID, WeChatConfig.MCH_ID, MdConfig.PAY_KEY,
MdConfig.CITY_CODE, MdConfig.HOSPITAL_NAME, MdConfig.ORG_NO, MdConfig.CHANNEL,
openid,
payAuthNo,
payOrdId,
outTradeNo,
serialNo,
totalFee,
insuranceFee,
cashFee,
cardNo,
realName,
ip,
notifyUrl,
callbackUrl,
body,
attach);
log.info("【医保】创建订单 {}", order);
if (order == null) {
throw new ServiceException("【医保】请求失败");
}
if (!order.isOk()) {
throw new ServiceException(order.getMessage());
}
String payUrl = order.getPayUrl();
if (payUrl == null) {
throw new ServiceException("【医保】下单链接为空");
}
log.info("[医保]下单url payUrl={}", payUrl);
map.put("payUrl", payUrl);
return map;
}
/**
* [医保]订单查询
*
* @param accessToken accessToken
* @param outTradeNo 订单号
* @param medTransId 医保订单号
*/
public static MedicalOrder queryOrder(String accessToken, String outTradeNo, String medTransId) {
return WxFactory.Medical.Common().queryOrder(
accessToken,
MdConfig.MD_APP_ID,
WeChatConfig.MCH_ID,
MdConfig.PAY_KEY,
outTradeNo,
medTransId);
}
/**
* [医保]获取授权链接
*/
public static JSONObject getMdAuthUrl(String callbackUrl, String callNo) {
if (callNo != null) {
callNo = "?callNo=" + callNo;
}
JSONObject jsonObj = new JSONObject();
jsonObj.put("url", WxFactory.Medical.Common().getAuthUrl(WeChatConfig.getWebUrl() + callbackUrl) + callNo);
jsonObj.put("type", MerchantEnum.WX_MEDICAL.CODE);
return jsonObj;
}
/**
* [医保]获取授权链接
*/
public static MedicalOrder refund(String outTradeNo, String outRefundNo, String payOrdId, BigDecimal cashFee, String reason) {
return WxFactory.Medical.Common().refund(
WxCacheHelper.getAccessToken(),
MdConfig.MD_APP_ID,
WeChatConfig.MCH_ID,
MdConfig.PAY_KEY,
outTradeNo,
outRefundNo,
payOrdId,
cashFee,
reason
);
}
/**
* [医保]获取授权链接
*/
public static MedicalOrder downBill(String accessToken, String billDate, String billType) {
return WxFactory.Medical.Common().downBill(
accessToken,
MdConfig.MD_APP_ID,
WeChatConfig.MCH_ID,
MdConfig.PAY_KEY,
billDate,
billType);
}
/**
* [医保]获取授权链接
*/
public static MedicalRefundInfo queryRefund(String accessToken, String outTradeNo, String mdTransId) {
return WxFactory.Medical.Common().queryRefund(
accessToken,
MdConfig.MD_APP_ID,
WeChatConfig.MCH_ID,
MdConfig.PAY_KEY,
outTradeNo,
mdTransId);
}
/**
* [微信]获取token
*/
public synchronized static AccessToken getAccessToken(Cache<String, AccessToken> cache) {
if (cache == null) {
return null;
}
AccessToken cacheToken = cache.get(WxCacheHelper.ACCESS_TOKEN_CACHE_NAME);
if (cacheToken != null) {
return cacheToken;
}
RespAccessToken response = WxFactory.Base.OAuth().getAccessToken(MdConfig.MD_APP_ID, MdConfig.MD_APP_SECRET);
if (!response.isSuccess()) {
log.error("[微信]access_token请求失败 code={}, message={}", response.getErrCode(), response.getErrMsg());
return null;
}
AccessToken token = new AccessToken();
token.setAccessToken(response.getAccessToken());
token.setCreateTime(DateHelper.getCurDateTime());
return token;
}
}