- * 注意,可通过 {@link #main(String[])} 读取
+ * apiclient_cert.pem 证书文件的对应的字符串
*/
@NotBlank(message = "apiclient_cert 不能为空", groups = V3.class)
private String privateCertContent;
/**
* apiV3 密钥值
*/
- @NotBlank(message = "apiV3 密钥值 不能为空", groups = V3.class)
+ @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class)
private String apiV3Key;
/**
@@ -97,8 +95,9 @@ public class WXPayClientConfig implements PayClientConfig {
}
@Override
- public Set
- * 参考 https://www.pingxx.com/api/支付渠道属性值.html
+ *
+ * 参考 支付渠道属性值
*/
private final String code;
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayDisplayModeEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java
similarity index 61%
rename from yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayDisplayModeEnum.java
rename to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java
index d19bfde331..129c406029 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayDisplayModeEnum.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.framework.pay.core.enums;
+package cn.iocoder.yudao.framework.pay.core.enums.order;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -10,15 +10,15 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
-public enum PayDisplayModeEnum {
+public enum PayOrderDisplayModeEnum {
URL("url"), // Redirect 跳转链接的方式
- IFRAME("iframe"), // IFrame 内嵌链接的方式
+ IFRAME("iframe"), // IFrame 内嵌链接的方式【目前暂时用不到】
FORM("form"), // HTML 表单提交
QR_CODE("qr_code"), // 二维码的文字内容
QR_CODE_URL("qr_code_url"), // 二维码的图片链接
BAR_CODE("bar_code"), // 条形码
- APP("app"), // 应用
+ APP("app"), // 应用:Android、iOS、微信小程序、微信公众号等,需要做自定义处理的
;
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java
new file mode 100644
index 0000000000..eac381c472
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.framework.pay.core.enums.order;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Objects;
+
+/**
+ * 渠道的支付状态枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum PayOrderStatusRespEnum {
+
+ WAITING(0, "未支付"),
+ SUCCESS(10, "支付成功"),
+ REFUND(20, "已退款"),
+ CLOSED(30, "支付关闭"),
+ ;
+
+ private final Integer status;
+ private final String name;
+
+ /**
+ * 判断是否支付成功
+ *
+ * @param status 状态
+ * @return 是否支付成功
+ */
+ public static boolean isSuccess(Integer status) {
+ return Objects.equals(status, SUCCESS.getStatus());
+ }
+
+ /**
+ * 判断是否已退款
+ *
+ * @param status 状态
+ * @return 是否支付成功
+ */
+ public static boolean isRefund(Integer status) {
+ return Objects.equals(status, REFUND.getStatus());
+ }
+
+ /**
+ * 判断是否支付关闭
+ *
+ * @param status 状态
+ * @return 是否支付关闭
+ */
+ public static boolean isClosed(Integer status) {
+ return Objects.equals(status, CLOSED.getStatus());
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java
new file mode 100644
index 0000000000..8ad61a6cff
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.framework.pay.core.enums.refund;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Objects;
+
+/**
+ * 渠道的退款状态枚举
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum PayRefundStatusRespEnum {
+
+ WAITING(0, "等待退款"),
+ SUCCESS(10, "退款成功"),
+ FAILURE(20, "退款失败");
+
+ private final Integer status;
+ private final String name;
+
+ public static boolean isSuccess(Integer status) {
+ return Objects.equals(status, SUCCESS.getStatus());
+ }
+
+ public static boolean isFailure(Integer status) {
+ return Objects.equals(status, FAILURE.getStatus());
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java
index 071f53d127..9842560636 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java
@@ -2,17 +2,14 @@ package cn.iocoder.yudao.framework.pay.core.client.impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RandomUtil;
-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.order.PayOrderUnifiedReqDTO;
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;
-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 cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig;
+import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPubPayClient;
+import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -27,18 +24,20 @@ import java.io.FileNotFoundException;
@Disabled
public class PayClientFactoryImplIntegrationTest {
+ private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
+
private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
/**
- * {@link WXPubPayClient} 的 V2 版本
+ * {@link WxPubPayClient} 的 V2 版本
*/
@Test
public void testCreatePayClient_WX_PUB_V2() {
// 创建配置
- WXPayClientConfig config = new WXPayClientConfig();
+ WxPayClientConfig config = new WxPayClientConfig();
config.setAppId("wx041349c6f39b268b");
config.setMchId("1545083881");
- config.setApiVersion(WXPayClientConfig.API_VERSION_V2);
+ config.setApiVersion(WxPayClientConfig.API_VERSION_V2);
config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p");
// 创建客户端
Long channelId = RandomUtil.randomLong();
@@ -51,15 +50,15 @@ public class PayClientFactoryImplIntegrationTest {
}
/**
- * {@link WXPubPayClient} 的 V3 版本
+ * {@link WxPubPayClient} 的 V3 版本
*/
@Test
public void testCreatePayClient_WX_PUB_V3() throws FileNotFoundException {
// 创建配置
- WXPayClientConfig config = new WXPayClientConfig();
+ WxPayClientConfig config = new WxPayClientConfig();
config.setAppId("wx041349c6f39b268b");
config.setMchId("1545083881");
- config.setApiVersion(WXPayClientConfig.API_VERSION_V3);
+ config.setApiVersion(WxPayClientConfig.API_VERSION_V3);
config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem")));
config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem")));
config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase");
@@ -82,7 +81,7 @@ public class PayClientFactoryImplIntegrationTest {
// 创建配置
AlipayPayClientConfig config = new AlipayPayClientConfig();
config.setAppId("2021000118634035");
- config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX);
+ config.setServerUrl(SERVER_URL_SANDBOX);
config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
@@ -106,7 +105,7 @@ public class PayClientFactoryImplIntegrationTest {
// 创建配置
AlipayPayClientConfig config = new AlipayPayClientConfig();
config.setAppId("2021000118634035");
- config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX);
+ config.setServerUrl(SERVER_URL_SANDBOX);
config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8=");
config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB");
@@ -122,10 +121,10 @@ public class PayClientFactoryImplIntegrationTest {
private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() {
PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO();
- reqDTO.setAmount(123);
+ reqDTO.setPrice(123);
reqDTO.setSubject("IPhone 13");
reqDTO.setBody("biubiubiu");
- reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis()));
+ reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis()));
reqDTO.setUserIp("127.0.0.1");
reqDTO.setNotifyUrl("http://127.0.0.1:8080");
return reqDTO;
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java
index 78939aa830..0eb354cd05 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java
@@ -1,8 +1,6 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.util.ReflectUtil;
-import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
-import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
@@ -22,9 +20,11 @@ import static org.mockito.Mockito.when;
public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
+ private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";
+
private final AlipayPayClientConfig config = new AlipayPayClientConfig()
.setAppId("2021000118634035")
- .setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX)
+ .setServerUrl(SERVER_URL_SANDBOX)
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
// TODO @tina:key 可以随机就好,简洁一点哈。
.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJ" +
@@ -72,8 +72,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
// 这里,设置可以直接随机整个对象。
Long shopOrderId = System.currentTimeMillis();
PayOrderUnifiedReqDTO reqDTO=new PayOrderUnifiedReqDTO();
- reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis()));
- reqDTO.setAmount(1);
+ reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis()));
+ reqDTO.setPrice(1);
reqDTO.setBody("内容:" + shopOrderId);
reqDTO.setSubject("标题:"+shopOrderId);
String notify="http://niubi.natapp1.cc/api/pay/order/notify";
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java
new file mode 100644
index 0000000000..9af11ac3fc
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java
@@ -0,0 +1,123 @@
+package cn.iocoder.yudao.framework.pay.core.client.impl.weixin;
+
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
+import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
+import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+
+import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.AbstractWxPayClient.formatDateV2;
+
+/**
+ * {@link WxBarPayClient} 的集成测试,用于快速调试微信条码支付
+ *
+ * @author 芋道源码
+ */
+@Disabled
+public class WxBarPayClientIntegrationTest {
+
+ @Test
+ public void testPayV2() throws WxPayException {
+ // 创建 config 配置
+ WxPayConfig config = buildWxPayConfigV2();
+ // 创建 WxPayService 客户端
+ WxPayService client = new WxPayServiceImpl();
+ client.setConfig(config);
+
+ // 执行发起支付
+ WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder()
+ .outTradeNo(String.valueOf(System.currentTimeMillis()))
+ .body("测试支付-body")
+ .detail("测试支付-detail")
+ .totalFee(1) // 单位分
+ .timeExpire(formatDateV2(LocalDateTimeUtils.addTime(Duration.ofMinutes(2))))
+ .spbillCreateIp("127.0.0.1")
+ .authCode("134298744426278497")
+ .build();
+ System.out.println("========= request ==========");
+ System.out.println(JsonUtils.toJsonPrettyString(request));
+ WxPayMicropayResult response = client.micropay(request);
+ System.out.println("========= response ==========");
+ System.out.println(JsonUtils.toJsonPrettyString(response));
+ }
+
+ @Test
+ public void testParseRefundNotifyV2() throws WxPayException {
+ // 创建 config 配置
+ WxPayConfig config = buildWxPayConfigV2();
+ // 创建 WxPayService 客户端
+ WxPayService client = new WxPayServiceImpl();
+ client.setConfig(config);
+
+ // 执行解析
+ String xml = "
- * 枚举 {@link CommonStatusEnum}
- */
- private Integer status;
/**
* 库存
*/
private Integer stock;
- /**
- * 预警预存
- */
- private Integer warnStock;
/**
* 商品重量,单位:kg 千克
*/
@@ -74,22 +60,4 @@ public class ProductSkuRespDTO {
*/
private Double volume;
- /**
- * 商品属性
- */
- @Data
- public static class Property {
-
- /**
- * 属性编号
- */
- private Long propertyId;
- /**
- * 属性值编号
- */
- private Long valueId;
-
- }
-
-
}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
index 45d42f41be..3188f96321 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.product.api.spu.dto;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
-import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import lombok.Data;
@@ -29,17 +28,23 @@ public class ProductSpuRespDTO {
*/
private String name;
/**
- * 商品编码
+ * 关键字
*/
- private String code;
+ private String keyword;
/**
- * 促销语
+ * 商品简介
*/
- private String sellPoint;
+ private String introduction;
/**
* 商品详情
*/
private String description;
+ // TODO @芋艿:是不是要删除
+ /**
+ * 商品条码(一维码)
+ */
+ private String barCode;
+
/**
* 商品分类编号
*/
@@ -49,13 +54,13 @@ public class ProductSpuRespDTO {
*/
private Long brandId;
/**
- * 商品图片的数组
- *
- * 1. 第一张图片将作为商品主图,支持同时上传多张图;
- * 2. 建议使用尺寸 800x800 像素以上、大小不超过 1M 的正方形图片;
- * 3. 至少 1 张,最多上传 10 张
+ * 商品封面图
*/
- private List
- * 枚举 {@link ProductSpuSpecTypeEnum}
+ *
+ * false - 单规格
+ * true - 多规格
*/
- private Integer specType;
+ private Boolean specType;
/**
- * 最小价格,单位使用:分
- *
- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值
+ * 商品价格,单位使用:分
*/
- private Integer minPrice;
- /**
- * 最大价格,单位使用:分
- *
- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值
- */
- private Integer maxPrice;
+ private Integer price;
/**
* 市场价,单位使用:分
- *
- * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值
*/
private Integer marketPrice;
/**
- * 总库存
- *
- * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和
+ * 成本价,单位使用:分
*/
- private Integer totalStock;
+ private Integer costPrice;
/**
- * 是否展示库存
+ * 库存
*/
- private Boolean showStock;
+ private Integer stock;
+
+ // ========== 物流相关字段 =========
+
+ /**
+ * 物流配置模板编号
+ *
+ * 对应 TradeDeliveryExpressTemplateDO 的 id 编号
+ */
+ private Long deliveryTemplateId;
// ========== 统计相关字段 =========
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java
new file mode 100644
index 0000000000..85725a18ea
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.product.enums;
+
+/**
+ * product 字典类型的枚举类
+ *
+ * @author HUIHUI
+ */
+public interface DictTypeConstants {
+
+ String PRODUCT_UNIT = "product_unit"; // 商品单位
+ String PRODUCT_SPU_STATUS = "product_spu_status"; // 商品 SPU 状态
+
+}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
index 4adad0afcb..d97a2613f8 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
@@ -15,10 +15,11 @@ public interface ErrorCodeConstants {
ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1008001002, "父分类不能是二级分类");
ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1008001003, "存在子分类,无法删除");
ErrorCode CATEGORY_DISABLED = new ErrorCode(1008001004, "商品分类({})已禁用,无法使用");
+ ErrorCode CATEGORY_HAVE_BIND_SPU = new ErrorCode(1008001005, "类别下存在商品,无法删除");
// ========== 商品品牌相关编号 1008002000 ==========
ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1008002000, "品牌不存在");
- ErrorCode BRAND_DISABLED = new ErrorCode(1008002001, "品牌不存在");
+ ErrorCode BRAND_DISABLED = new ErrorCode(1008002001, "品牌已禁用");
ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1008002002, "品牌名称已存在");
// ========== 商品属性项 1008003000 ==========
@@ -32,8 +33,9 @@ public interface ErrorCodeConstants {
// ========== 商品 SPU 1008005000 ==========
ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");
- ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1008005001, "商品分类不正确,原因:必须使用第三级的商品分类下");
+ ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1008005001, "商品分类不正确,原因:必须使用第二级的商品分类及以下");
ErrorCode SPU_NOT_ENABLE = new ErrorCode(1008005002, "商品 SPU 不处于上架状态");
+ ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1008005003, "商品 SPU 不处于回收站状态");
// ========== 商品 SKU 1008006000 ==========
ErrorCode SKU_NOT_EXISTS = new ErrorCode(1008006000, "商品 SKU 不存在");
@@ -42,4 +44,14 @@ public interface ErrorCodeConstants {
ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复");
ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足");
+ // ========== 商品 评价 1008007000 ==========
+ ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品 评价 不存在");
+ ErrorCode ORDER_SPU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在");
+ ErrorCode COMMENT_ERROR_OPT = new ErrorCode(1008007002, "商品评价非法操作");
+ ErrorCode COMMENT_ADDITIONAL_EXISTS = new ErrorCode(1008007003, "商品追加评价已存在");
+
+ // ========== 商品 收藏 1008008000 ==========
+ ErrorCode FAVORITE_EXISTS = new ErrorCode(1008008000, "该商品已经被收藏");
+ ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1008008001, "商品收藏不存在");
+
}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java
new file mode 100644
index 0000000000..f3570c5896
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.product.enums;
+
+/**
+ * Product 常量
+ *
+ * @author HUIHUI
+ */
+public interface ProductConstants {
+
+ /**
+ * 警戒库存 TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换
+ */
+ int ALERT_STOCK = 10;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java
new file mode 100644
index 0000000000..a114e1ab8b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.product.enums.comment;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 商品评论的星级枚举
+ *
+ * @author wangzhs
+ */
+@Getter
+@AllArgsConstructor
+public enum ProductCommentScoresEnum implements IntArrayValuable {
+
+ ONE(1, "1星"),
+ TWO(2, "2星"),
+ THREE(3, "3星"),
+ FOUR(4, "4星"),
+ FIVE(5, "5星");
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentScoresEnum::getScores).toArray();
+
+ /**
+ * 星级
+ */
+ private final Integer scores;
+
+ /**
+ * 星级名
+ */
+ private final String name;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuSpecTypeEnum.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuSpecTypeEnum.java
deleted file mode 100644
index fbc227b530..0000000000
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuSpecTypeEnum.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cn.iocoder.yudao.module.product.enums.spu;
-
-import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * 商品 SPU 规格类型
- *
- * @author 芋道源码
- */
-@Getter
-@AllArgsConstructor
-public enum ProductSpuSpecTypeEnum implements IntArrayValuable {
-
- RECYCLE(1, "统一规格"),
- DISABLE(2, "多规格");
-
- public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuSpecTypeEnum::getType).toArray();
-
- /**
- * 规格类型
- */
- private final Integer type;
- /**
- * 规格名称
- */
- private final String name;
-
- @Override
- public int[] array() {
- return ARRAYS;
- }
-
-}
diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java
index 2223cf23d5..4ba6124e00 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java
@@ -17,7 +17,7 @@ public enum ProductSpuStatusEnum implements IntArrayValuable {
RECYCLE(-1, "回收站"),
DISABLE(0, "下架"),
- ENABLE(1, "上架"),;
+ ENABLE(1, "上架");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStatus).toArray();
diff --git a/yudao-module-mall/yudao-module-product-biz/pom.xml b/yudao-module-mall/yudao-module-product-biz/pom.xml
index e89ed105e7..674f49fc4b 100644
--- a/yudao-module-mall/yudao-module-product-biz/pom.xml
+++ b/yudao-module-mall/yudao-module-product-biz/pom.xml
@@ -23,12 +23,27 @@
> {
+
+ private static final String COMMA = ",";
+
+ @Override
+ public void setParameter(PreparedStatement ps, int i, List