提交 994e8035 authored 作者: hzh's avatar hzh

退款发起功能实现

上级 6daa7ada
......@@ -3,6 +3,7 @@ package org.dromara.order.api;
import org.dromara.order.api.domain.OrderPay;
import org.dromara.order.api.domain.RemoteOrder;
import org.dromara.order.api.domain.RemoteSaveOrder;
import org.dromara.order.api.domain.RemoteSaveRefundOrder;
import org.dromara.order.api.enums.OrderType;
import org.dromara.order.api.enums.Source;
......@@ -23,6 +24,14 @@ public interface RemoteOrderService {
*/
OrderPay createOrder(RemoteSaveOrder order) throws Exception;
/**
* 创建退款订单
*
* @param order 订单信息
* @return 是否成功
*/
Boolean createRefundOrder(RemoteSaveRefundOrder order) throws Exception;
/**
* 查询订单列表
*
......
package org.dromara.order.api.domain;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.order.api.enums.OrderType;
import java.io.Serial;
import java.io.Serializable;
/**
* 生成退款单
*
* @author hzh
* @date 2024-12-05
**/
@Data
@Accessors(chain = true)
public class RemoteSaveRefundOrder implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 原订单号
*/
@NotNull(message = "原订单号不能为空")
private String originOrderNo;
/**
* 订单类型
*/
private OrderType orderType;
}
......@@ -65,6 +65,11 @@ public class OrderRefund extends TenantEntity {
*/
private String reason;
/**
* 订单总金额
*/
private BigDecimal total;
/**
* 退款金额
*/
......
......@@ -5,6 +5,7 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
......@@ -19,6 +20,7 @@ import java.math.BigDecimal;
* @date 2024-12-31
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = OrderRefund.class, reverseConvertGenerate = false)
public class OrderRefundBo extends BaseEntity {
......@@ -71,6 +73,12 @@ public class OrderRefundBo extends BaseEntity {
@NotBlank(message = "退款原因不能为空", groups = {AddGroup.class, EditGroup.class})
private String reason;
/**
* 订单总金额
*/
@NotBlank(message = "订单总金额", groups = {AddGroup.class, EditGroup.class})
private BigDecimal total;
/**
* 退款金额
*/
......
......@@ -4,6 +4,7 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.order.domain.OrderRefund;
import java.io.Serial;
......@@ -18,6 +19,7 @@ import java.math.BigDecimal;
* @date 2024-12-31
*/
@Data
@Accessors(chain = true)
@ExcelIgnoreUnannotated
@AutoMapper(target = OrderRefund.class)
public class OrderRefundVo implements Serializable {
......@@ -73,6 +75,12 @@ public class OrderRefundVo implements Serializable {
@ExcelProperty(value = "退款原因")
private String reason;
/**
* 订单总金额
*/
@ExcelProperty(value = "订单总金额")
private BigDecimal total;
/**
* 退款金额
*/
......
......@@ -12,20 +12,26 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.pay.domain.RefundModel;
import org.dromara.common.pay.service.IWxPayService;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.order.api.RemoteOrderService;
import org.dromara.order.api.domain.OrderPay;
import org.dromara.order.api.domain.RemoteOrder;
import org.dromara.order.api.domain.RemoteSaveOrder;
import org.dromara.order.api.domain.RemoteSaveRefundOrder;
import org.dromara.order.api.enums.OrderStatus;
import org.dromara.order.api.enums.OrderType;
import org.dromara.order.api.enums.Source;
import org.dromara.order.api.enums.TradeType;
import org.dromara.order.constant.WechatTradeState;
import org.dromara.order.domain.bo.OrderBo;
import org.dromara.order.domain.bo.OrderFeeBo;
import org.dromara.order.domain.bo.OrderRefundBo;
import org.dromara.order.domain.bo.OrderTradeBo;
import org.dromara.order.domain.vo.OrderFeeVo;
import org.dromara.order.domain.vo.OrderRefundVo;
import org.dromara.order.domain.vo.OrderTradeVo;
import org.dromara.order.domain.vo.OrderVo;
import org.dromara.order.service.*;
......@@ -33,6 +39,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;
......@@ -49,6 +56,7 @@ public class RemoteOrderServiceImpl implements RemoteOrderService {
private final IOrderService orderService;
private final IOrderTradeService orderTradeService;
private final IOrderRefundService orderRefundService;
private final IOrderFeeService orderFeeService;
private final IWxPayService wxPayService;
......@@ -160,6 +168,69 @@ public class RemoteOrderServiceImpl implements RemoteOrderService {
.setPayInfo(IPayStrategy.pay(JSON.toJSONString(ot), feeList, remoteOrder.getTradeType().name()));
}
@Override
public Boolean createRefundOrder(RemoteSaveRefundOrder remoteOrder) throws Exception {
OrderVo order = orderService.queryList(new OrderBo()
.setOriginOrderNo(remoteOrder.getOriginOrderNo())
.setOrderType(remoteOrder.getOrderType().getType())
).stream().findFirst().orElse(null);
if (Objects.isNull(order)) {
throw new ServiceException("订单不存在,无法进行退款");
}
if (!StringUtils.equals(order.getStatus(), OrderStatus.PAYED.getCode())) {
throw new ServiceException("订单未支付,无法进行退款");
}
OrderRefundVo or = orderRefundService.queryList(
new OrderRefundBo()
.setOrderNo(order.getOrderNo())
.setOrderPayNo(order.getOrderPayNo())
).stream().findFirst().orElse(null);
if (Objects.nonNull(or)) {
throw new ServiceException("订单已发起退款,无法再次进行退款");
}
or = new OrderRefundVo()
.setUserId(order.getUserId())
.setOrderNo(order.getOrderNo())
.setOrderPayNo(order.getOrderPayNo())
.setOrderRefundNo(System.currentTimeMillis() + "")
.setTotal(order.getPayAmount())
.setAmount(order.getPayAmount());
String refund = IPayStrategy.refund(JSON.toJSONString(or), TradeType.JSAPI.name());
RefundModel model = JsonUtils.parseObject(refund, RefundModel.class);
if (Objects.nonNull(model)) {
or.setTransactionId(model.getTransaction_id());
or.setRefundId(model.getRefund_id());
or.setChannel(model.getChannel());
or.setUserReceivedAccount(model.getUser_received_account());
or.setSuccessTime(model.getSuccess_time());
or.setRefundCreateTime(model.getCreate_time());
or.setFundsAccount(model.getFunds_account());
RefundModel.RefundAmount amount = model.getAmount();
if (Objects.nonNull(amount)) {
or.setPayerTotal(convertScoreToYuan(amount.getPayer_total()));
or.setPayerRefund(convertScoreToYuan(amount.getPayer_refund()));
or.setSettlementRefund(convertScoreToYuan(amount.getSettlement_refund()));
or.setSettlementTotal(convertScoreToYuan(amount.getSettlement_total()));
or.setDiscountRefund(convertScoreToYuan(amount.getDiscount_refund()));
or.setRefundFee(convertScoreToYuan(amount.getRefund_fee()));
}
orderRefundService.insertByBo(BeanUtil.copyProperties(or, OrderRefundBo.class));
}
return true;
}
private BigDecimal convertScoreToYuan(Integer score) {
if (score == null) {
return null;
}
return new BigDecimal(score).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
@Override
public List<RemoteOrder> queryList(String orderType, List<String> orderNoList) {
if (CollectionUtils.isEmpty(orderNoList)) {
......
......@@ -31,6 +31,24 @@ public interface IPayStrategy {
return instance.pay(tradeBody, feeList);
}
/**
* 退款
*
* @param tradeBody 交易对象
* @param tradeType 支付类型
* @return 退款信息
* @throws Exception
*/
static String refund(String tradeBody, String tradeType) throws Exception {
// 授权类型和客户端id
String beanName = tradeType + BASE_NAME;
if (!SpringUtils.containsBean(beanName)) {
throw new ServiceException("支付类型不正确!");
}
IPayStrategy instance = SpringUtils.getBean(beanName);
return instance.refund(tradeBody);
}
/**
* 获得支付信息
*
......@@ -40,4 +58,14 @@ public interface IPayStrategy {
*/
String pay(String tradeBody, List<OrderFeeVo> feeList) throws Exception;
/**
* 退款
*
* @param tradeBody 交易对象
* @return 退款信息
* @throws Exception
*/
String refund(String tradeBody) throws Exception;
}
package org.dromara.order.service.impl;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.Payer;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import com.ijpay.wxpay.model.v3.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.pay.service.IWxPayService;
import org.dromara.order.domain.bo.OrderTradeBo;
import org.dromara.order.domain.vo.OrderFeeVo;
import org.dromara.order.domain.vo.OrderRefundVo;
import org.dromara.order.service.IPayStrategy;
import org.springframework.stereotype.Service;
......@@ -53,5 +52,19 @@ public class JsapiPayStrategy implements IPayStrategy {
return wxPayService.jsapi(model);
}
@Override
public String refund(String tradeBody) throws Exception {
OrderRefundVo or = JsonUtils.parseObject(tradeBody, OrderRefundVo.class);
//获取支付金额
int amount = new BigDecimal("100").multiply(or.getAmount()).intValue();
if (amount <= 0) {
throw new RuntimeException("退款金额不能小于等于0");
}
RefundModel model = new RefundModel()
.setOut_trade_no(or.getOrderNo())
.setOut_refund_no(or.getOrderRefundNo())
.setAmount(new RefundAmount().setRefund(amount).setTotal(amount).setCurrency("CNY"));
return JsonUtils.toJsonString(wxPayService.refund(model));
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论