|
|
@@ -1,29 +1,45 @@
|
|
|
package cn.iocoder.yudao.module.system.controller.admin.pay;
|
|
|
|
|
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
|
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
|
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
|
|
-import cn.iocoder.yudao.module.system.controller.admin.pay.vo.WechatUnifiedOrderRequest;
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderDO;
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderItemDO;
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniPayRequestInfoDO;
|
|
|
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniOrderItemMapper;
|
|
|
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniOrderMapper;
|
|
|
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniPayRequestInfoMapper;
|
|
|
+import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
|
|
|
+import cn.iocoder.yudao.module.system.service.miniapp.MiniAppUserService;
|
|
|
import cn.iocoder.yudao.module.system.util.pay.CertUtils;
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import com.wechat.pay.java.core.Config;
|
|
|
import com.wechat.pay.java.core.RSAPublicKeyConfig;
|
|
|
+import com.wechat.pay.java.core.notification.NotificationConfig;
|
|
|
+import com.wechat.pay.java.core.notification.NotificationParser;
|
|
|
+import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
|
|
|
import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension;
|
|
|
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.Amount;
|
|
|
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.Payer;
|
|
|
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayRequest;
|
|
|
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayWithRequestPaymentResponse;
|
|
|
+import com.wechat.pay.java.service.partnerpayments.jsapi.model.*;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
-import org.apache.http.client.methods.HttpPost;
|
|
|
-import org.apache.http.entity.StringEntity;
|
|
|
-import org.apache.http.util.EntityUtils;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.http.MediaType;
|
|
|
-import org.springframework.web.bind.annotation.PostMapping;
|
|
|
-import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
-import org.springframework.web.bind.annotation.RestController;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
import javax.annotation.security.PermitAll;
|
|
|
-import java.util.Arrays;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.IOException;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.List;
|
|
|
+import java.util.concurrent.ThreadLocalRandom;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 微信小程序统一下单控制器
|
|
|
@@ -33,59 +49,51 @@ import java.util.Arrays;
|
|
|
@RequestMapping("/pay/wx")
|
|
|
public class WeChatPayController {
|
|
|
|
|
|
- private static final String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzbDDaK6pFz8fEBIM/pFlIV4uApuhr/TDm8mlK0+Cw1+om1p2s2RFItgBw7Gk9qTN72L68utj5bEDJRQgdr1ixAjc4AH1AOYeV4YZnWTQkcjsRiEimqo+bkIm+osTpFEO9kdvfFMILOl1MDipIAcUrNq9CMs6s6nFDLxLlwy8Ap4VrP4N+FF04efG+8dj35z8dUdi/8WrAe4p7GYGojHHoZ/mIqEDnLdt+PM5pRizCfUCtmSF5UxnmNUlUAutIedvtOAT9rs9E71aO+ldhXNMfA+jLxuBmyp+oy3hWS4Vqp4RbC1a2xRSULvEgSUwrdNq/rytpK66/XY7Vk2f/onCdAgMBAAECggEAXtI/ox1OeGSN01b7MggeMzApBo2u6Vs+m97irGv7JBqHoYzseWuiScX9x6/5EmA4WCw86Srp/i8qsfOsjVucyLc+DXecufNtZ1VvnXC0MMq50tMuaf5btMAXO8tzuyY9gpLyGxwyTJLEuawGxlVBKUxWJOsK9LFVuEbJeunDDlmWsn+euRw3F7jxtNnjVjfqXsY9O+TtB8p0bOduWZc7OvDHoIZQL4NnDivnAR5q1dSLt77pzdinvGiXNYNuTTULstR+KVhJy5Kmsldtj3nrP/fcy/N+JsXm9+3xgaJ2edKwmfnwvQjJAWOtltOSoHx4RK3kzbC8UhKs/E3iaUEUgQKBgQDp0qoNKHbTCiwDhmrnnCyaoW16qEOj0MqHOy5mKYmJkcSDGgNQM/44gN7vOu5BBJHXdkizxaoX3w/ufW2ahhJ/LcjITjFIq8gpiFKbLNfhkCw47ZDtmhB9jAnaB+9+rLeAFXkfXKi+PYJGZIIzbgn0u5LADzRjvzaxe/Z+Ed5ooQKBgQDEcKkk0SmcsHdTkLs2kf6fu8z7MAg9l42fCO18TPt3PeoRcvf8AKw+WDjARSo0ojqL23T9U0IydKdsbcxrYsHETUBS+MAP09Ckpd8p7F5evJghXwhhQRx0gzVuNMkbeP1a3xnC3yL7V5fluGQqz7Xiv3sg9dxYDh8cVQBu6ckafQKBgQCcoF0Ay2YtH9cz1UqvMtI+Enw/eY81oJrJ0z7VeGWFHXvBRh+KDgnw14J+Rb9rFiCLb9Rrd7DkpKsLWkGdDMo/HvAsHRSuVUOTbpnHEFbb5bN5vskiH92D+9Ztkns/I3sX9UpZU7xFEva9KH5+7OsGYM+Aj67MUj3UzfDjqhyNgQKBgFcNojeZpbo1jbvvsLd/PXqmLDHI2G4LIoyu1Se3qdzvCDLRY0o/NhWu3P9/5zNKDW37RD4bToOzpJptkiCotDv9DBt49wxMjvLYOyyF/lA3faeUSM9onmaX2u7K37CYDpbdtbnhTsxZxgvcii9auz0QJE24BvzSzUCt/rIoUqG1AoGAX9sTEp77kdVrM8ECEKgLsOtRWEAgeNkWLgHZKYcEYyu3D4XEVScYNtTBLBHXs3n1GIYdLjWEAWWb55sqKSlVzVWfOhpnOqoFq51xi2TGr3pkp9cqZf0lxYKs7P4tlgeL0icXfb+lFTPmgfgE5vjHBvYQcj7o9lO5hRe46fVoxT8=";
|
|
|
-
|
|
|
- private static final String merchantId = "1105835366";
|
|
|
-
|
|
|
- private static final String certPem = "MIIELjCCAxagAwIBAgIUOjdSdMmYC2qOKZOM68wXFlQcfbEwDQYJKoZIhvcNAQEL\n" +
|
|
|
- "BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
|
|
|
- "FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
|
|
|
- "Q0EwHhcNMjYwMzAyMDM0MzM5WhcNMzEwMzAxMDM0MzM5WjCBhzETMBEGA1UEAwwK\n" +
|
|
|
- "MTEwNTgzNTM2NjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL\n" +
|
|
|
- "DCrpopDlubTlgaXlurfkuqfkuJrvvIjpm4blm6LvvInmnInpmZDlhazlj7gxCzAJ\n" +
|
|
|
- "BgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
|
|
|
- "ggEPADCCAQoCggEBALNsMNorqkXPx8QEgz+kWUhXi4Cm6Gv9MObyaUrT4LDX6ibW\n" +
|
|
|
- "nazZEUi2AHDsaT2pM3vYvry62PlsQMlFCB2vWLECNzgAfUA5h5XhhmdZNCRyOxGI\n" +
|
|
|
- "SKaqj5uQib6ixOkUQ72R298Uwgs6XUwOKkgBxSs2r0IyzqzqcUMvEuXDLwCnhWs/\n" +
|
|
|
- "g34UXTh58b7x2PfnPx1R2L/xasB7insZgaiMcehn+YioQOct2348zmlGLMJ9QK2Z\n" +
|
|
|
- "IXlTGeY1SVQC60h52+04BP2uz0TvVo76V2Fc0x8D6MvG4GbKn6jLeFZLhWqnhFsL\n" +
|
|
|
- "VrbFFJQu8SBJTCt02r+vK2krrr9djtWTZ/+icJ0CAwEAAaOBuTCBtjAJBgNVHRME\n" +
|
|
|
- "AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov\n" +
|
|
|
- "L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw\n" +
|
|
|
- "REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF\n" +
|
|
|
- "MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB\n" +
|
|
|
- "AQAVEO4RR9o+W0SySh9S6RwLV9e+GNl96K8BnfswLMeTcZTA5XJQRTfCSlE5v/mf\n" +
|
|
|
- "NQw5HdDigF2BeIDJqWSDyApbILfngsZadH0I6fDk1u2zifeIQcN0C9yFRPn2uf3O\n" +
|
|
|
- "YRc2sX7CJdPSbMGFaozaH40uZDl86/63qVFMuaOa3iAwiqQVVsSOcnhUhLBL1fh/\n" +
|
|
|
- "0AauGFk5fyGgNqMIJ+7+z+nBtWfq1i2quRda66Ao0ytQP+L5CV0jePmQ0uOiv8AE\n" +
|
|
|
- "EcqAqJ+/d0nqhFd7hVcmW+uzQ3eTTeuHnsAZt7bkUhTF5PJBvZipI+CYtUhZFlaT\n" +
|
|
|
- "rXbHeFgiQcZb/sR8sTBV0KXR";
|
|
|
-
|
|
|
- private static final String apiV3Key = "W2sE4rF6tY8uI0oP1aQ2wS3dF4gH5jK6";
|
|
|
-
|
|
|
- private static final String wechatpayPublicKeyPem = "-----BEGIN PUBLIC KEY-----\n" +
|
|
|
- "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuh82JjfQ/r0+mz8W9ZAr\n" +
|
|
|
- "Uw5nLSSzUKxvepSnWny0a7ccZFB+j8q9pZWq7gmfyOmsC6uq8gmzPDnOD+xrBfj7\n" +
|
|
|
- "t8R3x/VU7tpmGtdNecQFTaJ6NrausM82sMVdf9XOpQvERgVtfIO5U1q3jqSfTyNk\n" +
|
|
|
- "MchXhQMoWa3RXDl7EO0okLIKoNgA1o4AWZZaVyiJ0BjF/URwk6O0eg+g2PqDldFr\n" +
|
|
|
- "RxQIHLsaFnFsDJx5bNia9Jb48g+nNpoKtW1njsPDn/ckTOvnZxdkbkwIaQ2NDli1\n" +
|
|
|
- "ehsaDK6ACReD/A6nIlDQB50duKhVNzx10MZwikD2OWAPUnY6rIE9cqWwKUH4okWJ\n" +
|
|
|
- "BwIDAQAB\n" +
|
|
|
- "-----END PUBLIC KEY-----\n";
|
|
|
-
|
|
|
- //Call Unified Order API
|
|
|
+ @Autowired
|
|
|
+ private WechatMiniPayRequestInfoMapper wechatMiniPayRequestInfoMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MiniAppUserService miniAppUserService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WechatMiniOrderMapper wechatMiniOrderMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WechatMiniOrderItemMapper wechatMiniOrderItemMapper;
|
|
|
+
|
|
|
+ @Value("${wechat.miniapp.pay.public-key}")
|
|
|
+ private String publicKey;
|
|
|
+
|
|
|
+ @Value("${wechat.miniapp.pay.public-key-id}")
|
|
|
+ private String publicKeyId;
|
|
|
+
|
|
|
+ @Value("${wechat.miniapp.pay.api-v3-key}")
|
|
|
+ private String apiV3Key;
|
|
|
+
|
|
|
+ private static final String PREFIX = "OUT_TRADE_NO_";
|
|
|
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
+ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss");
|
|
|
+
|
|
|
@PostMapping(value = "/unifiedOrder", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
|
|
|
@PermitAll
|
|
|
@TenantIgnore
|
|
|
- public CommonResult<String> unifiedOrder() throws Exception {
|
|
|
- String merchantSerialNumber = CertUtils.getMerchantSerialNumberFromPem(certPem);
|
|
|
- // 1. 构建配置类(就是你之前写的那部分)
|
|
|
+ public CommonResult<JSONObject> unifiedOrder(@RequestBody WechatMiniOrderDO req) throws Exception {
|
|
|
+ String openId = miniAppUserService.getByPhone(req.getPhone()).getOpenId();
|
|
|
+ String outTradeNo = generateOrderNo();
|
|
|
+ req.setOutTradeNo(outTradeNo);
|
|
|
+ // 记录支付订单信息
|
|
|
+ String description = insertMiniOrder(req);
|
|
|
+ WechatMiniPayRequestInfoDO wechatMiniPayRequestInfoDO = wechatMiniPayRequestInfoMapper.selectOne(new LambdaQueryWrapperX<WechatMiniPayRequestInfoDO>()
|
|
|
+ .eq(WechatMiniPayRequestInfoDO::getStatus, 1)
|
|
|
+ .eq(WechatMiniPayRequestInfoDO::getTenantId, req.getTenantId()));
|
|
|
+ String merchantSerialNumber = CertUtils.getMerchantSerialNumberFromPem(wechatMiniPayRequestInfoDO.getCertPem());
|
|
|
+ // 1. 构建配置类
|
|
|
Config config =
|
|
|
new RSAPublicKeyConfig.Builder()
|
|
|
- .merchantId(merchantId)
|
|
|
- .privateKey(privateKey) // 商户私钥字符串
|
|
|
- .publicKey(wechatpayPublicKeyPem) // 微信支付公钥字符串
|
|
|
- .publicKeyId("PUB_KEY_ID_0111058353662026030200381966000601") // 公钥ID(必须!)
|
|
|
+ .merchantId(wechatMiniPayRequestInfoDO.getSpMchid())
|
|
|
+ .privateKey(wechatMiniPayRequestInfoDO.getPrivateKey()) // 商户私钥字符串
|
|
|
+ .publicKey(publicKey) // 微信支付公钥字符串
|
|
|
+ .publicKeyId(publicKeyId) // 公钥ID(必须!)
|
|
|
.merchantSerialNumber(merchantSerialNumber)
|
|
|
.apiV3Key(apiV3Key)
|
|
|
.build();
|
|
|
@@ -96,36 +104,136 @@ public class WeChatPayController {
|
|
|
// 3. 构造统一下单请求
|
|
|
PrepayRequest request = new PrepayRequest();
|
|
|
Amount amount = new Amount();
|
|
|
- amount.setTotal(1); // 金额,单位:分
|
|
|
+ amount.setTotal(req.getTotalAmount()); // 金额,单位:分
|
|
|
request.setAmount(amount);
|
|
|
- request.setSpAppid("wx0fe6b44ff9e5d4d6");
|
|
|
- request.setSpMchid(merchantId);
|
|
|
- request.setSubAppid("wx0fe6b44ff9e5d4d6");
|
|
|
- request.setSpMchid("1739815694");
|
|
|
- request.setDescription("测试商品");
|
|
|
- request.setNotifyUrl("https://47.112.126.153:48080//pay/wx/callback");
|
|
|
- request.setOutTradeNo("OUT_TRADE_NO_20250303_001");
|
|
|
+ request.setSpAppid(wechatMiniPayRequestInfoDO.getSpAppid());
|
|
|
+ request.setSpMchid(wechatMiniPayRequestInfoDO.getSpMchid());
|
|
|
+ request.setSubAppid(wechatMiniPayRequestInfoDO.getSubAppid());
|
|
|
+ request.setSubMchid(wechatMiniPayRequestInfoDO.getSubMchid());
|
|
|
+ request.setDescription(description);
|
|
|
+ request.setNotifyUrl(wechatMiniPayRequestInfoDO.getNotifyUrl());
|
|
|
+ request.setOutTradeNo(outTradeNo);
|
|
|
+ request.setAttach("{}");
|
|
|
|
|
|
Payer payer = new Payer();
|
|
|
- payer.setSpOpenid("omRZq10rC8JR5SysFqVj82CJDqVk"); // 必须传入用户的openid
|
|
|
+ payer.setSpOpenid(openId); // 必须传入用户的openid
|
|
|
request.setPayer(payer);
|
|
|
String requestPaymentAppid = request.getSubAppid() != null ? request.getSubAppid() : request.getSpAppid();
|
|
|
// 4. 调用扩展方法,直接得到前端调起支付所需的参数
|
|
|
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request,requestPaymentAppid);
|
|
|
|
|
|
// 5. 输出或返回给前端
|
|
|
- System.out.println("package: " + response.getPackageVal());
|
|
|
- System.out.println("nonceStr: " + response.getNonceStr());
|
|
|
- System.out.println("timeStamp: " + response.getTimeStamp());
|
|
|
- System.out.println("signType: " + response.getSignType());
|
|
|
- System.out.println("paySign: " + response.getPaySign());
|
|
|
- return CommonResult.success("ok");
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+ result.put("package",response.getPackageVal());
|
|
|
+ result.put("nonceStr",response.getNonceStr());
|
|
|
+ result.put("timeStamp",response.getTimeStamp());
|
|
|
+ result.put("signType",response.getSignType());
|
|
|
+ result.put("paySign",response.getPaySign());
|
|
|
+ result.put("outTradeNo",outTradeNo);
|
|
|
+ return CommonResult.success(result);
|
|
|
}
|
|
|
@PostMapping(value = "/callback", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
|
|
|
@PermitAll
|
|
|
@TenantIgnore
|
|
|
- public CommonResult<String> weChatPayCallBack(){
|
|
|
- System.out.println("wechat callback");
|
|
|
- return CommonResult.success("callBackOk");
|
|
|
+ public String weChatPayCallBack(HttpServletRequest request){
|
|
|
+ try {
|
|
|
+ // 1. 读取请求体
|
|
|
+ String requestBody = getRequestBody(request);
|
|
|
+ // 2. 获取请求头
|
|
|
+ String wechatPaySerial = request.getHeader("Wechatpay-Serial");
|
|
|
+ String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
|
|
|
+ String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
|
|
|
+ String wechatSignature = request.getHeader("Wechatpay-Signature");
|
|
|
+ // 3. 构建 RequestParam
|
|
|
+ com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
|
|
|
+ .serialNumber(wechatPaySerial)
|
|
|
+ .nonce(wechatpayNonce)
|
|
|
+ .signature(wechatSignature)
|
|
|
+ .timestamp(wechatTimestamp)
|
|
|
+ .body(requestBody)
|
|
|
+ .build();
|
|
|
+ // 4. 构建 RSAPublicKeyNotificationConfig
|
|
|
+ NotificationConfig config = new RSAPublicKeyNotificationConfig.Builder()
|
|
|
+ .publicKey(publicKey) // 微信支付公钥字符串
|
|
|
+ .publicKeyId(publicKeyId) // 公钥ID(必须)
|
|
|
+ .apiV3Key(apiV3Key) // APIv3密钥
|
|
|
+ .build();
|
|
|
+ // 5. 初始化解析器
|
|
|
+ NotificationParser parser = new NotificationParser(config);
|
|
|
+ // 6. 验签并解密,直接转换为 Transaction 对象(微信支付订单对象)
|
|
|
+ Transaction transaction = parser.parse(requestParam, Transaction.class);
|
|
|
+ // 9. 获取订单关键信息
|
|
|
+ String outTradeNo = transaction.getOutTradeNo(); // 商户订单号
|
|
|
+ String transactionId = transaction.getTransactionId(); // 微信支付订单号
|
|
|
+ Transaction.TradeStateEnum tradeState = transaction.getTradeState(); // 支付状态
|
|
|
+ // 其他字段请参考 Transaction 类
|
|
|
+ log.info("支付回调成功: outTradeNo={}, transactionId={}, tradeState={}",
|
|
|
+ outTradeNo, transactionId, tradeState);
|
|
|
+
|
|
|
+ // 9. 业务处理(幂等更新订单)
|
|
|
+ boolean success = processOrder(outTradeNo, transactionId, tradeState, transaction);
|
|
|
+ if (!success) {
|
|
|
+ return "FAIL";
|
|
|
+ }
|
|
|
+ // 10. 返回 SUCCESS
|
|
|
+ return "SUCCESS";
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("回调处理异常", e);
|
|
|
+ return "FAIL";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成订单号格式:OUT_TRADE_NO_yyyyMMdd_HHmmssSSS + 两位随机数
|
|
|
+ * 例如:OUT_TRADE_NO_20250303_14353012345
|
|
|
+ */
|
|
|
+ private String generateOrderNo() {
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ String datePart = now.format(DATE_FORMATTER);
|
|
|
+ String timePart = now.format(TIME_FORMATTER); // 精确到毫秒(3位)
|
|
|
+ int randomSuffix = ThreadLocalRandom.current().nextInt(100); // 0-99 两位
|
|
|
+ return PREFIX + datePart + "_" + timePart + String.format("%02d", randomSuffix);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String insertMiniOrder(WechatMiniOrderDO wechatMiniOrderDO){
|
|
|
+ if(CollectionUtils.isEmpty(wechatMiniOrderDO.getItems())){
|
|
|
+ throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR,"明细不能为空");
|
|
|
+ }
|
|
|
+ StringBuilder description = new StringBuilder();
|
|
|
+ wechatMiniOrderDO.setStatus(0);
|
|
|
+ wechatMiniOrderMapper.insert(wechatMiniOrderDO);
|
|
|
+ List<WechatMiniOrderItemDO> items = wechatMiniOrderDO.getItems();
|
|
|
+ for (WechatMiniOrderItemDO item : items) {
|
|
|
+ item.setOrderId(wechatMiniOrderDO.getId());
|
|
|
+ description.append(item.getGoodsName()).append(",数量:").append(item.getQuantity())
|
|
|
+ .append(",单价:").append(item.getPrice())
|
|
|
+ .append(",金额:").append(item.getAmount()).append("。");
|
|
|
+ }
|
|
|
+ wechatMiniOrderItemMapper.insertBatch(items);
|
|
|
+ return description.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 HttpServletRequest 中读取请求体(原始字符串)
|
|
|
+ */
|
|
|
+ private String getRequestBody(HttpServletRequest request) throws IOException {
|
|
|
+ try (BufferedReader reader = request.getReader()) {
|
|
|
+ return reader.lines().collect(Collectors.joining(System.lineSeparator()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean processOrder(String outTradeNo, String transactionId, Transaction.TradeStateEnum tradeState, Transaction transaction) {
|
|
|
+ try {
|
|
|
+ if(tradeState.equals(Transaction.TradeStateEnum.SUCCESS)){
|
|
|
+ wechatMiniOrderMapper.update(new LambdaUpdateWrapper<WechatMiniOrderDO>()
|
|
|
+ .eq(WechatMiniOrderDO::getOutTradeNo,outTradeNo)
|
|
|
+ .set(WechatMiniOrderDO::getStatus,1));
|
|
|
+ }
|
|
|
+ return true; // 成功返回 true
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("业务处理失败", e);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
}
|