diff --git a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUPaymentService.java b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUPaymentService.java new file mode 100644 index 0000000..de191da --- /dev/null +++ b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUPaymentService.java @@ -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 aliPayRefund(@RequestParam(value = "orderId") Long orderId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); + + @PostMapping(value = "/refund") + R wxPayRefund(@RequestParam(value = "orderId") Long orderId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); +} diff --git a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUUserService.java b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUUserService.java index 80aff8a..3b085ec 100644 --- a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUUserService.java +++ b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/RemoteUUserService.java @@ -86,8 +86,12 @@ public interface RemoteUUserService @PostMapping("/client/recordClientUser") public R recordClientUser(@RequestBody UClientBo clientBo); - @PostMapping("/order/paySuccess/{id}") - public R paySuccess(@PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); + @PostMapping("/order/paySuccess/{paymentType}/{id}") + public R paySuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); + + @PostMapping("/order/refundSuccess/{paymentType}/{id}") + public R refundSuccess(@PathVariable("paymentType")Integer paymentType, @PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); + @GetMapping(value = "/order/{id}") public R getOrderById(@PathVariable("id") Long id); diff --git a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUPaymentFallbackFactory.java b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUPaymentFallbackFactory.java new file mode 100644 index 0000000..a9742af --- /dev/null +++ b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUPaymentFallbackFactory.java @@ -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 { + @Override + public RemoteUPaymentService create(Throwable throwable) { + log.error("Payment service call failed:{}", throwable.getMessage()); + return new RemoteUPaymentService() { + + @Override + public R aliPayRefund(Long orderId, String source) { + return R.fail("Failed to alipay refund:" + throwable.getMessage()); + } + + @Override + public R wxPayRefund(Long orderId, String source) { + return R.fail("Failed to wxpay refund:" + throwable.getMessage()); + } + }; + } +} diff --git a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUUserFallbackFactory.java b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUUserFallbackFactory.java index afedfe1..1dcdd5f 100644 --- a/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUUserFallbackFactory.java +++ b/wfc-api/wfc-api-user/src/main/java/org/wfc/user/api/factory/RemoteUUserFallbackFactory.java @@ -74,10 +74,15 @@ public class RemoteUUserFallbackFactory implements FallbackFactory paySuccess(Long id, String source) { + public R paySuccess(Integer type, Long id, String source) { return R.fail("pay callback error:" + throwable.getMessage()); } + @Override + public R refundSuccess(Integer paymentType, Long id, String source) { + return R.fail("refund callback error:" + throwable.getMessage()); + } + @Override public R getOrderById(Long id) { return R.fail("get order error:" + throwable.getMessage()); diff --git a/wfc-api/wfc-api-user/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/wfc-api/wfc-api-user/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 9408c8a..797dc66 100644 --- a/wfc-api/wfc-api-user/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/wfc-api/wfc-api-user/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -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 diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/ServiceNameConstants.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/ServiceNameConstants.java index ab81b6b..35027ac 100644 --- a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/ServiceNameConstants.java +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/constant/ServiceNameConstants.java @@ -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 diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderStatusEnum.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/OrderStatusEnum.java similarity index 70% rename from wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderStatusEnum.java rename to wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/OrderStatusEnum.java index 911016b..12dc987 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/constant/OrderStatusEnum.java +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/OrderStatusEnum.java @@ -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; diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/PaymentTypeEnum.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/PaymentTypeEnum.java new file mode 100644 index 0000000..0c99e90 --- /dev/null +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/PaymentTypeEnum.java @@ -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; + } +} diff --git a/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/RefundStatusEnum.java b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/RefundStatusEnum.java new file mode 100644 index 0000000..69a1018 --- /dev/null +++ b/wfc-common/wfc-common-core/src/main/java/org/wfc/common/core/enums/RefundStatusEnum.java @@ -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; +} diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/controller/AliPayController.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/controller/AliPayController.java index e17576b..ae5bdb8 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/controller/AliPayController.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/controller/AliPayController.java @@ -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 tradeRefund(@RequestParam Long orderId) { - return aliPayService.tradeRefund(orderId); + return R.ok(aliPayService.tradeRefund(orderId)); } /** diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/IAliPayService.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/IAliPayService.java index 0e6bc6d..0643de1 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/IAliPayService.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/IAliPayService.java @@ -16,5 +16,5 @@ public interface IAliPayService { String notifyUrl(HttpServletRequest request, String publicKey); - String tradeRefund(Long orderId); + Boolean tradeRefund(Long orderId); } diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/impl/AliPayServiceImpl.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/impl/AliPayServiceImpl.java index 81671c0..98d00c5 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/impl/AliPayServiceImpl.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/alipay/service/impl/AliPayServiceImpl.java @@ -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; } } diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/controller/WxPayController.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/controller/WxPayController.java index f5b8271..17d2111 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/controller/WxPayController.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/controller/WxPayController.java @@ -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 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 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 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 xml = new HashMap(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}) diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/IWxPayService.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/IWxPayService.java index 4a16f0f..32c0c90 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/IWxPayService.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/IWxPayService.java @@ -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); } diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/impl/WxPayServiceImpl.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/impl/WxPayServiceImpl.java index fc879b6..490bb08 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/impl/WxPayServiceImpl.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/wxpay/service/impl/WxPayServiceImpl.java @@ -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 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 xml = new HashMap(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 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 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 xml = new HashMap(2); + xml.put("return_code", "SUCCESS"); + xml.put("return_msg", "OK"); + return WxPayKit.toXml(xml); + } + } + return null; + } + + private @NotNull String getAmountByOrder(Long orderId) { + R 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; + } } diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/controller/URefundController.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/controller/URefundController.java new file mode 100644 index 0000000..f2855ea --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/controller/URefundController.java @@ -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; + +/** + *

+ * 用户平台-退款表 前端控制器 + *

+ * + * @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 list = uRefundService.queryList(uRefund); + return getDataTable(list); + } + + @GetMapping("/list") + public AjaxResult list(URefund uRefund) { + List 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 pass(@RequestBody URefundApproveBo refundApproveBo) { + uRefundService.pass(refundApproveBo); + return R.ok(true); + } + + @PostMapping("reject") + public R reject(@RequestBody URefundApproveBo refundApproveBo) { + uRefundService.reject(refundApproveBo); + return R.ok(true); + } + +} diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/URefund.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/URefund.java new file mode 100644 index 0000000..48e605d --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/URefund.java @@ -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; + +/** + *

+ * 用户平台-退款表 + *

+ * + * @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; +} diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/bo/URefundApproveBo.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/bo/URefundApproveBo.java new file mode 100644 index 0000000..919973c --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/domain/bo/URefundApproveBo.java @@ -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; +} diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/mapper/URefundMapper.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/mapper/URefundMapper.java new file mode 100644 index 0000000..046aa29 --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/mapper/URefundMapper.java @@ -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; + +/** + *

+ * 用户平台-退款表 Mapper 接口 + *

+ * + * @author sys + * @since 2025-03-27 + */ +@DS("user") +public interface URefundMapper extends BaseMapper { + +} diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/IURefundService.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/IURefundService.java new file mode 100644 index 0000000..3d415f9 --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/IURefundService.java @@ -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; + +/** + *

+ * 用户平台-退款表 服务类 + *

+ * + * @author sys + * @since 2025-03-27 + */ +public interface IURefundService extends IService { + + List queryList(URefund uRefund); + + void pass(URefundApproveBo refundApproveBo); + + void reject(URefundApproveBo refundApproveBo); + +} diff --git a/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/impl/URefundServiceImpl.java b/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/impl/URefundServiceImpl.java new file mode 100644 index 0000000..f2a7e5b --- /dev/null +++ b/wfc-modules/wfc-system/src/main/java/org/wfc/system/service/impl/URefundServiceImpl.java @@ -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; + +/** + *

+ * 用户平台-退款表 服务实现类 + *

+ * + * @author sys + * @since 2025-03-27 + */ +@Service +public class URefundServiceImpl extends ServiceImpl implements IURefundService { + + @Autowired + private UOrderMapper orderMapper; + + @Autowired + private RemoteUUserService remoteUUserService; + + @Autowired + private RemoteUPaymentService remoteUPaymentService; + + @Override + public List queryList(URefund uRefund) { + return this.list(buildQueryWrapper(uRefund)); + } + + private LambdaQueryWrapper buildQueryWrapper(URefund bo) { + LambdaQueryWrapper 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 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); + } +} diff --git a/wfc-modules/wfc-system/src/main/resources/mapper/user/URefundMapper.xml b/wfc-modules/wfc-system/src/main/resources/mapper/user/URefundMapper.xml new file mode 100644 index 0000000..4f6e746 --- /dev/null +++ b/wfc-modules/wfc-system/src/main/resources/mapper/user/URefundMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UOrderController.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UOrderController.java index 75c070e..8de3a15 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UOrderController.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/UOrderController.java @@ -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 list = uOrderService.list(Wrappers.lambdaQuery() - .eq(UOrder::getUserId, SecurityUtils.getUserId()).eq(UOrder::getType, 0) - .orderByDesc(UOrder::getCreateTime)); - for (UOrder uOrder : list) { + List 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}") diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/URefundController.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/URefundController.java new file mode 100644 index 0000000..9568603 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/controller/URefundController.java @@ -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; + +/** + *

