|
|
@@ -0,0 +1,195 @@
|
|
|
+package com.zhentao.service.impl;
|
|
|
+
|
|
|
+import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
|
|
|
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
|
|
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
|
|
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
|
|
|
+import com.github.binarywang.wxpay.config.WxPayConfig;
|
|
|
+import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
+import com.github.binarywang.wxpay.service.WxPayService;
|
|
|
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
|
|
+import com.github.binarywang.wxpay.util.SignUtils;
|
|
|
+import com.zhentao.entity.ActivityOrder;
|
|
|
+import com.zhentao.entity.ActivityRegistration;
|
|
|
+import com.zhentao.entity.Wx;
|
|
|
+import com.zhentao.pojo.Users;
|
|
|
+import com.zhentao.mapper.ActivityOrderMapper;
|
|
|
+import com.zhentao.mapper.ActivityRegistrationMapper;
|
|
|
+import com.zhentao.service.ActivityOrderService;
|
|
|
+import com.zhentao.service.UsersService;
|
|
|
+import com.zhentao.service.WxService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.RandomStringUtils;
|
|
|
+import org.apache.commons.lang3.RandomUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动订单服务实现
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class ActivityOrderServiceImpl implements ActivityOrderService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ActivityOrderMapper activityOrderMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ActivityRegistrationMapper activityRegistrationMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private UsersService usersService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WxService wxService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Map<String, Object> createOrderAndGetPayParams(Long userId, Integer activityId, String activityName, Double price) throws WxPayException {
|
|
|
+ // 1. 生成订单号
|
|
|
+ String orderNo = generateOrderNo();
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+
|
|
|
+ // 2. 创建待支付订单
|
|
|
+ ActivityOrder order = new ActivityOrder();
|
|
|
+ order.setUserId(userId);
|
|
|
+ order.setActivityId(activityId);
|
|
|
+ order.setActivityName(activityName);
|
|
|
+ order.setOrderNo(orderNo);
|
|
|
+ order.setPaymentAmount(BigDecimal.valueOf(price));
|
|
|
+ order.setPaymentMethod("微信支付");
|
|
|
+ order.setStatus(0); // 待支付
|
|
|
+ order.setCreateTime(now);
|
|
|
+ activityOrderMapper.insert(order);
|
|
|
+
|
|
|
+ // 3. 构建微信支付请求
|
|
|
+ WxPayUnifiedOrderRequest payRequest = buildWxPayRequest(orderNo, activityName, price, userId);
|
|
|
+ WxPayUnifiedOrderResult wxPayResult = createWxPayOrder(payRequest);
|
|
|
+
|
|
|
+ // 4. 生成前端调起支付的参数
|
|
|
+ Map<String, Object> payParams = generatePayParams(wxPayResult, price);
|
|
|
+ payParams.put("orderNo", orderNo);
|
|
|
+ return payParams;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public String handlePayNotify(String notifyData) throws WxPayException {
|
|
|
+ // 1. 解析回调数据并验证签名
|
|
|
+ WxPayConfig payConfig = getWxPayConfig();
|
|
|
+ WxPayService wxPayService = new WxPayServiceImpl();
|
|
|
+ wxPayService.setConfig(payConfig);
|
|
|
+
|
|
|
+ WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(notifyData);
|
|
|
+ String orderNo = notifyResult.getOutTradeNo();
|
|
|
+ String transactionId = notifyResult.getTransactionId();
|
|
|
+
|
|
|
+ // 2. 查询待支付订单
|
|
|
+ ActivityOrder order = activityOrderMapper.selectByOrderNo(orderNo);
|
|
|
+ if (order == null || order.getStatus() != 0) {
|
|
|
+ log.warn("活动订单不存在或已处理:{}", orderNo);
|
|
|
+ return WxPayNotifyResponse.fail("订单不存在或已处理");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 验证支付金额
|
|
|
+ int totalFee = order.getPaymentAmount().multiply(new BigDecimal("100")).intValue();
|
|
|
+ if (Integer.parseInt(String.valueOf(notifyResult.getTotalFee())) != totalFee) {
|
|
|
+ log.warn("活动订单金额不一致:{},实际支付:{}", orderNo, notifyResult.getTotalFee());
|
|
|
+ return WxPayNotifyResponse.fail("金额不一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 更新订单状态为已支付
|
|
|
+ order.setStatus(1);
|
|
|
+ order.setPaymentTime(LocalDateTime.now());
|
|
|
+ order.setTransactionId(transactionId);
|
|
|
+ order.setUpdateTime(LocalDateTime.now());
|
|
|
+ activityOrderMapper.updateById(order);
|
|
|
+
|
|
|
+ // 5. 创建活动报名记录
|
|
|
+ ActivityRegistration registration = new ActivityRegistration();
|
|
|
+ registration.setActivityId(order.getActivityId());
|
|
|
+ registration.setUserId(order.getUserId().intValue());
|
|
|
+ registration.setRegistrationTime(LocalDateTime.now());
|
|
|
+ registration.setStatus(1); // 已报名
|
|
|
+ registration.setCreatedTime(LocalDateTime.now());
|
|
|
+ registration.setUpdatedTime(LocalDateTime.now());
|
|
|
+ activityRegistrationMapper.insert(registration);
|
|
|
+
|
|
|
+ log.info("活动报名成功:用户{},活动{},订单{}", order.getUserId(), order.getActivityId(), orderNo);
|
|
|
+ return WxPayNotifyResponse.success("处理成功");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ActivityOrder getOrderByOrderNo(String orderNo) {
|
|
|
+ return activityOrderMapper.selectByOrderNo(orderNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateOrderNo() {
|
|
|
+ return "ACTIVITY" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayUnifiedOrderRequest buildWxPayRequest(String orderNo, String activityName, Double price, Long userId) {
|
|
|
+ Users user = usersService.getById(userId);
|
|
|
+ if (user == null || user.getWechatOpenid() == null) {
|
|
|
+ throw new RuntimeException("用户微信信息未绑定");
|
|
|
+ }
|
|
|
+
|
|
|
+ WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
|
|
|
+ request.setOutTradeNo(orderNo);
|
|
|
+ request.setBody("活动报名-" + activityName);
|
|
|
+ request.setTotalFee(BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
|
|
|
+ request.setSpbillCreateIp("127.0.0.1");
|
|
|
+ request.setNotifyUrl("https://mini.workervip.com/api/activity-order/notify");
|
|
|
+ request.setTradeType("JSAPI");
|
|
|
+ request.setOpenid(user.getWechatOpenid());
|
|
|
+ return request;
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayUnifiedOrderResult createWxPayOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
|
|
|
+ WxPayService wxPayService = new WxPayServiceImpl();
|
|
|
+ wxPayService.setConfig(getWxPayConfig());
|
|
|
+ return wxPayService.unifiedOrder(request);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> generatePayParams(WxPayUnifiedOrderResult wxPayResult, Double price) {
|
|
|
+ Wx wxConfig = wxService.list().get(0);
|
|
|
+ String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
|
|
|
+ String nonceStr = RandomStringUtils.randomAlphanumeric(32);
|
|
|
+ String prepayId = wxPayResult.getPrepayId();
|
|
|
+
|
|
|
+ Map<String, String> signParams = new HashMap<>();
|
|
|
+ signParams.put("appId", wxConfig.getAppId());
|
|
|
+ signParams.put("timeStamp", timeStamp);
|
|
|
+ signParams.put("nonceStr", nonceStr);
|
|
|
+ signParams.put("package", "prepay_id=" + prepayId);
|
|
|
+ signParams.put("signType", "MD5");
|
|
|
+
|
|
|
+ String paySign = SignUtils.createSign(signParams, "7f633cbabd894b4d213bc6edffe3b119");
|
|
|
+
|
|
|
+ Map<String, Object> payParams = new HashMap<>();
|
|
|
+ payParams.put("appId", wxConfig.getAppId());
|
|
|
+ payParams.put("timeStamp", timeStamp);
|
|
|
+ payParams.put("nonceStr", nonceStr);
|
|
|
+ payParams.put("package", "prepay_id=" + prepayId);
|
|
|
+ payParams.put("signType", "MD5");
|
|
|
+ payParams.put("paySign", paySign);
|
|
|
+ payParams.put("totalFee", BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
|
|
|
+ return payParams;
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayConfig getWxPayConfig() {
|
|
|
+ Wx wxConfig = wxService.list().get(0);
|
|
|
+ WxPayConfig payConfig = new WxPayConfig();
|
|
|
+ payConfig.setAppId(wxConfig.getAppId());
|
|
|
+ payConfig.setMchId(wxConfig.getMchId());
|
|
|
+ payConfig.setMchKey("7f633cbabd894b4d213bc6edffe3b119");
|
|
|
+ payConfig.setNotifyUrl("https://mini.workervip.com/api/activity-order/notify");
|
|
|
+ return payConfig;
|
|
|
+ }
|
|
|
+}
|