系统支付对接、避免返回过多数据

This commit is contained in:
Jerry Yan 2025-04-16 14:55:28 +08:00
parent f6f847e41c
commit 877f37b6f9
16 changed files with 275 additions and 547 deletions

View File

@ -1,73 +0,0 @@
package com.ycwl.basic.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信小程序配置
*
* @author songmingsong
**/
@Data
@Component
@ConfigurationProperties(prefix = "wx")
public class WechatConfig {
/**
* 公众号的appId
*/
private String appId;
/**
* 公众号的密钥
*/
private String appSecret;
/**
* 小程序的AppId
*/
private String miniProgramAppId;
/**
* 小程序的secret
*/
private String miniProgramSecret;
/**
* 申请openid授权
*/
private String grandType;
/**
* 商户号
*/
private String mchId;
/**
* 商户证书序列号
*/
private String mchSerialNo;
/**
* 支付回调接口地址
*/
private String payNotifyUrl;
/**
* 退款回调接口地址
*/
private String refundNotifyUrl;
/**
* 商户API私钥路径
*/
private String keyPath;
/**
* 商户APIV3密钥
*/
private String apiV3;
}

View File

@ -6,7 +6,6 @@ import com.ycwl.basic.biz.PriceBiz;
import com.ycwl.basic.constant.BaseContextHandler; import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.mapper.FaceMapper; import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.model.jwt.JwtInfo; import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.GoodsPriceQueryReq;
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO; import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO; import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.OrderAppPageReq; import com.ycwl.basic.model.mobile.order.OrderAppPageReq;
@ -14,12 +13,7 @@ import com.ycwl.basic.model.mobile.order.RefundOrderReq;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO; import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.order.req.CreateBatchOrderReqVO; import com.ycwl.basic.model.pc.order.req.CreateBatchOrderReqVO;
import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO; import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO;
import com.ycwl.basic.model.pc.order.req.OrderAddReq;
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO; import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.service.mobile.GoodsService;
import com.ycwl.basic.service.pc.OrderService; import com.ycwl.basic.service.pc.OrderService;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil; import com.ycwl.basic.utils.JwtTokenUtil;
@ -28,6 +22,8 @@ import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Map;
/** /**
* @Authorlongbinbin * @Authorlongbinbin
* @Date2024/12/4 17:16 * @Date2024/12/4 17:16
@ -62,7 +58,7 @@ public class AppOrderController {
@ApiOperation("用户端订单新增") @ApiOperation("用户端订单新增")
@PostMapping("/addOrder") @PostMapping("/addOrder")
public ApiResponse<WxPayRespVO> addOrder(@RequestBody CreateOrderReqVO orderAddReq) throws Exception { public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateOrderReqVO orderAddReq) throws Exception {
JwtInfo worker = JwtTokenUtil.getWorker(); JwtInfo worker = JwtTokenUtil.getWorker();
return orderService.createOrder(worker.getUserId(), orderAddReq); return orderService.createOrder(worker.getUserId(), orderAddReq);
} }
@ -70,7 +66,7 @@ public class AppOrderController {
@ApiOperation("用户端打包订单新增") @ApiOperation("用户端打包订单新增")
@PostMapping("/addBatchOrder") @PostMapping("/addBatchOrder")
public ApiResponse<WxPayRespVO> addOrder(@RequestBody CreateBatchOrderReqVO batchOrderReqVO) throws Exception { public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
JwtInfo worker = JwtTokenUtil.getWorker(); JwtInfo worker = JwtTokenUtil.getWorker();
return orderService.createBatchOrder(worker.getUserId(), batchOrderReqVO); return orderService.createBatchOrder(worker.getUserId(), batchOrderReqVO);
} }

View File

@ -8,6 +8,7 @@ import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO; import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity; import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicConfigResp;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO; import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService; import com.ycwl.basic.service.mobile.AppScenicService;
@ -51,9 +52,24 @@ public class AppScenicController {
@GetMapping("/{id}/config") @GetMapping("/{id}/config")
@IgnoreToken @IgnoreToken
public ApiResponse<ScenicConfigEntity> getConfig(@PathVariable Long id){ public ApiResponse<ScenicConfigResp> getConfig(@PathVariable Long id){
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(id); ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(id);
return ApiResponse.success(scenicConfig); ScenicConfigResp resp = new ScenicConfigResp();
resp.setBookRoutine(scenicConfig.getBookRoutine());
resp.setForceFinishTime(scenicConfig.getForceFinishTime());
resp.setTourTime(scenicConfig.getTourTime());
resp.setSampleStoreDay(scenicConfig.getSampleStoreDay());
resp.setFaceStoreDay(scenicConfig.getFaceStoreDay());
resp.setVideoStoreDay(scenicConfig.getVideoStoreDay());
resp.setAllFree(scenicConfig.getAllFree());
resp.setDisableSourceVideo(scenicConfig.getDisableSourceVideo());
resp.setDisableSourceImage(scenicConfig.getDisableSourceImage());
resp.setAntiScreenRecordType(scenicConfig.getAntiScreenRecordType());
resp.setVideoSourceStoreDay(scenicConfig.getVideoSourceStoreDay());
resp.setImageSourceStoreDay(scenicConfig.getImageSourceStoreDay());
resp.setUserSourceExpireDay(scenicConfig.getUserSourceExpireDay());
resp.setBrokerDirectRate(scenicConfig.getBrokerDirectRate());
return ApiResponse.success(resp);
} }
@ApiOperation("查询景区设备总数和拍到用户的机位数量") @ApiOperation("查询景区设备总数和拍到用户的机位数量")

View File

@ -10,6 +10,7 @@ import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -33,12 +34,6 @@ public class AppWxPayController {
@Autowired @Autowired
private WxPayService wxPayService; private WxPayService wxPayService;
@ApiOperation(value = "微信预支付", notes = "微信预支付")
@PostMapping("/createOrder")
public ApiResponse<WxPayRespVO> createOrder(@RequestBody WXPayOrderReqVO req) throws Exception {
return ApiResponse.success(wxPayService.createOrder(req));
}
@ApiOperation(value = "微信支付回调", notes = "微信支付回调") @ApiOperation(value = "微信支付回调", notes = "微信支付回调")
@PostMapping("/payNotify") @PostMapping("/payNotify")
@IgnoreToken @IgnoreToken
@ -46,29 +41,19 @@ public class AppWxPayController {
wxPayService.payNotify(request); wxPayService.payNotify(request);
return ApiResponse.success(BizCodeEnum.REQUEST_OK); return ApiResponse.success(BizCodeEnum.REQUEST_OK);
} }
@PostMapping("/{scenicId}/payNotify")
@ApiOperation(value = "微信退款", notes = "微信退款") @IgnoreToken
@PostMapping("/refundOrder") public ApiResponse<?> payNotifyByScenicId(@PathVariable Long scenicId, HttpServletRequest request) {
public ApiResponse<?> refundOrder(@RequestBody String orderId) throws Exception { wxPayService.payNotify(scenicId, request);
return ApiResponse.buildResult(wxPayService.refundOrder(orderId) ? return ApiResponse.success(BizCodeEnum.REQUEST_OK);
BizCodeEnum.SUCCESS :
BizCodeEnum.ADVANCE_PAYMENT_REFUND_FAILED);
} }
@ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调") @ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调")
@PostMapping("/refundNotify") @PostMapping("/{scenicId}/refundNotify")
@IgnoreToken @IgnoreToken
public ApiResponse<?> refundNotify(@RequestBody String refundResult) throws GeneralSecurityException, IOException { public ApiResponse<?> refundNotify(@PathVariable Long scenicId, HttpServletRequest request) throws GeneralSecurityException, IOException {
return ApiResponse.buildResult(wxPayService.refundNotify(refundResult) ? return ApiResponse.buildResult(wxPayService.refundNotify(scenicId, request) ?
BizCodeEnum.SUCCESS : BizCodeEnum.SUCCESS :
BizCodeEnum.ADVANCE_PAYMENT_CALLBACK_REFUND_FAILED); BizCodeEnum.ADVANCE_PAYMENT_CALLBACK_REFUND_FAILED);
} }
@ApiOperation(value = "微信关闭订单", notes = "微信关闭订单")
@PostMapping("/closeOrder")
@IgnoreToken
public ApiResponse<?> closeOrder(@RequestBody String orderId) {
wxPayService.closeOrder(orderId);
return ApiResponse.buildResult(BizCodeEnum.REQUEST_OK);
}
} }

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType; import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import com.ycwl.basic.pay.enums.PayAdapterType;
import com.ycwl.basic.storage.enums.StorageType; import com.ycwl.basic.storage.enums.StorageType;
import lombok.Data; import lombok.Data;
@ -84,4 +85,7 @@ public class ScenicConfigEntity {
private FaceBodyAdapterType faceType; private FaceBodyAdapterType faceType;
private String faceConfigJson; private String faceConfigJson;
private PayAdapterType payType;
private String payConfigJson;
} }

View File

@ -0,0 +1,45 @@
package com.ycwl.basic.model.pc.scenic.resp;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import com.ycwl.basic.pay.enums.PayAdapterType;
import com.ycwl.basic.storage.enums.StorageType;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @Authorlongbinbin
* @Date2024/12/2 10:53
* 景区配置
*/
@Data
public class ScenicConfigResp {
/**
* 预约流程1-预约2-在线3-全部
*/
private Integer bookRoutine;
private Integer forceFinishTime;
private Integer tourTime;
/**
* 样本保存时间
*/
private Integer sampleStoreDay;
private Integer faceStoreDay;
/**
* 视频保存时间
*/
private Integer videoStoreDay;
private Integer allFree;
private Integer disableSourceVideo;
private Integer disableSourceImage;
private Integer antiScreenRecordType;
private Integer videoSourceStoreDay;
private Integer imageSourceStoreDay;
private Integer userSourceExpireDay;
private BigDecimal brokerDirectRate;
}

