Commit c47aeba4 by 郑云飞

支付功能完善

parent e86b0ede
...@@ -176,6 +176,7 @@ wx: ...@@ -176,6 +176,7 @@ wx:
subAppId: #服务商模式下的子商户公众账号ID subAppId: #服务商模式下的子商户公众账号ID
subMchId: #服务商模式下的子商户号 subMchId: #服务商模式下的子商户号
keyPath: C:\\ProgramData\\certKey\xinrenli\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头) keyPath: C:\\ProgramData\\certKey\xinrenli\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
notifyUrl: http://xinrenli.nyinhong.com/api//xinrenli/order/notify # 微信支付回调接口
# mp: # mp:
# useRedis: false # useRedis: false
# redisConfig: # redisConfig:
......
...@@ -31,6 +31,7 @@ public class WxPayConfiguration { ...@@ -31,6 +31,7 @@ public class WxPayConfiguration {
payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId())); payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId())); payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath())); payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
// 可以指定是否使用沙箱环境 // 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false); payConfig.setUseSandboxEnv(false);
......
...@@ -41,4 +41,9 @@ public class WxPayProperties { ...@@ -41,4 +41,9 @@ public class WxPayProperties {
*/ */
private String keyPath; private String keyPath;
/**
* 支付回调接口
*/
private String notifyUrl;
} }
...@@ -12,6 +12,10 @@ import lombok.AccessLevel; ...@@ -12,6 +12,10 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/** /**
* 获取地址类 * 获取地址类
* *
...@@ -57,4 +61,46 @@ public class AddressUtils { ...@@ -57,4 +61,46 @@ public class AddressUtils {
} }
return UNKNOWN; return UNKNOWN;
} }
/**
* 获取ip
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ipAddress;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
log.error(e.getMessage(), e);
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress = "";
}
return ipAddress;
}
} }
package com.yongqi.common.utils.redis;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.yongqi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CodeUtils {
public static String next(String type) {
return next(type, 4);
}
public static String next(String type, int limit) {
return type + DateUtils.dateTimeNow("yyyyMMdd") + autoGenericCode(RandomUtil.randomInt(getMax(limit)), limit);
}
private static String autoGenericCode(int code, int num) {
// System.out.println(code);
String result = "";
// 保留num的位数
// num 代表长度为4
// d 代表参数为正数型
result = String.format("%0" + num + "d", code);
return result;
}
private static Integer getMax(int limit) {
String a = "";
for (int i = 0; i < limit; i++) {
a = a + "9";
}
return Integer.valueOf(a);
}
private static String random(){
Random random = new Random();
int ends = random.nextInt(99);
return autoGenericCode(ends, 2);
}
public static String createSerialNumber(String type) {
Object object = RedisUtils.getCacheObject(type);
int num = 0;
if (ObjectUtil.isEmpty(object)) {
RedisUtils.setCacheObject(type, 1, Duration.ofMillis(-1));
num = 1;
}else {
num = Integer.parseInt(object.toString());
}
log.info("redis中的编码为:{}", num);
String code = autoGenericCode(num, 4);
RedisUtils.setCacheObject(type, num + 1);
return type + DateUtils.dateTimeNow("yyMMdd") + code + random();
}
public static void main(String[] args) {
// System.out.println(next("KBHMD"));
// createSerialNumber("KBHMD");
System.out.println(createSerialNumber("KBHMD"));
}
}
...@@ -5,15 +5,18 @@ import java.util.Arrays; ...@@ -5,15 +5,18 @@ import java.util.Arrays;
import com.yongqi.common.core.domain.model.LoginUser; import com.yongqi.common.core.domain.model.LoginUser;
import com.yongqi.common.helper.LoginHelper; import com.yongqi.common.helper.LoginHelper;
import com.yongqi.common.utils.ip.AddressUtils;
import com.yongqi.xinrenli.domain.DbOrder; import com.yongqi.xinrenli.domain.DbOrder;
import com.yongqi.xinrenli.domain.bo.DbOrderEditBo; import com.yongqi.xinrenli.domain.bo.DbOrderEditBo;
import com.yongqi.xinrenli.domain.vo.ReportFormsVo; import com.yongqi.xinrenli.domain.vo.ReportFormsVo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*; import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.aspectj.weaver.ast.Var;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import com.yongqi.common.annotation.RepeatSubmit; import com.yongqi.common.annotation.RepeatSubmit;
...@@ -146,10 +149,23 @@ public class DbOrderController extends BaseController { ...@@ -146,10 +149,23 @@ public class DbOrderController extends BaseController {
@Log(title = "下单", businessType = BusinessType.DELETE) @Log(title = "下单", businessType = BusinessType.DELETE)
@RequestMapping("/orderPay") @RequestMapping("/orderPay")
public R orderPay(@NotNull(message = "主键不能为空") @RequestParam("id") Long orderId public R orderPay(@NotNull(message = "主键不能为空") @RequestParam("id") Long orderId
, @RequestParam(value = "id", required = false) Long couponId) { , @RequestParam(value = "id", required = false) Long couponId
, HttpServletRequest request) {
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
return iDbOrderService.orderPay(orderId, couponId, loginUser); String ipAddr = AddressUtils.getIpAddr(request);
return iDbOrderService.orderPay(orderId, couponId, loginUser, ipAddr);
} }
/**
* 下单
*/
@SaCheckPermission("xinrenli:order:notify")
@Log(title = "下单", businessType = BusinessType.DELETE)
@RequestMapping("/notify")
public R payCallback(@RequestBody String xmlData) {
return iDbOrderService.payCallback(xmlData);
}
/** /**
* 报表 * 报表
*/ */
......
package com.yongqi.xinrenli.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
* @author Administrator
*/
@Data
public class WxPayOrderResult {
/**
* 微信生成的预支付会话标识
*/
private String prepayId;
/**
* 交易类型
*/
private String tradeType;
private String timeStamp;
/**
* 随机字符串
*/
private String nonceStr;
/**
* 签名
*/
private String sign;
/**
* 签名方式
*/
private String signType = "MD5";
/**
* 支付时间
*/
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss")
@JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss")
private LocalDateTime createTime;
}
...@@ -10,11 +10,10 @@ public enum OrderStatusEnum { ...@@ -10,11 +10,10 @@ public enum OrderStatusEnum {
PUBLISHED(0, "已发布"), PUBLISHED(0, "已发布"),
REJECTED(1, "已驳回"), REJECTED(1, "已驳回"),
TO_BE_PAID(2, "待支付"), TO_BE_PAID(2, "待支付"),
PAYMENT_IN_PROGRESS(3, "支付中"), RECEIVED_ORDER(3, "已接单"),
RECEIVED_ORDER(4, "已接单"), FINISHED(4, "已完成"),
FINISHED(5, "已完成"), REFUBD_IN_PROGRESS(5, "退款中"),
REFUBD_IN_PROGRESS(6, "退款中"), REFUNDED(6, "已退款"),
REFUNDED(7, "已退款"),
; ;
private final Integer code; private final Integer code;
......
package com.yongqi.xinrenli.service; package com.yongqi.xinrenli.service;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.yongqi.common.core.domain.R; import com.yongqi.common.core.domain.R;
import com.yongqi.common.core.domain.model.LoginUser; import com.yongqi.common.core.domain.model.LoginUser;
import com.yongqi.xinrenli.domain.DbOrder;
import com.yongqi.xinrenli.domain.bo.DbOrderEditBo; import com.yongqi.xinrenli.domain.bo.DbOrderEditBo;
import com.yongqi.xinrenli.domain.vo.DbOrderVo; import com.yongqi.xinrenli.domain.vo.DbOrderVo;
import com.yongqi.xinrenli.domain.bo.DbOrderBo; import com.yongqi.xinrenli.domain.bo.DbOrderBo;
...@@ -10,7 +10,6 @@ import com.yongqi.common.core.page.TableDataInfo; ...@@ -10,7 +10,6 @@ import com.yongqi.common.core.page.TableDataInfo;
import com.yongqi.common.core.domain.PageQuery; import com.yongqi.common.core.domain.PageQuery;
import com.yongqi.xinrenli.domain.vo.ReportFormsVo; import com.yongqi.xinrenli.domain.vo.ReportFormsVo;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
...@@ -69,7 +68,7 @@ public interface IDbOrderService { ...@@ -69,7 +68,7 @@ public interface IDbOrderService {
*/ */
TableDataInfo<DbOrderVo> homeList(DbOrderBo bo, PageQuery pageQuery); TableDataInfo<DbOrderVo> homeList(DbOrderBo bo, PageQuery pageQuery);
R orderPay(Long id, Long couponId, LoginUser loginUser); R orderPay(Long id, Long couponId, LoginUser loginUser, String ipAddr);
ReportFormsVo reportForms(); ReportFormsVo reportForms();
...@@ -80,4 +79,11 @@ public interface IDbOrderService { ...@@ -80,4 +79,11 @@ public interface IDbOrderService {
* @return * @return
*/ */
Integer unpaidJob(); Integer unpaidJob();
/**
* 支付回调
* @param xmlData
* @return
*/
R payCallback(String xmlData) throws WxPayException;
} }
package com.yongqi.xinrenli.service.impl; package com.yongqi.xinrenli.service.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.WxPayService;
import com.yongqi.common.core.domain.R; import com.yongqi.common.core.domain.R;
import com.yongqi.common.core.domain.entity.SysUser;
import com.yongqi.common.core.domain.model.LoginUser; import com.yongqi.common.core.domain.model.LoginUser;
import com.yongqi.common.utils.StringUtils; import com.yongqi.common.utils.StringUtils;
import com.yongqi.common.core.page.TableDataInfo; import com.yongqi.common.core.page.TableDataInfo;
...@@ -16,19 +16,20 @@ import com.yongqi.common.core.domain.PageQuery; ...@@ -16,19 +16,20 @@ import com.yongqi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yongqi.common.utils.redis.CodeUtils;
import com.yongqi.xinrenli.domain.DbCoupon; import com.yongqi.xinrenli.domain.DbCoupon;
import com.yongqi.xinrenli.domain.DbFile; import com.yongqi.xinrenli.domain.DbFile;
import com.yongqi.xinrenli.domain.bo.DbFileBo;
import com.yongqi.xinrenli.domain.bo.DbOrderEditBo; import com.yongqi.xinrenli.domain.bo.DbOrderEditBo;
import com.yongqi.xinrenli.domain.vo.DbFileVo; import com.yongqi.xinrenli.domain.vo.DbFileVo;
import com.yongqi.xinrenli.domain.vo.ReportFormsVo; import com.yongqi.xinrenli.domain.vo.ReportFormsVo;
import com.yongqi.xinrenli.domain.vo.WxPayOrderResult;
import com.yongqi.xinrenli.enums.DeleteStatusEnum; import com.yongqi.xinrenli.enums.DeleteStatusEnum;
import com.yongqi.xinrenli.enums.FileEnumServiceType; import com.yongqi.xinrenli.enums.FileEnumServiceType;
import com.yongqi.xinrenli.enums.OrderStatusEnum;
import com.yongqi.xinrenli.mapper.DbCouponMapper; import com.yongqi.xinrenli.mapper.DbCouponMapper;
import com.yongqi.xinrenli.mapper.DbFileMapper; import com.yongqi.xinrenli.mapper.DbFileMapper;
import com.yongqi.xinrenli.service.IDbCouponService;
import lombok.Data;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
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 com.yongqi.xinrenli.domain.bo.DbOrderBo; import com.yongqi.xinrenli.domain.bo.DbOrderBo;
...@@ -47,6 +48,7 @@ import java.util.*; ...@@ -47,6 +48,7 @@ import java.util.*;
* @author zyf * @author zyf
* @date 2023-03-09 * @date 2023-03-09
*/ */
@Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
public class DbOrderServiceImpl implements IDbOrderService { public class DbOrderServiceImpl implements IDbOrderService {
...@@ -278,13 +280,15 @@ public class DbOrderServiceImpl implements IDbOrderService { ...@@ -278,13 +280,15 @@ public class DbOrderServiceImpl implements IDbOrderService {
/** /**
* 下单 * 下单
*
* @param orderId 订单id * @param orderId 订单id
* @param couponId 优惠券id * @param couponId 优惠券id
* @param loginUser 当前登录用户 * @param loginUser 当前登录用户
* @param ipAddr
* @return * @return
*/ */
@Override @Override
public R orderPay(Long orderId, Long couponId, LoginUser loginUser) { public R orderPay(Long orderId, Long couponId, LoginUser loginUser, String ipAddr) {
// 1.根据订单id获取订单信息 // 1.根据订单id获取订单信息
DbOrder dbOrder = this.baseMapper.selectById(orderId); DbOrder dbOrder = this.baseMapper.selectById(orderId);
// 2.根据卡券id获取卡券信息 // 2.根据卡券id获取卡券信息
...@@ -296,7 +300,8 @@ public class DbOrderServiceImpl implements IDbOrderService { ...@@ -296,7 +300,8 @@ public class DbOrderServiceImpl implements IDbOrderService {
BigDecimal payAmount = dbOrder.getActualAmount().subtract(dbCoupon.getFullSubtraction()); BigDecimal payAmount = dbOrder.getActualAmount().subtract(dbCoupon.getFullSubtraction());
dbOrder.setPayAmount(payAmount); dbOrder.setPayAmount(payAmount);
dbOrder.setUseCouponId(couponId); dbOrder.setUseCouponId(couponId);
dbOrder.setStatus(); String orderNo = CodeUtils.createSerialNumber("XQ");
dbOrder.setOrderNo(orderNo);
// 4.组装支付数据 // 4.组装支付数据
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
// 需求标题 // 需求标题
...@@ -306,30 +311,30 @@ public class DbOrderServiceImpl implements IDbOrderService { ...@@ -306,30 +311,30 @@ public class DbOrderServiceImpl implements IDbOrderService {
} }
request.setBody(join); request.setBody(join);
// 商户订单号 // 商户订单号
request.setOutTradeNo(consumerOrder.getOrderCode()); request.setOutTradeNo(orderNo);
// 子商户号
request.setSubMchId(dealer.getWxShopNo()); BigDecimal actualPrice = payAmount.multiply(BigDecimal.valueOf(100));
BigDecimal actualPrice = consumerOrder.getFinalPrice().multiply(BigDecimal.valueOf(100));
// 标价金额 // 标价金额
request.setTotalFee((actualPrice.intValue())); request.setTotalFee((actualPrice.intValue()));
// 客户端IP // 客户端IP
request.setSpbillCreateIp(ip); request.setSpbillCreateIp(ipAddr);
// 交易类型 // 交易类型
request.setTradeType(WxPayConstants.TradeType.JSAPI); request.setTradeType(WxPayConstants.TradeType.JSAPI);
// 签名类型,默认为MD5,支持HMAC-SHA256和MD5。 // 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
request.setSignType(WxPayConstants.SignType.MD5); request.setSignType(WxPayConstants.SignType.MD5);
// 用户标识 // 用户标识
request.setOpenid(wxUser.getOpenId()); request.setOpenid(loginUser.getOpenId());
// 5.调用微信统一下单接口 // 5.调用微信统一下单接口
try { try {
wxPayService.createOrder(request); Object order = wxPayService.createOrder(request);
String json = JSON.toJSONString(order);
WxPayOrderResult result = JSON.parseObject(json, WxPayOrderResult.class);
// 6.返回支付所需数据 // 6.返回支付所需数据
return R.ok(result);
} catch (WxPayException e) { } catch (WxPayException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return null;
} }
/** /**
...@@ -353,4 +358,17 @@ public class DbOrderServiceImpl implements IDbOrderService { ...@@ -353,4 +358,17 @@ public class DbOrderServiceImpl implements IDbOrderService {
public Integer unpaidJob() { public Integer unpaidJob() {
return baseMapper.unpaidJob(); return baseMapper.unpaidJob();
} }
/**
* 支付回调
* @param xmlData
* @return
*/
@Override
public R payCallback(String xmlData) throws WxPayException {
final WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
log.info("支付回调参数解析:{}", notifyResult);
// 1.查询订单信息
return null;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment