2 Commits

Author SHA1 Message Date
xiafang
2bd091e268 init 2.0.0 2023-06-27 14:01:26 +08:00
xiafang
1ba456f5dd - 电商二级商户进件补充最终受益人列表 2023-06-27 14:00:52 +08:00
35 changed files with 396 additions and 536 deletions

View File

@@ -45,7 +45,7 @@ Starter支持微信优惠券代金券、商家券、智慧商圈、商家
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
</dependency>
```
@@ -55,47 +55,24 @@ Starter支持微信优惠券代金券、商家券、智慧商圈、商家
## 文档地址
- ~~[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot) (暂时不可用)~~
- [payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
## API清单
目前已经实现绝大部分微信支付直连商户和服务商的接口具体的API明细可查看[API清单(暂时不可用)](https://dromara.github.io/payment-spring-boot/#/wechat_v3_api)
目前已经实现绝大部分微信支付直连商户和服务商的接口具体的API明细可查看[API清单](https://dromara.github.io/payment-spring-boot/#/wechat_v3_api)
> 随着版本迭代功能会增加也可通过API注册表类`WechatPayV3Type`进行API接口检索。
## CHANGELOG
~~更新日志[CHANGELOG](https://dromara.github.io/payment-spring-boot/#/changelog) (暂时不可用)~~
更新日志[CHANGELOG](https://dromara.github.io/payment-spring-boot/#/changelog)
## 使用入门
### 集成配置
~~关于集成配置请详细阅读[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
中[快速接入](https://dromara.github.io/payment-spring-boot/#/quick_start)章节 (暂时不可用)~~
关于集成配置请详细阅读[payment-spring-boot GitHub文档](https://dromara.github.io/payment-spring-boot)
中[快速接入](https://dromara.github.io/payment-spring-boot/#/quick_start)章节
[关于微信支付公钥](https://pay.weixin.qq.com/doc/v3/merchant/4012153196)
微信官方推出了微信支付公钥产品以替代原来的微信平台证书,我们对此进行了适配
相关配置如下
```yaml
wechat:
pay:
v3:
# 租户id
<tentantId>:
# 是否使用微信支付公钥验签 默认false
enable-wechat-pay-public: true
# 微信支付公钥id
wechat-pay-public-key-id: PUB_KEY_ID_1111213
# 微信支付公钥路径
wechat-pay-public-key-path: 'pub_key.pem'
wechat-pay-public-key-absolute-path: ''
# 是否启用签名验签方法切换 默认false
switch-verify-sign-method: true
```
- 对于旧版本商户,若不使用微信支付公钥,则不需要配置上述对应参数,则默认使用微信平台证书验签。
- 对于新进件的商户,微信官方默认启用支付公钥,需要配置上述参数。其中 `switch-verify-sign-method` 参数不需要配置
- 若旧版版商户使用微信支付公钥,则需要配置上述参数,并启用 `switch-verify-sign-method : true` [原理参考](https://pay.weixin.qq.com/doc/v3/merchant/4012154180)。<font color=red>当完成从平台证书切换到微信支付公钥后,请务必将`switch-verify-sign-method`参数设置为false 或删除该字段</font>
### 调用示例
#### 开启支付

View File

@@ -35,7 +35,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
</dependency>
```
## 采用技术
@@ -51,4 +51,4 @@
## **免责声明**
**<span style="color:red;">本项目涉及到资金交易开发,开发者需要经严格测试后方能用于生产环境,本项目不对使用者的行为负责。</span>**
**<span style="color:red;">本项目涉及到资金交易开发,开发者需要经严格测试后方能用于生产环境,本项目不对使用者的行为负责。</span>**

View File