View File

@ -1,24 +1,26 @@
package com.ycwl.basic.service.mobile; package com.ycwl.basic.service.mobile;
import com.ycwl.basic.model.wx.WXPayOrderReqVO; import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData; import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Map;
public interface WxPayService { public interface WxPayService {
/** /**
* 微信预支付 * 微信预支付
*/ */
WxPayRespVO createOrder(WXPayOrderReqVO req) throws Exception; Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) throws Exception;
/** /**
* 微信支付回调 * 微信支付回调
*/ */
void payNotify(HttpServletRequest xml); void payNotify(HttpServletRequest request);
void payNotify(Long scenicId, HttpServletRequest request);
/** /**
@ -38,7 +40,7 @@ public interface WxPayService {
/** /**
* 微信退款回调 * 微信退款回调
*/ */
boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException; boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException;
/** /**
* 关闭订单 * 关闭订单
@ -46,4 +48,5 @@ public interface WxPayService {
* @param orderId 订单id订单编号 * @param orderId 订单id订单编号
*/ */
void closeOrder(String orderId) ; void closeOrder(String orderId) ;
} }

View File

@ -3,7 +3,6 @@ package com.ycwl.basic.service.mobile.impl;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.ycwl.basic.config.WechatConfig;
import com.ycwl.basic.constant.BaseContextHandler; import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.constant.NumberConstant; import com.ycwl.basic.constant.NumberConstant;
import com.ycwl.basic.constant.WeiXinConstant; import com.ycwl.basic.constant.WeiXinConstant;

