Merge remote-tracking branch 'origin/main'

This commit is contained in:
attiya 2025-05-12 15:39:29 +08:00
commit ab0d67f477
27 changed files with 495 additions and 144 deletions

View File

@ -50,6 +50,18 @@ public class ConvertUtil {
return utcZoned.format(formatter);
}
/**
* 格式化LocalDateTime为字符串
* 格式yyyy-MM-dd HH:mm:ss
*
* @param localDateTime 要格式化的LocalDateTime对象
* @return
*/
public static String formatLocalDateTime(LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return localDateTime.format(formatter);
}
//public static void main(String[] args) {
// LocalDateTime localDateTime = LocalDateTime.now();
// String utcTime = localDateTimeToUTC(localDateTime);

View File

@ -78,9 +78,9 @@ public interface OperateFeignClient {
/**
* 根据区域id获取计费规则
*
* @param regionId 运营区id
* @param operationRegionId 运营区id
* @return 返回结果
*/
@GetMapping("ebikesysrcostset/getRegionFeeConfigById")
JsonResult<ResFeignEbikeSysRcostsetDto> getRegionFeeConfigById(@RequestParam(name = "regionId") Long regionId);
JsonResult<ResFeignEbikeSysRcostsetDto> getRegionFeeConfigById(@RequestParam(name = "operationRegionId") Long operationRegionId);
}

View File