@@ -1,14 +1,3 @@
## 1.0.21.RELEASE
### 微信支付
- enhance: 增加了通过微信公钥对微信支付相关接口的响应内容或微信回调通知的参数进行验签的支持。
- 微信配置项增加了:```enable-wechat-pay-public: 是否启用微信支付公钥验签、 wechat-pay-public-key-id: 微信支付公钥的ID、 wechat-pay-public-key-path微信支付公钥的路径、wechat-pay-public-key-absolute-path: 微信支付公钥的绝对路径、 switch-verify-sign-method: 是否启用从平台证书切换到微信支公钥```
- `enable-wechat-pay-public``wechat-pay-public-key-id ``wechat-pay-public-key-path或wechat-pay-public-key-absolute-path`<font color=red>同时正确配置</font>,才会启用微信支付公钥验签,否则默认使用平台证书进行验签。
-
- 如果需要[从平台证书切换成微信支付公钥](https://pay.weixin.qq.com/doc/v3/merchant/4012154180#5.-%E6%B2%A1%E6%9C%89%E4%BD%BF%E7%94%A8%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98SDK%E7%9A%84%E5%95%86%E6%88%B7%E5%A6%82%E4%BD%95%E5%B0%86%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6%E5%88%87%E6%8D%A2%E6%88%90%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E5%85%AC%E9%92%A5),请启用`switch-verify-sign-method`参数
- enhance: 增加了微信支付V3版本的付款码支付``codePay``与撤销API``reverse``(仅支持普通商户模式,服务商模式暂不支持)
- factor: 升级了spring-boot-parent版本从 2.7.7 到2.7.18
- factor: 升级了Alipay SDK版本从4.31.7.ALL到4.40.251.ALL
## 1.0.18.RELEASE
### 微信支付

View File

@@ -4,7 +4,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
</dependency>
```
> 基于 **Spring Boot 2.x**
@@ -15,7 +15,7 @@
```xml
<properties>
<!-- 修改为你对应的Spring Boot版本号 -->
<spring-boot.version>2.7.18</spring-boot.version>
<spring-boot.version>2.4.0</spring-boot.version>
</properties>
```
然后安装使用
@@ -86,15 +86,6 @@ wechat:
mch-id: 1603337223
domain: https://felord.cn/miniapp
cert-path: miniapp/apiclient_cert.p12
# 是否启用微信支付公钥
enable-wechat-pay-public: true
#微信公钥ID
wechat-pay-public-key-id: PUB_KEY_ID_0116278111111115222222501
#微信公钥
wechat-pay-public-key-path: pub_key.pem
wechat-pay-public-key-absolute-path: D:\\felord\\wechat\\cert\\pub_key.pem
#是否启用从平台证书切换成微信支付公钥 不填默认为false
switch-verify-sign-method: true
```
> ❗注意:在一套系统中需要开发者保证`tentanID`唯一。
@@ -183,4 +174,4 @@ public class PayConfig {
System.out.println("execute = " + execute.getBody());
}
```
```

View File

@@ -22,11 +22,11 @@
<parent>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
</parent>
<artifactId>payment-spring-boot-autoconfigure</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -64,6 +64,42 @@
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava3</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jaxb</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
@@ -92,4 +128,4 @@
</plugin>
</plugins>
</build>
</project>
</project>

View File

@@ -17,23 +17,15 @@
package cn.felord.payment.wechat;
import cn.felord.payment.PayException;
import cn.felord.payment.wechat.v3.*;
import cn.felord.payment.wechat.v3.KeyPairFactory;
import cn.felord.payment.wechat.v3.WechatMetaBean;
import lombok.AllArgsConstructor;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -70,7 +62,6 @@ public class InMemoryWechatTenantService implements WechatTenantService {
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(resource, mchId);
wechatMetaBean.setV3(v3);
wechatMetaBean.setTenantId(tenantId);
SignatureProvider.addWeChatPublicKey(initWeChatPublicKeyInfo(wechatMetaBean));
return wechatMetaBean;
})
.collect(Collectors.toSet());
@@ -78,29 +69,4 @@ public class InMemoryWechatTenantService implements WechatTenantService {
}
return cache;
}
private WeChatPublicKeyInfo initWeChatPublicKeyInfo(WechatMetaBean meta) {
boolean enablePublicKey=StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyId()) &&
(StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyPath())||StringUtils.hasLength(meta.getV3().getWechatPayPublicKeyAbsolutePath()));
if (!enablePublicKey) {
return null;
}
try {
String certPath=meta.getV3().getWechatPayPublicKeyPath();
String certAbsolutePath = meta.getV3().getWechatPayPublicKeyAbsolutePath();
Resource resource =
StringUtils.hasLength(certAbsolutePath) ? new FileSystemResource(certAbsolutePath) :
resourceLoader.getResource(!StringUtils.hasLength(certPath) ? "classpath:wechat/pub_key.pem" :
certPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) ? certPath : ResourceUtils.CLASSPATH_URL_PREFIX + certPath);
PemReader pemReader = new PemReader(new InputStreamReader(resource.getInputStream()));
PemObject pemObject = pemReader.readPemObject();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pemObject.getContent());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
// 生成公钥
return new WeChatPublicKeyInfo(publicKey, meta.getV3().getWechatPayPublicKeyId(), meta.getTenantId());
}catch (Exception e){
throw new PayException("An error occurred while generating the public key,Please check the format and content of the configured public key");
}
}
}

View File

@@ -76,31 +76,5 @@ public class WechatPayProperties {
* your pay server domain
*/
private String domain;
private Boolean enableWechatPayPublic=false;
/**
* wechat pay public key id
*/
private String wechatPayPublicKeyId;
/**
* see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012154180#4.1-%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E5%85%AC%E9%92%A5">
* </a>
* wechat pay public key
*/
private String wechatPayPublicKeyPath;
private String wechatPayPublicKeyAbsolutePath;
/**
*
* see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012154180">
* Indicate whether to switch from the platform certificate to the WeChat Pay public key
* </a>
*/
private Boolean switchVerifySignMethod = false;
}
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* The enum Business cert type.
*
* @author dax
* @since 2023 /7/1 8:34
*/
public enum BusinessCertType {
/**
* 事业单位法人证书
*/
CERTIFICATE_TYPE_2388,
/**
* 统一社会信用代码证书
*/
CERTIFICATE_TYPE_2389,
/**
* 社会团体法人登记证书
*/
CERTIFICATE_TYPE_2394,
/**
* 民办非企业单位登记证书
*/
CERTIFICATE_TYPE_2395,
/**
* 基金会法人登记证书
*/
CERTIFICATE_TYPE_2396,
/**
* 宗教活动场所登记证
*/
CERTIFICATE_TYPE_2399,
/**
* 政府部门下发的其他有效证明文件
*/
CERTIFICATE_TYPE_2400,
/**
* 执业许可证/执业证
*/
CERTIFICATE_TYPE_2520,
/**
* 基层群众性自治组织特别法人统一社会信用代码证
*/
CERTIFICATE_TYPE_2521,
/**
* 农村集体经济组织登记证
*/
CERTIFICATE_TYPE_2522
}

View File