View File

@ -1,28 +1,8 @@
package com.ycwl.basic.service.mobile.impl; package com.ycwl.basic.service.mobile.impl;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.utils.StringUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.TransactionAmount;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.ycwl.basic.biz.OrderBiz; import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.config.WechatConfig;
import com.ycwl.basic.constant.HttpConstant;
import com.ycwl.basic.constant.NumberConstant; import com.ycwl.basic.constant.NumberConstant;
import com.ycwl.basic.constant.WeiXinConstant;
import com.ycwl.basic.enums.BizCodeEnum; import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.enums.OrderStateEnum; import com.ycwl.basic.enums.OrderStateEnum;
import com.ycwl.basic.enums.StatisticEnum; import com.ycwl.basic.enums.StatisticEnum;
@ -35,37 +15,28 @@ import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.req.OrderUpdateReq; import com.ycwl.basic.model.pc.order.req.OrderUpdateReq;
import com.ycwl.basic.model.pc.payment.entity.PaymentEntity; import com.ycwl.basic.model.pc.payment.entity.PaymentEntity;
import com.ycwl.basic.model.wx.WXPayOrderReqVO; import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData; import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
import com.ycwl.basic.pay.adapter.IPayAdapter;
import com.ycwl.basic.pay.entity.CancelOrderRequest;
import com.ycwl.basic.pay.entity.CreateOrderRequest;
import com.ycwl.basic.pay.entity.CreateOrderResponse;
import com.ycwl.basic.pay.entity.PayResponse;
import com.ycwl.basic.pay.entity.RefundResponse;
import com.ycwl.basic.pay.entity.RefundOrderRequest;
import com.ycwl.basic.pay.entity.RefundOrderResponse;
import com.ycwl.basic.repository.OrderRepository; import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.service.mobile.WxPayService; import com.ycwl.basic.service.mobile.WxPayService;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.utils.SnowFlakeUtil; import com.ycwl.basic.utils.SnowFlakeUtil;
import com.ycwl.basic.utils.WXPayUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.wechat.pay.java.core.http.Constant.*;
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
import static com.ycwl.basic.constant.WeiXinConstant.*;
/** /**
* @Author: songmingsong * @Author: songmingsong
@ -77,8 +48,6 @@ import static com.ycwl.basic.constant.WeiXinConstant.*;
@Service @Service
public class WxPayServiceImpl implements WxPayService { public class WxPayServiceImpl implements WxPayService {
@Autowired
private WechatConfig wechatConfig;
@Autowired @Autowired
private PaymentMapper paymentMapper; private PaymentMapper paymentMapper;
@Autowired @Autowired
@ -89,116 +58,50 @@ public class WxPayServiceImpl implements WxPayService {
private OrderBiz orderBiz; private OrderBiz orderBiz;
@Autowired @Autowired
private OrderMapper orderMapper; private OrderMapper orderMapper;
@Autowired
private ScenicService scenicService;
@Override @Override
public WxPayRespVO createOrder(WXPayOrderReqVO req) { public Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) {
PaymentEntity entity = new PaymentEntity(); PaymentEntity entity = new PaymentEntity();
entity.setOrderId(req.getOrderSn()); entity.setOrderId(req.getOrderSn());
entity.setMemberId(req.getMemberId()); entity.setMemberId(req.getMemberId());
entity.setPayPrice(new BigDecimal(BigInteger.valueOf(req.getTotalPrice()), 2)); entity.setPayPrice(new BigDecimal(BigInteger.valueOf(req.getTotalPrice()), 2));
Long entityId = paymentMapper.addGetId(entity); Long entityId = paymentMapper.addGetId(entity);
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
try { try {
// 使用自动更新平台证书的RSA配置 CreateOrderRequest request = new CreateOrderRequest()
Config config = getInstance(wechatConfig); .setOrderNo(String.valueOf(req.getOrderSn()))
// 构建service .setPriceInCents(req.getTotalPrice())
JsapiService service = new JsapiService.Builder().config(config).build(); .setDescription(req.getDescription())
.setGoodsName(req.getGoodsName())
// request.setXxx(val)设置所需参数具体参数可见Request定义 .setUserIdentify(req.getOpenId())
PrepayRequest request = new PrepayRequest(); .setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+scenicId+"/payNotify");
Amount amount = new Amount(); CreateOrderResponse order = scenicPayAdapter.createOrder(request);
amount.setTotal(req.getTotalPrice()); Map<String, Object> paymentParams = scenicPayAdapter.getPaymentParams(order);
request.setAmount(amount); paymentParams.put("needPay", !order.isSkipPay());
request.setAppid(wechatConfig.getMiniProgramAppId()); return paymentParams;
request.setMchid(wechatConfig.getMchId());
request.setDescription(req.getGoodsName());
request.setNotifyUrl(wechatConfig.getPayNotifyUrl());
request.setOutTradeNo(req.getOrderSn().toString());
request.setDescription(req.getDescription());
Payer payer = new Payer();
payer.setOpenid(req.getOpenId());
request.setPayer(payer);
// SettleInfo settleInfo = new SettleInfo();
// settleInfo.setProfitSharing(true);
// request.setSettleInfo(settleInfo);
// 调用下单方法得到应答
PrepayResponse response = service.prepay(request);
WxPayRespVO vo = new WxPayRespVO();
Long timeStamp = System.currentTimeMillis() / NumberConstant.THOUSAND;
vo.setTimeStamp(timeStamp);
String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
vo.setNonceStr(substring);
String signatureStr = Stream.of(wechatConfig.getMiniProgramAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId())
.collect(Collectors.joining("\n", "", "\n"));
String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath());
vo.setPaySign(sign);
vo.setSignType("RSA-SHA256");
vo.setPrepayId("prepay_id=" + response.getPrepayId());
return vo;
} catch (ServiceException e) {
JSONObject parse = JSONObject.parseObject(e.getResponseBody());
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, parse.getString(HttpConstant.Message));
} catch (Exception e) { } catch (Exception e) {
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, e.toString()); throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, e.toString());
} }
} }
@Override @Override
public void payNotify(HttpServletRequest request) { public void payNotify(Long scenicId, HttpServletRequest request) {
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
try { try {
// 读取请求体的信息 PayResponse callbackResponse = scenicPayAdapter.handleCallback(request);
ServletInputStream inputStream = request.getInputStream(); log.info("[微信支付]parse = {}", callbackResponse);
StringBuffer stringBuffer = new StringBuffer();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s;
// 读取回调请求体
while ((s = bufferedReader.readLine()) != null) {
stringBuffer.append(s);
}
String s1 = stringBuffer.toString();
log.warn("微信支付回调:{}", s1);
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
String nonce = request.getHeader(WECHAT_PAY_NONCE);
String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE);
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMchId())
.privateKey(wechatConfig.getKeyPath())
.merchantSerialNumber(wechatConfig.getMchSerialNo())
.apiV3Key(wechatConfig.getApiV3())
.build();
// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(config);
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(serialNo)
.nonce(nonce)
.signature(signature)
.timestamp(timestamp)
// 若未设置signType默认值为 WECHATPAY2-SHA256-RSA2048
.signType(signType)
.body(s1)
.build();
Transaction parse = parser.parse(requestParam, Transaction.class);
log.info("[微信支付]parse = {}", parse);
// 更新订单信息 // 更新订单信息
new Thread(() -> { new Thread(() -> {
long orderId = Long.parseLong(parse.getOutTradeNo()); long orderId = Long.parseLong(callbackResponse.getOrderNo());
switch (parse.getTradeState()) { if (callbackResponse.isPay()) {
case SUCCESS: orderBiz.paidOrder(orderId);
orderBiz.paidOrder(orderId); } else if (callbackResponse.isCancel()) {
break; orderBiz.cancelOrder(orderId);
case NOTPAY: } else if (callbackResponse.isRefund()) {
case CLOSED: orderBiz.refundOrder(orderId);
case REVOKED:
orderBiz.cancelOrder(orderId);
break;
case REFUND:
orderBiz.refundOrder(orderId);
break;
} }
}).start(); }).start();
} catch (Exception e) { } catch (Exception e) {
@ -207,59 +110,29 @@ public class WxPayServiceImpl implements WxPayService {
} }
@Override @Override
public WxchatCallbackSuccessData queryPay(Long orderId) { public void payNotify(HttpServletRequest request) {
WxchatCallbackSuccessData wxchatCallbackSuccessData = new WxchatCallbackSuccessData(); payNotify(0L, request);
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest(); }
queryRequest.setMchid(wechatConfig.getMchId());
queryRequest.setOutTradeNo(orderId.toString());
Config config = getInstance(wechatConfig);
// 构建service
JsapiService service = new JsapiService.Builder().config(config).build();
try {
com.wechat.pay.java.service.payments.model.Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
String successTime = transaction.getSuccessTime();
wxchatCallbackSuccessData.setOrderId(orderId.toString()); @Override
wxchatCallbackSuccessData.setSuccessTime(successTime); public WxchatCallbackSuccessData queryPay(Long orderId) {
wxchatCallbackSuccessData.setTradetype(WeiXinConstant.getDescriptionType(transaction.getTradeType())); return null;
wxchatCallbackSuccessData.setTradestate(WeiXinConstant.getDescriptionState(transaction.getTradeState()));
TransactionAmount amount = transaction.getAmount();
Integer total = amount.getTotal();
wxchatCallbackSuccessData.setTotalMoney(new BigDecimal(total).movePointLeft(2));
} catch (ServiceException e) {
// API返回失败, 例如ORDER_NOT_EXISTS
log.error("[微信退款] code={}, message={}", e.getErrorCode(), e.getErrorMessage());
log.error("[微信退款] Response_body={}", e.getResponseBody());
}
return wxchatCallbackSuccessData;
} }
@Override @Override
public Boolean refundOrder(String orderId) { public Boolean refundOrder(String orderId) {
OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId)); OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
BigDecimal payPrice = order.getPayPrice(); BigDecimal payPrice = order.getPayPrice();
long priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).longValue(); // 转换为分int int priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).intValue(); // 转换为分int
RefundOrderRequest request = new RefundOrderRequest()
Config config = .setOrderNo(orderId)
new RSAAutoCertificateConfig.Builder() .setPrice(priceInCents)
.merchantId(wechatConfig.getMchId()) .setRefundNo(SnowFlakeUtil.getId())
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥商户私钥会用来生成请求的签名 .setRefundPrice(priceInCents)
.privateKey(wechatConfig.getKeyPath()) .setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+order.getScenicId()+"/refundNotify");
.merchantSerialNumber(wechatConfig.getMchSerialNo()) RefundOrderResponse response = scenicPayAdapter.refund(request);
.apiV3Key(wechatConfig.getApiV3()) if (response.isSuccess()) {
.build();
RefundService service = new RefundService.Builder().config(config).build();
CreateRequest request = new CreateRequest();
request.setNotifyUrl(wechatConfig.getRefundNotifyUrl());
AmountReq amountReq = new AmountReq();
amountReq.setTotal(priceInCents);
amountReq.setRefund(priceInCents);
amountReq.setCurrency(WECHATPAY_CURRENCY_CNY);
request.setAmount(amountReq);
request.setOutTradeNo(orderId);
request.setOutRefundNo(SnowFlakeUtil.getId());
Refund refundResult = service.create(request);
if (refundResult.getStatus() == SUCCESS) {
OrderUpdateReq orderUpdateReq = new OrderUpdateReq(); OrderUpdateReq orderUpdateReq = new OrderUpdateReq();
orderUpdateReq.setId(Long.parseLong(orderId)); orderUpdateReq.setId(Long.parseLong(orderId));
orderUpdateReq.setRefundStatus(OrderStateEnum.REFUNDED.getType()); orderUpdateReq.setRefundStatus(OrderStateEnum.REFUNDED.getType());
@ -272,31 +145,14 @@ public class WxPayServiceImpl implements WxPayService {
} }
@Override @Override
public boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException { public boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException {
// 转为map格式 IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
Map<String, String> jsonMap = JSONObject.parseObject(refundResult, Map.class); try {
RefundResponse callbackResponse = scenicPayAdapter.handleRefundCallback(request);
log.info("[微信支付]parse = {}", callbackResponse);
/* // 更新订单信息
* 退款成功后返回一个加密字段resource,以下为解密 long orderId = Long.parseLong(callbackResponse.getOrderNo());
* 解密需要从resource参数中获取到ciphertextnonceassociated_data这三个参数进行解密
*/
String resource = JSONObject.toJSONString(jsonMap.get(REFUNDS_RESOURCE));
JSONObject object = JSONObject.parseObject(resource);
String ciphertext = String.valueOf(object.get(REFUNDS_CIPHERTEXT));
String nonce = String.valueOf(object.get(REFUNDS_NONCE));
String associated_data = String.valueOf(object.get(REFUNDS_ASSOCIATED_DATA));
String resultStr = decryptToString(associated_data.getBytes(String.valueOf(StandardCharsets.UTF_8)),
nonce.getBytes(String.valueOf(StandardCharsets.UTF_8)),
ciphertext);
Map<String, String> reqInfo = JSONObject.parseObject(resultStr, Map.class);
String refund_status = reqInfo.get(REFUNDS_REFUND_STATUS);// 退款状态
String out_trade_no = reqInfo.get(WECHATPAY_OUT_TRADE_NO); // 订单号
if (!StringUtils.isEmpty(refund_status) && WECHATPAY_SUCCESS.equals(refund_status)) {
long orderId = Long.parseLong(out_trade_no);
orderBiz.refundOrder(orderId); orderBiz.refundOrder(orderId);
OrderEntity order = orderRepository.getOrder(orderId); OrderEntity order = orderRepository.getOrder(orderId);
@ -306,117 +162,19 @@ public class WxPayServiceImpl implements WxPayService {
statisticsRecordAddReq.setScenicId(order.getScenicId()); statisticsRecordAddReq.setScenicId(order.getScenicId());
statisticsRecordAddReq.setMorphId(orderId); statisticsRecordAddReq.setMorphId(orderId);
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq); statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
log.info("[微信退款回调]退款成功");
return true; return true;
} else { } catch (Exception e) {
log.error("[微信退款回调]退款失败"); log.error("微信退款回调失败", e);
return false; return false;
} }
} }
@Override @Override
public void closeOrder(String orderId) { public void closeOrder(String orderId) {
CloseOrderRequest closeOrderRequest = new CloseOrderRequest(); OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
closeOrderRequest.setOutTradeNo(orderId); IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
closeOrderRequest.setMchid(wechatConfig.getMchId()); CancelOrderRequest request = new CancelOrderRequest()
Config config = getInstance(wechatConfig); .setOrderNo(orderId);
// 构建service scenicPayAdapter.cancelOrder(request);
JsapiService service = new JsapiService.Builder().config(config).build();
service.closeOrder(closeOrderRequest);
}
/**
* 退款回调 解密数据
*
* @param associatedData
* @param nonce
* @param ciphertext
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(wechatConfig.getApiV3().getBytes(), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 生成退款请求token
*
* @param method
* @param orderId
* @param body
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws SignatureException
*/
public String getToken(String method, String orderId, String body) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, SignatureException {
String nonceStr = WXPayUtil.generateNonceStr();
long timestamp = System.currentTimeMillis() / NumberConstant.THOUSAND; // 生成时间戳
String parameter = method + "\n"
+ REFUNDS_URi + orderId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
// 对参数进行加密
byte[] bytes = parameter.getBytes(String.valueOf(StandardCharsets.UTF_8));
Signature sign = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = PemUtil.loadPrivateKeyFromString(wechatConfig.getKeyPath()); // privateKeyPath是商户证书密钥的位置apiclient_key.pem
sign.initSign(privateKey); // 商户密钥文件路径
sign.update(bytes);
String signature = Base64.getEncoder().encodeToString(sign.sign());
// 获取token
String token = "mchid=\"" + wechatConfig.getMchId() + "\"," // 商户号
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + wechatConfig.getMchSerialNo() + "\"," // merchantSerialNumber是微信支付中申请的证书序列号
+ "signature=\"" + signature + "\"";
return REFUNDS_SCHEMA + token;
}
/**
* 一个商户号只能初始化一个配置否则会因为重复的下载任务报错
*/
private static class Holder {
private static volatile Config instance;
static void init(WechatConfig wechatConfig) {
instance = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMchId())
.privateKey(wechatConfig.getKeyPath())
.merchantSerialNumber(wechatConfig.getMchSerialNo())
.apiV3Key(wechatConfig.getApiV3())
.build();
}
}
public static Config getInstance(WechatConfig wechatConfig) {
if (Holder.instance == null) {
synchronized (Holder.class) {
if (Holder.instance == null) {
Holder.init(wechatConfig);
}
}
}
return Holder.instance;
} }
} }

