微信后端代码
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.

473 lines
23 KiB

package com.ynxbd.bcm.config;
import com.alibaba.fastjson.JSONObject;
import com.bocom.api.DefaultBocomClient;
import com.bocom.api.utils.ApiUtils;
import com.ynxbd.bcm.bean.pmssMpng.*;
import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.PayResult;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.RepeatKeyHelper;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException;
import com.ynxbd.wx.config.WeChatConfig;
import com.ynxbd.wx.wxfactory.utils.WxSignHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
@Slf4j
public class BCMHelper {
// 排重
public static final RepeatKeyHelper KEYS = new RepeatKeyHelper(60);
// 支付类型JSAPI
public static String B2C_JSAPI_WECHAT = "B2C-JSAPI-WECHAT";
public static String VERSION = "V-1.0";
public static String ONLINE = "ONLINE"; // 线上或线下{ ONLINE/OFFLINE }
public static String CNY = "CNY"; // 币种
// head交易状态
private static final String RESP_STATUS_P = "P"; // 处理中
private static final String RESP_STATUS_F = "F"; // 失败
private static final String RESP_STATUS_S = "S"; // 成功
// 订单处理状态
private static final String TRAN_STATE_PROCESS = "PROCESS"; // 处理中
private static final String TRAN_STATE_SUCCESS = "SUCCESS"; // 交易成功
private static final String TRAN_STATE_FAILURE = "FAILURE"; // 交易失败
// body交易状态
private static final String ORDER_STATUS_PAIED = "PAIED"; // 交易成功
private static final String ORDER_STATUS_WAITPAY = "WAITPAY"; // 等待支付
private static final String ORDER_STATUS_REFUNDED = "REFUNDED"; // 部分退款
private static final String ORDER_STATUS_REFUNDALL = "REFUNDALL"; // 全部退款
private static final String ORDER_STATUS_CLOSED = "CLOSED"; // 部分退款
private static final String ORDER_STATUS_INITIAL = "INITIAL"; // 初始化
/**
* 交行支付调用及通知
*
* @param request 请求
* @return 交行支付信息
*/
public static PayResult payNotify(HttpServletRequest request) throws ServiceException {
try {
// 获取请求数据
String respJson = WxSignHelper.getReqData(request);
if (respJson == null) {
throw new ServiceException("【交行】回调通知参数解析失败");
}
PmmsMpngNotifyRequestV1.PmmsMpngNotifyRequestV1Biz bizContent;
bizContent = (PmmsMpngNotifyRequestV1.PmmsMpngNotifyRequestV1Biz) ApiUtils.parseNotifyJsonWithBocomSign(respJson, "UTF-8", BCMConfig.API_GW_PUBLIC_KEY, PmmsMpngNotifyRequestV1.PmmsMpngNotifyRequestV1Biz.class);
if (bizContent == null || !TRAN_STATE_SUCCESS.equals(bizContent.getTranState())) {
throw new ServiceException("【交行】回调通知参数缺失");
}
PmmsMpngNotifyRequestV1.PmmsMpngNotifyRequestV1Biz.RequireValues requireValues = bizContent.getRequireValues();
String bankTransNo = requireValues.getThirdPartyTranNo();
// 已处理 去重
if (KEYS.isContainsKey(bankTransNo)) {
throw new ServiceException(ResultEnum.PAY_NOTIFY_REPEAT, String.format("【交行】[重复请求]回调通知去重 bankTransNo={%s}", bankTransNo));
}
log.info("【交行】回调通知返回 bankTransNo={} resp={}", bankTransNo, JsonHelper.toJsonString(bizContent));
String outTradeNo = bizContent.getMerTranNo();
String bankMerchantNo = requireValues.getBankTranNo();
String totalAmount = bizContent.getTotalAmount();
if (outTradeNo == null || bankTransNo == null || bankMerchantNo == null) {
throw new ServiceException(String.format("【交行】回调通知错误 outTradeNo={%s}, bankTransNo={%s}, bankMerchantNo={%s}", outTradeNo, bankTransNo, bankMerchantNo));
}
// 保存支付结果
PayResult payInfo = new PayResult();
payInfo.setPatDate(DateHelper.getCurDate());
payInfo.setPatDate(DateHelper.getCurTime());
payInfo.setOutTradeNo(outTradeNo);
payInfo.setTransId(bankTransNo);
payInfo.setBankMerchantNo(bankMerchantNo);
payInfo.setTotalFee(new BigDecimal(totalAmount));
JSONObject respJsonObj = JsonHelper.parseObject(respJson);
if (respJsonObj != null) {
JSONObject info = respJsonObj.getJSONObject("notify_biz_content");
payInfo.setInfo(JsonHelper.toJsonString(info));
}
return payInfo;
} catch (Exception e) {
if (e instanceof ServiceException) {
throw new ServiceException(((ServiceException) e).getResultEnum(), e.getMessage());
}
ErrorHelper.println(e);
throw new ServiceException(String.format("【交行】支付通知异常:[%s]", e.getMessage()));
}
}
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String outTradeNo, String totalFee, String notifyType) {
try {
DefaultBocomClient client = BCMConfig.createClient();
MPNG210003RequestV1 clientRequest = new MPNG210003RequestV1();
clientRequest.setServiceUrl(BCMConfig.API_GW_URL_ADDRESS + "/api/pmssMpng/MPNG210003/v1");
MPNG210003RequestV1.MPNG210003RequestV1Biz bizContent = new MPNG210003RequestV1.MPNG210003RequestV1Biz();
MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqHead reqHead = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqHead();
reqHead.setTransTime(BCMConfig.getTransTime()); // 交易时间
reqHead.setVersion(VERSION); // 版本信息
bizContent.setReqHead(reqHead);
MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody reqBody = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody();
reqBody.setMerPtcId(BCMConfig.MER_PTC_ID); // 商户编号
reqBody.setPartnerId(BCMConfig.PARTNER_ID); // 服务商编号
reqBody.setTranScene(B2C_JSAPI_WECHAT); // 交易场景{微 信:B2C-JSAPI-WECHAT 支付宝:B2C-JSAPI-ALIPAY}
reqBody.setMerTradeDate(BCMConfig.getMerTradeDate()); // 商户侧交易日期
reqBody.setMerTradeTime(BCMConfig.getMerTradeTime()); // 商户侧交易时间
// 回调地址
reqBody.setNotifyUrl(WeChatConfig.getBaseUrl() + merchantEnum.getNotifyUrl(null, notifyType));
reqBody.setPayMerTranNo(outTradeNo); // 商户订单号
reqBody.setTotalAmount(totalFee); // 订单总金额
reqBody.setTranContent(title); // 交易内容
reqBody.setLocation(ONLINE);
reqBody.setCurrency(CNY);
List<MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields> require_fieldsList = new ArrayList<>();
// 行端交易流水号
MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields require_fields = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("bank_tran_no");
require_fieldsList.add(require_fields);
// 第三方渠道
require_fields = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("third_party");
require_fieldsList.add(require_fields);
// 第三方渠道交易流水号
require_fields = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("third_party_tran_no");
require_fieldsList.add(require_fields);
// 微信支付宝详细付款信息
require_fields = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("payment_info");
require_fieldsList.add(require_fields);
// 微信支付宝详细付款信息
require_fields = new MPNG210003RequestV1.MPNG210003RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("refund_info");
require_fieldsList.add(require_fields);
// 设置额外字段
reqBody.setRequireFields(require_fieldsList);
bizContent.setReqBody(reqBody);
clientRequest.setBizContent(bizContent);
MPNG210003ResponseV1 clientResponse = client.execute(clientRequest, UUID.randomUUID().toString().replace("-", ""));
log.info("【交行】下单 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
if (clientResponse == null) {
log.info("【交行】下单失败 outTradeNo={}", outTradeNo);
return null;
}
if (!clientResponse.isSuccess()) {
log.info("【交行】下单失败 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
return null;
}
// head
MPNG210003ResponseV1.RspHead rspHead = clientResponse.getRspHead();
if (rspHead == null) {
log.info("【交行】下单失败 outTradeNo={}, rspHead={}", outTradeNo, JsonHelper.toJsonString(rspHead));
return null;
}
if (!RESP_STATUS_S.equals(rspHead.getResponseStatus())) {
log.info("【交行】下单失败 outTradeNo={}, code={}, message={}", outTradeNo, rspHead.getResponseCode(), rspHead.getResponseMsg());
return null;
}
// body
MPNG210003ResponseV1.RspBody rspBody = clientResponse.getRspBody();
if (rspBody == null) {
log.info("【交行】下单失败 outTradeNo={}, rspBody={}", outTradeNo, JsonHelper.toJsonString(rspBody));
return null;
}
String payUrl = rspBody.getRedirectUrl();
if (ObjectUtils.isEmpty(payUrl)) {
log.info("【交行】下单失败 outTradeNo={}, rspBody={}", outTradeNo, JsonHelper.toJsonString(rspBody));
return null;
}
JSONObject jsonObj = new JSONObject();
jsonObj.put("outTradeNo", outTradeNo);
jsonObj.put("url", payUrl);
jsonObj.put("type", MerchantEnum.BCM.CODE);
return jsonObj;
} catch (Exception e) {
ErrorHelper.println(e);
}
return null;
}
public static Order queryOrder(String outTradeNo) {
Order order = new Order();
order.setOutTradeNo(outTradeNo);
try {
DefaultBocomClient client = BCMConfig.createClient();
MPNG020702RequestV1 clientRequest = new MPNG020702RequestV1();
clientRequest.setServiceUrl(BCMConfig.API_GW_URL_ADDRESS + "/api/pmssMpng/MPNG020702/v1");
MPNG020702RequestV1.MPNG020702RequestV1Biz bizContent = new MPNG020702RequestV1.MPNG020702RequestV1Biz();
MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqHead reqHead = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqHead();
reqHead.setTransTime(BCMConfig.getTransTime()); // 交易时间
reqHead.setVersion(VERSION);
bizContent.setReqHead(reqHead);
MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody reqBody = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody();
reqBody.setMerTradeDate(BCMConfig.getMerTradeDate());
reqBody.setPayMerTranNo(outTradeNo);
reqBody.setTranScene(B2C_JSAPI_WECHAT); // 交易场景
List<MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields> require_fieldsList = new ArrayList<>();
MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields require_fields = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("bank_tran_no");
require_fieldsList.add(require_fields);
//--------------------------------------------
require_fields = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("third_party");
require_fieldsList.add(require_fields);
// ----------------------------------------------
require_fields = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("third_party_tran_no");
require_fieldsList.add(require_fields);
// ----------------------------------------------
require_fields = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("payment_info");
require_fieldsList.add(require_fields);
// ----------------------------------------------
require_fields = new MPNG020702RequestV1.MPNG020702RequestV1Biz.ReqBody.RequireFields();
require_fields.setRequireField("refund_info");
require_fieldsList.add(require_fields);
reqBody.setRequireFields(require_fieldsList);
reqBody.setMerPtcId(BCMConfig.MER_PTC_ID);
reqBody.setPartnerId(BCMConfig.PARTNER_ID);
bizContent.setReqBody(reqBody);
clientRequest.setBizContent(bizContent);
// --------------------------------------------------
MPNG020702ResponseV1 clientResponse = client.execute(clientRequest, UUID.randomUUID().toString().replace("-", ""));
log.info("【交行】查询订单 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
if (clientResponse == null) {
order.setErrorMsg("【交行】调用查询订单失败");
return order;
}
if (!clientResponse.isSuccess()) {
order.setErrorMsg(clientResponse.getRspMsg());
return order;
}
// head
MPNG020702ResponseV1.RspHead rspHead = clientResponse.getRspHead();
if (rspHead == null) {
order.setErrorMsg("【交行】查询订单失败 outTradeNo=" + outTradeNo);
return order;
}
if (!RESP_STATUS_S.equals(rspHead.getResponseStatus())) {
order.setErrorCode(rspHead.getResponseCode());
order.setErrorMsg(rspHead.getResponseMsg());
return order;
}
MPNG020702ResponseV1.RspBody rspBody = clientResponse.getRspBody();
if (rspBody == null) {
order.setErrorCode(rspHead.getResponseCode());
order.setErrorMsg(rspHead.getResponseMsg());
return order;
}
MPNG020702ResponseV1.RspBody.RequireValues requireValues = rspBody.getRequireValues();
if (requireValues != null) {
order.setBankTransNo(requireValues.getBankTranNo());
}
order.setPayMoney(new BigDecimal(rspBody.getTotalAmount())); // 订单总金额
String tranState = rspBody.getTranState(); // PROCESS 处理中 SUCCESS 交易成功 FAILURE 交易失败
String orderStatus = rspBody.getOrderStatus(); // PAIED交易成功 WAITPAY等待支付 REFUNDED部分退款 REFUNDALL全部退款 CLOSED订单关闭 INITIAL初始化
order.setTradeState(orderStatus);
if (TRAN_STATE_SUCCESS.equals(tranState) && ORDER_STATUS_PAIED.equals(orderStatus)) {
order.setSuccess(true); // 订单支付成功(判断条件)
} else if (ORDER_STATUS_REFUNDED.equals(orderStatus) || ORDER_STATUS_REFUNDALL.equals(orderStatus)) {
order.setErrorMsg("订单发生过退款");
if (ORDER_STATUS_REFUNDED.equals(orderStatus)) order.setErrorMsg("订单发生过退款");
if (ORDER_STATUS_REFUNDALL.equals(orderStatus)) order.setErrorMsg("订单已全额退款");
order.setRefund(true); // 订单发生过退款
} else {
// 交易错未成功
order.setErrorCode(orderStatus);
if (ORDER_STATUS_WAITPAY.equals(orderStatus)) order.setErrorMsg("等待支付");
if (ORDER_STATUS_CLOSED.equals(orderStatus)) order.setErrorMsg("订单关闭");
if (ORDER_STATUS_INITIAL.equals(orderStatus)) order.setErrorMsg("初始化");
}
return order;
} catch (Exception e) {
ErrorHelper.println(e);
order.setErrorMsg("【交行】" + e.getMessage());
return order;
}
}
/**
* 退款
*
* @param outTradeNo 订单号
* @param outRefundNo 退款单号(28位)
* @param tradeDate 发生交易的日期
* @param refundMoney 退款金额
* @param desc 退款描述
*/
public static Order refund(String outTradeNo, String outRefundNo, String tradeDate, BigDecimal refundMoney, String desc) {
outRefundNo = outRefundNo.substring(4);
log.info("【交行】退款申请 outTradeNo={}, outRefundNo={}, tradeDate={}, refundMoney={}", outTradeNo, outRefundNo, tradeDate, refundMoney);
Order order = new Order();
try {
DefaultBocomClient client = BCMConfig.createClient();
MPNG020701RequestV1 clientRequest = new MPNG020701RequestV1();
clientRequest.setServiceUrl(BCMConfig.API_GW_URL_ADDRESS + "/api/pmssMpng/MPNG020701/v1");
MPNG020701RequestV1.MPNG020701RequestV1Biz bizContent = new MPNG020701RequestV1.MPNG020701RequestV1Biz();
MPNG020701RequestV1.MPNG020701RequestV1Biz.ReqHead reqHead = new MPNG020701RequestV1.MPNG020701RequestV1Biz.ReqHead();
reqHead.setTransTime(BCMConfig.getTransTime()); // 交易时间 yyyyMMddHHmmss
reqHead.setVersion(VERSION);
// req-body
MPNG020701RequestV1.MPNG020701RequestV1Biz.ReqBody reqBody = new MPNG020701RequestV1.MPNG020701RequestV1Biz.ReqBody();
reqBody.setTranScene(B2C_JSAPI_WECHAT);
reqBody.setCurrency(CNY);
reqBody.setMerPtcId(BCMConfig.MER_PTC_ID);
reqBody.setPartnerId(BCMConfig.PARTNER_ID);
reqBody.setMerRefundDate(DateHelper.dateToStr(new Date(), DateHelper.DateEnum.yyyyMMdd));
reqBody.setMerRefundTime(DateHelper.dateToStr(new Date(), DateHelper.DateEnum.HHmmss));
// --------------
reqBody.setPayMerTranNo(outTradeNo); // 订单号
reqBody.setRefundMerTranNo(outRefundNo); // 退费订单号
reqBody.setMerTradeDate(tradeDate);
reqBody.setAmount(refundMoney.setScale(2, RoundingMode.DOWN).toString());
reqBody.setTranContent(desc);
bizContent.setReqHead(reqHead);
bizContent.setReqBody(reqBody);
clientRequest.setBizContent(bizContent);
// --------------------------------------------------
log.info("request={}", JsonHelper.toJsonString(clientRequest));
MPNG020701ResponseV1 clientResponse = client.execute(clientRequest, UUID.randomUUID().toString().replace("-", ""));
log.info("【交行】退款 outTradeNo={}, resp={}", outTradeNo, JsonHelper.toJsonString(clientResponse));
if (clientResponse == null) {
order.setErrorMsg("【交行】调用退款失败");
order.setRefundResult("调用退款失败");
return order;
}
if (!clientResponse.isSuccess()) {
order.setErrorMsg(clientResponse.getRspMsg());
order.setRefundResult(clientResponse.getRspMsg());
return order;
}
// head
MPNG020701ResponseV1.RspHead rspHead = clientResponse.getRspHead();
if (rspHead == null) {
order.setErrorMsg("【交行】退款失败 outTradeNo=" + outTradeNo);
order.setRefundResult("退款失败");
return order;
}
if (!RESP_STATUS_S.equals(rspHead.getResponseStatus())) {
order.setErrorCode(rspHead.getResponseCode());
order.setErrorMsg(rspHead.getResponseMsg());
order.setRefundResult(rspHead.getResponseMsg());
return order;
}
MPNG020701ResponseV1.RspBody rspBody = clientResponse.getRspBody();
if (rspBody == null) {
order.setErrorCode(rspHead.getResponseCode());
order.setErrorMsg(rspHead.getResponseMsg());
order.setRefundResult(rspHead.getResponseMsg());
return order;
}
order.setRefundResult("OK");
order.setSuccess(true); // 操作成功标识
return order;
} catch (Exception e) {
ErrorHelper.println(e);
order.setErrorMsg("【交行】" + e.getMessage());
return order;
}
}
/**
* 【交行】回调通知成功
*/
public static Map<String, Object> resp(ServiceException e) {
if (ResultEnum.PAY_NOTIFY_REPEAT.equals(e.getResultEnum())) {
return respOk();
}
return respError(e.getMessage());
}
/**
* 【交行】回调通知成功
*/
public static Map<String, Object> respOk() {
log.info("【交行】回调通知成功");
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("biz_state", "S");
resultMap.put("rsp_code", "0000");
resultMap.put("rsp_msg", "success");
return resultMap;
}
/**
* 【交行】回调通知失败
*/
public static Map<String, Object> respError(String message) {
log.info("回调通知: {}", message);
if (message == null) {
message = "error";
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("biz_state", "F");
resultMap.put("rsp_code", "0000");
resultMap.put("rsp_msg", "error");
return resultMap;
}
}