@@ -66,13 +66,6 @@ public enum WechatPayV3Type {
MERCHANT_MEDIA_VIDEO(HttpMethod.POST, "%s/v3/merchant/media/video_upload"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 付款码支付
*
* @since 1.0.0.RELEASE
*/
CODE(HttpMethod.POST, "%s/v3/pay/transactions/codepay"),
/**
* 微信公众号支付或者小程序支付.
*
@@ -106,13 +99,6 @@ public enum WechatPayV3Type {
* @since 1.0.0.RELEASE
*/
CLOSE(HttpMethod.POST, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}/close"),
/**
* 关闭订单.
*
* @since 1.0.0.RELEASE
*/
REVERSE(HttpMethod.POST, "%s/v3/pay/transactions/out-trade-no/{out_trade_no}/reverse"),
/**
* 微信支付订单号查询API.
*
@@ -647,7 +633,6 @@ public enum WechatPayV3Type {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 服务商APP下单API.
*
@@ -719,7 +704,7 @@ public enum WechatPayV3Type {
*
* @since 1.0.11.RELEASE
*/
PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/profitsharing/return-orders/{out_return_no}"),
PROFITSHARING_RETURN_ORDERS_RESULT(HttpMethod.GET, "%s/v3/profitsharing/return-orders"),
/**
* 解冻剩余资金API.
*

View File

@@ -73,7 +73,7 @@ import java.util.stream.Collectors;
*/
@Getter
public abstract class BaseModel {
public static final String HMAC_SHA256="HMAC-SHA256";
public static final String HMAC_SHA256 = "HMAC-SHA256";
private static final XmlMapper XML_MAPPER = new XmlMapper();
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@@ -84,8 +84,7 @@ public abstract class BaseModel {
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
OBJECT_MAPPER
// .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
@@ -165,7 +164,7 @@ public abstract class BaseModel {
@SneakyThrows
private String hmacSha256(String src) {
String algorithm = "HmacSHA256";
Mac sha256HMAC = Mac.getInstance(algorithm,"BC");
Mac sha256HMAC = Mac.getInstance(algorithm, "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(), algorithm);
sha256HMAC.init(secretKeySpec);
byte[] bytes = sha256HMAC.doFinal(src.getBytes(StandardCharsets.UTF_8));
@@ -182,7 +181,7 @@ public abstract class BaseModel {
@SneakyThrows
private <T> String link(T t) {
Assert.hasText(appSecret, "wechat pay appSecret is required");
String json = OBJECT_MAPPER
String json = OBJECT_MAPPER
.writeValueAsString(t);
TreeMap<String, String> map = OBJECT_MAPPER.readValue(json, new TypeReference<TreeMap<String, String>>() {
@@ -200,8 +199,8 @@ public abstract class BaseModel {
public JsonNode request(String mchId, HttpMethod method, String url) {
String xml = this.xml();
RequestEntity<String> body = RequestEntity.method(method, UriComponentsBuilder.fromHttpUrl(url)
.build()
.toUri())
.build()
.toUri())
.contentType(MediaType.valueOf("application/x-www-form-urlencoded;charset=UTF-8"))
.body(xml);
ResponseEntity<String> responseEntity = this.getRestTemplateClientAuthentication(mchId)

View File

@@ -31,9 +31,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
@@ -47,8 +44,6 @@ import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Optional;
@@ -97,16 +92,12 @@ public abstract class AbstractApi {
* @param mapper the mapper
*/
private void applyObjectMapper(ObjectMapper mapper) {
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// empty string error
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(javaTimeModule);
.registerModule(new JavaTimeModule());
}

View File

@@ -27,15 +27,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.util.*;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import org.springframework.util.IdGenerator;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
@@ -46,16 +44,12 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
@@ -91,11 +85,6 @@ public class SignatureProvider {
* 微信平台证书容器 key = 序列号 value = 证书对象
*/
private static final Set<X509WechatCertificateInfo> CERTIFICATE_SET = Collections.synchronizedSet(new HashSet<>());
private static final Set<WeChatPublicKeyInfo> PUBLIC_KEY_SET = Collections.synchronizedSet(new HashSet<>());
private static final String PUBLIC_KYE_ID_PREFIX = "PUB_KEY_ID";
/**
* 加密算法提供方 - BouncyCastle
*/
@@ -128,10 +117,6 @@ public class SignatureProvider {
wechatMetaContainer.getTenantIds().forEach(this::refreshCertificate);
}
public static void addWeChatPublicKey(WeChatPublicKeyInfo weChatPublicKeyInfo) {
PUBLIC_KEY_SET.add(weChatPublicKeyInfo);
}
/**
* 我方请求前用 SHA256withRSA 加签使用API证书.
@@ -186,19 +171,7 @@ public class SignatureProvider {
* @return the boolean
*/
public boolean responseSignVerify(ResponseSignVerifyParams params) {
log.debug("wechatpaySerial: {}", params.getWechatpaySerial());
boolean verifyResult= params.getWechatpaySerial().startsWith(PUBLIC_KYE_ID_PREFIX)?
responseSignVerifyWithWeChatPublicKeyInfo(params):
responseSignVerifyWithX509WechatCertificate(params);
log.debug("responseSignVerify: {}", verifyResult);
return verifyResult;
}
/***
*通过平台证书进行验签
*/
private boolean responseSignVerifyWithX509WechatCertificate(ResponseSignVerifyParams params){
log.debug("responseSignVerifyWithX509WechatCertificate: {}", params);
String wechatpaySerial = params.getWechatpaySerial();
X509WechatCertificateInfo certificate = CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(wechatpaySerial, cert.getWechatPaySerial()))
@@ -211,41 +184,17 @@ public class SignatureProvider {
.orElseThrow(() -> new PayException("cannot obtain the certificate"));
});
try {
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(certificate.getX509Certificate());
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
} catch (Exception e) {
throw new PayException("An exception occurred during the response verification, the cause: " + e.getMessage());
}
try {
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(certificate.getX509Certificate());
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
}catch (Exception e){
throw new PayException("An exception occurred during the response verification, the cause: "+e.getMessage());
}
}
/***
*通过微信支付公钥进行验签
*/
private boolean responseSignVerifyWithWeChatPublicKeyInfo(ResponseSignVerifyParams params){
log.debug("responseSignVerifyWithWeChatPublicKeyInfo: {}", params);
String wechatpaySerial = params.getWechatpaySerial();
if (wechatpaySerial.startsWith(PUBLIC_KYE_ID_PREFIX)){
WeChatPublicKeyInfo info = PUBLIC_KEY_SET.stream()
.filter(key -> Objects.equals(wechatpaySerial, key.getPublicKeyId()))
.findAny()
.orElseThrow(() -> new PayException("cannot obtain the public key"));
try {
final String signatureStr = createSign(params.getWechatpayTimestamp(), params.getWechatpayNonce(), params.getBody());
Signature signer = Signature.getInstance("SHA256withRSA", BC_PROVIDER);
signer.initVerify(info.getPublicKey());
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return signer.verify(Base64Utils.decodeFromString(params.getWechatpaySignature()));
} catch (Exception e) {
throw new PayException("An exception occurred during the response verification, the cause: " + e.getMessage());
}
}
return false;
}
/**
* 当我方服务器不存在平台证书或者证书同当前响应报文中的证书序列号不一致时应当刷新 调用/v3/certificates
@@ -254,12 +203,8 @@ public class SignatureProvider {
*/
@SneakyThrows
private synchronized void refreshCertificate(String tenantId) {
WechatMetaBean wechatMetaBean = wechatMetaContainer.getWechatMeta(tenantId);
if (wechatMetaBean.getV3().getEnableWechatPayPublic() && !wechatMetaBean.getV3().getSwitchVerifySignMethod()){
return;
}
String url = WechatPayV3Type.CERT.uri(WeChatServer.CHINA);
UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).build();
String canonicalUrl = uri.getPath();
@@ -285,9 +230,12 @@ public class SignatureProvider {
throw new PayException("cant obtain the response body");
}
ArrayNode certificates = bodyObjectNode.withArray("data");
if (certificates.isArray() && !certificates.isEmpty()) {
CERTIFICATE_SET.removeIf(x509WechatCertificateInfo ->
Objects.equals(tenantId, x509WechatCertificateInfo.getTenantId()));
if (certificates.isArray() && certificates.size() > 0) {
CERTIFICATE_SET.forEach(x509WechatCertificateInfo -> {
if (Objects.equals(tenantId, x509WechatCertificateInfo.getTenantId())) {
CERTIFICATE_SET.remove(x509WechatCertificateInfo);
}
});
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", BC_PROVIDER);
certificates.forEach(objectNode -> {
JsonNode encryptCertificate = objectNode.get("encrypt_certificate");
@@ -354,42 +302,18 @@ public class SignatureProvider {
}
}
public String encryptRequestMessage(String message, WechatMetaBean wechatMetaBean) {
PublicKey publicKey;
if (wechatMetaBean.getEnableWechatPayPublicEncrypt()){
WeChatPublicKeyInfo info=this.getWechatPublicKeyInfo(wechatMetaBean.getTenantId());
publicKey=info.getPublicKey();
}else {
X509WechatCertificateInfo certificate = getCertificate(wechatMetaBean.getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
publicKey=x509Certificate.getPublicKey();
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] cipherData = cipher.doFinal(data);
return Base64Utils.encodeToString(cipherData);
} catch (Exception e) {
throw new PayException(e);
}
}
/**
* 对请求敏感字段进行加密
* 只有使用平台证书进行验签与签名的商户使用该方法
*
* @param message the message
* @param publicKey the wechatPubicKey certificate
* @param certificate the certificate
* @return encrypt message
* @since 1.0.6.RELEASE
*/
@Deprecated
public String encryptRequestMessage(String message, RSAPublicKey publicKey) {
public String encryptRequestMessage(String message, Certificate certificate) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", BC_PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] cipherData = cipher.doFinal(data);
@@ -429,7 +353,7 @@ public class SignatureProvider {
* @param tenantId the tenant id
* @return the x 509 wechat certificate info
*/
private X509WechatCertificateInfo getCertificate(String tenantId) {
public X509WechatCertificateInfo getCertificate(String tenantId) {
return CERTIFICATE_SET.stream()
.filter(cert -> Objects.equals(tenantId, cert.getTenantId()))
@@ -443,15 +367,6 @@ public class SignatureProvider {
});
}
private WeChatPublicKeyInfo getWechatPublicKeyInfo(String tenantId) {
return PUBLIC_KEY_SET.stream()
.filter(publicKeyInfo -> Objects.equals(tenantId, publicKeyInfo.getTenantId()))
.findAny()
.orElseThrow(
() -> new PayException("cannot obtain the public key")
);
}
/**
* Wechat meta container.
@@ -483,21 +398,4 @@ public class SignatureProvider {
.collect(Collectors.joining("\n", "", "\n"));
}
public boolean isSwitchVerifySignMethod(String tenantId) {
return wechatMetaContainer.getWechatMeta(tenantId).getV3().getSwitchVerifySignMethod()
&& wechatMetaContainer.getWechatMeta(tenantId).getV3().getEnableWechatPayPublic();
}
public String getWechatPublicKeyId(String tenantId) {
return wechatMetaContainer.getWechatMeta(tenantId).getV3().getWechatPayPublicKeyId();
}
public String getWechatPaySerial(WechatMetaBean wechatMetaBean) {
if (wechatMetaBean.getEnableWechatPayPublicEncrypt()){
return this.getWechatPublicKeyInfo(wechatMetaBean.getTenantId()).getPublicKeyId();
}else {
return this.getCertificate(wechatMetaBean.getTenantId()).getWechatPaySerial();
}
}
}

View File

@@ -1,24 +0,0 @@
package cn.felord.payment.wechat.v3;
import lombok.Data;
import java.security.interfaces.RSAPublicKey;
@Data
public class WeChatPublicKeyInfo {
private RSAPublicKey publicKey;
private String publicKeyId;
private String tenantId;
public WeChatPublicKeyInfo(RSAPublicKey publicKey, String publicKeyId, String tenantId) {
this.publicKeyId = publicKeyId;
this.tenantId = tenantId;
this.publicKey = publicKey;
}
public WeChatPublicKeyInfo() {
}
}

View File

@@ -77,16 +77,18 @@ public class WechatBatchTransferApi extends AbstractApi {
List<CreateBatchTransferParams.TransferDetailListItem> transferDetailList = createBatchTransferParams.getTransferDetailList();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
List<CreateBatchTransferParams.TransferDetailListItem> encrypted = transferDetailList.stream()
.peek(transferDetailListItem -> {
String userName = transferDetailListItem.getUserName();
if (StringUtils.hasText(userName)) {
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, this.wechatMetaBean());
String encryptedUserName = signatureProvider.encryptRequestMessage(userName, x509Certificate);
transferDetailListItem.setUserName(encryptedUserName);
}
String userIdCard = transferDetailListItem.getUserIdCard();
if (StringUtils.hasText(userIdCard)) {
String encryptedUserIdCard = signatureProvider.encryptRequestMessage(userIdCard, this.wechatMetaBean());
String encryptedUserIdCard = signatureProvider.encryptRequestMessage(userIdCard, x509Certificate);
transferDetailListItem.setUserIdCard(encryptedUserIdCard);
}
}).collect(Collectors.toList());
@@ -96,7 +98,7 @@ public class WechatBatchTransferApi extends AbstractApi {
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, createBatchTransferParams, httpHeaders);
}

View File

@@ -56,8 +56,11 @@ public class WechatCapitalApi extends AbstractApi{
this.client().withType(WechatPayV3Type.CAPITAL_SEARCH, accountNumber)
.function((type, param) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.queryParam("account_number", signatureProvider.encryptRequestMessage(param,this.wechatMetaBean()))
.queryParam("account_number", signatureProvider.encryptRequestMessage(param,x509Certificate))
.build()
.toUri();
return Get(uri);

View File

@@ -57,34 +57,11 @@ public class WechatDirectPayApi extends AbstractApi {
}
/**
* 付款码支付API
* APP下单API
*
* @param payParams the pay params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> codePay(PayParams payParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.CODE, payParams)
.function(this::payFunction)
.consumer(responseEntity -> {
ObjectNode body = responseEntity.getBody();
if (Objects.isNull(body)) {
throw new PayException("response body cannot be resolved");
}
wechatResponseEntity.setHttpStatus(responseEntity.getStatusCodeValue());
wechatResponseEntity.setBody(body);
})
.request();
return wechatResponseEntity;
}
/**
* APP下单API
*
* @param payParams the pay params
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> appPay(PayParams payParams) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.APP, payParams)
@@ -208,10 +185,8 @@ public class WechatDirectPayApi extends AbstractApi {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
payParams.setAppid(v3.getAppId());
payParams.setMchid(v3.getMchId());
if (!type.equals(WechatPayV3Type.CODE)){
String notifyUrl = v3.getDomain().concat(payParams.getNotifyUrl());
payParams.setNotifyUrl(notifyUrl);
}
String notifyUrl = v3.getDomain().concat(payParams.getNotifyUrl());
payParams.setNotifyUrl(notifyUrl);
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.toUri();
@@ -277,21 +252,6 @@ public class WechatDirectPayApi extends AbstractApi {
return wechatResponseEntity;
}
/**
* 撤销API
*
* @param outTradeNo the out trade no
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> reverse(String outTradeNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.REVERSE, outTradeNo)
.function(this::reverseOutTradeNoFunction)
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
private RequestEntity<?> closeByOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
@@ -305,20 +265,6 @@ public class WechatDirectPayApi extends AbstractApi {
return Post(uri, queryParams);
}
private RequestEntity<?> reverseOutTradeNoFunction(WechatPayV3Type type, String outTradeNo) {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
Map<String, String> queryParams = new HashMap<>(1);
queryParams.put("mchid", v3.getMchId());
queryParams.put("appid", v3.getAppId());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(outTradeNo)
.toUri();
return Post(uri, queryParams);
}
/**
* 申请退款API
*

View File

@@ -158,9 +158,7 @@ public class WechatMarketingFavorApi extends AbstractApi {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setAppid(v3.getAppId());
if (StringUtils.hasText(params.getStockCreatorMchid())){
params.setStockCreatorMchid(v3.getMchId());
}
params.setStockCreatorMchid(v3.getMchId());
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(params.getOpenid())

View File

@@ -46,9 +46,5 @@ public class WechatMetaBean {
* The V3.
*/
private WechatPayProperties.V3 v3;
public Boolean getEnableWechatPayPublicEncrypt() {
return v3.getEnableWechatPayPublic();
}
}

View File

@@ -79,6 +79,8 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
List<Receiver> receivers = params.getReceivers();
if (!CollectionUtils.isEmpty(receivers)) {
@@ -86,7 +88,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.peek(receiversItem -> {
String name = receiversItem.getName();
if (StringUtils.hasText(name)) {
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
receiversItem.setName(encryptedName);
}
}).collect(Collectors.toList());
@@ -96,7 +98,7 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -292,17 +294,19 @@ public class WechatPartnerProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
if (ReceiverType.MERCHANT_ID.equals(params.getType())) {
String encryptedName = signatureProvider.encryptRequestMessage(params.getName(), this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(params.getName(), x509Certificate);
params.setName(encryptedName);
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)

View File

@@ -63,12 +63,14 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
this.client().withType(WechatPayV3Type.SPEC_MCH_APPLY_PARTNER, params)
.function((wechatPayV3Type, applymentParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
ApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider);
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
ApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, applyRequestParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -131,15 +133,17 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
this.client().withType(WechatPayV3Type.SPEC_MCH_SUB_MODIFY, params)
.function((type, subMchModifyParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
URI uri = UriComponentsBuilder.fromHttpUrl(type.uri(WeChatServer.CHINA))
.build()
.expand(subMchModifyParams.getSubMchid())
.toUri();
subMchModifyParams.setSubMchid(null);
subMchModifyParams.setAccountNumber(signatureProvider.encryptRequestMessage(subMchModifyParams.getAccountNumber(), this.wechatMetaBean()));
subMchModifyParams.setAccountNumber(signatureProvider.encryptRequestMessage(subMchModifyParams.getAccountNumber(), x509Certificate));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, subMchModifyParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -171,55 +175,55 @@ public class WechatPartnerSpecialMchApi extends AbstractApi {
return wechatResponseEntity;
}
private ApplymentParams convert(ApplymentParams applymentParams, SignatureProvider signatureProvider) {
private ApplymentParams convert(ApplymentParams applymentParams, SignatureProvider signatureProvider, final X509Certificate x509Certificate) {
ContactInfo contactInfo = applymentParams.getContactInfo();
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), this.wechatMetaBean()));
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
String contactIdNumber = contactInfo.getContactIdNumber();
if (contactIdNumber != null) {
contactInfo.setContactIdNumber(signatureProvider.encryptRequestMessage(contactIdNumber,this.wechatMetaBean()));
contactInfo.setContactIdNumber(signatureProvider.encryptRequestMessage(contactIdNumber, x509Certificate));
}
String openid = contactInfo.getOpenid();
if (openid != null) {
contactInfo.setOpenid(signatureProvider.encryptRequestMessage(openid,this.wechatMetaBean()));
contactInfo.setOpenid(signatureProvider.encryptRequestMessage(openid, x509Certificate));
}
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), this.wechatMetaBean()));
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactInfo.getContactEmail(), this.wechatMetaBean()));
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), x509Certificate));
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactInfo.getContactEmail(), x509Certificate));
SubjectInfo subjectInfo = applymentParams.getSubjectInfo();
IdentityInfo identityInfo = subjectInfo.getIdentityInfo();
IdCardInfo idCardInfo = identityInfo.getIdCardInfo();
if (idCardInfo != null) {
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), this.wechatMetaBean()));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), this.wechatMetaBean()));
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
String idCardAddress = idCardInfo.getIdCardAddress();
if (StringUtils.hasText(idCardAddress)){
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress,this.wechatMetaBean()));
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
}
}
IdDocInfo idDocInfo = identityInfo.getIdDocInfo();
if (idDocInfo != null) {
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), this.wechatMetaBean()));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), this.wechatMetaBean()));
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
String idDocAddress = idDocInfo.getIdDocAddress();
if (StringUtils.hasText(idDocAddress)){
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress,this.wechatMetaBean()));
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
}
}
List<UboInfoListItem> uboInfoList = subjectInfo.getUboInfoList();
if (!CollectionUtils.isEmpty(uboInfoList)) {
uboInfoList.forEach(uboInfoListItem -> {
uboInfoListItem.setUboIdDocName(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocName(), this.wechatMetaBean()));
uboInfoListItem.setUboIdDocNumber(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocNumber(), this.wechatMetaBean()));
uboInfoListItem.setUboIdDocAddress(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocAddress(), this.wechatMetaBean()));
uboInfoListItem.setUboIdDocName(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocName(), x509Certificate));
uboInfoListItem.setUboIdDocNumber(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocNumber(), x509Certificate));
uboInfoListItem.setUboIdDocAddress(signatureProvider.encryptRequestMessage(uboInfoListItem.getUboIdDocAddress(), x509Certificate));
});
}
BankAccountInfo bankAccountInfo = applymentParams.getBankAccountInfo();
bankAccountInfo.setAccountName(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountName(), this.wechatMetaBean()));
bankAccountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountNumber(), this.wechatMetaBean()));
bankAccountInfo.setAccountName(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountName(), x509Certificate));
bankAccountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(bankAccountInfo.getAccountNumber(), x509Certificate));
return applymentParams;
}