View File

@ -8,14 +8,13 @@ import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.req.CreateBatchOrderReqVO; import com.ycwl.basic.model.pc.order.req.CreateBatchOrderReqVO;
import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO; import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO;
import com.ycwl.basic.model.pc.order.req.OrderUpdateReq; import com.ycwl.basic.model.pc.order.req.OrderUpdateReq;
import com.ycwl.basic.model.pc.order.req.OrderAddReq;
import com.ycwl.basic.model.pc.order.req.OrderReqQuery; import com.ycwl.basic.model.pc.order.req.OrderReqQuery;
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO; import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
import com.ycwl.basic.model.pc.order.resp.OrderRespVO; import com.ycwl.basic.model.pc.order.resp.OrderRespVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @Authorlongbinbin * @Authorlongbinbin
@ -63,7 +62,7 @@ public interface OrderService {
ApiResponse<PageInfo<OrderRespVO>> refundPageQuery(OrderReqQuery query); ApiResponse<PageInfo<OrderRespVO>> refundPageQuery(OrderReqQuery query);
ApiResponse<WxPayRespVO> createOrder(Long userId, CreateOrderReqVO orderAddReq) throws Exception; ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO orderAddReq) throws Exception;
ApiResponse<WxPayRespVO> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception; ApiResponse<Map<String, Object>> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception;
} }

