|
|
@@ -0,0 +1,440 @@
|
|
|
+package shop.alien.store.strategy.platformMembershipPayment.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import okhttp3.*;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import shop.alien.entity.result.R;
|
|
|
+import shop.alien.entity.store.PlatformShopMembershipOrder;
|
|
|
+import shop.alien.entity.store.PlatformShopMembershipPaymentOrder;
|
|
|
+import shop.alien.store.service.PlatformShopMembershipOrderService;
|
|
|
+import shop.alien.store.service.PlatformShopMembershipPaymentOrderService;
|
|
|
+import shop.alien.store.strategy.payment.impl.WeChatPaymentStrategyImpl;
|
|
|
+import shop.alien.store.strategy.platformMembershipPayment.PlatformMembershipPaymentStrategy;
|
|
|
+import shop.alien.store.util.WXPayUtility;
|
|
|
+import shop.alien.util.common.UniqueRandomNumGenerator;
|
|
|
+import shop.alien.util.common.constant.PaymentEnum;
|
|
|
+import shop.alien.util.system.OSUtil;
|
|
|
+
|
|
|
+import javax.annotation.PostConstruct;
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.PrivateKey;
|
|
|
+import java.security.PublicKey;
|
|
|
+import java.security.Signature;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 平台店铺会员卡 — 微信预支付/查单(支付流水写入 platform_shop_membership_payment_order)
|
|
|
+ * <p>支付参数与 {@link shop.alien.store.strategy.payment.impl.WeChatPaymentStrategyImpl} 一致,从 payment.wechatPay.business 读取,不读 store_payment_config。
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class PlatformMembershipWechatPaymentStrategyImpl implements PlatformMembershipPaymentStrategy {
|
|
|
+
|
|
|
+ private static final String POSTMETHOD = "POST";
|
|
|
+ private static final String GETMETHOD = "GET";
|
|
|
+ private static final String REDIS_PREPAY_KEY_PREFIX = "platform:membership:wechat:prepay:order:";
|
|
|
+ private static final long REDIS_PREPAY_EXPIRE_SECONDS = 15 * 60;
|
|
|
+ private static final String REDIS_PREPAY_DEBOUNCE_KEY_PREFIX = "platform:membership:wechat:prepay:debounce:order:";
|
|
|
+ private static final long REDIS_PREPAY_DEBOUNCE_SECONDS = 5;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.host}")
|
|
|
+ private String wechatPayApiHost;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.prePayPath}")
|
|
|
+ private String prePayPath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.searchOrderByOutTradeNoPath}")
|
|
|
+ private String searchOrderByOutTradeNoPath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.refundPath:/v3/refund/domestic/refunds}")
|
|
|
+ private String refundPath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.refundNotifyUrl:}")
|
|
|
+ private String businessRefundNotifyUrl;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.appId}")
|
|
|
+ private String appId;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.mchId}")
|
|
|
+ private String mchId;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.win.privateKeyPath}")
|
|
|
+ private String privateWinKeyPath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.linux.privateKeyPath}")
|
|
|
+ private String privateLinuxKeyPath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.win.wechatPayPublicKeyFilePath}")
|
|
|
+ private String wechatWinPayPublicKeyFilePath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.linux.wechatPayPublicKeyFilePath}")
|
|
|
+ private String wechatLinuxPayPublicKeyFilePath;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.merchantSerialNumber}")
|
|
|
+ private String merchantSerialNumber;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.wechatPayPublicKeyId}")
|
|
|
+ private String wechatPayPublicKeyId;
|
|
|
+
|
|
|
+ @Value("${payment.wechatPay.business.prePayNotifyUrl}")
|
|
|
+ private String prePayNotifyUrl;
|
|
|
+
|
|
|
+ private PrivateKey privateKey;
|
|
|
+ private PublicKey wechatPayPublicKey;
|
|
|
+
|
|
|
+ private final PlatformShopMembershipOrderService platformShopMembershipOrderService;
|
|
|
+ private final PlatformShopMembershipPaymentOrderService membershipPaymentOrderService;
|
|
|
+ private final StringRedisTemplate stringRedisTemplate;
|
|
|
+
|
|
|
+ @PostConstruct
|
|
|
+ public void loadWechatBusinessKeys() {
|
|
|
+ String privateKeyPath;
|
|
|
+ String wechatPayPublicKeyFilePath;
|
|
|
+ if ("windows".equals(OSUtil.getOsName())) {
|
|
|
+ privateKeyPath = privateWinKeyPath;
|
|
|
+ wechatPayPublicKeyFilePath = wechatWinPayPublicKeyFilePath;
|
|
|
+ } else {
|
|
|
+ privateKeyPath = privateLinuxKeyPath;
|
|
|
+ wechatPayPublicKeyFilePath = wechatLinuxPayPublicKeyFilePath;
|
|
|
+ }
|
|
|
+ this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
|
|
|
+ this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Map<String, Object>> createPrePay(Integer storeId, Integer membershipOrderId, String amountYuan, String subject, Integer userId) {
|
|
|
+ if (storeId == null || membershipOrderId == null) {
|
|
|
+ return R.fail("门店ID和会员卡订单ID不能为空");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(amountYuan)) {
|
|
|
+ return R.fail("支付金额不能为空");
|
|
|
+ }
|
|
|
+ BigDecimal amountYuanBD;
|
|
|
+ try {
|
|
|
+ amountYuanBD = new BigDecimal(amountYuan).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return R.fail("支付金额格式不正确");
|
|
|
+ }
|
|
|
+ if (amountYuanBD.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ return R.fail("支付金额必须大于0");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(subject)) {
|
|
|
+ return R.fail("订单描述不能为空");
|
|
|
+ }
|
|
|
+ PlatformShopMembershipOrder order = platformShopMembershipOrderService.getById(membershipOrderId);
|
|
|
+ if (order == null) {
|
|
|
+ return R.fail("会员卡订单不存在");
|
|
|
+ }
|
|
|
+ if (!order.getStoreId().equals(storeId)) {
|
|
|
+ return R.fail("订单与门店不匹配");
|
|
|
+ }
|
|
|
+ if (order.getPayStatus() != null && order.getPayStatus() != PlatformShopMembershipOrder.PAY_STATUS_PENDING) {
|
|
|
+ return R.fail("订单不可支付");
|
|
|
+ }
|
|
|
+ BigDecimal expect = order.getPayAmount() != null ? order.getPayAmount() : BigDecimal.ZERO;
|
|
|
+ if (amountYuanBD.compareTo(expect.setScale(2, RoundingMode.HALF_UP)) != 0) {
|
|
|
+ return R.fail("支付金额与订单金额不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ String redisKey = REDIS_PREPAY_KEY_PREFIX + membershipOrderId;
|
|
|
+ String cached = stringRedisTemplate.opsForValue().get(redisKey);
|
|
|
+ if (StringUtils.isNotBlank(cached)) {
|
|
|
+ try {
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> data = JSON.parseObject(cached, Map.class);
|
|
|
+ if (data != null && !data.isEmpty()) {
|
|
|
+ log.info("会员卡微信预支付命中缓存,membershipOrderId={}", membershipOrderId);
|
|
|
+ return R.data(data);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析会员卡微信预支付缓存失败,将重新发起,membershipOrderId={}", membershipOrderId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String debounceKey = REDIS_PREPAY_DEBOUNCE_KEY_PREFIX + membershipOrderId;
|
|
|
+ Boolean debounceSet = stringRedisTemplate.opsForValue().setIfAbsent(debounceKey, "1", REDIS_PREPAY_DEBOUNCE_SECONDS, TimeUnit.SECONDS);
|
|
|
+ if (Boolean.FALSE.equals(debounceSet)) {
|
|
|
+ return R.fail("请勿重复提交,请稍后再试");
|
|
|
+ }
|
|
|
+
|
|
|
+ int deleted = membershipPaymentOrderService.logicDeletePendingByMembershipOrderIdAndPayType(
|
|
|
+ membershipOrderId, PaymentEnum.WECHAT_PAY.getType());
|
|
|
+ if (deleted > 0) {
|
|
|
+ log.info("已逻辑删除该会员卡订单下微信支付单 {} 条,membershipOrderId={}", deleted, membershipOrderId);
|
|
|
+ }
|
|
|
+
|
|
|
+ String outTradeNo = UniqueRandomNumGenerator.generateUniqueCode(19);
|
|
|
+ Date now = new Date();
|
|
|
+ PlatformShopMembershipPaymentOrder paymentOrder = new PlatformShopMembershipPaymentOrder();
|
|
|
+ paymentOrder.setPaymentNo(membershipPaymentOrderService.generatePaymentNo());
|
|
|
+ paymentOrder.setMembershipOrderId(order.getId());
|
|
|
+ paymentOrder.setOrderSn(order.getOrderSn());
|
|
|
+ paymentOrder.setStoreId(storeId);
|
|
|
+ paymentOrder.setPayType(PaymentEnum.WECHAT_PAY.getType());
|
|
|
+ paymentOrder.setOutTradeNo(outTradeNo);
|
|
|
+ paymentOrder.setPayAmount(amountYuanBD);
|
|
|
+ paymentOrder.setPayStatus(0);
|
|
|
+ paymentOrder.setPayerUserId(userId);
|
|
|
+ paymentOrder.setSubject(subject);
|
|
|
+ paymentOrder.setCreatedTime(now);
|
|
|
+ paymentOrder.setUpdatedTime(now);
|
|
|
+ membershipPaymentOrderService.save(paymentOrder);
|
|
|
+
|
|
|
+ try {
|
|
|
+ WeChatPaymentStrategyImpl.CommonPrepayRequest request = new WeChatPaymentStrategyImpl.CommonPrepayRequest();
|
|
|
+ request.appid = appId;
|
|
|
+ request.mchid = mchId;
|
|
|
+ request.description = subject;
|
|
|
+ request.outTradeNo = outTradeNo;
|
|
|
+ request.notifyUrl = StringUtils.isNotBlank(prePayNotifyUrl) ? prePayNotifyUrl : "";
|
|
|
+ request.amount = new WeChatPaymentStrategyImpl.CommonAmountInfo();
|
|
|
+ request.amount.total = amountYuanBD.multiply(new BigDecimal(100)).longValue();
|
|
|
+ request.amount.currency = "CNY";
|
|
|
+
|
|
|
+ WeChatPaymentStrategyImpl.DirectAPIv3AppPrepayResponse response = prePayOrderRun(request);
|
|
|
+ if (response == null || StringUtils.isBlank(response.prepayId)) {
|
|
|
+ return R.fail("微信预支付失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ long timestamp = System.currentTimeMillis() / 1000;
|
|
|
+ String nonce = WXPayUtility.createNonce(32);
|
|
|
+ String message = String.format("%s\n%s\n%s\n%s\n", appId, timestamp, nonce, response.prepayId);
|
|
|
+ Signature sign = Signature.getInstance("SHA256withRSA");
|
|
|
+ sign.initSign(privateKey);
|
|
|
+ sign.update(message.getBytes(StandardCharsets.UTF_8));
|
|
|
+ String signStr = Base64.getEncoder().encodeToString(sign.sign());
|
|
|
+
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ data.put("outTradeNo", outTradeNo);
|
|
|
+ data.put("orderSn", order.getOrderSn());
|
|
|
+ data.put("orderId", order.getId());
|
|
|
+ data.put("paymentNo", paymentOrder.getPaymentNo());
|
|
|
+ data.put("prepayId", response.prepayId);
|
|
|
+ data.put("appId", appId);
|
|
|
+ data.put("mchId", mchId);
|
|
|
+ data.put("sign", signStr);
|
|
|
+ data.put("timestamp", String.valueOf(timestamp));
|
|
|
+ data.put("nonce", nonce);
|
|
|
+ data.put("orderStr", "");
|
|
|
+
|
|
|
+ stringRedisTemplate.opsForValue().set(redisKey, JSON.toJSONString(data), REDIS_PREPAY_EXPIRE_SECONDS, TimeUnit.SECONDS);
|
|
|
+ log.info("会员卡微信预支付成功 storeId={}, orderSn={}, outTradeNo={}", storeId, order.getOrderSn(), outTradeNo);
|
|
|
+ return R.data(data);
|
|
|
+ } catch (WXPayUtility.ApiException e) {
|
|
|
+ log.error("会员卡微信预支付异常 storeId={}, membershipOrderId={}", storeId, membershipOrderId, e);
|
|
|
+ return R.fail("预支付失败:" + e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("会员卡微信预支付异常 storeId={}", storeId, e);
|
|
|
+ return R.fail("预支付失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Object> queryPayStatus(Integer storeId, String outTradeNo) {
|
|
|
+ if (storeId == null || StringUtils.isBlank(outTradeNo)) {
|
|
|
+ return R.fail("门店ID和商户订单号不能为空");
|
|
|
+ }
|
|
|
+ PlatformShopMembershipPaymentOrder paymentOrder = membershipPaymentOrderService.getByOutTradeNo(outTradeNo);
|
|
|
+ if (paymentOrder == null) {
|
|
|
+ return R.fail("支付单不存在");
|
|
|
+ }
|
|
|
+ if (!storeId.equals(paymentOrder.getStoreId())) {
|
|
|
+ return R.fail("支付单与门店不匹配");
|
|
|
+ }
|
|
|
+ PlatformShopMembershipOrder order = platformShopMembershipOrderService.getById(paymentOrder.getMembershipOrderId());
|
|
|
+ if (order == null) {
|
|
|
+ return R.fail("会员卡订单不存在");
|
|
|
+ }
|
|
|
+ if (order.getPayStatus() != null && order.getPayStatus() == PlatformShopMembershipOrder.PAY_STATUS_PAID) {
|
|
|
+ return R.success("支付成功");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ WeChatPaymentStrategyImpl.QueryByWxTradeNoRequest req = new WeChatPaymentStrategyImpl.QueryByWxTradeNoRequest();
|
|
|
+ req.transactionId = outTradeNo;
|
|
|
+ req.mchid = mchId;
|
|
|
+ WeChatPaymentStrategyImpl.DirectAPIv3QueryResponse response = searchOrderRun(req);
|
|
|
+ if (response == null) {
|
|
|
+ return R.fail("查询失败");
|
|
|
+ }
|
|
|
+ if ("SUCCESS".equals(response.tradeState)) {
|
|
|
+ Date now = new Date();
|
|
|
+ paymentOrder.setPayStatus(1);
|
|
|
+ paymentOrder.setTradeNo(response.transactionId);
|
|
|
+ paymentOrder.setPayTime(now);
|
|
|
+ paymentOrder.setUpdatedTime(now);
|
|
|
+ membershipPaymentOrderService.updateById(paymentOrder);
|
|
|
+ platformShopMembershipOrderService.applyPaySuccess(order.getId(), now, outTradeNo, response.transactionId, PaymentEnum.WECHAT_PAY.getType());
|
|
|
+ return R.success("支付成功");
|
|
|
+ }
|
|
|
+ if ("CLOSED".equals(response.tradeState)) {
|
|
|
+ return R.fail("交易已关闭");
|
|
|
+ }
|
|
|
+ if ("NOTPAY".equals(response.tradeState) || "USERPAYING".equals(response.tradeState)) {
|
|
|
+ return R.fail("等待用户付款");
|
|
|
+ }
|
|
|
+ return R.fail("订单状态:" + (response.tradeStateDesc != null ? response.tradeStateDesc : response.tradeState));
|
|
|
+ } catch (WXPayUtility.ApiException e) {
|
|
|
+ log.error("会员卡微信查单异常 outTradeNo={}", outTradeNo, e);
|
|
|
+ return R.fail("查询异常:" + e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("会员卡微信查单异常 storeId={}", storeId, e);
|
|
|
+ return R.fail("查询失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getType() {
|
|
|
+ return PaymentEnum.WECHAT_PAY.getType();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<String> refundForTest(PlatformShopMembershipPaymentOrder po, String refundAmountYuan, String refundReason) {
|
|
|
+ if (po == null || StringUtils.isBlank(po.getOutTradeNo())) {
|
|
|
+ return R.fail("支付单或商户订单号无效");
|
|
|
+ }
|
|
|
+ if (!PaymentEnum.WECHAT_PAY.getType().equals(po.getPayType())) {
|
|
|
+ return R.fail("非微信会员卡支付单");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(refundAmountYuan)) {
|
|
|
+ return R.fail("退款金额不能为空");
|
|
|
+ }
|
|
|
+ BigDecimal refundYuan;
|
|
|
+ try {
|
|
|
+ refundYuan = new BigDecimal(refundAmountYuan).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return R.fail("退款金额格式不正确");
|
|
|
+ }
|
|
|
+ if (refundYuan.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ return R.fail("退款金额必须大于0");
|
|
|
+ }
|
|
|
+ String outTradeNo = po.getOutTradeNo();
|
|
|
+ long refundFen = refundYuan.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue();
|
|
|
+ if (refundFen <= 0) {
|
|
|
+ return R.fail("退款金额(分)无效");
|
|
|
+ }
|
|
|
+ long totalFen = po.getPayAmount() != null
|
|
|
+ ? po.getPayAmount().multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue()
|
|
|
+ : 0L;
|
|
|
+ if (totalFen > 0 && refundFen > totalFen) {
|
|
|
+ return R.fail("退款金额不能超过原支付金额");
|
|
|
+ }
|
|
|
+ if (totalFen <= 0) {
|
|
|
+ return R.fail("原支付金额异常,无法计算退款分");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ WeChatPaymentStrategyImpl.CreateRequest request = new WeChatPaymentStrategyImpl.CreateRequest();
|
|
|
+ request.outTradeNo = outTradeNo;
|
|
|
+ request.outRefundNo = UniqueRandomNumGenerator.generateUniqueCode(19);
|
|
|
+ request.reason = StringUtils.isNotBlank(refundReason) ? refundReason : "测试退款";
|
|
|
+ if (StringUtils.isNotBlank(businessRefundNotifyUrl)) {
|
|
|
+ request.notifyUrl = businessRefundNotifyUrl;
|
|
|
+ }
|
|
|
+ request.amount = new WeChatPaymentStrategyImpl.AmountReq();
|
|
|
+ request.amount.refund = refundFen;
|
|
|
+ request.amount.total = totalFen;
|
|
|
+ request.amount.currency = "CNY";
|
|
|
+ WeChatPaymentStrategyImpl.Refund response = refundRun(request);
|
|
|
+ String status = response.status != null ? response.status.name() : "UNKNOWN";
|
|
|
+ if ("SUCCESS".equals(status) || "PROCESSING".equals(status)) {
|
|
|
+ membershipPaymentOrderService.markPaymentAndMembershipOrderRefunded(po);
|
|
|
+ }
|
|
|
+ log.warn("会员卡微信退款接口已返回 membershipOrderId={}, outTradeNo={}, outRefundNo={}, status={}, refundId={}",
|
|
|
+ po.getMembershipOrderId(), outTradeNo, response.outRefundNo, status, response.refundId);
|
|
|
+ return R.data(("SUCCESS".equals(status) || "PROCESSING".equals(status) ? "退款受理并已回写支付单/业务订单状态(PROCESSING 表示处理中)" : "退款返回")
|
|
|
+ + ",membershipOrderId=" + po.getMembershipOrderId()
|
|
|
+ + ", status=" + status
|
|
|
+ + ", refund_id=" + response.refundId
|
|
|
+ + ", out_refund_no=" + (response.outRefundNo != null ? response.outRefundNo : request.outRefundNo));
|
|
|
+ } catch (WXPayUtility.ApiException e) {
|
|
|
+ log.error("[测试]会员卡微信退款失败 outTradeNo={}", outTradeNo, e);
|
|
|
+ return R.fail("退款失败:" + e.getMessage());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[测试]会员卡微信退款异常 membershipOrderId={}", po.getMembershipOrderId(), e);
|
|
|
+ return R.fail("退款失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private WeChatPaymentStrategyImpl.Refund refundRun(WeChatPaymentStrategyImpl.CreateRequest request) throws IOException {
|
|
|
+ String uri = refundPath;
|
|
|
+ String reqBody = WXPayUtility.toJson(request);
|
|
|
+ Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
|
|
|
+ reqBuilder.addHeader("Accept", "application/json");
|
|
|
+ reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
|
|
|
+ reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, POSTMETHOD, uri, reqBody));
|
|
|
+ reqBuilder.addHeader("Content-Type", "application/json");
|
|
|
+ MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8");
|
|
|
+ RequestBody body = RequestBody.create(reqBody, jsonMediaType);
|
|
|
+ reqBuilder.method(POSTMETHOD, body);
|
|
|
+ OkHttpClient client = new OkHttpClient.Builder()
|
|
|
+ .connectTimeout(10, TimeUnit.SECONDS)
|
|
|
+ .readTimeout(30, TimeUnit.SECONDS)
|
|
|
+ .build();
|
|
|
+ try (Response httpResponse = client.newCall(reqBuilder.build()).execute()) {
|
|
|
+ String respBody = WXPayUtility.extractBody(httpResponse);
|
|
|
+ if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
|
|
|
+ WXPayUtility.validateResponse(wechatPayPublicKeyId, wechatPayPublicKey, httpResponse.headers(), respBody);
|
|
|
+ return WXPayUtility.fromJson(respBody, WeChatPaymentStrategyImpl.Refund.class);
|
|
|
+ }
|
|
|
+ throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private WeChatPaymentStrategyImpl.DirectAPIv3AppPrepayResponse prePayOrderRun(WeChatPaymentStrategyImpl.CommonPrepayRequest request) throws IOException {
|
|
|
+ String uri = prePayPath;
|
|
|
+ String reqBody = WXPayUtility.toJson(request);
|
|
|
+ Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
|
|
|
+ reqBuilder.addHeader("Accept", "application/json");
|
|
|
+ reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
|
|
|
+ reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, POSTMETHOD, uri, reqBody));
|
|
|
+ reqBuilder.addHeader("Content-Type", "application/json");
|
|
|
+ MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8");
|
|
|
+ RequestBody body = RequestBody.create(reqBody, jsonMediaType);
|
|
|
+ reqBuilder.method(POSTMETHOD, body);
|
|
|
+ OkHttpClient client = new OkHttpClient.Builder().build();
|
|
|
+ try (Response httpResponse = client.newCall(reqBuilder.build()).execute()) {
|
|
|
+ String respBody = WXPayUtility.extractBody(httpResponse);
|
|
|
+ if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
|
|
|
+ WXPayUtility.validateResponse(wechatPayPublicKeyId, wechatPayPublicKey, httpResponse.headers(), respBody);
|
|
|
+ return WXPayUtility.fromJson(respBody, WeChatPaymentStrategyImpl.DirectAPIv3AppPrepayResponse.class);
|
|
|
+ }
|
|
|
+ throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private WeChatPaymentStrategyImpl.DirectAPIv3QueryResponse searchOrderRun(WeChatPaymentStrategyImpl.QueryByWxTradeNoRequest request) throws IOException {
|
|
|
+ String uri = searchOrderByOutTradeNoPath.replace("{out_trade_no}", WXPayUtility.urlEncode(request.transactionId));
|
|
|
+ Map<String, Object> args = new HashMap<>();
|
|
|
+ args.put("mchid", mchId);
|
|
|
+ String queryString = WXPayUtility.urlEncode(args);
|
|
|
+ if (!queryString.isEmpty()) {
|
|
|
+ uri = uri + "?" + queryString;
|
|
|
+ }
|
|
|
+ Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
|
|
|
+ reqBuilder.addHeader("Accept", "application/json");
|
|
|
+ reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
|
|
|
+ reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, GETMETHOD, uri, null));
|
|
|
+ reqBuilder.method(GETMETHOD, null);
|
|
|
+ OkHttpClient client = new OkHttpClient.Builder()
|
|
|
+ .connectTimeout(10, TimeUnit.SECONDS)
|
|
|
+ .readTimeout(15, TimeUnit.SECONDS)
|
|
|
+ .build();
|
|
|
+ try (Response httpResponse = client.newCall(reqBuilder.build()).execute()) {
|
|
|
+ String respBody = WXPayUtility.extractBody(httpResponse);
|
|
|
+ if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
|
|
|
+ WXPayUtility.validateResponse(wechatPayPublicKeyId, wechatPayPublicKey, httpResponse.headers(), respBody);
|
|
|
+ return WXPayUtility.fromJson(respBody, WeChatPaymentStrategyImpl.DirectAPIv3QueryResponse.class);
|
|
|
+ }
|
|
|
+ throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|