View File

@@ -232,11 +232,6 @@ public class WechatPayClient {
// 避免出现因为中文导致的 HttpRetryException
httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
}
if (signatureProvider.isSwitchVerifySignMethod(tenantId)){
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPublicKeyId(tenantId));
}
httpHeaders.add("Authorization", authorization);
httpHeaders.add("User-Agent", "X-Pay-Service");
httpHeaders.remove("Meta-Info");

View File

@@ -76,7 +76,6 @@ public class WechatPayScoreParkingApi extends AbstractApi {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.encode()
.build()
.toUri();
return Get(uri);

View File

@@ -77,6 +77,8 @@ public class WechatProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
List<Receiver> receivers = params.getReceivers();
if (!CollectionUtils.isEmpty(receivers)) {
@@ -84,7 +86,7 @@ public class WechatProfitsharingApi extends AbstractApi {
.peek(receiversItem -> {
String name = receiversItem.getName();
if (StringUtils.hasText(name)) {
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
receiversItem.setName(encryptedName);
}
}).collect(Collectors.toList());
@@ -94,7 +96,7 @@ public class WechatProfitsharingApi extends AbstractApi {
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -261,17 +263,19 @@ public class WechatProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
String name = params.getName();
if (StringUtils.hasText(name)) {
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
params.setName(encryptedName);
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)

View File

@@ -65,13 +65,15 @@ public class WechatSmartGuideApi extends AbstractApi {
this.client().withType(WechatPayV3Type.SMART_GUIDES, params)
.function((wechatPayV3Type, smartGuidesParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), this.wechatMetaBean()));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), this.wechatMetaBean()));
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, smartGuidesParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -135,8 +137,10 @@ public class WechatSmartGuideApi extends AbstractApi {
String mobile = smartGuidesQueryParams.getMobile();
if (mobile != null) {
SignatureProvider signatureProvider = this.client().signatureProvider();
queryParams.add("mobile", signatureProvider.encryptRequestMessage(mobile,this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
queryParams.add("mobile", signatureProvider.encryptRequestMessage(mobile, x509Certificate));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
}
String workId = smartGuidesQueryParams.getWorkId();
if (workId != null) {
@@ -173,13 +177,15 @@ public class WechatSmartGuideApi extends AbstractApi {
this.client().withType(WechatPayV3Type.SMART_GUIDES_MODIFY, params)
.function((wechatPayV3Type, smartGuidesParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), this.wechatMetaBean()));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), this.wechatMetaBean()));
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
smartGuidesParams.setName(signatureProvider.encryptRequestMessage(smartGuidesParams.getName(), x509Certificate));
smartGuidesParams.setMobile(signatureProvider.encryptRequestMessage(smartGuidesParams.getMobile(), x509Certificate));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Patch(uri, smartGuidesParams, httpHeaders);
})
.consumer(wechatResponseEntity::convert)

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.client;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.util.concurrent.TimeUnit;
/**
* The type Retrofit factory.
*
* @author dax
* @since 2023 /5/21
*/
public final class RetrofitFactory {
/**
* The constant JACKSON_CONVERTER_FACTORY.
*/
public static final JacksonConverterFactory JACKSON_CONVERTER_FACTORY = JacksonConverterFactoryBuilder.build();
/**
* Create retrofit.
*
* @param baseUrl the base url
* @return the retrofit
*/
public static Retrofit create(String baseUrl) {
return create(baseUrl, new ConnectionPool());
}
/**
* Create retrofit.
*
* @param baseUrl the base url
* @param connectionPool the connection pool
* @return the retrofit
*/
public static Retrofit create(String baseUrl, ConnectionPool connectionPool) {
return create(baseUrl, connectionPool, HttpLoggingInterceptor.Level.NONE);
}
/**
* Create retrofit.
*
* @param baseUrl the base url
* @param connectionPool the connection pool
* @param level the level
* @return the retrofit
*/
public static Retrofit create(String baseUrl, ConnectionPool connectionPool, HttpLoggingInterceptor.Level level) {
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient(connectionPool, level))
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.addConverterFactory(JACKSON_CONVERTER_FACTORY)
.build();
}
private static OkHttpClient okHttpClient(ConnectionPool connectionPool, HttpLoggingInterceptor.Level level) {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.level(level);
return new OkHttpClient.Builder()
.connectionPool(connectionPool)
.addInterceptor(httpLoggingInterceptor)
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
}
/**
* The type Jackson converter factory builder.
*/
static final class JacksonConverterFactoryBuilder {
private JacksonConverterFactoryBuilder() {
}
/**
* Build jackson converter factory.
*
* @return the jackson converter factory
*/
public static JacksonConverterFactory build() {
ObjectMapper objectMapper = new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// empty string error
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(new JavaTimeModule());
return JacksonConverterFactory.create(objectMapper);
}
}
}