View File

@ -6,6 +6,7 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq; import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO; import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.pay.adapter.IPayAdapter;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
@ -41,4 +42,6 @@ public interface ScenicService {
IStorageAdapter getScenicLocalStorageAdapter(Long scenicId); IStorageAdapter getScenicLocalStorageAdapter(Long scenicId);
IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId); IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId);
IPayAdapter getScenicPayAdapter(Long scenicId);
} }

View File

@ -33,7 +33,6 @@ import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.task.entity.TaskEntity; import com.ycwl.basic.model.pc.task.entity.TaskEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity; import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.model.wx.WXPayOrderReqVO; import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.repository.FaceRepository; import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.PriceRepository; import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.repository.VideoRepository; import com.ycwl.basic.repository.VideoRepository;
@ -52,7 +51,9 @@ import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -167,11 +168,12 @@ public class OrderServiceImpl implements OrderService {
/** /**
* 发起支付 * 发起支付
* @param order 订单 *
* @param order 订单
* @param orderItems 商品详情 * @param orderItems 商品详情
* @return 支付请求结果 * @return 支付请求结果
*/ */
private WxPayRespVO initiatePayment(OrderEntity order, List<OrderItemEntity> orderItems) throws Exception { private Map<String, Object> initiatePayment(OrderEntity order, List<OrderItemEntity> orderItems) throws Exception {
WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO(); WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO();
String goodsName = null; String goodsName = null;
if (orderItems.size() > 1) { if (orderItems.size() > 1) {
@ -186,12 +188,6 @@ public class OrderServiceImpl implements OrderService {
goodsName = "景区照片包"; goodsName = "景区照片包";
} }
} }
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
// 0元支付
WxPayRespVO wxPayRespVO = new WxPayRespVO();
wxPayRespVO.setNeedPay(false);
return wxPayRespVO;
}
wxPayOrderReqVO.setOpenId(order.getOpenId()) wxPayOrderReqVO.setOpenId(order.getOpenId())
.setMemberId(order.getMemberId()) .setMemberId(order.getMemberId())
.setOrderSn(order.getId()) .setOrderSn(order.getId())
@ -199,7 +195,7 @@ public class OrderServiceImpl implements OrderService {
.setGoodsName(goodsName) .setGoodsName(goodsName)
.setDescription(goodsName); .setDescription(goodsName);
return wxPayService.createOrder(wxPayOrderReqVO); return wxPayService.createOrder(order.getScenicId(), wxPayOrderReqVO);
} }
@Override @Override
@ -360,7 +356,7 @@ public class OrderServiceImpl implements OrderService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ApiResponse<WxPayRespVO> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception { public ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception {
IsBuyRespVO isBuy = orderBiz.isBuy(userId, createOrderReqVO.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId()); IsBuyRespVO isBuy = orderBiz.isBuy(userId, createOrderReqVO.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
if (isBuy.isBuy()) { if (isBuy.isBuy()) {
return ApiResponse.fail("您已购买此内容,无需重复购买!"); return ApiResponse.fail("您已购买此内容,无需重复购买!");
@ -442,16 +438,18 @@ public class OrderServiceImpl implements OrderService {
} }
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) { if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
orderBiz.paidOrder(order.getId()); orderBiz.paidOrder(order.getId());
return ApiResponse.success(new WxPayRespVO()); HashMap<String, Object> data = new HashMap<>();
data.put("needPay", false);
return ApiResponse.success(data);
} else { } else {
WxPayRespVO wxPayRespVO = initiatePayment(order, orderItems); Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
return ApiResponse.success(wxPayRespVO); return ApiResponse.success(wxPayRespVO);
} }
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ApiResponse<WxPayRespVO> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception { public ApiResponse<Map<String, Object>> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(batchOrderReqVO.getScenicId(), batchOrderReqVO.getType(), batchOrderReqVO.getGoodsId()); PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(batchOrderReqVO.getScenicId(), batchOrderReqVO.getType(), batchOrderReqVO.getGoodsId());
if (priceConfig == null) { if (priceConfig == null) {
return ApiResponse.fail("该套餐暂未开放购买"); return ApiResponse.fail("该套餐暂未开放购买");
@ -504,9 +502,11 @@ public class OrderServiceImpl implements OrderService {
} }
if (order.getPayPrice().equals(BigDecimal.ZERO)) { if (order.getPayPrice().equals(BigDecimal.ZERO)) {
orderBiz.paidOrder(order.getId()); orderBiz.paidOrder(order.getId());
return ApiResponse.success(new WxPayRespVO()); HashMap<String, Object> data = new HashMap<>();
data.put("needPay", false);
return ApiResponse.success(data);
} else { } else {
WxPayRespVO wxPayRespVO = initiatePayment(order, orderItems); Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
return ApiResponse.success(wxPayRespVO); return ApiResponse.success(wxPayRespVO);
} }
} }

View File

@ -12,6 +12,8 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq; import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery; import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO; import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.pay.PayFactory;
import com.ycwl.basic.pay.adapter.IPayAdapter;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService; import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService; import com.ycwl.basic.service.task.TaskFaceService;
@ -106,6 +108,7 @@ public class ScenicServiceImpl implements ScenicService {
scenicRepository.clearCache(id); scenicRepository.clearCache(id);
scenicFaceBodyAdapterMap.remove(id); scenicFaceBodyAdapterMap.remove(id);
scenicStorageAdapterMap.remove(id); scenicStorageAdapterMap.remove(id);
scenicPayAdapterMap.remove(id);
return ApiResponse.success(true); return ApiResponse.success(true);
}else { }else {
return ApiResponse.fail("景区删除失败"); return ApiResponse.fail("景区删除失败");
@ -200,6 +203,7 @@ public class ScenicServiceImpl implements ScenicService {
scenicStorageAdapterMap.remove(config.getScenicId()); scenicStorageAdapterMap.remove(config.getScenicId());
scenicTmpStorageAdapterMap.remove(config.getScenicId()); scenicTmpStorageAdapterMap.remove(config.getScenicId());
scenicLocalStorageAdapterMap.remove(config.getScenicId()); scenicLocalStorageAdapterMap.remove(config.getScenicId());
scenicPayAdapterMap.remove(config.getScenicId());
} }
@ -276,4 +280,20 @@ public class ScenicServiceImpl implements ScenicService {
return adapter; return adapter;
}); });
} }
private static final Map<Long, IPayAdapter> scenicPayAdapterMap = new ConcurrentHashMap<>();
@Override
public IPayAdapter getScenicPayAdapter(Long scenicId) {
return scenicPayAdapterMap.computeIfAbsent(scenicId, (key) -> {
IPayAdapter adapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getPayType() != null) {
adapter = PayFactory.getAdapter(scenicConfig.getPayType());
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getPayConfigJson(), Map.class));
} else {
adapter = PayFactory.use();
}
return adapter;
});
}
} }