+ * 用户平台-退款表 前端控制器 + *

+ * + * @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 list = uRefundService.queryList(uRefund); + return getDataTable(list); + } + + @GetMapping("/list") + public AjaxResult list(URefund uRefund) { + List 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 apply(URefundApplyBo refundApplyBo) { + uRefundService.apply(refundApplyBo); + return R.ok(true); + } + +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/URefund.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/URefund.java new file mode 100644 index 0000000..3f7b800 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/URefund.java @@ -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; + +/** + *

+ * 用户平台-退款表 + *

+ * + * @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; +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/URefundApplyBo.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/URefundApplyBo.java new file mode 100644 index 0000000..244639d --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/bo/URefundApplyBo.java @@ -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; +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/vo/UOrderPackageVo.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/vo/UOrderPackageVo.java new file mode 100644 index 0000000..9ca583c --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/domain/vo/UOrderPackageVo.java @@ -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; +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/UOrderMapper.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/UOrderMapper.java index e5e84ed..83c15ef 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/UOrderMapper.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/UOrderMapper.java @@ -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; /** *

@@ -13,4 +17,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface UOrderMapper extends BaseMapper { + List getOrderPackage(@Param("userId") Long userId); } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/URefundMapper.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/URefundMapper.java new file mode 100644 index 0000000..5d6b5c7 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/mapper/URefundMapper.java @@ -0,0 +1,16 @@ +package org.wfc.user.mapper; + +import org.wfc.user.domain.URefund; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 用户平台-退款表 Mapper 接口 + *

+ * + * @author sys + * @since 2025-03-26 + */ +public interface URefundMapper extends BaseMapper { + +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUOrderService.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUOrderService.java index dc7af6d..0336577 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUOrderService.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IUOrderService.java @@ -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; /** *

@@ -15,7 +18,11 @@ public interface IUOrderService extends IService { 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 getOrderPackage(Long userId); } diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IURefundService.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IURefundService.java new file mode 100644 index 0000000..c5b6c6e --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/IURefundService.java @@ -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; + +/** + *

+ * 用户平台-退款表 服务类 + *

+ * + * @author sys + * @since 2025-03-26 + */ +public interface IURefundService extends IService { + + List queryList(URefund uRefund); + + void apply(URefundApplyBo refundApplyBo); +} diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UAccountServiceImpl.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UAccountServiceImpl.java index e4ffb89..9f1815a 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UAccountServiceImpl.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UAccountServiceImpl.java @@ -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; diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java index 203bc45..066a639 100644 --- a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/UOrderServiceImpl.java @@ -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 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 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.lambdaQuery().eq(UAccount::getUserId, order.getUserId()), false); + if (account != null) { + account.setBalance(account.getBalance().add(order.getOrderAmount())); + accountService.updateById(account); + } + } + // 删除待生效套餐 + accountPackageMapper.delete(Wrappers.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 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 impleme return true; } + @Override + public List 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 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); diff --git a/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/URefundServiceImpl.java b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/URefundServiceImpl.java new file mode 100644 index 0000000..d2a8713 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/java/org/wfc/user/service/impl/URefundServiceImpl.java @@ -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; + +/** + *

