新增:微信Native支付

This commit is contained in:
gxwebsoft
2024-05-12 22:52:37 +08:00
parent a0a090dc6d
commit ba214b7290
11 changed files with 392 additions and 254 deletions

View File

@@ -52,6 +52,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/api/login-alipay/*",
"/api/wx-login/loginByMpWxPhone",
"/api/system/wx-native-pay/**",
"/api/system/wx-pay/**",
"/api/wxWorkQrConnect",
"/api/sys/user-plan-log/wx-pay/**",
"/api/wx-official/**",

View File

@@ -0,0 +1,19 @@
package com.gxwebsoft.common.core.utils;
import java.util.HashMap;
import java.util.Map;
import com.wechat.pay.java.core.Config;
public class WxNativeUtil {
private static final Map<Integer, Config> tenantConfigs = new HashMap<>();
public static void addConfig(Integer tenantId, Config config) {
tenantConfigs.put(tenantId, config);
}
public static Config getConfig(Integer tenantId) {
return tenantConfigs.get(tenantId);
}
}

View File

@@ -1,22 +1,20 @@
package com.gxwebsoft.common.system.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Company;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.entity.OrderInfo;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.param.OrderParam;
import com.gxwebsoft.common.system.service.CompanyService;
import com.gxwebsoft.common.system.service.OrderInfoService;
import com.gxwebsoft.common.system.service.OrderService;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.param.OrderParam;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -24,8 +22,9 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 订单控制器
@@ -103,9 +102,9 @@ public class OrderController extends BaseController {
order.setUserId(loginUser.getUserId());
order.setOpenid(loginUser.getOpenid());
order.setRealName(loginUser.getRealName());
order.setStartTime(timeMillis / 1000);
order.setAddTime(timeMillis / 1000);
order.setPhone(loginUser.getPhone());
final List<Integer> collect = order.getOrderInfoList().stream().map(OrderInfo::getStartTime).collect(Collectors.toList());
order.setStartTime(Collections.min(collect));
order.setVersion(10);
if (orderService.save(order)) {
order.getOrderInfoList().forEach(d -> {

View File

@@ -1,23 +1,19 @@
package com.gxwebsoft.common.system.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.WxNativeUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.entity.Setting;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.common.system.param.SettingParam;
import com.gxwebsoft.common.system.service.OrderService;
import com.gxwebsoft.common.system.service.SettingService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSANotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
@@ -25,69 +21,59 @@ import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Map;
import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_NO_PAY;
import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_SUCCESS;
import java.util.Set;
@Api(tags = "微信Native支付接口")
@RestController
@RequestMapping("/api/system/wx-native-pay")
public class WxNativePayController extends BaseController {
/** 商户号 */
@Value("${spring.profiles.active}")
String active;
public static String merchantId = "1246610101";
/** 商户API私钥路径 */
public static String privateKeyPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/apiclient_key.pem";
// public static String privateKeyPath = "/Users/gxwebsoft/cert/1246610101_20240511_cert/apiclient_cert.pem";
/** 商户证书序列号 */
public static String merchantSerialNumber = "48749613B40AA8F1D768583FC352358E13EB5AF0";
/** 商户APIV3密钥 */
public static String apiV3Key = "zGufUcqa7ovgxRL0kF5OlPr482EZwtn9";
// 公众号的AppID
public static String appId = "wx541db955e7a62709";
private final Config wxPayConfig;
@Resource
private OrderService orderService;
private RedisUtil redisUtil;
private Config wxPayConfig;
@Resource
private ConfigProperties config;
@Resource
private SettingService settingService;
@Resource
private OrderService orderService;
public WxNativePayController() {
File file = new File(privateKeyPath);
if (file.exists()) {
this.wxPayConfig =
new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
}else {
System.out.println("无法访问文件");
this.wxPayConfig = null ;
}
}
@ApiOperation("生成付款码")
@PostMapping("/codeUrl")
public ApiResult<?> getCodeUrl(@RequestBody Order order) {
order.setMoney(new BigDecimal(0.01));
order.setOrderNo(CommonUtil.createOrderNo());
String key = "Payment:wxPay:".concat(getTenantId().toString());
final Payment payment = redisUtil.get(key, Payment.class);
if (payment == null) {
return fail("微信支付未配置");
}
// 获取微信小程序配置信息
JSONObject setting = settingService.getBySettingKey("mp-weixin");
final String appId = setting.getString("appId");
final String appSecret = setting.getString("appSecret");
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
// 构建service
NativePayService service = new NativePayService.Builder().config(wxPayConfig).build();
NativePayService service = new NativePayService.Builder().config(this.getWxPayConfig()).build();
// request.setXxx(val)设置所需参数具体参数可见Request定义
PrepayRequest request = new PrepayRequest();
// 计算金额
order.setMoney(new BigDecimal(0.01));
order.setOrderNo(CommonUtil.createOrderNo());
BigDecimal decimal = order.getMoney();
final BigDecimal multiply = decimal.multiply(new BigDecimal(100));
// 将 BigDecimal 转换为 Integer
@@ -96,9 +82,9 @@ public class WxNativePayController extends BaseController {
amount.setTotal(money);
request.setAmount(amount);
request.setAppid(appId);
request.setMchid(merchantId);
request.setDescription("网宿软件企业版-1年授权");
request.setNotifyUrl("https://server.gxwebsoft.com/api/system/wx-native-pay/notify/10150");
request.setMchid(payment.getMchId());
request.setDescription("企业版-1年授权");
request.setNotifyUrl("https://server.gxwebsoft.com/api/system/wx-native-pay/notify/" + getTenantId());
request.setOutTradeNo(order.getOrderNo());
// 调用下单方法,得到应答
PrepayResponse response = service.prepay(request);
@@ -110,6 +96,32 @@ public class WxNativePayController extends BaseController {
}
private Config getWxPayConfig() {
// 获取租户ID
final Integer tenantId = getTenantId();
Config build = WxNativeUtil.getConfig(tenantId);
if (build != null) {
return build;
}
String key = "Payment:wxPay:".concat(tenantId.toString());
final Payment payment = redisUtil.get(key, Payment.class);
System.out.println("payment = " + payment);
String apiclientKey = config.getUploadPath().concat("/file").concat(payment.getApiclientKey());
// 开发环境配置
if(active.equals("dev")){
apiclientKey = privateKeyPath;
}
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(payment.getMchId())
.privateKeyFromPath(apiclientKey)
.merchantSerialNumber(payment.getMerchantSerialNumber())
.apiV3Key(payment.getApiKey())
.build();
System.out.println("config = " + config);
WxNativeUtil.addConfig(tenantId, config);
return config;
}
@ApiModelProperty("异步通知")
@PostMapping("/notify/{tenantId}")
public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
@@ -126,7 +138,4 @@ public class WxNativePayController extends BaseController {
return "fail";
}
}

View File

@@ -2,43 +2,25 @@ package com.gxwebsoft.common.system.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.AlipayConfigUtil;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.entity.Setting;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.common.system.mapper.SettingMapper;
import com.gxwebsoft.common.system.param.SettingParam;
import com.gxwebsoft.common.system.service.OrderInfoService;
import com.gxwebsoft.common.system.service.OrderService;
import com.gxwebsoft.common.system.service.SettingService;
import com.gxwebsoft.common.system.service.UserService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSANotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_NO_PAY;
@@ -52,35 +34,36 @@ import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_SUCC
*/
@Api(tags = "会员特权购买记录表管理")
@RestController
@RequestMapping("/api/system/notify")
@RequestMapping("/api/system/wx-pay")
public class WxPayNotifyController extends BaseController {
@Value("${spring.profiles.active}")
String active;
@Resource
private OrderService orderService;
@Resource
private ConfigProperties config;
private RedisUtil redisUtil;
@Resource
private SettingMapper settingMapper;
private ConfigProperties conf;
// 本地证书
public static String wechatpayCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/wechatpay_4A3231584E93B6AE77820074D07EADEACCB7E223.pem"; // 平台证书
@ApiModelProperty("异步通知")
@PostMapping("/wx-pay/notify/{tenantId}")
@PostMapping("/notify/{tenantId}")
public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
System.out.println("异步通知*************** = ");
System.out.println("request header = " + header);
System.out.println("request body = " + body);
System.out.println("tenantId = " + tenantId);
// System.out.println("request header = " + header);
// System.out.println("request body = " + body);
// System.out.println("tenantId = " + tenantId);
// 获取支付配置信息用于解密
final SettingParam param = new SettingParam();
param.setSettingKey("payment");
param.setTenantId(tenantId);
final String uploadPath = config.getUploadPath(); // 服务器本地路径
final Setting payment = settingMapper.getBySettingKeyIgnore(param);
final JSONObject jsonObject = JSONObject.parseObject(payment.getContent());
final String apiV3key = jsonObject.getString("wechatApiKey");
final String apiclientCert = uploadPath.concat("file").concat(jsonObject.getString("apiclientCert"));
// System.out.println("apiV3key ====== " + apiV3key);
// System.out.println("payment ===== " + payment);
String key = "Payment:wxPay:".concat(tenantId.toString());
final Payment payment = redisUtil.get(key, Payment.class);
String privateKey = payment.getApiKey();
String apiclientCert = conf.getUploadPath().concat("/file").concat(payment.getApiclientCert());
// 开发环境配置
if(active.equals("dev")){
apiclientCert = wechatpayCertPath;
}
com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
.serialNumber(header.get("wechatpay-serial"))
@@ -93,10 +76,11 @@ public class WxPayNotifyController extends BaseController {
// 如果已经初始化了 RSAAutoCertificateConfig可直接使用
// 没有的话,则构造一个
NotificationConfig config = new RSANotificationConfig.Builder()
.apiV3Key(apiV3key)
.apiV3Key(privateKey)
.certificatesFromPath(apiclientCert)
.build();
// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(config);
@@ -107,18 +91,19 @@ public class WxPayNotifyController extends BaseController {
final String transactionId = transaction.getTransactionId();
final Integer total = transaction.getAmount().getTotal();
final String tradeStateDesc = transaction.getTradeStateDesc();
// final Transaction.TradeStateEnum tradeState = transaction.getTradeState();
// final Transaction.TradeTypeEnum tradeType = transaction.getTradeType();
// System.out.println("transaction = " + transaction);
// System.out.println("tradeStateDesc = " + tradeStateDesc);
// System.out.println("tradeType = " + tradeType);
// System.out.println("tradeState = " + tradeState);
// System.out.println("outTradeNo = " + outTradeNo);
// System.out.println("amount = " + total);
final Transaction.TradeStateEnum tradeState = transaction.getTradeState();
final Transaction.TradeTypeEnum tradeType = transaction.getTradeType();
System.out.println("transaction = " + transaction);
System.out.println("tradeStateDesc = " + tradeStateDesc);
System.out.println("tradeType = " + tradeType);
System.out.println("tradeState = " + tradeState);
System.out.println("outTradeNo = " + outTradeNo);
System.out.println("amount = " + total);
if (StrUtil.equals("支付成功", tradeStateDesc)) {
// 1. 查询要处理的订单
Order order = orderService.getByOutTradeNo(outTradeNo);
System.out.println("order = " + order);
// 2. 已支付则跳过
if (order.getPayStatus().equals(PAY_STATUS_SUCCESS)) {
return "SUCCESS";
@@ -126,8 +111,8 @@ public class WxPayNotifyController extends BaseController {
// 2. 未支付则处理更新订单状态
if (order.getPayStatus().equals(PAY_STATUS_NO_PAY)) {
// 5. TODO 处理订单状态
order.setPayStatus(PAY_STATUS_SUCCESS);
order.setPayTime(DateUtil.date());
order.setPayStatus(PAY_STATUS_SUCCESS);
order.setTransactionId(transactionId);
// 实际付款金额Integer除以100后转BigDecimal
DecimalFormat df = new DecimalFormat("0.00");

View File

@@ -2,9 +2,8 @@ package com.gxwebsoft.common.system.entity;
import java.math.BigDecimal;
import cn.hutool.core.util.DesensitizedUtil;
import com.baomidou.mybatisplus.annotation.*;
import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@@ -27,21 +26,146 @@ import lombok.EqualsAndHashCode;
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "ID")
@ApiModelProperty(value = "订单号")
@TableId(value = "order_id", type = IdType.AUTO)
private Integer orderId;
@ApiModelProperty(value = "订单号")
@ApiModelProperty(value = "订单")
private String orderNo;
@ApiModelProperty(value = "类型")
private Integer type;
@ApiModelProperty(value = "微信支付订单号")
private String wechatOrder;
@ApiModelProperty(value = "订单金额")
@ApiModelProperty(value = "微信退款订单号")
private String refundOrder;
@ApiModelProperty(value = "场馆id用于权限判断")
private Integer merchantId;
@ApiModelProperty(value = "用户id")
private Integer userId;
@ApiModelProperty(value = "使用的优惠券id")
private Integer couponId;
@ApiModelProperty(value = "使用的会员卡id")
private Integer cardId;
@ApiModelProperty(value = "关联管理员id")
private Integer aid;
@ApiModelProperty(value = "核销管理员id")
private Integer adminId;
@ApiModelProperty(value = "IC卡号")
private String code;
@ApiModelProperty(value = "真实姓名")
private String name;
@ApiModelProperty(value = "手机号码")
private String phone;
@ApiModelProperty(value = "订单总额")
private BigDecimal totalPrice;
@ApiModelProperty(value = "减少的金额使用VIP会员折扣、优惠券抵扣、优惠券折扣后减去的价格")
private BigDecimal reducePrice;
@ApiModelProperty(value = "实际付款")
private BigDecimal payPrice;
@ApiModelProperty(value = "用于统计")
private BigDecimal price;
@ApiModelProperty(value = "价钱,用于积分赠送")
private BigDecimal money;
@ApiModelProperty(value = "实际付款金额(包含运费)")
private BigDecimal payPrice;
@ApiModelProperty(value = "退款金额")
private BigDecimal refundMoney;
@ApiModelProperty(value = "教练价格")
private BigDecimal coachPrice;
@ApiModelProperty(value = "教练id")
private Integer coachId;
@ApiModelProperty(value = "1微信支付2积分3支付宝4现金5POS机6VIP月卡7VIP年卡8VIP次卡9IC月卡10IC年卡11IC次卡12免费13VIP充值卡14IC充值卡15积分支付16VIP季卡17IC季卡")
private Integer payType;
@ApiModelProperty(value = "1已付款2未付款")
private Integer payStatus;
@ApiModelProperty(value = "1已完成2未使用3已取消4退款申请中5退款被拒绝6退款成功7客户端申请退款")
private Integer orderStatus;
@ApiModelProperty(value = "优惠类型0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡")
private Integer type;
@ApiModelProperty(value = "二维码地址,保存订单号,支付成功后才生成")
private String qrcode;
@ApiModelProperty(value = "优惠说明")
private String desc;
@ApiModelProperty(value = "vip月卡年卡、ic月卡年卡回退次数")
private Integer returnNum;
@ApiModelProperty(value = "vip充值回退金额")
private BigDecimal returnMoney;
@ApiModelProperty(value = "预约详情开始时间数组")
private Integer startTime;
@ApiModelProperty(value = "是否已开具发票1已开发票2未开发票3不能开具发票")
private Integer isInvoice;
@ApiModelProperty(value = "付款时间")
private Date payTime;
@ApiModelProperty(value = "退款时间")
private Integer refundTime;
@ApiModelProperty(value = "申请退款时间")
private Integer refundApplyTime;
@ApiModelProperty(value = "对账情况1=已对账2=未对账3=已对账金额对不上4=未查询到该订单")
private Integer checkBill;
@ApiModelProperty(value = "系统版本")
private Integer version;
@ApiModelProperty(value = "备注")
private String comments;
@ApiModelProperty(value = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "租户id")
private Integer tenantId;
@ApiModelProperty(value = "商户名称")
@TableField(exist = false)
private String merchantName;
@ApiModelProperty(value = "商户图标")
@TableField(exist = false)
private String merchantAvatar;
@ApiModelProperty(value = "微信OPENID,用于微信支付")
@TableField(exist = false)
private String openid;
@ApiModelProperty(value = "订单详情")
@TableField(exist = false)
private List<OrderInfo> orderInfoList;
@ApiModelProperty(value = "套餐ID")
private Integer planId;
@@ -55,33 +179,17 @@ public class Order implements Serializable {
@ApiModelProperty(value = "卡名称")
private String priceName;
@ApiModelProperty(value = "用户ID")
private Integer userId;
@ApiModelProperty(value = "持有者ID")
private Integer memberId;
@ApiModelProperty(value = "真实姓名")
private String realName;
@ApiModelProperty(value = "联系电话")
private String phone;
@ApiModelProperty(value = "订单总额")
private BigDecimal totalPrice;
@ApiModelProperty(value = "付款时间")
private Date payTime;
@ApiModelProperty(value = "1微信支付2积分3支付宝4现金5POS机6VIP月卡7VIP年卡8VIP次卡9IC月卡10IC年卡11IC次卡12免费13VIP充值卡14IC充值卡15积分支付16VIP季卡17IC季卡")
private Integer payType;
@ApiModelProperty(value = "支付流水号")
private String transactionId;
@ApiModelProperty(value = "付款状态(10未付款 20已付款)")
private Integer payStatus;
@ApiModelProperty(value = "支付方式(余额/微信/支付宝)")
private String payMethod;
@@ -115,41 +223,9 @@ public class Order implements Serializable {
@ApiModelProperty(value = "排序(数字越小越靠前)")
private Integer sortNumber;
@ApiModelProperty(value = "商户ID")
private Integer merchantId;
@ApiModelProperty(value = "备注")
private String comments;
@ApiModelProperty(value = "状态, 0正常, 1冻结")
private Integer status;
@ApiModelProperty(value = "是否删除, 0否, 1是")
@TableLogic
private Integer deleted;
@ApiModelProperty(value = "租户id")
private Integer tenantId;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "修改时间")
private Date updateTime;
@ApiModelProperty(value = "用于微信支付")
@TableField(exist = false)
private String openid;
@ApiModelProperty(value = "预约详情开始时间数组")
private Long startTime;
@ApiModelProperty(value = "下单时间")
private Long addTime;
@ApiModelProperty(value = "系统版本")
private Integer version;
@ApiModelProperty(value = "租户名称")
@TableField(exist = false)
private String tenantName;
@@ -158,8 +234,12 @@ public class Order implements Serializable {
@TableField(exist = false)
private Integer companyId;
@ApiModelProperty(value = "订单详情")
@ApiModelProperty("手机号(脱敏)")
@TableField(exist = false)
private List<OrderInfo> orderInfoList;
private String mobile;
public String getMobile() {
return DesensitizedUtil.mobilePhone(this.phone);
}
}

View File

@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -91,4 +93,10 @@ public class OrderInfo implements Serializable {
@ApiModelProperty(value = "租户id")
private Integer tenantId;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "修改时间")
private Date updateTime;
}

View File

@@ -60,6 +60,9 @@ public class Payment implements Serializable {
@ApiModelProperty(value = "商户证书序列号")
private String merchantSerialNumber;
@ApiModelProperty(value = "支付结果通知")
private String notifyUrl;
@ApiModelProperty(value = "备注")
private String comments;

View File

@@ -4,9 +4,8 @@
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*,b.tenant_name
SELECT a.*
FROM sys_order a
LEFT JOIN sys_tenant b ON a.tenant_id = b.tenant_id
<where>
<if test="param.orderId != null">
AND a.order_id = #{param.orderId}

View File

@@ -1,17 +1,17 @@
package com.gxwebsoft.common.system.service.impl;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.system.entity.OrderInfo;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.common.system.mapper.OrderMapper;
import com.gxwebsoft.common.system.service.OrderService;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.param.OrderParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.Order;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.common.system.mapper.OrderMapper;
import com.gxwebsoft.common.system.param.OrderParam;
import com.gxwebsoft.common.system.service.OrderService;
import com.gxwebsoft.common.system.service.PaymentService;
import com.gxwebsoft.common.system.service.SettingService;
import com.wechat.pay.java.core.Config;
@@ -21,6 +21,7 @@ import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -36,6 +37,8 @@ import java.util.List;
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Value("${spring.profiles.active}")
String active;
@Resource
private ConfigProperties config;
@Resource
@@ -44,6 +47,19 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
private RedisUtil redisUtil;
@Resource
private PaymentService paymentService;
public static String privateKeyPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/apiclient_key.pem";
public static String privateCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/apiclient_cert.pem";
public static String serialNumber = "48749613B40AA8F1D768583FC352358E13EB5AF0";
public static String merchantId = "1246610101";
public static String appId = "wx541db955e7a62709";
public static String apiV3Key = "zGufUcqa7ovgxRL0kF5OlPr482EZwtn9";
/**
* 平台证书生成命令(勿删)
* java -jar CertificateDownloader.jar -k zGufUcqa7ovgxRL0kF5OlPr482EZwtn9 -m 1246610101 -f /www/wwwroot/file.ws//file/20240511/280fb6cf7eec4c2d9661c2508123c6a8.pem -s 48749613B40AA8F1D768583FC352358E13EB5AF0 -o /www/cert/
*/
public static String wechatpayCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/wechatpay_4A3231584E93B6AE77820074D07EADEACCB7E223.pem"; // 平台证书
@Override
public PageResult<Order> pageRel(OrderParam param) {
PageParam<Order, OrderParam> page = new PageParam<>(param);
@@ -57,7 +73,6 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
List<Order> list = baseMapper.selectListRel(param);
// 排序
PageParam<Order, OrderParam> page = new PageParam<>();
//page.setDefaultOrder("create_time desc");
return page.sortRecords(list);
}
@@ -68,6 +83,19 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
return param.getOne(baseMapper.selectListRel(param));
}
@Override
public Order getByOutTradeNo(String outTradeNo) {
System.out.println("outTradeNo = " + outTradeNo);
OrderParam param = new OrderParam();
param.setOrderNo(outTradeNo);
return param.getOne(baseMapper.getByOutTradeNo(param));
}
@Override
public void updateByOutTradeNo(Order order) {
baseMapper.updateByOutTradeNo(order);
}
/**
* 创建微信支付
*
@@ -76,44 +104,32 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
*/
@Override
public HashMap<String, String> createWxOrder(Order order) {
final String uploadPath = config.getUploadPath(); // 服务器本地路径
// 服务器本地路径
final String uploadPath = config.getUploadPath();
final HashMap<String, String> orderInfo = new HashMap<>();
// 微信小程序(微信支付)
String key = "Payment:wxPay:".concat(order.getTenantId().toString());
final Payment payment = redisUtil.get(key, Payment.class);
System.out.println("payment1 = " + payment);
final JSONObject mpWx = settingService.getBySettingKey("mp-weixin");
// final JSONObject payment = settingService.getBySettingKey("payment");
// 计算金额
BigDecimal decimal = order.getTotalPrice();
final BigDecimal multiply = decimal.multiply(new BigDecimal(100));
// 将 BigDecimal 转换为 Integer
Integer money = multiply.intValue();
final String appId = mpWx.getString("appId");
final String mchId = payment.getMchId();
final String openid = order.getOpenid(); // openid
final String notifyUrl = config.getServerUrl() + "/system/notify/" + order.getTenantId(); // 异步通知地址
final String privateKey = uploadPath.concat("file").concat(payment.getApiclientKey()); // 秘钥证书
final String apiclientCert = uploadPath.concat("file").concat(payment.getApiclientCert());
final String merchantSerialNumber = payment.getMerchantSerialNumber(); // 证书序列号
final String apiV3key = payment.getApiKey();
System.out.println("privateKey = " + privateKey);
System.out.println("apiclientCert = " + apiclientCert);
System.out.println("merchantSerialNumber = " + merchantSerialNumber);
System.out.println("apiV3key = " + apiV3key);
System.out.println("mchId = " + mchId);
System.out.println("appId = " + appId);
String privateKey = uploadPath.concat("/file").concat(payment.getApiclientKey()); // 秘钥证书
String apiclientCert = uploadPath.concat("/file").concat(payment.getApiclientCert());
// 开发环境配置
if(active.equals("dev")){
privateKey = privateKeyPath;
apiclientCert = wechatpayCertPath;
}
Config config =
new RSAConfig.Builder()
.merchantId(mchId)
.merchantId(payment.getMchId())
.privateKeyFromPath(privateKey)
.merchantSerialNumber(merchantSerialNumber)
.merchantSerialNumber(payment.getMerchantSerialNumber())
.wechatPayCertificatesFromPath(apiclientCert)
.build();
@@ -125,18 +141,25 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
amount.setTotal(money);
amount.setCurrency("CNY");
request.setAmount(amount);
request.setAppid(appId);
request.setMchid(mchId);
request.setAppid(mpWx.getString("appId"));
request.setMchid(payment.getMchId());
request.setDescription(order.getComments());
request.setNotifyUrl(notifyUrl);
request.setNotifyUrl("https://server.gxwebsoft.com/api/system/wx-pay/notify/" + order.getTenantId());
request.setOutTradeNo(order.getOrderNo());
request.setAttach(order.getTenantId().toString());
final Payer payer = new Payer();
payer.setOpenid(openid);
payer.setOpenid(order.getOpenid());
request.setPayer(payer);
System.out.println("request2 = " + request);
if (StrUtil.isNotBlank(payment.getNotifyUrl())) {
request.setNotifyUrl(payment.getNotifyUrl().concat("/").concat(order.getTenantId().toString()));
}
// 测试金额
if(active.equals("dev")){
amount.setTotal(1);
request.setAmount(amount);
}
System.out.println("request = " + request);
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
System.out.println("response = " + response);
orderInfo.put("provider", "wxpay");
orderInfo.put("timeStamp", response.getTimeStamp());
orderInfo.put("nonceStr", response.getNonceStr());
@@ -145,16 +168,4 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
orderInfo.put("paySign", response.getPaySign());
return orderInfo;
}
@Override
public Order getByOutTradeNo(String outTradeNo) {
OrderParam param = new OrderParam();
param.setOrderNo(outTradeNo);
return param.getOne(baseMapper.getByOutTradeNo(param));
}
@Override
public void updateByOutTradeNo(Order order) {
baseMapper.updateByOutTradeNo(order);
}
}

View File

@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgIUSjIxWE6Ttq53ggB00H6t6sy34iMwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjMwOTE5MTUxNTQ4WhcNMjgwOTE3MTUxNTQ4WjBuMRgwFgYDVQQDDA9U
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5AOeoNuRReVPfOodE
TTE/wq96OK/7MI1lkwgtRlOIqwFGbGPxPx+wiLweWOWAeGrd0h+YuktIZezLhMhB
8pkJBzxz4U+zoQ9n3yY4CgDUBeAO8eNHhEQTTOTFUIvIlRxyr0EVuTHNP7pIkxA6
gUvajWjJFbvU393vDHA9RflWrBNw1qVjkPPUx6axizD3wS8f77bwuspEWGTza/pS
g96HWUwFh9OSlQNPOjPG4km2YRQwGhoRMlLeZsUB+a0PtV0HI/B0TbY5u2EmPt0R
uNZLmcwImtiANYmySww6gp5uo4+im0P/kHKynPrW1SkS+8M9JP5T7Xck3bnHNv4S
9UOPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAHd42YyvxvvjYEIkCURHweCSQpWQrdsnP
AU2rcVzOx0kDxjq7+W2HkIkYeAZfE8pyBs5c39tgK+qospiDsKa9WYeBNyIRcCvN
q9ObLqSV4Cy/8lQMNh4Q37cdc3X+pAlTr7MtKka8ZcXYvbMBqus0dfJZayZvW7Ak
nnaXXJ4k7urgHOGYsZlZ+HC+DC/sYoN3DXzvg3XPlL0SNEQH0cWrRbaQnpOKVMk5
TptbeNHKJfUxVW5jh4GtBFqvLeiOruY+gFYg7UkCKWo9ZIYe7/mEvJeHYh3acTTl
DOl3L0fR5KR7vqFMwZEUZxVOs6K2ANSCr57OQPBV++MG4DPr3yOhCQ==
-----END CERTIFICATE-----