View File

@ -49,60 +49,6 @@ mybatis-plus:
# 指定使用的日志配置文件 # 指定使用的日志配置文件
logging: logging:
config: classpath:logback-spring.xml config: classpath:logback-spring.xml
# 微信小程序相关配置
wx:
# 公众号的appId
appId: fix
# 公众号的密钥
appSecret: fix
# 小程序的AppId
miniProgramAppId: wxe7ff26af70bfc37c
# 小程序的secret
miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695
# 申请openid授权
grandType: authorization_code
# 推送模板
push:
templateId: 5b8vTm7kvwYubqDxb3dxBqFIhc3Swt5l7QHSK5r-ZRI
# 商户号
mchId: 1700540331
# 商户证书序列号
mchSerialNo: 2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0
# 支付回调接口地址
payNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/payNotify
# 退款回调接口地址
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
# 商户API私钥路径
keyPath: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
# 商户APIV3密钥
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai
# 存储 # 存储
storage: storage:
@ -168,7 +114,45 @@ facebody:
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx" accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c" accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
region: "cn-shanghai" region: "cn-shanghai"
#支付
pay:
default-use: zt
configs:
- name: zt
type: WX_MP_PAY
config:
merchantId: "1700540331"
appId: "wxe7ff26af70bfc37c"
privateKey: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
serialNumber: "2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0"
apiV3Key: ZHENTUAIzhentuaiZHENTUAIzhentuai
notify: notify:
defaultUse: "" defaultUse: ""
configs: configs:

