diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java similarity index 97% rename from yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java rename to yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java index 582840e4e..4ba9e5088 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.core.client.impl; +package cn.iocoder.yudao.framework.pay.core.client.impl; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.RandomUtil; @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; @@ -14,6 +13,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import com.alipay.api.response.AlipayTradePrecreateResponse; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.FileInputStream; @@ -24,7 +24,8 @@ import java.io.FileNotFoundException; * * @author 芋道源码 */ -public class PayClientFactoryImplTest { +@Disabled +public class PayClientFactoryImplIntegrationTest { private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); @@ -91,7 +92,7 @@ public class PayClientFactoryImplTest { PayClient client = payClientFactory.getPayClient(channelId); // 发起支付 PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); - reqDTO.setNotifyUrl("http://niubi.natapp1.cc/api/pay/order/notify/alipay-qr/1"); // TODO @tina: 这里改成你的 natapp 回调地址 + reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址 CommonResult result = (CommonResult) client.unifiedOrder(reqDTO); System.out.println(JsonUtils.toJsonString(result)); System.out.println(result.getData().getQrCode()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index c3dba8d9e..5a6996e4b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -83,7 +83,7 @@ public class TradeAfterSaleController { return success(true); } - @PutMapping("/receive") + @PutMapping("/refuse") @ApiOperation("确认收货") @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java new file mode 100644 index 000000000..ab0693e0d --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.pay.controller.admin.notify; + +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND; + +@Api(tags = "管理后台 - 支付通知") +@RestController +@RequestMapping("/pay/notify") +@Validated +@Slf4j +public class PayNotifyController { + + @Resource + private PayOrderService orderService; + @Resource + private PayRefundService refundService; + + @Resource + private PayClientFactory payClientFactory; + + /** + * 统一的跳转页面,支付宝跳转参数说明 + * + * 支付宝 - 前台回跳参数说明 + * + * @param channelId 渠道编号 + * @return 返回跳转页面 + */ + @GetMapping(value = "/return/{channelId}") + @ApiOperation("渠道统一的支付成功返回地址") + @Deprecated // TODO yunai:如果是 way 的情况,应该是跳转回前端地址 + public String returnCallback(@PathVariable("channelId") Long channelId, + @RequestParam Map params) { + log.info("[returnCallback][app_id({}) 跳转]", params.get("app_id")); + return String.format("渠道[%s]支付成功", channelId); + } + + /** + * 统一的渠道支付回调,支付宝的退款回调 + * + * @param channelId 渠道编号 + * @param params form 参数 + * @param body request body + * @return 成功返回 "success" + */ + @PostMapping(value = "/callback/{channelId}") + @ApiOperation(value = "支付渠道的统一回调接口", notes = "包括支付回调,退款回调") + @PermitAll + public String notifyCallback(@PathVariable("channelId") Long channelId, + @RequestParam Map params, + @RequestBody String body) throws Exception { + // 校验支付渠道是否存在 + PayClient payClient = payClientFactory.getPayClient(channelId); + if (payClient == null) { + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); + } + // 校验通知数据是否合法 + PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(body).build(); + payClient.verifyNotifyData(notifyData); + + // 情况一:如果是退款,则发起退款通知 + if (payClient.isRefundNotify(notifyData)) { + refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(body).build()); + return "success"; + } + + // 情况二:如果非退款,则发起支付通知 + orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(body).build()); + return "success"; + } + + +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java index e01f7f4f4..72f037a28 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java @@ -2,29 +2,25 @@ package cn.iocoder.yudao.module.pay.controller.app.order; import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.pay.core.client.PayClient; -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; -import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO; import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitRespDTO; -import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; -import java.util.Map; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; @Api(tags = "用户 APP - 支付订单") @RestController @@ -35,11 +31,6 @@ public class AppPayOrderController { @Resource private PayOrderService orderService; - @Resource - private PayRefundService refundService; - - @Resource - private PayClientFactory payClientFactory; @PostMapping("/submit") @ApiOperation("提交支付订单") @@ -59,64 +50,4 @@ public class AppPayOrderController { return success(AppPayOrderSubmitRespVO.builder().invokeResponse(respDTO.getInvokeResponse()).build()); } - // ========== 支付渠道的回调 ========== - // TODO @芋艿:是不是放到 notify 模块更合适 - //TODO 芋道源码 换成了统一的地址了 /notify/{channelId},测试通过可以删除 - @PostMapping("/notify/wx-pub/{channelId}") - @ApiOperation("通知微信公众号支付的结果") - public String notifyWxPayOrder(@PathVariable("channelId") Long channelId, - @RequestBody String xmlData) throws Exception { - orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().body(xmlData).build()); - return "success"; - } - - /** - * 统一的跳转页面, 支付宝跳转参数说明 - * https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E - * @param channelId 渠道id - * @return 返回跳转页面 - */ - @GetMapping(value = "/return/{channelId}") - @ApiOperation("渠道统一的支付成功返回地址") - public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map params){ - //TODO 可以根据渠道和 app_id 返回不同的页面 - log.info("app_id is {}", params.get("app_id")); - return String.format("渠道[%s]支付成功", channelId); - } - - /** - * 统一的渠道支付回调,支付宝的退款回调 - * - * @param channelId 渠道编号 - * @param params form 参数 - * @param originData http request body - * @return 成功返回 "success" - */ - @PostMapping(value = "/notify/{channelId}") - @ApiOperation("渠道统一的支付成功,或退款成功 通知url") - public String notifyChannelPay(@PathVariable("channelId") Long channelId, - @RequestParam Map params, - @RequestBody String originData) throws Exception { - // 校验支付渠道是否存在 - PayClient payClient = payClientFactory.getPayClient(channelId); - if (payClient == null) { - log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channelId); - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); - } - - // 校验通知数据是否合法 - PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(originData).build(); - payClient.verifyNotifyData(notifyData); - - // 如果是退款,则发起退款通知 - if (payClient.isRefundNotify(notifyData)) { - refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build()); - return "success"; - } - - // 如果非退款,则发起支付通知 - orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build()); - return "success"; - } - } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java index 502c0515a..656cea01c 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.pay.dal.dataobject.merchant; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; @@ -26,7 +26,7 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class PayChannelDO extends BaseDO { +public class PayChannelDO extends TenantBaseDO { /** * 渠道编号,数据库自增 diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java index 67a3e7152..dbeb7baa1 100755 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java @@ -211,7 +211,7 @@ public class PayOrderServiceImpl implements PayOrderService { @Override @Transactional - public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception { + public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception { // TODO 芋艿,记录回调日志 log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody()); diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 87f781091..9a352266c 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -117,7 +117,7 @@ yudao: - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 - - /app-api/pay/order/notify/* # 支付回调通知,不携带租户编号 + - /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号 - /jmreport/* # 积木报表,无法携带租户编号 ignore-tables: - system_tenant