View File

@@ -71,10 +71,12 @@ public class ApplymentApi extends AbstractApi {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.ECOMMERCE_APPLYMENT, params).function((wechatPayV3Type, applymentParams) -> {
SignatureProvider signatureProvider = this.client().signatureProvider();
EcommerceApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider);
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
EcommerceApplymentParams applyRequestParams = this.convert(applymentParams, signatureProvider, x509Certificate);
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)).build().toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, applyRequestParams, httpHeaders);
}).consumer(wechatResponseEntity::convert).request();
return wechatResponseEntity;
@@ -136,50 +138,49 @@ public class ApplymentApi extends AbstractApi {
return this.wechatPartnerSpecialMchApi.querySettlement(subMchid);
}
private EcommerceApplymentParams convert(EcommerceApplymentParams applymentParams, SignatureProvider signatureProvider) {
private EcommerceApplymentParams convert(EcommerceApplymentParams applymentParams, SignatureProvider signatureProvider, X509Certificate x509Certificate) {
EcommerceIdCardInfo idCardInfo = applymentParams.getIdCardInfo();
if (idCardInfo != null) {
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), this.wechatMetaBean()));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), this.wechatMetaBean()));
idCardInfo.setIdCardName(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardName(), x509Certificate));
idCardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(idCardInfo.getIdCardNumber(), x509Certificate));
String idCardAddress = idCardInfo.getIdCardAddress();
if (StringUtils.hasText(idCardAddress)) {
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress,this.wechatMetaBean()));
idCardInfo.setIdCardAddress(signatureProvider.encryptRequestMessage(idCardAddress, x509Certificate));
}
}
EcommerceIdDocInfo idDocInfo = applymentParams.getIdDocInfo();
if (idDocInfo != null) {
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), this.wechatMetaBean()));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), this.wechatMetaBean()));
idDocInfo.setIdDocName(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocName(), x509Certificate));
idDocInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(idDocInfo.getIdDocNumber(), x509Certificate));
String idDocAddress = idDocInfo.getIdDocAddress();
if (StringUtils.hasText(idDocAddress)) {
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress,this.wechatMetaBean()));
idDocInfo.setIdDocAddress(signatureProvider.encryptRequestMessage(idDocAddress, x509Certificate));
}
}
UboInfo uboInfo = applymentParams.getUboInfo();
if (uboInfo != null) {
UboInfo.IdCardInfo cardInfo = uboInfo.getIdCardInfo();
if (cardInfo != null) {
cardInfo.setIdCardName(signatureProvider.encryptRequestMessage(cardInfo.getIdCardName(), this.wechatMetaBean()));
cardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(cardInfo.getIdCardNumber(), this.wechatMetaBean()));
cardInfo.setIdCardName(signatureProvider.encryptRequestMessage(cardInfo.getIdCardName(), x509Certificate));
cardInfo.setIdCardNumber(signatureProvider.encryptRequestMessage(cardInfo.getIdCardNumber(), x509Certificate));
}
UboInfo.IdDocInfo docInfo = uboInfo.getIdDocInfo();
if (docInfo != null) {
docInfo.setIdDocName(signatureProvider.encryptRequestMessage(docInfo.getIdDocName(), this.wechatMetaBean()));
docInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(docInfo.getIdDocNumber(), this.wechatMetaBean()));
docInfo.setIdDocName(signatureProvider.encryptRequestMessage(docInfo.getIdDocName(), x509Certificate));
docInfo.setIdDocNumber(signatureProvider.encryptRequestMessage(docInfo.getIdDocNumber(), x509Certificate));
}
}
EcommerceAccountInfo accountInfo = applymentParams.getAccountInfo();
if (accountInfo != null) {
accountInfo.setAccountName(signatureProvider.encryptRequestMessage(accountInfo.getAccountName(), this.wechatMetaBean()));
accountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(accountInfo.getAccountNumber(), this.wechatMetaBean()));
accountInfo.setAccountName(signatureProvider.encryptRequestMessage(accountInfo.getAccountName(), x509Certificate));
accountInfo.setAccountNumber(signatureProvider.encryptRequestMessage(accountInfo.getAccountNumber(), x509Certificate));
}
EcommerceContactInfo contactInfo = applymentParams.getContactInfo();
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), this.wechatMetaBean()));
contactInfo.setContactIdCardNumber(signatureProvider.encryptRequestMessage(contactInfo.getContactIdCardNumber(), this.wechatMetaBean()));
contactInfo.setMobilePhone(signatureProvider.encryptRequestMessage(contactInfo.getMobilePhone(), this.wechatMetaBean()));
contactInfo.setContactName(signatureProvider.encryptRequestMessage(contactInfo.getContactName(), x509Certificate));
contactInfo.setContactIdCardNumber(signatureProvider.encryptRequestMessage(contactInfo.getContactIdCardNumber(), x509Certificate));
String contactEmail = contactInfo.getContactEmail();
if (contactEmail != null) {
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactEmail,this.wechatMetaBean()));
contactInfo.setContactEmail(signatureProvider.encryptRequestMessage(contactEmail, x509Certificate));
}
return applymentParams;
}