View File

@ -54,57 +54,6 @@ mybatis-plus:
# 指定使用的日志配置文件 # 指定使用的日志配置文件
logging: logging:
config: classpath:logback-spring-prod.xml config: classpath:logback-spring-prod.xml
# 微信小程序相关配置
wx:
# 公众号的appId
appId: fix
# 公众号的密钥
appSecret: fix
# 小程序的AppId
miniProgramAppId: wxe7ff26af70bfc37c
# 小程序的secret
miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695
# 申请openid授权
grandType: authorization_code
# 商户号
mchId: 1700540331
# 商户证书序列号
mchSerialNo: 2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0
# 支付回调接口地址
payNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/payNotify
# 退款回调接口地址
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
# 商户API私钥路径
keyPath: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
# 商户APIV3密钥
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai
# 存储 # 存储
storage: storage:
@ -171,7 +120,45 @@ facebody:
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx" accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c" accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
region: "cn-shanghai" region: "cn-shanghai"
#支付
pay:
default-use: zt
configs:
- name: zt
type: WX_MP_PAY
config:
merchantId: "1700540331"
appId: "wxe7ff26af70bfc37c"
privateKey: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
serialNumber: "2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0"
apiV3Key: ZHENTUAIzhentuaiZHENTUAIzhentuai
# 通知到人 # 通知到人
notify: notify:
defaultUse: "developer" defaultUse: "developer"

View File

@ -118,7 +118,9 @@
watermark_scenic_text=#{watermarkScenicText}, watermark_scenic_text=#{watermarkScenicText},
watermark_dt_format=#{watermarkDtFormat}, watermark_dt_format=#{watermarkDtFormat},
face_type=#{faceType}, face_type=#{faceType},
face_config_json=#{faceConfigJson} face_config_json=#{faceConfigJson},
pay_type=#{payType},
pay_config_json=#{payConfigJson}
</set> </set>
where id = #{id} where id = #{id}
</update> </update>