feat: 退款审批
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.wfc.user.api;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.wfc.common.core.constant.SecurityConstants;
|
||||
import org.wfc.common.core.constant.ServiceNameConstants;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.user.api.factory.RemoteUPaymentFallbackFactory;
|
||||
|
||||
/**
|
||||
* @description: 支付服务
|
||||
* @author: cyc
|
||||
* @since: 2025-03-27
|
||||
*/
|
||||
@FeignClient(contextId = "remoteUPaymentService", value = ServiceNameConstants.PAYMENT_SERVICE, fallbackFactory = RemoteUPaymentFallbackFactory.class)
|
||||
public interface RemoteUPaymentService {
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*
|
||||
* @param orderId 订单id
|
||||
* @return boolean
|
||||
*/
|
||||
@PostMapping(value = "/aliPay/tradeRefund")
|
||||
R<Boolean> aliPayRefund(@RequestParam(value = "orderId") Long orderId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
@PostMapping(value = "/refund")
|
||||
R<String> wxPayRefund(@RequestParam(value = "orderId") Long orderId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
@@ -86,8 +86,12 @@ public interface RemoteUUserService
|
||||
@PostMapping("/client/recordClientUser")
|
||||
public R<Boolean> recordClientUser(@RequestBody UClientBo clientBo);
|
||||
|
||||
@PostMapping("/order/paySuccess/{id}")
|
||||
public R<Boolean> paySuccess(@PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
@PostMapping("/order/paySuccess/{paymentType}/{id}")
|
||||
public R<Boolean> paySuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
@PostMapping("/order/refundSuccess/{paymentType}/{id}")
|
||||
public R<Boolean> refundSuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
@GetMapping(value = "/order/{id}")
|
||||
public R<UOrderVo> getOrderById(@PathVariable("id") Long id);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.wfc.user.api.factory;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.user.api.RemoteUPaymentService;
|
||||
|
||||
/**
|
||||
* @description: 支付服务降级处理
|
||||
* @author: cyc
|
||||
* @since: 2025-03-27
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RemoteUPaymentFallbackFactory implements FallbackFactory<RemoteUPaymentService> {
|
||||
@Override
|
||||
public RemoteUPaymentService create(Throwable throwable) {
|
||||
log.error("Payment service call failed:{}", throwable.getMessage());
|
||||
return new RemoteUPaymentService() {
|
||||
|
||||
@Override
|
||||
public R<Boolean> aliPayRefund(Long orderId, String source) {
|
||||
return R.fail("Failed to alipay refund:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<String> wxPayRefund(Long orderId, String source) {
|
||||
return R.fail("Failed to wxpay refund:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,10 +74,15 @@ public class RemoteUUserFallbackFactory implements FallbackFactory<RemoteUUserSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> paySuccess(Long id, String source) {
|
||||
public R<Boolean> paySuccess(Integer type, Long id, String source) {
|
||||
return R.fail("pay callback error:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> refundSuccess(Integer paymentType, Long id, String source) {
|
||||
return R.fail("refund callback error:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<UOrderVo> getOrderById(Long id) {
|
||||
return R.fail("get order error:" + throwable.getMessage());
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
org.wfc.user.api.factory.RemoteUUserFallbackFactory
|
||||
org.wfc.user.api.factory.RemoteULogFallbackFactory
|
||||
org.wfc.user.api.factory.RemoteUFileFallbackFactory
|
||||
org.wfc.user.api.factory.RemoteUPaymentFallbackFactory
|
||||
|
||||
@@ -22,6 +22,10 @@ public class ServiceNameConstants
|
||||
*/
|
||||
public static final String FILE_SERVICE = "wfc-file";
|
||||
|
||||
/**
|
||||
* 支付服务的serviceid
|
||||
*/
|
||||
public static final String PAYMENT_SERVICE = "wfc-payment";
|
||||
|
||||
/**
|
||||
* 用户平台模块的 service_id
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.wfc.user.domain.constant;
|
||||
package org.wfc.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@@ -14,8 +14,10 @@ public enum OrderStatusEnum {
|
||||
|
||||
UNPAID(0, "未支付"),
|
||||
PAID(1, "已支付"),
|
||||
CANCELLED(2, "已取消");
|
||||
|
||||
CANCELLED(2, "已取消"),
|
||||
REFUNDING(3, "退款中"),
|
||||
REFUNDED(4, "已退款"),
|
||||
;
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.wfc.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @description: 支付方式枚举
|
||||
* @author: cyc
|
||||
* @since: 2025-03-27
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PaymentTypeEnum {
|
||||
|
||||
BALANCE(0, "余额"),
|
||||
ALIPAY(1, "支付宝"),
|
||||
WX_PAY(2, "微信");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public static PaymentTypeEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (PaymentTypeEnum typeEnum : PaymentTypeEnum.values()) {
|
||||
if (typeEnum.getCode().equals(code)) {
|
||||
return typeEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.wfc.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @description: 退款状态枚举
|
||||
* @author: cyc
|
||||
* @since: 2025-03-26
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RefundStatusEnum {
|
||||
|
||||
PENDING(0, "待审批"),
|
||||
PASSED(1, "已通过"),
|
||||
REJECTED(2, "已驳回"),
|
||||
EXPIRED(3, "已过期");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
}
|
||||
@@ -37,6 +37,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.security.annotation.InnerAuth;
|
||||
import org.wfc.payment.domain.AliPayBean;
|
||||
import org.wfc.payment.domain.vo.AjaxResult;
|
||||
import org.wfc.payment.pay.alipay.service.IAliPayService;
|
||||
@@ -384,10 +386,11 @@ public class AliPayController extends AbstractAliPayApiController {
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
@InnerAuth
|
||||
@PostMapping(value = "/tradeRefund")
|
||||
public String tradeRefund(@RequestParam Long orderId) {
|
||||
public R<Boolean> tradeRefund(@RequestParam Long orderId) {
|
||||
|
||||
return aliPayService.tradeRefund(orderId);
|
||||
return R.ok(aliPayService.tradeRefund(orderId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,5 +16,5 @@ public interface IAliPayService {
|
||||
|
||||
String notifyUrl(HttpServletRequest request, String publicKey);
|
||||
|
||||
String tradeRefund(Long orderId);
|
||||
Boolean tradeRefund(Long orderId);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ import com.alipay.api.domain.AlipayTradePagePayModel;
|
||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||
import com.alipay.api.domain.AlipayTradeWapPayModel;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||
import com.ijpay.alipay.AliPayApi;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.core.enums.PaymentTypeEnum;
|
||||
import org.wfc.payment.pay.alipay.service.IAliPayService;
|
||||
import org.wfc.user.api.RemoteUUserService;
|
||||
import org.wfc.user.api.domain.vo.UOrderVo;
|
||||
@@ -105,7 +107,7 @@ public class AliPayServiceImpl implements IAliPayService {
|
||||
if (verifyResult) {
|
||||
// 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
|
||||
String outTradeNo = params.get("out_trade_no");
|
||||
remoteUUserService.paySuccess(Long.valueOf(outTradeNo), "inner");
|
||||
remoteUUserService.paySuccess(PaymentTypeEnum.ALIPAY.getCode(), Long.valueOf(outTradeNo), "inner");
|
||||
return "success";
|
||||
} else {
|
||||
log.error("notify_url 验证失败");
|
||||
@@ -118,7 +120,7 @@ public class AliPayServiceImpl implements IAliPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tradeRefund(Long orderId) {
|
||||
public Boolean tradeRefund(Long orderId) {
|
||||
try {
|
||||
String totalAmount = getAmountByOrder(orderId);
|
||||
if (StrUtil.isBlank(totalAmount)) {
|
||||
@@ -131,10 +133,13 @@ public class AliPayServiceImpl implements IAliPayService {
|
||||
}
|
||||
model.setRefundAmount(totalAmount);
|
||||
model.setRefundReason("normal refund");
|
||||
return AliPayApi.tradeRefundToResponse(model).getBody();
|
||||
AlipayTradeRefundResponse alipayTradeRefundResponse = AliPayApi.tradeRefundToResponse(model);
|
||||
if ("Y".equals(alipayTradeRefundResponse.getFundChange())) {
|
||||
return true;
|
||||
}
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("alipay refund error", e);
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.ijpay.wxpay.model.MicroPayModel;
|
||||
import com.ijpay.wxpay.model.OrderQueryModel;
|
||||
import com.ijpay.wxpay.model.ProfitSharingModel;
|
||||
import com.ijpay.wxpay.model.ReceiverModel;
|
||||
import com.ijpay.wxpay.model.RefundModel;
|
||||
import com.ijpay.wxpay.model.RefundQueryModel;
|
||||
import com.ijpay.wxpay.model.SendRedPackModel;
|
||||
import com.ijpay.wxpay.model.TransferModel;
|
||||
@@ -29,11 +28,14 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.security.annotation.InnerAuth;
|
||||
import org.wfc.payment.domain.H5SceneInfo;
|
||||
import org.wfc.payment.domain.WxPayBean;
|
||||
import org.wfc.payment.domain.vo.AjaxResult;
|
||||
@@ -766,37 +768,11 @@ public class WxPayController extends AbstractWxPayApiController {
|
||||
/**
|
||||
* 微信退款
|
||||
*/
|
||||
@RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET})
|
||||
@InnerAuth
|
||||
@PostMapping(value = "/refund")
|
||||
@ResponseBody
|
||||
public String refund(@RequestParam(value = "transactionId", required = false) String transactionId,
|
||||
@RequestParam(value = "outTradeNo", required = false) String outTradeNo) {
|
||||
try {
|
||||
log.info("transactionId: {} outTradeNo:{}", transactionId, outTradeNo);
|
||||
|
||||
if (StrUtil.isBlank(outTradeNo) && StrUtil.isBlank(transactionId)) {
|
||||
return "transactionId、out_trade_no二选一";
|
||||
}
|
||||
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
|
||||
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(wxPayApiConfig.getAppId())
|
||||
.mch_id(wxPayApiConfig.getMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.transaction_id(transactionId)
|
||||
.out_trade_no(outTradeNo)
|
||||
.out_refund_no(WxPayKit.generateStr())
|
||||
.total_fee("1")
|
||||
.refund_fee("1")
|
||||
.notify_url(refundNotifyUrl)
|
||||
.build()
|
||||
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
|
||||
String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
|
||||
log.info("refundStr: {}", refundStr);
|
||||
return refundStr;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
public R<String> refund(@RequestParam(value = "orderId") Long orderId) {
|
||||
return R.ok(wxPayService.refund(orderId, refundNotifyUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -831,24 +807,7 @@ public class WxPayController extends AbstractWxPayApiController {
|
||||
@RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
|
||||
@ResponseBody
|
||||
public String refundNotify(HttpServletRequest request) {
|
||||
String xmlMsg = HttpKit.readData(request);
|
||||
log.info("退款通知=" + xmlMsg);
|
||||
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
|
||||
|
||||
String returnCode = params.get("return_code");
|
||||
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
|
||||
if (WxPayKit.codeIsOk(returnCode)) {
|
||||
String reqInfo = params.get("req_info");
|
||||
String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
|
||||
log.info("退款通知解密后的数据=" + decryptData);
|
||||
// 更新订单信息
|
||||
// 发送通知等
|
||||
Map<String, String> xml = new HashMap<String, String>(2);
|
||||
xml.put("return_code", "SUCCESS");
|
||||
xml.put("return_msg", "OK");
|
||||
return WxPayKit.toXml(xml);
|
||||
}
|
||||
return null;
|
||||
return wxPayService.refundNotify(request);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/sendRedPack", method = {RequestMethod.POST, RequestMethod.GET})
|
||||
|
||||
@@ -12,4 +12,8 @@ public interface IWxPayService {
|
||||
String scanCode2(HttpServletRequest request, Long orderId, String notifyUrl);
|
||||
|
||||
String payNotify(HttpServletRequest request);
|
||||
|
||||
String refund(Long orderId, String notifyUrl);
|
||||
|
||||
String refundNotify(HttpServletRequest request);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.wfc.payment.pay.wxpay.service.impl;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
@@ -13,11 +15,14 @@ import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.WxPayApiConfig;
|
||||
import com.ijpay.wxpay.WxPayApiConfigKit;
|
||||
import com.ijpay.wxpay.model.RefundModel;
|
||||
import com.ijpay.wxpay.model.UnifiedOrderModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.core.enums.PaymentTypeEnum;
|
||||
import org.wfc.common.core.exception.ServiceException;
|
||||
import org.wfc.payment.pay.wxpay.service.IWxPayService;
|
||||
import org.wfc.payment.utils.MultipartFileUtil;
|
||||
@@ -51,16 +56,7 @@ public class WxPayServiceImpl implements IWxPayService {
|
||||
|
||||
@Override
|
||||
public String scanCode2(HttpServletRequest request, Long orderId, String notifyUrl) {
|
||||
R<UOrderVo> orderRes = remoteUUserService.getOrderById(orderId);
|
||||
UOrderVo orderVo = orderRes.getData();
|
||||
if (orderVo == null) {
|
||||
throw new ServiceException("payment.pay.error");
|
||||
}
|
||||
|
||||
String totalFee = orderVo.getOrderAmount().multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).toString();
|
||||
if (StrUtil.isBlank(totalFee)) {
|
||||
throw new ServiceException("payment.pay.error");
|
||||
}
|
||||
String totalFee = getAmountByOrder(orderId);
|
||||
|
||||
String ip = IpKit.getRealIp(request);
|
||||
if (StrUtil.isBlank(ip)) {
|
||||
@@ -140,7 +136,7 @@ public class WxPayServiceImpl implements IWxPayService {
|
||||
// 发送通知等
|
||||
Map<String, String> xml = new HashMap<String, String>(2);
|
||||
String outTradeNo = params.get("out_trade_no");
|
||||
remoteUUserService.paySuccess(Long.valueOf(outTradeNo), "inner");
|
||||
remoteUUserService.paySuccess(PaymentTypeEnum.WX_PAY.getCode(), Long.valueOf(outTradeNo), "inner");
|
||||
xml.put("return_code", "SUCCESS");
|
||||
xml.put("return_msg", "OK");
|
||||
return WxPayKit.toXml(xml);
|
||||
@@ -148,4 +144,76 @@ public class WxPayServiceImpl implements IWxPayService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refund(Long orderId, String notifyUrl) {
|
||||
try {
|
||||
String totalFee = getAmountByOrder(orderId);
|
||||
log.info("outTradeNo:{}", orderId);
|
||||
|
||||
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
|
||||
|
||||
Map<String, String> params = RefundModel.builder()
|
||||
.appid(wxPayApiConfig.getAppId())
|
||||
.mch_id(wxPayApiConfig.getMchId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.out_trade_no(orderId.toString())
|
||||
.out_refund_no(WxPayKit.generateStr())
|
||||
.total_fee(totalFee)
|
||||
.refund_fee(totalFee)
|
||||
.notify_url(notifyUrl)
|
||||
.build()
|
||||
.createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
|
||||
String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
|
||||
|
||||
log.info("refundStr: {}", refundStr);
|
||||
return refundStr;
|
||||
} catch (Exception e) {
|
||||
log.error("refund error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refundNotify(HttpServletRequest request) {
|
||||
String xmlMsg = HttpKit.readData(request);
|
||||
log.info("退款通知=" + xmlMsg);
|
||||
Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
|
||||
|
||||
String returnCode = params.get("return_code");
|
||||
// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
|
||||
if (WxPayKit.codeIsOk(returnCode)) {
|
||||
String reqInfo = params.get("req_info");
|
||||
String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
|
||||
log.info("退款通知解密后的数据=" + decryptData);
|
||||
JSONObject dataJson = JSONUtil.parseObj(decryptData);
|
||||
String refundStatus = dataJson.get("refund_status").toString();
|
||||
if ("SUCCESS".equals(refundStatus)) {
|
||||
String outTradeNo = dataJson.get("out_trade_no").toString();
|
||||
remoteUUserService.refundSuccess(PaymentTypeEnum.WX_PAY.getCode(), Long.valueOf(outTradeNo), "inner");
|
||||
|
||||
// 更新订单信息
|
||||
// 发送通知等
|
||||
Map<String, String> xml = new HashMap<String, String>(2);
|
||||
xml.put("return_code", "SUCCESS");
|
||||
xml.put("return_msg", "OK");
|
||||
return WxPayKit.toXml(xml);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @NotNull String getAmountByOrder(Long orderId) {
|
||||
R<UOrderVo> orderRes = remoteUUserService.getOrderById(orderId);
|
||||
UOrderVo orderVo = orderRes.getData();
|
||||
if (orderVo == null) {
|
||||
throw new ServiceException("payment.pay.error");
|
||||
}
|
||||
|
||||
String totalFee = orderVo.getOrderAmount().multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).toString();
|
||||
if (StrUtil.isBlank(totalFee)) {
|
||||
throw new ServiceException("payment.pay.error");
|
||||
}
|
||||
return totalFee;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.wfc.system.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.core.web.controller.BaseController;
|
||||
import org.wfc.common.core.web.domain.AjaxResult;
|
||||
import org.wfc.common.core.web.page.TableDataInfo;
|
||||
import org.wfc.system.domain.URefund;
|
||||
import org.wfc.system.domain.bo.URefundApproveBo;
|
||||
import org.wfc.system.service.IURefundService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/refund")
|
||||
public class URefundController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IURefundService uRefundService;
|
||||
|
||||
@GetMapping("/page")
|
||||
public TableDataInfo page(URefund uRefund) {
|
||||
startPage();
|
||||
List<URefund> list = uRefundService.queryList(uRefund);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(URefund uRefund) {
|
||||
List<URefund> list = uRefundService.queryList(uRefund);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getById(@PathVariable("id") Long id) {
|
||||
return success(uRefundService.getById(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody URefund uRefund) {
|
||||
return toAjax(uRefundService.save(uRefund));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody URefund uRefund) {
|
||||
return toAjax(uRefundService.updateById(uRefund));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(uRefundService.removeByIds(CollUtil.newArrayList(ids)));
|
||||
}
|
||||
|
||||
@PostMapping("pass")
|
||||
public R<Boolean> pass(@RequestBody URefundApproveBo refundApproveBo) {
|
||||
uRefundService.pass(refundApproveBo);
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@PostMapping("reject")
|
||||
public R<Boolean> reject(@RequestBody URefundApproveBo refundApproveBo) {
|
||||
uRefundService.reject(refundApproveBo);
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.wfc.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import org.wfc.common.mybatis.domain.BaseData;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-27
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("u_refund")
|
||||
@Schema(name = "URefund", description = "用户平台-退款表")
|
||||
public class URefund extends BaseData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "申请时间")
|
||||
private Date applyTime;
|
||||
|
||||
@Schema(description = "申请原因")
|
||||
private String applyReason;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private BigDecimal refundAmount;
|
||||
|
||||
@Schema(description = "退款方式")
|
||||
private Integer refundMethod;
|
||||
|
||||
@Schema(description = "审批状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.wfc.system.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description: 退款审批Bo
|
||||
* @author: cyc
|
||||
* @since: 2025-03-27
|
||||
*/
|
||||
@Data
|
||||
public class URefundApproveBo {
|
||||
private Long id;
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.wfc.system.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import org.wfc.system.domain.URefund;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-27
|
||||
*/
|
||||
@DS("user")
|
||||
public interface URefundMapper extends BaseMapper<URefund> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.wfc.system.service;
|
||||
|
||||
import org.wfc.system.domain.URefund;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.wfc.system.domain.bo.URefundApproveBo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-27
|
||||
*/
|
||||
public interface IURefundService extends IService<URefund> {
|
||||
|
||||
List<URefund> queryList(URefund uRefund);
|
||||
|
||||
void pass(URefundApproveBo refundApproveBo);
|
||||
|
||||
void reject(URefundApproveBo refundApproveBo);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.wfc.system.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.core.enums.OrderStatusEnum;
|
||||
import org.wfc.common.core.enums.PaymentTypeEnum;
|
||||
import org.wfc.common.core.enums.RefundStatusEnum;
|
||||
import org.wfc.system.domain.UOrder;
|
||||
import org.wfc.system.domain.URefund;
|
||||
import org.wfc.system.domain.bo.URefundApproveBo;
|
||||
import org.wfc.system.mapper.UOrderMapper;
|
||||
import org.wfc.system.mapper.URefundMapper;
|
||||
import org.wfc.system.service.IURefundService;
|
||||
import org.wfc.user.api.RemoteUPaymentService;
|
||||
import org.wfc.user.api.RemoteUUserService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-27
|
||||
*/
|
||||
@Service
|
||||
public class URefundServiceImpl extends ServiceImpl<URefundMapper, URefund> implements IURefundService {
|
||||
|
||||
@Autowired
|
||||
private UOrderMapper orderMapper;
|
||||
|
||||
@Autowired
|
||||
private RemoteUUserService remoteUUserService;
|
||||
|
||||
@Autowired
|
||||
private RemoteUPaymentService remoteUPaymentService;
|
||||
|
||||
@Override
|
||||
public List<URefund> queryList(URefund uRefund) {
|
||||
return this.list(buildQueryWrapper(uRefund));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<URefund> buildQueryWrapper(URefund bo) {
|
||||
LambdaQueryWrapper<URefund> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getOrderId() != null, URefund::getOrderId, bo.getOrderId());
|
||||
lqw.eq(bo.getApplyTime() != null, URefund::getApplyTime, bo.getApplyTime());
|
||||
lqw.like(StrUtil.isNotBlank(bo.getApplyReason()), URefund::getApplyReason, bo.getApplyReason());
|
||||
lqw.eq(bo.getRefundAmount() != null, URefund::getRefundAmount, bo.getRefundAmount());
|
||||
lqw.eq(bo.getRefundMethod() != null, URefund::getRefundMethod, bo.getRefundMethod());
|
||||
lqw.eq(bo.getStatus() != null, URefund::getStatus, bo.getStatus());
|
||||
lqw.like(StrUtil.isNotBlank(bo.getRemark()), URefund::getRemark, bo.getRemark());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void pass(URefundApproveBo refundApproveBo) {
|
||||
// 只有待审批状态的才能审批
|
||||
URefund refund = this.getById(refundApproveBo.getId());
|
||||
if (!RefundStatusEnum.PENDING.getCode().equals(refund.getStatus())) {
|
||||
return;
|
||||
}
|
||||
// 更新审批原因
|
||||
refund.setRemark(refundApproveBo.getRemark());
|
||||
this.updateById(refund);
|
||||
UOrder order = orderMapper.selectById(refund.getOrderId());
|
||||
switch (PaymentTypeEnum.getByCode(order.getPaymentId().intValue())) {
|
||||
case ALIPAY:
|
||||
// 支付宝
|
||||
// 调用退款接口
|
||||
R<Boolean> result = remoteUPaymentService.aliPayRefund(refund.getOrderId(), "inner");
|
||||
if (result.getData()) {
|
||||
remoteUUserService.refundSuccess(PaymentTypeEnum.ALIPAY.getCode(), refund.getId(), "inner");
|
||||
}
|
||||
break;
|
||||
case WX_PAY:
|
||||
// 微信
|
||||
remoteUPaymentService.wxPayRefund(refund.getOrderId(), "inner");
|
||||
break;
|
||||
case BALANCE:
|
||||
// 余额
|
||||
remoteUUserService.refundSuccess(PaymentTypeEnum.BALANCE.getCode(), refund.getId(), "inner");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void reject(URefundApproveBo refundApproveBo) {
|
||||
// 只有待审批状态的才能审批
|
||||
URefund refund = this.getById(refundApproveBo.getId());
|
||||
if (!RefundStatusEnum.PENDING.getCode().equals(refund.getStatus())) {
|
||||
return;
|
||||
}
|
||||
// 修改审批状态
|
||||
refund.setRemark(refundApproveBo.getRemark());
|
||||
refund.setStatus(RefundStatusEnum.REJECTED.getCode());
|
||||
this.save(refund);
|
||||
// 修改订单状态
|
||||
UOrder order = new UOrder();
|
||||
order.setId(refund.getOrderId());
|
||||
order.setStatus(OrderStatusEnum.PAID.getCode());
|
||||
orderMapper.updateById(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.wfc.system.mapper.URefundMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -20,6 +20,7 @@ import org.wfc.common.security.annotation.InnerAuth;
|
||||
import org.wfc.common.security.utils.SecurityUtils;
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import org.wfc.user.domain.UPackage;
|
||||
import org.wfc.user.domain.vo.UOrderPackageVo;
|
||||
import org.wfc.user.service.IUOrderService;
|
||||
import org.wfc.user.service.IUPackageService;
|
||||
import org.wfc.user.service.IURateLimitService;
|
||||
@@ -77,10 +78,8 @@ public class UOrderController extends BaseController {
|
||||
@GetMapping("/packagePage")
|
||||
public TableDataInfo packagePage() {
|
||||
startPage();
|
||||
List<UOrder> list = uOrderService.list(Wrappers.<UOrder>lambdaQuery()
|
||||
.eq(UOrder::getUserId, SecurityUtils.getUserId()).eq(UOrder::getType, 0)
|
||||
.orderByDesc(UOrder::getCreateTime));
|
||||
for (UOrder uOrder : list) {
|
||||
List<UOrderPackageVo> list = uOrderService.getOrderPackage(SecurityUtils.getUserId());
|
||||
for (UOrderPackageVo uOrder : list) {
|
||||
if (ObjectUtil.isNull(uOrder.getPackageId())) {
|
||||
continue;
|
||||
}
|
||||
@@ -117,9 +116,15 @@ public class UOrderController extends BaseController {
|
||||
}
|
||||
|
||||
@InnerAuth
|
||||
@PostMapping("paySuccess/{id}")
|
||||
public AjaxResult paySuccess(@PathVariable("id") Long id) {
|
||||
return toAjax(uOrderService.paySuccess(id));
|
||||
@PostMapping("paySuccess/{paymentType}/{id}")
|
||||
public AjaxResult paySuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id) {
|
||||
return toAjax(uOrderService.paySuccess(id, paymentType));
|
||||
}
|
||||
|
||||
@InnerAuth
|
||||
@PostMapping("refundSuccess/{paymentType}/{id}")
|
||||
public AjaxResult refundSuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id) {
|
||||
return toAjax(uOrderService.refundSuccess(id, paymentType));
|
||||
}
|
||||
|
||||
@PostMapping("payBalance/{id}")
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.wfc.user.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.wfc.common.core.domain.R;
|
||||
import org.wfc.common.core.web.controller.BaseController;
|
||||
import org.wfc.common.core.web.domain.AjaxResult;
|
||||
import org.wfc.common.core.web.page.TableDataInfo;
|
||||
import org.wfc.user.domain.URefund;
|
||||
import org.wfc.user.domain.bo.URefundApplyBo;
|
||||
import org.wfc.user.service.IURefundService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/refund")
|
||||
public class URefundController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IURefundService uRefundService;
|
||||
|
||||
@GetMapping("/page")
|
||||
public TableDataInfo page(URefund uRefund) {
|
||||
startPage();
|
||||
List<URefund> list = uRefundService.queryList(uRefund);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(URefund uRefund) {
|
||||
List<URefund> list = uRefundService.queryList(uRefund);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getById(@PathVariable("id") Long id) {
|
||||
return success(uRefundService.getById(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody URefund uRefund) {
|
||||
return toAjax(uRefundService.save(uRefund));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody URefund uRefund) {
|
||||
return toAjax(uRefundService.updateById(uRefund));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(uRefundService.removeByIds(CollUtil.newArrayList(ids)));
|
||||
}
|
||||
|
||||
@PutMapping("apply")
|
||||
public R<Boolean> apply(URefundApplyBo refundApplyBo) {
|
||||
uRefundService.apply(refundApplyBo);
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.wfc.user.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import org.wfc.common.mybatis.domain.BaseData;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-26
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("u_refund")
|
||||
@Schema(name = "URefund", description = "用户平台-退款表")
|
||||
public class URefund extends BaseData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "申请时间")
|
||||
private Date applyTime;
|
||||
|
||||
@Schema(description = "申请原因")
|
||||
private String applyReason;
|
||||
|
||||
@Schema(description = "退款金额")
|
||||
private BigDecimal refundAmount;
|
||||
|
||||
@Schema(description = "退款方式")
|
||||
private Integer refundMethod;
|
||||
|
||||
@Schema(description = "审批状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.wfc.user.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description: 退款申请Bo
|
||||
* @author: cyc
|
||||
* @since: 2025-03-26
|
||||
*/
|
||||
@Data
|
||||
public class URefundApplyBo {
|
||||
|
||||
private String orderId;
|
||||
|
||||
private String applyReason;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.wfc.user.domain.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.wfc.user.domain.UPackage;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description: 套餐订单Vo
|
||||
* @author: cyc
|
||||
* @since: 2025-03-26
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "UOrderPackageVo", description = "套餐订单Vo")
|
||||
public class UOrderPackageVo {
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "套餐ID")
|
||||
private Long packageId;
|
||||
|
||||
@Schema(description = "支付ID")
|
||||
private Long paymentId;
|
||||
|
||||
@Schema(description = "订单编号")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "订单类型(0套餐 1充值)")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private BigDecimal orderAmount;
|
||||
|
||||
@Schema(description = "订单状态(0待支付 1已支付 2已取消)")
|
||||
private Integer status;
|
||||
|
||||
@TableField(exist = false)
|
||||
private UPackage uPackage;
|
||||
|
||||
@Schema(description = "套餐名称")
|
||||
private String packageName;
|
||||
|
||||
@Schema(description = "套餐状态(0待生效 1已生效)")
|
||||
private Integer packageStatus;
|
||||
|
||||
@Schema(description = "订单时间")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package org.wfc.user.mapper;
|
||||
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import org.wfc.user.domain.vo.UOrderPackageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
*/
|
||||
public interface UOrderMapper extends BaseMapper<UOrder> {
|
||||
|
||||
List<UOrderPackageVo> getOrderPackage(@Param("userId") Long userId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.wfc.user.mapper;
|
||||
|
||||
import org.wfc.user.domain.URefund;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-26
|
||||
*/
|
||||
public interface URefundMapper extends BaseMapper<URefund> {
|
||||
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package org.wfc.user.service;
|
||||
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.wfc.user.domain.vo.UOrderPackageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -15,7 +18,11 @@ public interface IUOrderService extends IService<UOrder> {
|
||||
|
||||
Long saveOrder(UOrder order);
|
||||
|
||||
boolean paySuccess(Long orderId);
|
||||
boolean paySuccess(Long orderId, Integer paymentType);
|
||||
|
||||
boolean refundSuccess(Long refundId, Integer paymentType);
|
||||
|
||||
boolean payByBalance(Long orderId);
|
||||
|
||||
List<UOrderPackageVo> getOrderPackage(Long userId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.wfc.user.service;
|
||||
|
||||
import org.wfc.user.domain.URefund;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.wfc.user.domain.bo.URefundApplyBo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-26
|
||||
*/
|
||||
public interface IURefundService extends IService<URefund> {
|
||||
|
||||
List<URefund> queryList(URefund uRefund);
|
||||
|
||||
void apply(URefundApplyBo refundApplyBo);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import org.wfc.user.domain.UAccountPackage;
|
||||
import org.wfc.user.domain.UBill;
|
||||
import org.wfc.user.domain.UBillRule;
|
||||
import org.wfc.user.domain.UClient;
|
||||
import org.wfc.user.domain.constant.OrderStatusEnum;
|
||||
import org.wfc.common.core.enums.OrderStatusEnum;
|
||||
import org.wfc.user.domain.constant.OrderTypeEnum;
|
||||
import org.wfc.user.domain.vo.UAccountDashboardVo;
|
||||
import org.wfc.user.domain.vo.UCdrUserVo;
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.wfc.common.core.enums.PaymentTypeEnum;
|
||||
import org.wfc.common.core.enums.RefundStatusEnum;
|
||||
import org.wfc.common.core.exception.ServiceException;
|
||||
import org.wfc.common.security.utils.SecurityUtils;
|
||||
import org.wfc.user.api.IWifiApi;
|
||||
@@ -22,12 +24,15 @@ import org.wfc.user.domain.UClient;
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import org.wfc.user.domain.UPackage;
|
||||
import org.wfc.user.domain.URateLimit;
|
||||
import org.wfc.user.domain.constant.OrderStatusEnum;
|
||||
import org.wfc.common.core.enums.OrderStatusEnum;
|
||||
import org.wfc.user.domain.URefund;
|
||||
import org.wfc.user.domain.constant.OrderTypeEnum;
|
||||
import org.wfc.user.domain.vo.UOrderPackageVo;
|
||||
import org.wfc.user.mapper.UAccountPackageMapper;
|
||||
import org.wfc.user.mapper.UBillMapper;
|
||||
import org.wfc.user.mapper.UBillRuleMapper;
|
||||
import org.wfc.user.mapper.UOrderMapper;
|
||||
import org.wfc.user.mapper.URefundMapper;
|
||||
import org.wfc.user.service.IUAccountService;
|
||||
import org.wfc.user.service.IUClientService;
|
||||
import org.wfc.user.service.IUOrderService;
|
||||
@@ -72,18 +77,22 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
|
||||
@Autowired
|
||||
private UAccountPackageMapper accountPackageMapper;
|
||||
|
||||
@Autowired
|
||||
private URefundMapper refundMapper;
|
||||
|
||||
@Autowired
|
||||
private IWifiApi wifiApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean paySuccess(Long orderId) {
|
||||
public boolean paySuccess(Long orderId, Integer paymentType) {
|
||||
// 支付成功回调
|
||||
// 更新当前订单状态为已支付
|
||||
UOrder order = this.getById(orderId);
|
||||
if (OrderStatusEnum.PAID.getCode().equals(order.getStatus())) {
|
||||
return false;
|
||||
}
|
||||
order.setPaymentId(paymentType.longValue());
|
||||
order.setStatus(OrderStatusEnum.PAID.getCode());
|
||||
this.updateById(order);
|
||||
|
||||
@@ -145,6 +154,31 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean refundSuccess(Long refundId, Integer paymentType) {
|
||||
URefund refund = refundMapper.selectById(refundId);
|
||||
if (!RefundStatusEnum.PENDING.getCode().equals(refund.getStatus())) {
|
||||
return false;
|
||||
}
|
||||
// 修改审批状态
|
||||
refund.setStatus(RefundStatusEnum.PASSED.getCode());
|
||||
refundMapper.updateById(refund);
|
||||
// 修改订单状态
|
||||
UOrder order = this.getById(refund.getOrderId());
|
||||
order.setStatus(OrderStatusEnum.REFUNDING.getCode());
|
||||
this.updateById(order);
|
||||
if (PaymentTypeEnum.BALANCE.getCode().equals(paymentType)) {
|
||||
// 余额退款成功时恢复余额
|
||||
UAccount account = accountService.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, order.getUserId()), false);
|
||||
if (account != null) {
|
||||
account.setBalance(account.getBalance().add(order.getOrderAmount()));
|
||||
accountService.updateById(account);
|
||||
}
|
||||
}
|
||||
// 删除待生效套餐
|
||||
accountPackageMapper.delete(Wrappers.<UAccountPackage>lambdaQuery().eq(UAccountPackage::getPackageId, refund.getOrderId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean payByBalance(Long orderId) {
|
||||
@@ -164,7 +198,7 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
|
||||
if (order.getOrderAmount().compareTo(balance) > 0) {
|
||||
throw new ServiceException("user.order.pay.amount.error");
|
||||
}
|
||||
if (paySuccess(orderId)) {
|
||||
if (paySuccess(orderId, PaymentTypeEnum.BALANCE.getCode())) {
|
||||
UAccount updateAccount = new UAccount();
|
||||
updateAccount.setId(account.getId());
|
||||
updateAccount.setBalance(account.getBalance().subtract(order.getOrderAmount()));
|
||||
@@ -174,6 +208,11 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UOrderPackageVo> getOrderPackage(Long userId) {
|
||||
return this.baseMapper.getOrderPackage(userId);
|
||||
}
|
||||
|
||||
private void callbackPackage(UOrder order, UAccount account, boolean isValid) {
|
||||
if (ObjectUtil.isNull(order.getPackageId())) {
|
||||
return;
|
||||
@@ -197,11 +236,11 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
|
||||
accountPackage.setId(null);
|
||||
accountPackage.setCreateTime(null);
|
||||
accountPackage.setAccountId(account.getId());
|
||||
accountPackage.setPackageId(order.getPackageId());
|
||||
accountPackage.setPackageId(order.getId());
|
||||
accountPackageMapper.insert(accountPackage);
|
||||
} else {
|
||||
BeanUtils.copyProperties(uPackage, account);
|
||||
account.setPackageId(order.getPackageId());
|
||||
account.setPackageId(order.getId());
|
||||
account.setTrafficUsed(0L);
|
||||
account.setDurationUsed(0L);
|
||||
account.setClientNumUsed(0);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.wfc.user.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.wfc.user.domain.UOrder;
|
||||
import org.wfc.user.domain.URefund;
|
||||
import org.wfc.user.domain.bo.URefundApplyBo;
|
||||
import org.wfc.common.core.enums.OrderStatusEnum;
|
||||
import org.wfc.common.core.enums.RefundStatusEnum;
|
||||
import org.wfc.user.mapper.UOrderMapper;
|
||||
import org.wfc.user.mapper.URefundMapper;
|
||||
import org.wfc.user.service.IURefundService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户平台-退款表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author sys
|
||||
* @since 2025-03-26
|
||||
*/
|
||||
@Service
|
||||
public class URefundServiceImpl extends ServiceImpl<URefundMapper, URefund> implements IURefundService {
|
||||
|
||||
@Autowired
|
||||
private UOrderMapper orderMapper;
|
||||
|
||||
@Override
|
||||
public List<URefund> queryList(URefund uRefund) {
|
||||
return this.list(buildQueryWrapper(uRefund));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<URefund> buildQueryWrapper(URefund bo) {
|
||||
LambdaQueryWrapper<URefund> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getOrderId() != null, URefund::getOrderId, bo.getOrderId());
|
||||
lqw.eq(bo.getApplyTime() != null, URefund::getApplyTime, bo.getApplyTime());
|
||||
lqw.like(StrUtil.isNotBlank(bo.getApplyReason()), URefund::getApplyReason, bo.getApplyReason());
|
||||
lqw.eq(bo.getRefundAmount() != null, URefund::getRefundAmount, bo.getRefundAmount());
|
||||
lqw.eq(bo.getRefundMethod() != null, URefund::getRefundMethod, bo.getRefundMethod());
|
||||
lqw.eq(bo.getStatus() != null, URefund::getStatus, bo.getStatus());
|
||||
lqw.like(StrUtil.isNotBlank(bo.getRemark()), URefund::getRemark, bo.getRemark());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
public void apply(URefundApplyBo refundApplyBo) {
|
||||
UOrder order = orderMapper.selectById(refundApplyBo.getOrderId());
|
||||
// 发起退款申请
|
||||
URefund refund = new URefund();
|
||||
refund.setOrderId(order.getId());
|
||||
refund.setApplyReason(refundApplyBo.getApplyReason());
|
||||
refund.setApplyTime(new Date());
|
||||
refund.setRefundAmount(order.getOrderAmount());
|
||||
refund.setStatus(RefundStatusEnum.PENDING.getCode());
|
||||
this.save(refund);
|
||||
// 修改订单状态
|
||||
order.setStatus(OrderStatusEnum.REFUNDING.getCode());
|
||||
orderMapper.updateById(order);
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,20 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.wfc.user.mapper.UOrderMapper">
|
||||
|
||||
<select id="getOrderPackage" resultType="org.wfc.user.domain.vo.UOrderPackageVo">
|
||||
SELECT
|
||||
o.*, p.package_name, if(o.`status` = 1, if(ap.id is null, 1, 0),null) package_status
|
||||
FROM
|
||||
`u_order` o
|
||||
LEFT JOIN u_package p ON o.package_id = p.id
|
||||
AND p.del_flag = 0
|
||||
LEFT JOIN u_account_package ap ON o.id = ap.package_id
|
||||
AND ap.del_flag = 0
|
||||
AND o.type = 1
|
||||
WHERE
|
||||
o.del_flag = 0
|
||||
AND o.user_id = #{userId}
|
||||
ORDER BY o.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.wfc.user.mapper.URefundMapper">
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user