package com.stylefeng.guns.modular.system.util;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.StringUtils;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.text.SimpleDateFormat;
|
import java.util.Arrays;
|
import java.util.Date;
|
import java.util.HashSet;
|
import java.util.Set;
|
|
/**
|
* 创博优订单支付适配工具。
|
*/
|
@Component
|
public class CbyzxOrderPayHelper {
|
|
private static final String CALLBACK_PATH = "/base/cbyzxPayOrderTaxi";
|
private static final Set<String> SUCCESS_STATUS = new HashSet<>(Arrays.asList(
|
"SUCCESS", "SUCCEEDED", "PAY_SUCCESS", "TRADE_SUCCESS", "PAID", "PAYED", "1", "00", "TRUE"
|
));
|
private static final Set<String> FAIL_STATUS = new HashSet<>(Arrays.asList(
|
"FAIL", "FAILED", "CLOSED", "CANCEL", "CANCELED", "CANCELLED", "0", "FALSE"
|
));
|
|
@Value("${callbackPath}")
|
private String callbackPath;
|
|
public JSONObject createOrder(Integer buyerId, String openId, String outRequestNo, Double amount) {
|
CbyzxPayUtil.CreatePayOrderRequest request = new CbyzxPayUtil.CreatePayOrderRequest();
|
request.setOutRequestNo(outRequestNo);
|
request.setPaymentOrderAmount(new BigDecimal(String.valueOf(amount)).setScale(2, RoundingMode.HALF_UP));
|
request.setBuyerId(Long.valueOf(String.valueOf(buyerId)));
|
request.setOpenId(openId);
|
request.setPayEndTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis() + 30L * 60L * 1000L)));
|
request.setCallbackUrl(buildCallbackUrl());
|
return CbyzxPayUtil.createPayOrder(request);
|
}
|
|
public String buildCallbackUrl() {
|
return callbackPath + CALLBACK_PATH;
|
}
|
|
public boolean isCreateSuccess(JSONObject response) {
|
if (response == null) {
|
return false;
|
}
|
Object code = findValue(response, names("code"));
|
if (code != null && "0".equals(String.valueOf(code))) {
|
return true;
|
}
|
Object success = findValue(response, names("success"));
|
return success != null && Boolean.parseBoolean(String.valueOf(success));
|
}
|
|
/**
|
* 解析创博优表单回调参数。
|
* out_trade_no 为平台订单号,trade_no 为三方支付流水号。
|
*/
|
public JSONObject parseCallbackRequest(HttpServletRequest request) {
|
if (request == null || request.getParameterMap() == null || request.getParameterMap().isEmpty()) {
|
return null;
|
}
|
JSONObject payload = new JSONObject();
|
for (String key : request.getParameterMap().keySet()) {
|
String[] values = request.getParameterValues(key);
|
if (values == null || values.length == 0) {
|
continue;
|
}
|
payload.put(key, values.length == 1 ? values[0] : Arrays.asList(values));
|
}
|
return payload;
|
}
|
|
/**
|
* trade_status=TRADE_SUCCESS 视为支付成功。
|
*/
|
public boolean isPaySuccess(JSONObject payload) {
|
if (payload == null) {
|
return false;
|
}
|
Object status = findValue(payload, names("trade_status", "tradeStatus", "payStatus", "paymentStatus", "status", "result", "resultCode", "state"));
|
if (status != null) {
|
String normalized = String.valueOf(status).trim().toUpperCase();
|
if (SUCCESS_STATUS.contains(normalized)) {
|
return true;
|
}
|
if (FAIL_STATUS.contains(normalized)) {
|
return false;
|
}
|
}
|
Object success = findValue(payload, names("success"));
|
if (success != null) {
|
return Boolean.parseBoolean(String.valueOf(success));
|
}
|
Object code = findValue(payload, names("code"));
|
return code != null && "0".equals(String.valueOf(code)) && StringUtils.hasText(extractOutRequestNo(payload));
|
}
|
|
/**
|
* out_trade_no 为平台侧订单号,格式为 orderId_orderType_random。
|
*/
|
public String extractOutRequestNo(JSONObject payload) {
|
return valueToString(findValue(payload, names("outRequestNo", "out_trade_no")));
|
}
|
|
/**
|
* 回查本地支付记录时优先使用 out_trade_no。
|
*/
|
public String extractRecordCode(JSONObject payload) {
|
String code = valueToString(findValue(payload, names("out_trade_no", "outRequestNo", "merchantSerialNo", "merchant_serial_no")));
|
return StringUtils.hasText(code) ? code : null;
|
}
|
|
/**
|
* trade_no 为创博优侧交易流水号,用于标记实际支付成功流水。
|
*/
|
public String extractThirdPartyOrderNo(JSONObject payload) {
|
String orderNo = valueToString(findValue(payload, names(
|
"trade_no", "tradeNo", "merchantSerialNo", "merchant_serial_no", "paymentOrderId", "payment_order_id",
|
"transactionId", "transaction_id", "tradeNo", "trade_no"
|
)));
|
return StringUtils.hasText(orderNo) ? orderNo : null;
|
}
|
|
/**
|
* notify_type=directpay.status.sync 表示支付结果同步通知。
|
*/
|
public String extractNotifyType(JSONObject payload) {
|
String notifyType = valueToString(findValue(payload, names("notify_type", "notifyType")));
|
return StringUtils.hasText(notifyType) ? notifyType : null;
|
}
|
|
public String extractMessage(JSONObject payload) {
|
String message = valueToString(findValue(payload, names("msg", "message", "errorMsg", "errorMessage", "trade_status", "notify_type")));
|
return StringUtils.hasText(message) ? message : "支付回调处理失败";
|
}
|
|
private Set<String> names(String... names) {
|
return new HashSet<>(Arrays.asList(names));
|
}
|
|
private Object findValue(Object current, Set<String> names) {
|
if (current == null) {
|
return null;
|
}
|
if (current instanceof JSONObject) {
|
JSONObject jsonObject = (JSONObject) current;
|
for (String key : jsonObject.keySet()) {
|
if (names.contains(key)) {
|
return jsonObject.get(key);
|
}
|
}
|
for (String key : jsonObject.keySet()) {
|
Object found = findValue(jsonObject.get(key), names);
|
if (found != null) {
|
return found;
|
}
|
}
|
return null;
|
}
|
if (current instanceof JSONArray) {
|
JSONArray jsonArray = (JSONArray) current;
|
for (Object item : jsonArray) {
|
Object found = findValue(item, names);
|
if (found != null) {
|
return found;
|
}
|
}
|
}
|
return null;
|
}
|
|
private String valueToString(Object value) {
|
return value == null ? null : String.valueOf(value);
|
}
|
}
|