View File

@@ -77,13 +77,15 @@ public class ProfitsharingApi extends AbstractApi {
.function((wechatPayV3Type, params) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
params.setAppid(v3.getAppId());
List<Receiver> receivers = params.getReceivers();
if (!CollectionUtils.isEmpty(receivers)) {
receivers.forEach(receiversItem -> {
String name = receiversItem.getReceiverName();
if (StringUtils.hasText(name)) {
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
receiversItem.setReceiverName(encryptedName);
}
});
@@ -92,7 +94,7 @@ public class ProfitsharingApi extends AbstractApi {
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)
@@ -254,17 +256,20 @@ public class ProfitsharingApi extends AbstractApi {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
params.setAppid(v3.getAppId());
SignatureProvider signatureProvider = this.client().signatureProvider();
X509WechatCertificateInfo certificate = signatureProvider.getCertificate(this.wechatMetaBean().getTenantId());
final X509Certificate x509Certificate = certificate.getX509Certificate();
String name = params.getName();
if (ReceiverType.PERSONAL_OPENID.equals(params.getType()) && StringUtils.hasText(name)) {
// 个人应该必传
String encryptedName = signatureProvider.encryptRequestMessage(name,this.wechatMetaBean());
String encryptedName = signatureProvider.encryptRequestMessage(name, x509Certificate);
params.setEncryptedName(encryptedName);
}
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Wechatpay-Serial", signatureProvider.getWechatPaySerial(this.wechatMetaBean()));
httpHeaders.add("Wechatpay-Serial", certificate.getWechatPaySerial());
return Post(uri, params, httpHeaders);
})
.consumer(wechatResponseEntity::convert)

View File

@@ -38,6 +38,4 @@ public class Payer {
* 用户子标识
*/
private String subOpenid;
private String authCode;
}

View File

@@ -61,11 +61,6 @@ public class CreateBatchTransferParams {
* 指定该笔转账使用的转账场景ID
*/
private String transferSceneId;
/**
* 回调通知
* @since 1.0.20
*/
private String notifyUrl;
/**
* 转账明细.
@@ -101,4 +96,4 @@ public class CreateBatchTransferParams {
*/
private String userIdCard;
}
}
}