@ -47,6 +47,14 @@ public interface OrdersFeignClient {
@PostMapping("userOrders/payment")
JsonResult<?> payment(@RequestBody ResFeignOrderPaymentDto paymentParam);
/**
* 根据ID获取订单支付详情
* @param orderId 支付id
* @return 订单支付详情
*/
@PostMapping("userOrders/paymentDetailsInfo")
JsonResult<?> getPaymentDetails(@RequestParam("orderId")Long orderId);
/**
* 订单发起退款
* @param orderId 订单ID

View File

@ -1,4 +1,4 @@
package com.cdzy.payment.model.dto;
package com.ebike.feign.model.rsp;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.cdzy.payment.model.dto;
package com.ebike.feign.model.rsp;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.cdzy.payment.model.dto;
package com.ebike.feign.model.rsp;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.cdzy.payment.model.dto;
package com.ebike.feign.model.rsp;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -9,6 +9,7 @@ import com.ebike.feign.model.res.ResFeignOrderPaymentDto;
import com.cdzy.orders.model.dto.res.RspBikeDto;
import com.cdzy.orders.model.entity.EbikeUserOrders;
import com.cdzy.orders.service.UserOrdersService;
import com.ebike.feign.model.rsp.EbikePaymentDto;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
@ -193,6 +194,22 @@ public class EbikeUserOrdersController {
return JsonResult.success(info);
}
/**
* 根据ID获取订单支付详情
*
* @param orderId 订单表主键
* @ 订单支付详情
*/
@GetMapping("paymentDetailsInfo")
public JsonResult<?> paymentDetailsInfo(@RequestParam("orderId") Long orderId) {
try {
EbikePaymentDto info = userOrdersService.paymentDetailsInfo(orderId);
return JsonResult.success(info);
} catch (Exception e) {
return JsonResult.failed(e.getMessage());
}
}
/**
* 根据用户订单表主键获取详细信
*

View File

@ -5,6 +5,7 @@ import com.cdzy.orders.model.dto.req.ReqOrderDto;
import com.cdzy.orders.model.dto.res.RspOrderDetailsInfo;
import com.ebike.feign.model.res.ResFeignOrderPaymentDto;
import com.cdzy.orders.model.dto.res.RspBikeDto;
import com.ebike.feign.model.rsp.EbikePaymentDto;
import com.mybatisflex.core.service.IService;
import com.cdzy.orders.model.entity.EbikeUserOrders;
@ -107,4 +108,12 @@ public interface UserOrdersService extends IService<EbikeUserOrders> {
* @return 金额
*/
BigDecimal costOrderCalculation(ReqOrderDto orderDto);
/**
* 获取支付信息
*
* @param orderId 订单ID
* @return 支付信息
*/
EbikePaymentDto paymentDetailsInfo(Long orderId);
}

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.enums.Code;
import com.cdzy.common.model.JsonResult;
import com.cdzy.common.model.ResGPSDto;
import com.cdzy.common.utils.ConvertUtil;
import com.cdzy.orders.component.EbikeCoreHandler;
import com.cdzy.orders.enums.*;
import com.cdzy.orders.mapper.EbikeOrderDetailsMapper;
@ -14,7 +15,9 @@ import com.cdzy.orders.model.dto.res.RedisPoint;
import com.cdzy.orders.model.dto.res.RspBikeDto;
import com.cdzy.orders.model.dto.res.RspOrderDetailsInfo;
import com.cdzy.orders.model.entity.EbikeOrderDetails;
import com.cdzy.orders.model.entity.EbikeUser;
import com.cdzy.orders.model.entity.EbikeUserOrders;
import com.cdzy.orders.service.EbikeUserService;
import com.cdzy.orders.service.UserOrdersService;
import com.cdzy.orders.uitls.NumberUtils;
import com.cdzy.orders.uitls.RedisUtil;
@ -25,9 +28,7 @@ import com.ebike.feign.model.res.ResFeignEbikeSysRcostsetDto;
import com.ebike.feign.model.res.ResFeignEbikeSysRcostsetTimePeriodDto;
import com.ebike.feign.model.res.ResFeignEbikeSysRcostsetWeekDto;
import com.ebike.feign.model.res.ResFeignOrderPaymentDto;
import com.ebike.feign.model.rsp.FeignEbikeBikeInfoDto;
import com.ebike.feign.model.rsp.FeignEbikeEcuInfo;
import com.ebike.feign.model.rsp.FeignEbikeRegionDto;
import com.ebike.feign.model.rsp.*;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
@ -72,6 +73,9 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
@Resource
EbikeOrderDetailsMapper orderDetailsMapper;
@Resource
EbikeUserService ebikeUserService;
@Override
@Transactional
public Long saveRide(ReqOrderDto orderDto) {
@ -346,6 +350,54 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
return userOrders.getTotalAmount();
}
@Override
public EbikePaymentDto paymentDetailsInfo(Long orderId) {
RspOrderDetailsInfo orderDetailsInfo = orderDetailsInfo(orderId);
if (orderDetailsInfo == null) {
throw new RuntimeException("订单不存在");
}
// user openid
EbikeUser ebikeUser = ebikeUserService.getById(orderDetailsInfo.getUserId());
if (ebikeUser == null) {
throw new RuntimeException("用户不存在");
}
EbikePaymentDto ebikePaymentDto = new EbikePaymentDto();
ebikePaymentDto.setOpenId(ebikeUser.getOpenId());
ebikePaymentDto.setOrderId(String.valueOf(orderId));
ebikePaymentDto.setDescription(String.format("骑行:%s - %s",
ConvertUtil.formatLocalDateTime(orderDetailsInfo.getStartTime()),
ConvertUtil.formatLocalDateTime(orderDetailsInfo.getEndTime())));
int ot = orderDetailsInfo.getOrderType();
//1-单次骑行 2-骑行卡购买 3-会员卡续费
switch (ot) {
case 1:
ebikePaymentDto.setGoodsTag("单次骑行");
break;
case 2:
ebikePaymentDto.setGoodsTag("骑行卡购买");
break;
case 3:
ebikePaymentDto.setGoodsTag("会员卡续费");
break;
}
AmountDto amountDto = new AmountDto();
amountDto.setTotal(orderDetailsInfo.getActualAmount().doubleValue());
ebikePaymentDto.setAmount(amountDto);
DetailDto detailDto = new DetailDto();
detailDto.setCostPrice(orderDetailsInfo.getTotalAmount().doubleValue());
detailDto.setGoodsDetail(orderDetailsInfo.getDetails().stream().map(orderDetail -> {
PayDetailDto payDetailDto = new PayDetailDto();
payDetailDto.setItemName(orderDetail.getItemName());
payDetailDto.setItemId(String.valueOf(orderDetail.getItemId()));
payDetailDto.setQuantity(1);
payDetailDto.setUnitPrice(orderDetail.getItemAmount().doubleValue());
return payDetailDto;
}).toList());
ebikePaymentDto.setDetail(detailDto);
// client ip 后续如果可以获取到就加上
return ebikePaymentDto;
}
@Override
public void payment(ResFeignOrderPaymentDto paymentDto) {
EbikeUserOrders userOrders = this.mapper.selectOneById(paymentDto.getOrderId());

View File

@ -2,7 +2,6 @@ package com.cdzy.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.model.JsonResult;
import com.cdzy.payment.model.dto.EbikePaymentDto;
import com.cdzy.payment.model.dto.EbikeRefundDto;
import com.cdzy.payment.model.dto.HandleNotifyResult;
import com.cdzy.payment.service.WxPayService;
@ -10,12 +9,7 @@ import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
/**
* 用户订单微信支付 控制层
@ -34,73 +28,74 @@ public class EbikeWxPaymentController {
/**
* 微信支付下单
*
* @param paymentDto 支付信息
* @param orderId 骑行订单id
* @return 下单成功返回true否则返回false
*/
@PostMapping("/prepay")
public JsonResult<?> prepay(@RequestBody EbikePaymentDto paymentDto) {
JSONObject r = wxPayService.prepay(paymentDto.getOrderId(), paymentDto.getDescription(), paymentDto.getGoodsTag(), paymentDto.getOpenId(), paymentDto.getAmount(), paymentDto.getDetail(), paymentDto.getClientIp());
return r == null?JsonResult.failed("下单失败"):JsonResult.success(r);
}
/**
* 通过交易订单号查询支付订单
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
*/
@GetMapping("/queryOrderById/{transactionId}")
public JsonResult<?> queryOrderById(@PathVariable String transactionId) {
Transaction r = wxPayService.queryOrderById(transactionId);
return r == null?JsonResult.failed(String.format("交易订单号{%s}查询支付订单失败", transactionId)):JsonResult.success(r);
public JsonResult<?> prepay(@RequestParam(name = "orderId") String orderId) {
JSONObject r = wxPayService.prepay(orderId);
return r.containsKey("error")?JsonResult.failed("下单失败: "+ r.getString("error")):JsonResult.success(r);
}
/**
* 通过商户(骑行)订单号查询支付订单
*
* @param outTradeNo 商户(骑行)订单号
* @param orderId 商户(骑行)订单号
* @return 支付订单信息
*/
@GetMapping("/queryOrderByOutTradeNo/{outTradeNo}")
public JsonResult<?> queryOrderByOutTradeNo(@PathVariable String outTradeNo) {
Transaction r = wxPayService.queryOrderByOutTradeNo(outTradeNo);
return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", outTradeNo)):JsonResult.success(r);
@GetMapping("/queryOrder/{orderId}")
public JsonResult<?> queryOrderByOutTradeNo(@PathVariable String orderId) {
Transaction r = wxPayService.queryOrderByOutTradeNo(orderId);
return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", orderId)):JsonResult.success(r);
}
/**
* 通过交易订单号查询支付订单状态
* 通过商户(骑行)订单订单号查询支付订单状态
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
* @param orderId 微信支付订单号
* @return 订单信息支付状态
*/
@GetMapping("/queryOrderStatusById/{transactionId}")
public JsonResult<?> queryOrderStatusById(@PathVariable String transactionId) {
HandleNotifyResult r = wxPayService.queryOrderStatusById(transactionId);
@GetMapping("/queryOrderStatus/{orderId}")
public JsonResult<?> queryOrderStatusById(@PathVariable String orderId) {
HandleNotifyResult r = wxPayService.queryOrderStatusByOutTradeNo(orderId);
return JsonResult.success(r);
}
// 拆分为两个接口一个是退款申请(生成退款记录)一个是提交退款调用微信退款接口
/**
* 退款申请
*
* @param refundDto 退款信息
* @return 退款成功返回true否则返回false
*/
@PostMapping("/refund")
public JsonResult<?> refund(@RequestBody EbikeRefundDto refundDto) {
String r = wxPayService.refund(refundDto.getPaymentId(), refundDto.getOrderId(), refundDto.getReason(), refundDto.getAmount());
@PostMapping("/refundApply")
public JsonResult<?> refundApply(@RequestBody EbikeRefundDto refundDto) {
String r = wxPayService.refundApply(refundDto.getOrderId(), refundDto.getReason());
return r == null?JsonResult.failed("退款失败"):JsonResult.success(r);
}
/**
* 调用微信退款接口
*
* @param orderId 订单id
* @return 退款成功返回true否则返回false
*/
@PostMapping("/refund")
public JsonResult<?> refund(@RequestParam(name = "orderId") String orderId) {
boolean r = wxPayService.refund(orderId);
return r?JsonResult.failed("退款失败"):JsonResult.success(r);
}
/**
* 通过退款单号查询退款信息
*
* @param outRefundNo 商户(骑行)退款单号
* @param refundId 商户(骑行)退款单号
* @return 退款信息
*/
@GetMapping("/queryRefund/{outRefundNo}")
public JsonResult<?> refundQuery(@PathVariable String outRefundNo) {
Refund r = wxPayService.queryRefundByOutNo(outRefundNo);
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", outRefundNo)):JsonResult.success(r);
@GetMapping("/queryRefund/{refundId}")
public JsonResult<?> refundQuery(@PathVariable String refundId) {
Refund r = wxPayService.queryRefundByOutNo(refundId);
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", refundId)):JsonResult.success(r);
}
}

View File

@ -1,8 +1,6 @@
package com.cdzy.payment.model.dto;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
import com.wechat.pay.java.service.refund.model.AmountReq;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -21,18 +19,12 @@ public class EbikeRefundDto {
/**
* 商户(骑行)订单号
*/
@NotBlank(message = "订单id不能为空")
private String orderId;
/**
* 支付交易会话标识
*/
private String paymentId;
/**
* 退款原因
*/;
private String reason;
/**
* 金额
*/
private AmountRefundDto amount;
@NotBlank(message = "退款原因不能为空")
private String reason;
}

View File

@ -40,10 +40,15 @@ public class EbikePayment implements Serializable {
private String orderId;
/**
* 支付交易会话标识;有效期为2小时
* 支付交易会话标识;有效期为2小时
*/
private String paymentId;
/**
* 微信支付订单号
*/
private String transactionId;
/**
* 提交时间
*/
@ -75,7 +80,7 @@ public class EbikePayment implements Serializable {
private String currency;
/**
* 金额
* 实际支付金额
*/
private Double total;

View File

@ -3,7 +3,6 @@ package com.cdzy.payment.model.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.io.Serial;
import java.time.LocalDateTime;
@ -46,9 +45,9 @@ public class EbikeRefund implements Serializable {
private String recordId;
/**
* 支付交易会话标识;有效期为2小时
* 微信支付订单号
*/
private String paymentId;
private String transactionId;
/**
* 提交时间

View File

@ -38,10 +38,10 @@ public interface EbikePaymentService extends IService<EbikePayment> {
Boolean updatePaymentStatus(Transaction transaction);
/**
* 根据支付订单id查询支付记录
* 根据订单id查询支付记录
*
* @param paymentId 支付订单id
* @param orderId 订单id
* @return
*/
EbikePayment getByPaymentId(String paymentId);
EbikePayment getByOrderId(String orderId);
}

View File

@ -30,6 +30,14 @@ public interface EbikeRefundService extends IService<EbikeRefund> {
*/
List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration);
/**
* 根据订单id查询退款记录
*
* @param orderId 订单id
* @return
*/
EbikeRefund getByOrderId(String orderId);
/**
* 更新退款状态
*

View File

@ -2,9 +2,7 @@ package com.cdzy.payment.service;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.payment.model.dto.AmountDto;
import com.cdzy.payment.model.dto.AmountRefundDto;
import com.cdzy.payment.model.dto.DetailDto;
import com.cdzy.payment.model.dto.HandleNotifyResult;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
@ -30,23 +28,11 @@ public interface WxPayService {
/**
* JSAPI支付下单
*
* @param outTradeNo 商户(骑行)订单号
* @param description 商品描述
* @param goodsTag 商品标记
* @param openId 用户标识
* @param amount 金额
* @param detail 商品详情
* @param clientIp 客户端IP
* @return 下单成功返回true否则返回false
* @param outTradeNo 订单id
* @return 下单成功返回wx支付请求参数否则返回null
*/
JSONObject prepay(String outTradeNo, String description, String goodsTag, String openId, AmountDto amount, DetailDto detail, String clientIp);
/**
* 通过交易订单号查询支付订单
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
*/
Transaction queryOrderById(String transactionId);
JSONObject prepay(String outTradeNo);
/**
* 通过商户(骑行)订单号查询支付订单
@ -57,12 +43,12 @@ public interface WxPayService {
Transaction queryOrderByOutTradeNo(String outTradeNo);
/**
* 通过交易订单号查询支付订单状态
* 通过订单号查询支付订单状态
*
* @param transactionId 微信支付订单号
* @param outTradeNo 商户(骑行)订单号
* @return 支付订单信息
*/
HandleNotifyResult queryOrderStatusById(String transactionId);
HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo);
/**
* 处理支付回调
@ -75,13 +61,19 @@ public interface WxPayService {
/**
* 退款申请
*
* @param transactionId 微信支付订单号
* @param outTradeNo 商户(骑行)订单号
* @param reason 退款原因
* @param amount 退款金额
* @return 退款信息id
*/
String refund(String transactionId, String outTradeNo, String reason, AmountRefundDto amount);
String refundApply(String outTradeNo, String reason);
/**
* 调用微信退款接口
*
* @param outTradeNo 商户(骑行)订单号
* @return 退款信息id
*/
Boolean refund(String outTradeNo);
/**

View File

@ -36,7 +36,7 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60));
// trade_state 等于 NOTPAY未支付的 并且创建时间未超过duration分钟的订单
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.USERPAYING.ordinal()))
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).lt(QueryMethods.now()));
return list(query);
}
@ -46,7 +46,7 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60));
// trade_state 等于 NOTPAY未支付的 并且创建时间超过duration分钟的订单
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.USERPAYING.ordinal()))
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).ge(QueryMethods.now()));
return list(query);
}
@ -62,6 +62,7 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
ebikePayment.setTotal(v);
String paymentTime = transaction.getSuccessTime();
ebikePayment.setPaymentTime(StringUtils.toLocalDatetime(paymentTime));
ebikePayment.setTransactionId(transaction.getTransactionId());
// 同步支付状态
ResFeignOrderPaymentDto paymentParam = new ResFeignOrderPaymentDto();
paymentParam.setOrderId(Long.valueOf(transaction.getOutTradeNo()));
@ -70,14 +71,14 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
ordersFeignClient.payment(paymentParam);
}
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(transaction.getTransactionId()));
.where(EBIKE_PAYMENT.ORDER_ID.eq(transaction.getOutTradeNo()));
return update(ebikePayment, query);
}
@Override
public EbikePayment getByPaymentId(String paymentId) {
public EbikePayment getByOrderId(String orderId) {
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(paymentId));
.where(EBIKE_PAYMENT.ORDER_ID.eq(orderId));
return this.getOne(query);
}
}

View File

@ -48,6 +48,16 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
return list(query);
}
@Override
public EbikeRefund getByOrderId(String orderId) {
// create_time到排序取最新的一条
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_REFUND.ORDER_ID.eq(orderId))
.orderBy(EBIKE_REFUND.CREATE_TIME.desc())
.limit(1);
return getOne(query);
}
@Override
public Boolean updateRefundStatus(Refund refund) {
EbikeRefund ebikeRefund = new EbikeRefund();

View File

@ -1,7 +1,9 @@
package com.cdzy.payment.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.model.JsonResult;
import com.cdzy.payment.config.WxPayConfig;
import com.cdzy.payment.model.dto.*;
import com.cdzy.payment.model.entity.EbikePayment;
@ -12,6 +14,10 @@ import com.cdzy.payment.service.EbikeRefundService;
import com.cdzy.payment.service.WxPayService;
import com.cdzy.payment.utils.HttpServletUtils;
import com.cdzy.payment.utils.StringUtils;
import com.ebike.feign.clients.OrdersFeignClient;
import com.ebike.feign.model.rsp.AmountDto;
import com.ebike.feign.model.rsp.DetailDto;
import com.ebike.feign.model.rsp.EbikePaymentDto;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.RSASigner;
import com.wechat.pay.java.core.exception.HttpException;
@ -64,7 +70,8 @@ public class WxPayServiceImpl implements WxPayService {
private EbikePaymentService ebikePaymentService;
@Resource
private EbikeRefundService ebikeRefundService;
@Resource
private OrdersFeignClient orderFeingClient;
@Override
public boolean closeOrder(String outTradeNo) {
@ -81,8 +88,51 @@ public class WxPayServiceImpl implements WxPayService {
}
}
@Override
public JSONObject prepay(String outTradeNo, String description, String goodsTag, String openId, AmountDto amount, DetailDto detail, String clientIp) {
public JSONObject prepay(String outTradeNo){
JSONObject r = new JSONObject();
// 首先检查订单是否正在付中或者已经支付成功
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
if (ebikePayment != null) {
if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState())) {
log.info("订单已经支付成功,订单号:{}", outTradeNo);
r.put("error", "订单已经支付成功");
return r;
}
if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(ebikePayment.getTradeState())
||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(ebikePayment.getTradeState())) {
log.info("订单正在支付中,订单号:{}", outTradeNo);
r.put("error", "订单正在支付中");
return null;
}
}
//查询订单, orderFeingClient.getOrderById(orderId)
JsonResult<?> result = orderFeingClient.getPaymentDetails(Long.valueOf(outTradeNo));
if (result.getCode() != 200) {
log.error("查询订单 {} 失败, {}", outTradeNo, result.getMessage());
r.put("error", "查询订单失败, "+result.getMessage());
return r;
}
EbikePaymentDto paymentDto = JSON.parseObject(JSON.toJSONString(result.getData()), EbikePaymentDto.class);
return prepay(paymentDto, ebikePayment);
}
/**
* JSAPI支付下单
*
* @param paymentDto 支付信息
* @param ebikePayment 原始支付记录
* @return 下单成功返回wx支付请求参数否则返回null
*/
private JSONObject prepay(EbikePaymentDto paymentDto, EbikePayment ebikePayment) {
String outTradeNo = paymentDto.getOrderId();
String description = paymentDto.getDescription();
String goodsTag = paymentDto.getGoodsTag();
String openId = paymentDto.getOpenId();
AmountDto amount = paymentDto.getAmount();
DetailDto detail = paymentDto.getDetail();
try {
PrepayRequest request = new PrepayRequest();
request.setAppid(wxPayConfig.getAppId());
@ -112,23 +162,28 @@ public class WxPayServiceImpl implements WxPayService {
detailReq.setCostPrice(BigDecimal.valueOf(detail.getCostPrice()*100.0).intValue());
detailReq.setInvoiceId(detail.getInvoiceId());
request.setDetail(detailReq);
SceneInfo sceneInfo = new SceneInfo();
sceneInfo.setPayerClientIp(clientIp);
request.setSceneInfo(sceneInfo);
PrepayResponse response = wxJsapiService.prepay(request);
String payId = response.getPrepayId();
//入库
//入库 重新发起支付更新记录订单号<-->记录号一一对应
if (payId != null) {
EbikePayment ebikePayment = new EbikePayment();
ebikePayment.setOrderId(outTradeNo);
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
int state = Transaction.TradeStateEnum.USERPAYING.ordinal();
ebikePayment.setTradeState(String.valueOf(state));
ebikePaymentService.save(ebikePayment);
if (ebikePayment == null) {
ebikePayment = new EbikePayment();
ebikePayment.setOrderId(outTradeNo);
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()));
ebikePaymentService.save(ebikePayment);
}else{
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()));
ebikePaymentService.updateById(ebikePayment);
}
// 返回给小程序的参数调起微信支付
WxJsapiPromptDto wxJsapiPromptDto = new WxJsapiPromptDto();
wxJsapiPromptDto.setAppId(wxPayConfig.getAppId());
@ -145,28 +200,22 @@ public class WxPayServiceImpl implements WxPayService {
}
}
@Override
public Transaction queryOrderById(String transactionId) {
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setTransactionId(transactionId);
return wxJsapiService.queryOrderById(request);
}
@Override
public Transaction queryOrderByOutTradeNo(String outTradeNo) {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setOutTradeNo(outTradeNo);
request.setMchid(wxPayConfig.getMerchantId());
return wxJsapiService.queryOrderByOutTradeNo(request);
}
@Override
public HandleNotifyResult queryOrderStatusById(String transactionId) {
public HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo) {
// 先查本地数据库如果退款状态不为SUCCESS需要查询微信支付
HandleNotifyResult result = new HandleNotifyResult();
EbikePayment ebikePayment = ebikePaymentService.getByPaymentId(transactionId);
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
if (ebikePayment==null){
log.error("{}支付订单不存在", transactionId);
result.setMessage(String.format("{%s}支付订单不存在", transactionId));
log.error("{}支付订单不存在", outTradeNo);
result.setMessage(String.format("{%s}支付订单不存在", outTradeNo));
return result;
}
result.setSuccess(String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState()));
@ -174,9 +223,10 @@ public class WxPayServiceImpl implements WxPayService {
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
return result;
}
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setTransactionId(transactionId);
Transaction r = wxJsapiService.queryOrderById(request);
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setOutTradeNo(outTradeNo);
request.setMchid(wxPayConfig.getMerchantId());
Transaction r = wxJsapiService.queryOrderByOutTradeNo(request);
if(r!=null&& r.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
result.setSuccess(true);
@ -223,17 +273,55 @@ public class WxPayServiceImpl implements WxPayService {
}
@Override
public String refund(String transactionId, String outTradeNo, String reason, AmountRefundDto amount) {
// 雪花算法生成退款单号
public String refundApply(String outTradeNo, String reason) {
// 检查是否重复退款申请
EbikeRefund ebikeRefund = ebikeRefundService.getByOrderId(outTradeNo);
if (ebikeRefund!= null) {
if(String.valueOf(Status.PROCESSING.ordinal()).equals(ebikeRefund.getStatus())){
log.error("订单{}正在退款中", outTradeNo);
return null;
}
if(String.valueOf(Status.SUCCESS.ordinal()).equals(ebikeRefund.getStatus())) {
log.error("订单{}已经退款过", outTradeNo);
return null;
}
}
// 查询支付记录
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
String transactionId = ebikePayment.getTransactionId();
// 生成退款记录
String outRefundNo = StringUtils.generateSnowflakeId("refundId");
EbikeRefund ebikeRefund = new EbikeRefund();
ebikeRefund = new EbikeRefund();
ebikeRefund.setCreateTime(LocalDateTime.now());
ebikeRefund.setRefundId(outRefundNo);
ebikeRefund.setOrderId(outTradeNo);
ebikeRefund.setTransactionId(transactionId);
ebikeRefund.setReason(reason);
ebikeRefund.setStatus(String.valueOf(Status.PROCESSING.ordinal()));
ebikeRefundService.saveRefundResult(ebikeRefund);
return outRefundNo;
}
@Override
public Boolean refund(String outTradeNo) {
EbikeRefund ebikeRefund = ebikeRefundService.getByOrderId(outTradeNo);
if (ebikeRefund==null){
log.error("退款refund失败订单 {} 退款申请不存在", outTradeNo);
return false;
}
// 查询支付记录
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
String transactionId = ebikePayment.getTransactionId();
AmountRefundDto amount = new AmountRefundDto();
amount.setTotal(ebikePayment.getCostPrice());
amount.setRefund(ebikePayment.getTotal());
amount.setCurrency(ebikePayment.getCurrency());
// 发起退款
CreateRequest request = new CreateRequest();
request.setTransactionId(transactionId);
request.setOutTradeNo(outTradeNo);
request.setOutRefundNo(outRefundNo);
request.setReason(reason);
request.setOutRefundNo(ebikeRefund.getRefundId());
request.setReason(ebikeRefund.getReason());
request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
AmountReq amountReq = new AmountReq();
amountReq.setRefund(BigDecimal.valueOf(amount.getRefund() * 100.0).longValue());
@ -241,24 +329,22 @@ public class WxPayServiceImpl implements WxPayService {
amountReq.setCurrency(amount.getCurrency());
request.setAmount(amountReq);
Refund result = wxRefundService.create(request);
// 入库
// 更新退款信息
if (result != null) {
ebikeRefund.setRefundId(outRefundNo);
ebikeRefund.setOrderId(outTradeNo);
ebikeRefund.setPaymentId(transactionId);
ebikeRefund.setTransactionId(transactionId);
ebikeRefund.setTotal(amount.getTotal());
ebikeRefund.setReason(reason);
ebikeRefund.setStatus(String.valueOf(result.getStatus().ordinal()));
ebikeRefund.setCurrency(amount.getCurrency());
if(Status.SUCCESS.equals(result.getStatus())){
ebikeRefund.setRefund(result.getAmount().getRefund().doubleValue() / 100.0);
ebikeRefund.setRefundTime(LocalDateTime.now());
}
ebikeRefundService.saveRefundResult(ebikeRefund);
return outRefundNo;
ebikeRefundService.updateById(ebikeRefund);
return true;
}
log.error("退款申请refund失败订单号{}", outTradeNo);
return null;
log.error("退款refund失败订单号{}", outTradeNo);
return false;
}
@Override

View File

@ -68,6 +68,7 @@ public class PermissionsController {
* 查询所有
*
* @return 所有数据
* @return 所有数据
*/
@GetMapping("list")
public JsonResult<?> list() {

View File

@ -5,11 +5,14 @@ import com.cdzy.common.model.PageParam;
import com.cdzy.user.model.entity.RolePermissions;
import com.cdzy.user.service.RolePermissionsService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.cdzy.user.model.entity.table.RolePermissionsTableDef.ROLE_PERMISSIONS;
/**
* 角色权限控制层
*
@ -94,4 +97,19 @@ public class RolePermissionsController {
return JsonResult.success(page);
}
/**
* 查询角色下的权限列表
*
* @param roleId 角色id
* @return
*/
@GetMapping("getRolePermissionsByRoleId/{roleId}")
public JsonResult<?> getRolePermissionsByRoleId(@PathVariable("roleId") Long roleId) {
QueryWrapper queryWrapper = QueryWrapper.create()
.eq(ROLE_PERMISSIONS.ROLE_ID.getName(), roleId);
List<RolePermissions> list = rolePermissionsService.list(queryWrapper);
return JsonResult.success(list);
}
}

View File

@ -1,19 +1,32 @@
package com.cdzy.user.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.cdzy.common.model.JsonResult;
import com.cdzy.common.model.PageParam;
import com.cdzy.common.model.StaffDto;
import com.cdzy.user.model.dto.PageParamDto;
import com.cdzy.user.model.dto.ResRolesDto;
import com.cdzy.user.model.entity.Roles;
import com.cdzy.user.service.PermissionsService;
import com.cdzy.user.service.RolesService;
import com.cdzy.user.service.StaffService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.cdzy.user.model.entity.table.OrganizationsTableDef.ORGANIZATIONS;
import static com.cdzy.user.model.entity.table.PermissionsTableDef.PERMISSIONS;
import static com.cdzy.user.model.entity.table.RolePermissionsTableDef.ROLE_PERMISSIONS;
import static com.cdzy.user.model.entity.table.RolesTableDef.ROLES;
import static com.cdzy.user.model.entity.table.StaffRolesTableDef.STAFF_ROLES;
import static com.cdzy.user.model.entity.table.StaffTableDef.STAFF;
/**
* 角色控制层
@ -28,6 +41,11 @@ public class RolesController {
@Resource
private RolesService rolesService;
@Autowired
private PermissionsService permissionsService;
@Resource
private StaffService staffService;
/**
* 添加
*
@ -93,7 +111,7 @@ public class RolesController {
* @param pageParam 分页对象
* @return 分页对象
*/
@GetMapping("page")
@PostMapping("page")
public JsonResult<?> page(@Validated PageParam pageParam) {
Page<Roles> page = rolesService.page(pageParam.getPage());
return JsonResult.success(page);
@ -114,4 +132,58 @@ public class RolesController {
return JsonResult.success(list);
}
/**
* 分页查询角色列表
*
* @param pageParam
* @return
*/
@PostMapping("pageQueryRoles")
public JsonResult<?> pageQueryRoles(@RequestBody @Validated PageParamDto pageParam) {
String tokenValue = StpUtil.getTokenValue();
Object loginId = StpUtil.getLoginIdByToken(tokenValue);
QueryWrapper queryStaff = QueryWrapper.create()
.where(STAFF.STAFF_ID.eq(loginId));
StaffDto staff = staffService.getOneAs(queryStaff, StaffDto.class);
QueryWrapper queryWrapper = QueryWrapper.create()
.from(STAFF)
.select(STAFF.STAFF_ID, ROLES.ALL_COLUMNS, ORGANIZATIONS.ORG_NAME)
.innerJoin(STAFF_ROLES).on(STAFF_ROLES.STAFF_ID.eq(STAFF.STAFF_ID))
.innerJoin(ORGANIZATIONS).on(STAFF.ORG_ID.eq(ORGANIZATIONS.ORG_ID))
.innerJoin(ROLES).on(STAFF_ROLES.ROLE_ID.eq(ROLES.ROLE_ID))
.where(STAFF.ORG_ID.eq(staff.getOrgId()));
QueryWrapper countQuery = QueryWrapper.create()
.select(QueryMethods.count(STAFF.STAFF_ID.getName()).as("staff_count"))
.select(ROLES.ROLE_NAME.getName(), ROLES.ROLE_ID.getName(),
ROLES.ROLE_DESCRIPTION.getName(), ROLES.ROLE_CODE.getName(),
ORGANIZATIONS.ORG_NAME.getName())
.groupBy(ORGANIZATIONS.ORG_NAME, ROLES.ROLE_NAME)
.from(queryWrapper).as("a");
Page<ResRolesDto> page = Page.of(pageParam.getPage().getPageNumber(), pageParam.getPageSize());
Page<ResRolesDto> resRolesDtoPage = rolesService.pageAs(page, countQuery, ResRolesDto.class);
List<ResRolesDto> records = resRolesDtoPage.getRecords();
//统计pc权限数量和小程序权限数量
for (ResRolesDto record : records) {
QueryWrapper caseQuery = QueryWrapper.create()
.select(QueryMethods.sum(QueryMethods.case_()
.when(PERMISSIONS.PERM_TYPE.eq(1)).then(1)
.else_(0).end()).as("web_count"),
QueryMethods.sum(QueryMethods.case_()
.when(PERMISSIONS.PERM_TYPE.eq(2)).then(1)
.else_(0).end()).as("applet_count"))
.innerJoin(ROLE_PERMISSIONS).on(PERMISSIONS.PERM_ID.eq(ROLE_PERMISSIONS.PERM_ID))
.where(ROLE_PERMISSIONS.ROLE_ID.eq(record.getRoleId()))
.where(PERMISSIONS.PERM_TYPE.ne("0"));
ResRolesDto oneAs = permissionsService.getOneAs(caseQuery, ResRolesDto.class);
if (oneAs == null) continue;
record.setWebCount(oneAs.getWebCount());
record.setAppletCount(oneAs.getAppletCount());
}
return JsonResult.success(resRolesDtoPage);
}
}

View File

@ -0,0 +1,31 @@
package com.cdzy.user.model.dto;
import com.mybatisflex.core.paginate.Page;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.Data;
/**
* @author attiya
* @since 2025-03-14
*/
@Data
public class PageParamDto {
@Min(value = 1, message = "页码必须大于0")
private Integer pageNum; // 默认第1页
@Min(value = 1, message = "每页数量必须大于0")
@Max(value = 100, message = "每页数量不能超过100")
private Integer pageSize;
private String roleName;
public <T> Page<T> getPage() {
if (pageNum == null || pageSize == null) {
pageNum = 1;
pageSize = 10;
}
return new Page<>(pageNum, pageSize);
}
}

View File

@ -0,0 +1,39 @@
package com.cdzy.user.model.dto;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 实体类
*
* @author attiya
* @since 2025-03-14
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("ebike_roles")
public class ResRolesDto implements Serializable {
private Long roleId;
private String roleName;
private String roleDescription;
private String orgName;
private Integer staffCount;
private Integer webCount;
private Integer appletCount;
}

View File

@ -39,4 +39,6 @@ public class Permissions implements Serializable {
private Integer type;
private Integer permType;
}

View File

@ -11,7 +11,7 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 实体类
* 实体类
*
* @author attiya
* @since 2025-03-14
@ -39,4 +39,6 @@ public class Roles implements Serializable {
private Long createdStaff;
private String roleDescription;
}