+ * 用户平台-退款表 服务实现类 + *

+ * + * @author sys + * @since 2025-03-26 + */ +@Service +public class URefundServiceImpl extends ServiceImpl implements IURefundService { + + @Autowired + private UOrderMapper orderMapper; + + @Override + public List queryList(URefund uRefund) { + return this.list(buildQueryWrapper(uRefund)); + } + + private LambdaQueryWrapper buildQueryWrapper(URefund bo) { + LambdaQueryWrapper 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); + } +} diff --git a/wfc-modules/wfc-user/src/main/resources/mapper/user/UOrderMapper.xml b/wfc-modules/wfc-user/src/main/resources/mapper/user/UOrderMapper.xml index 6750ee7..b26c6fd 100644 --- a/wfc-modules/wfc-user/src/main/resources/mapper/user/UOrderMapper.xml +++ b/wfc-modules/wfc-user/src/main/resources/mapper/user/UOrderMapper.xml @@ -1,5 +1,21 @@ + + diff --git a/wfc-modules/wfc-user/src/main/resources/mapper/user/URefundMapper.xml b/wfc-modules/wfc-user/src/main/resources/mapper/user/URefundMapper.xml new file mode 100644 index 0000000..899e399 --- /dev/null +++ b/wfc-modules/wfc-user/src/main/resources/mapper/user/URefundMapper.xml @@ -0,0 +1,5 @@ + + + + +