View File

@@ -20,6 +20,9 @@ import cn.felord.payment.wechat.enumeration.ContactType;
import cn.felord.payment.wechat.enumeration.IdDocType;
import cn.felord.payment.wechat.v3.model.specmch.FinanceInstitutionInfo;
import lombok.Data;
import java.util.List;
/**
* 二级商户进件申请API请求参数
*
@@ -41,6 +44,7 @@ public class EcommerceApplymentParams{
private Boolean owner;
private UboInfo uboInfo;
private Boolean needAccountInfo;
private List<UboInfoListItem> uboInfoList;
private EcommerceAccountInfo accountInfo;
private EcommerceContactInfo contactInfo;
private SalesSceneInfo salesSceneInfo;

View File

@@ -17,7 +17,6 @@
package cn.felord.payment.wechat.v3.model.ecommerce;
import cn.felord.payment.wechat.enumeration.BusinessCertType;
import lombok.Data;
/**
@@ -26,7 +25,6 @@ import lombok.Data;
*/
@Data
public class EcommerceBusinessLicenseInfo {
private BusinessCertType certType;
private String businessLicenseCopy;
private String businessLicenseNumber;
private String merchantName;

View File

@@ -17,20 +17,13 @@
package cn.felord.payment.wechat.v3.model.ecommerce;
import cn.felord.payment.wechat.enumeration.IdDocType;
import lombok.Data;
@Data
public class EcommerceContactInfo {
private String contactType;
private String contactName;
private IdDocType contactIdDocType;
private String contactIdCardNumber;
private String contactIdDocCopy;
private String contactIdDocCopyBack;
private String contactIdDocPeriodEnd;
private String businessAuthorizationLetter;
private String contactIdDocPeriodBegin;
private String mobilePhone;
private String contactEmail;
}
}

