package com.stylefeng.guns.modular.system.util; import cn.hutool.Hutool; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.*; /** * 创博优支付工具类 * 目前仅实现创建支付单接口。 */ @Slf4j public class CbyzxPayUtil { /** * 测试环境域名 */ public static final String TEST_BASE_URL = "https://api-pay2.cbyzx.com"; /** * 创建支付单接口 */ public static final String CREATE_PAY_ORDER_PATH = "/api/inner/pay/create"; public static final String CLOSE_PAY_ORDER_PATH = "/api/inner/refund/create"; private static final String PAYMENT_ORDER_TYPE = "PAYMENT_ORDER"; private static final String DEFAULT_CURRENCY = "CNY"; private static final String DEFAULT_PAY_CHANNEL_CODE = "fxx-ride-wxmini"; private static final String DEFAULT_TENANT = "ha.xinx.fxx.platform"; private CbyzxPayUtil() { } /** * 创建支付单 * * @param request 请求参数 * @return 接口响应 */ public static JSONObject createPayOrder(CreatePayOrderRequest request) { return createPayOrder(TEST_BASE_URL, request); } /** * 创建支付单 * * @param baseUrl 域名 * @param request 请求参数 * @return 接口响应 */ public static JSONObject createPayOrder(String baseUrl, CreatePayOrderRequest request) { validateCreatePayOrderRequest(request); return postForJson(baseUrl, CREATE_PAY_ORDER_PATH, request.toParamMap(), "create pay order"); } /** * * 关闭支付单 * @param request * @return */ public static JSONObject closePayOrder(ClosePayOrderRequest request) { return closePayOrder(TEST_BASE_URL, request); } public static JSONObject closePayOrder(String baseUrl, ClosePayOrderRequest request) { validateClosePayOrderRequest(request); return postForJson(baseUrl, CLOSE_PAY_ORDER_PATH, request.toParamMap(), "close pay order"); } private static JSONObject postForJson(String baseUrl, String path, Map params, String actionName) { HttpClientUtil httpClientUtil = new HttpClientUtil(); log.info("{} request: {}", actionName, JSONObject.toJSONString(params)); String responseText = httpClientUtil.pushHttpRequset( "POST", buildUrl(baseUrl, path), params, buildJsonHeader(), "json" ); if (!StringUtils.hasText(responseText)) { throw new IllegalStateException(actionName + " failed: empty response"); } try { return JSON.parseObject(responseText); } catch (Exception ex) { JSONObject result = new JSONObject(); result.put("success", false); result.put("rawResponse", responseText); result.put("message", "response is not json"); return result; } } private static Map buildJsonHeader() { Map header = new LinkedHashMap<>(); header.put("Content-Type", "application/json;charset=UTF-8"); header.put("Accept", "application/json"); return header; } private static String buildUrl(String baseUrl, String path) { String finalBaseUrl = baseUrl; if (!StringUtils.hasText(finalBaseUrl)) { finalBaseUrl = TEST_BASE_URL; } if (finalBaseUrl.endsWith("/")) { finalBaseUrl = finalBaseUrl.substring(0, finalBaseUrl.length() - 1); } return finalBaseUrl + path; } private static void validateCreatePayOrderRequest(CreatePayOrderRequest request) { if (request == null) { throw new IllegalArgumentException("request must not be null"); } if (!StringUtils.hasText(request.getOutRequestNo())) { throw new IllegalArgumentException("outRequestNo must not be blank"); } if (request.getPaymentOrderAmount() == null) { throw new IllegalArgumentException("paymentOrderAmount must not be null"); } if (request.getBuyerId() == null) { throw new IllegalArgumentException("buyerId must not be null"); } if (!StringUtils.hasText(request.getOpenId())) { throw new IllegalArgumentException("openId must not be blank"); } if (!StringUtils.hasText(request.getPayEndTime())) { throw new IllegalArgumentException("payEndTime must not be blank"); } if (!StringUtils.hasText(request.getCallbackUrl())) { throw new IllegalArgumentException("callbackUrl must not be blank"); } } private static void validateClosePayOrderRequest(ClosePayOrderRequest request) { if (request == null) { throw new IllegalArgumentException("request must not be null"); } if (!StringUtils.hasText(request.getOutRequestNo())) { throw new IllegalArgumentException("outRequestNo must not be blank"); } } /** * 构造一份本地测试数据 */ public static CreatePayOrderRequest mockRequest() { CreatePayOrderRequest request = new CreatePayOrderRequest(); request.setOutRequestNo("TEST" + System.currentTimeMillis()); request.setPaymentOrderAmount(new BigDecimal("100")); request.setBuyerId(10001L); request.setOpenId("oMockOpenId123456789"); request.setPayEndTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis() + 30L * 60L * 1000L))); request.setCallbackUrl("http://127.0.0.1:8080/pay/mockCallback"); return request; } public static ClosePayOrderRequest mockCloseRequest(String outRequestNo) { ClosePayOrderRequest request = new ClosePayOrderRequest(); request.setOutRequestNo(outRequestNo); return request; } public static void main(String[] args) { CreatePayOrderRequest request = mockRequest(); System.out.println("request url: " + buildUrl(TEST_BASE_URL, CREATE_PAY_ORDER_PATH)); System.out.println("request body: " + JSON.toJSONString(request.toParamMap(), true)); try { JSONObject response = createPayOrder(request); System.out.println("response body: " + JSON.toJSONString(response, true)); } catch (Exception ex) { System.err.println("request failed: " + ex.getMessage()); ex.printStackTrace(); } } /** * 创建支付单请求参数 */ public static class CreatePayOrderRequest { private String outRequestNo; private BigDecimal paymentOrderAmount; private Long buyerId; private String openId; private String payEndTime; private String callbackUrl; public Map toParamMap() { Map params = new LinkedHashMap<>(); params.put("tenant", DEFAULT_TENANT); params.put("paymentOrderType", PAYMENT_ORDER_TYPE); params.put("outRequestNo", outRequestNo); //转为分 paymentOrderAmount = BigDecimal.valueOf(paymentOrderAmount.multiply(new BigDecimal(100)).intValue()); params.put("paymentOrderAmount", paymentOrderAmount); params.put("currency", DEFAULT_CURRENCY); params.put("buyerId", buyerId); params.put("subOpenid", openId); params.put("storeIds", Arrays.asList("1004")); params.put("payChannelCode", DEFAULT_PAY_CHANNEL_CODE); params.put("payEndTime", payEndTime); params.put("callbackUrl", callbackUrl); params.put("businessCode", "passenger"); return params; } public String getOutRequestNo() { return outRequestNo; } public void setOutRequestNo(String outRequestNo) { this.outRequestNo = outRequestNo; } public BigDecimal getPaymentOrderAmount() { return paymentOrderAmount; } public void setPaymentOrderAmount(BigDecimal paymentOrderAmount) { this.paymentOrderAmount = paymentOrderAmount; } public Long getBuyerId() { return buyerId; } public void setBuyerId(Long buyerId) { this.buyerId = buyerId; } public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public String getPayEndTime() { return payEndTime; } public void setPayEndTime(String payEndTime) { this.payEndTime = payEndTime; } public String getCallbackUrl() { return callbackUrl; } public void setCallbackUrl(String callbackUrl) { this.callbackUrl = callbackUrl; } } public static class ClosePayOrderRequest { private String outRequestNo; private String refundOutRequestNo; private Integer refundAmount; private String refundDesc; public Map toParamMap() { Map params = new LinkedHashMap<>(); params.put("tenant",DEFAULT_TENANT ); params.put("outRequestNo", outRequestNo); params.put("refundOutRequestNo", refundOutRequestNo); params.put("refundAmount", refundAmount); params.put("refundDesc", refundDesc); return params; } public String getRefundOutRequestNo() { return refundOutRequestNo; } public void setRefundOutRequestNo(String refundOutRequestNo) { this.refundOutRequestNo = refundOutRequestNo; } public Integer getRefundAmount() { return refundAmount; } public void setRefundAmount(Integer refundAmount) { this.refundAmount = refundAmount; } public String getRefundDesc() { return refundDesc; } public void setRefundDesc(String refundDesc) { this.refundDesc = refundDesc; } public String getOutRequestNo() { return outRequestNo; } public void setOutRequestNo(String outRequestNo) { this.outRequestNo = outRequestNo; } } }