View File

@@ -31,5 +31,5 @@ public class UboInfoListItem {
private String uboIdDocNumber;
private String uboIdDocAddress;
private LocalDate uboIdDocPeriodBegin;
private String uboIdDocPeriodEnd;
private LocalDate uboIdDocPeriodEnd;
}

View File

@@ -22,11 +22,11 @@
<parent>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.20.RELEASE</version>
<version>1.0.19.RELEASE</version>
</parent>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -62,4 +62,4 @@
</dependency>
</dependencies>
</project>
</project>

88
pom.xml
View File

@@ -21,7 +21,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.21.RELEASE</version>
<version>1.0.19.RELEASE</version>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -88,9 +88,14 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-boot.version>2.7.18</spring-boot.version>
<alipay-sdk.version>4.40.251.ALL</alipay-sdk.version>
<bcprov.version>1.84</bcprov.version>
<spring-boot.version>2.7.7</spring-boot.version>
<alipay-sdk.version>4.31.7.ALL</alipay-sdk.version>
<bcprov.version>1.69</bcprov.version>
<retrofit.version>2.9.0</retrofit.version>
<okhttp3.version>4.10.0</okhttp3.version>
<lombok.version>1.18.26</lombok.version>
<jackson.version>2.13.5</jackson.version>
<slf4j.version>2.0.7</slf4j.version>
</properties>
<distributionManagement>
@@ -116,7 +121,6 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
@@ -132,6 +136,78 @@
<artifactId>payment-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>${retrofit.version}</version>
<exclusions>
<exclusion>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava3</artifactId>
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jaxb</artifactId>
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -212,4 +288,4 @@
</plugin>
</plugins>
</build>
</project>
</project>