Merge pull request #27 from NotFound403/1.0.10.SNAPSHOT

1.0.10.RELEASE
This commit is contained in:
felord.cn
2021-04-08 14:24:37 +08:00
committed by GitHub
40 changed files with 1387 additions and 59 deletions

View File

@@ -1,13 +1,21 @@
# 相当于脚本用途的一个声明
name: Maven Central Repo Deployment
# 触发脚本的事件 这里为发布release之后触发
on:
release:
types: [released]
# 定义一个发行任务
jobs:
publish:
# 任务运行的环境
runs-on: ubuntu-latest
# 任务的步骤
steps:
- name: Checkout
# 1. 声明 checkout 仓库代码到工作区
- name: Checkout Git Repo
uses: actions/checkout@v2
# 2. 安装Java 环境 这里会用到的参数就是 Git Action secrets中配置的
# 取值要在key前面加 secrets.
- name: Set up Maven Central Repo
uses: actions/setup-java@v1
with:
@@ -16,7 +24,9 @@ jobs:
server-username: ${{ secrets.OSSRH_USER }}
server-password: ${{ secrets.OSSRH_PASSWORD }}
gpg-passphrase: ${{ secrets.GPG_PASSWORD }}
# 3. 发布到Maven中央仓库
- name: Publish to Maven Central Repo
# 这里用到了其他人写的action脚本详细可以去看他的文档。
uses: samuelmeuli/action-maven-publish@v1
with:
gpg_private_key: ${{ secrets.GPG_SECRET }}

View File

@@ -11,7 +11,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
</dependency>
```

View File

@@ -35,7 +35,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
</dependency>
```
## 采用技术

View File

@@ -1,9 +1,20 @@
## 1.0.10.RELEASE
- 微信支付
- feat: 微信支付V2分账接口实现感谢**zacone**同学贡献的PR
- factor: 优化证书加载方式
- factor: 商家券修改API的请求方式变更为`Patch`
- fix: 修复微信支付V3中native支付通知回调`successTime`字段无时区信息的问题([#I3ED43](https://gitee.com/felord/payment-spring-boot/issues/I3ED43))
- 支付宝
- fix: 修复支付宝Maven打包无法读取证书的问题([#24](https://github.com/NotFound403/payment-spring-boot/issues/24))
## 1.0.9.RELEASE
- 微信支付
- refactor: 服务商支付 WechatPartnerPayApi 加入Spring IOC
- refactor: `WechatPartnerPayApi` 加入**Spring IOC**
- fix: 支付分支付成功回调反序列化异常 ([#21](https://github.com/NotFound403/payment-spring-boot/issues/21))
- fix: 修复枚举空指针问题 ([#22](https://github.com/NotFound403/payment-spring-boot/issues/22))
## 1.0.8.RELEASE
- 微信支付

View File

@@ -4,7 +4,7 @@
<dependency>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
</dependency>
```
> 基于 **Spring Boot 2.x**

View File

@@ -5,11 +5,11 @@
<parent>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
</parent>
<artifactId>payment-spring-boot-autoconfigure</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>

View File

@@ -19,11 +19,12 @@
package cn.felord.payment.alipay;
import cn.felord.payment.PayException;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import cn.felord.payment.PayException;
import com.alipay.api.internal.util.file.IOUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -32,7 +33,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author felord.cn
@@ -57,28 +60,28 @@ public class AliPayConfiguration {
propertyMapper.from(v1::getFormat).to(certAlipayRequest::setFormat);
propertyMapper.from(v1::getCharset).to(certAlipayRequest::setCharset);
propertyMapper.from(v1::getSignType).to(certAlipayRequest::setSignType);
propertyMapper.from(v1::getAppCertPublicKeyPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setCertPath);
propertyMapper.from(v1::getAlipayPublicCertPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setAlipayPublicCertPath);
propertyMapper.from(v1::getAlipayRootCertPath).as(this::getFileAbsolutePath).to(certAlipayRequest::setRootCertPath);
propertyMapper.from(v1::getAppCertPublicKeyPath).as(this::getContentFromClassPath).to(certAlipayRequest::setCertContent);
propertyMapper.from(v1::getAlipayPublicCertPath).as(this::getContentFromClassPath).to(certAlipayRequest::setAlipayPublicCertContent);
propertyMapper.from(v1::getAlipayRootCertPath).as(this::getContentFromClassPath).to(certAlipayRequest::setRootCertContent);
return new DefaultAlipayClient(certAlipayRequest);
}
private String getFileAbsolutePath(String classPath) {
try {
return new ClassPathResource(classPath).getFile().getAbsolutePath();
} catch (IOException e) {
log.error("ali pay cert path is not exist ,{}", e.getMessage());
throw new PayException("ali pay cert path is not exist");
}
private String getContentFromClassPath(String classPath) {
ClassPathResource resource = new ClassPathResource(classPath);
try (InputStreamReader in = new InputStreamReader(resource.getInputStream())) {
return IOUtils.toString(in);
} catch (IOException e) {
log.error("ali pay root cert is invalid ,{}", e.getMessage());
throw new PayException("ali pay root cert path is invalid");
}
}
private String appRSAPrivateKey(String classPath) {
ClassPathResource resource = new ClassPathResource(classPath);
try {
FileReader in = new FileReader(resource.getFile());
try(BufferedReader bufferedReader = new BufferedReader(in)){
try (InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream())) {
try (BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
return bufferedReader.readLine();
}
} catch (IOException e) {
@@ -87,5 +90,4 @@ public class AliPayConfiguration {
}
}
}

View File

@@ -60,7 +60,7 @@ public class WechatPayConfiguration {
WechatPayProperties.V3 v3 = v3Map.get(tenantId);
String certPath = v3.getCertPath();
String mchId = v3.getMchId();
WechatMetaBean wechatMetaBean = keyPairFactory.createPKCS12(certPath, CERT_ALIAS, mchId);
WechatMetaBean wechatMetaBean = keyPairFactory.initWechatMetaBean(certPath, CERT_ALIAS, mchId);
wechatMetaBean.setV3(v3);
wechatMetaBean.setTenantId(tenantId);
container.addWechatMeta(tenantId, wechatMetaBean);

View File

@@ -431,7 +431,7 @@ public enum WechatPayV3Type {
*
* @since 1.0.4.RELEASES
*/
MARKETING_BUSI_FAVOR_UPDATE(HttpMethod.POST, "%s/v3/marketing/busifavor/stocks/{stock_id}"),
MARKETING_BUSI_FAVOR_UPDATE(HttpMethod.PATCH, "%s/v3/marketing/busifavor/stocks/{stock_id}"),
/**
* 申请退券API.
*

View File

@@ -0,0 +1,248 @@
/*
* Copyright 2019-2021 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.v2;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.v2.model.BaseModel;
import cn.felord.payment.wechat.v2.model.allocation.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import java.util.List;
/**
* 微信支付分账
* <p>
*
* @since 1.0.10.RELEASE
*/
@Slf4j
public class WechatAllocationApi {
/**
* The constant MAPPER.
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
.registerModule(new JavaTimeModule());
}
private final WechatV2Client wechatV2Client;
/**
* Instantiates a new Wechat allocation api.
*
* @param wechatV2Client the wechat v 2 client
*/
public WechatAllocationApi(WechatV2Client wechatV2Client) {
this.wechatV2Client = wechatV2Client;
}
/**
* 请求单次分账
*
* @param profitSharingModel the profit sharing model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharing(ProfitSharingModel profitSharingModel) {
ProfitSharingSModel profitSharingSModel = new ProfitSharingSModel();
List<Receiver> receivers = profitSharingModel.getReceivers();
profitSharingSModel.setReceivers(MAPPER.writeValueAsString(receivers));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingSModel.setAppid(v3.getAppId());
profitSharingSModel.setMchId(v3.getMchId());
profitSharingSModel.setTransactionId(profitSharingModel.getTransactionId());
profitSharingSModel.setOutOrderNo(profitSharingModel.getOutOrderNo());
profitSharingSModel.certPath(v3.getCertPath());
profitSharingSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharing");
}
/**
* 请求单次分账
*
* @param multiProfitSharingModel the multi profit sharing model
* @return json node
*/
@SneakyThrows
public JsonNode multiProfitSharing(MultiProfitSharingModel multiProfitSharingModel) {
MultiProfitSharingSModel multiProfitSharingSModel = new MultiProfitSharingSModel();
List<Receiver> receivers = multiProfitSharingModel.getReceivers();
multiProfitSharingSModel.setReceivers(MAPPER.writeValueAsString(receivers));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
multiProfitSharingSModel.setAppid(v3.getAppId());
multiProfitSharingSModel.setMchId(v3.getMchId());
multiProfitSharingSModel.setTransactionId(multiProfitSharingModel.getTransactionId());
multiProfitSharingSModel.setOutOrderNo(multiProfitSharingModel.getOutOrderNo());
multiProfitSharingSModel.certPath(v3.getCertPath());
multiProfitSharingSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(multiProfitSharingSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/multiprofitsharing");
}
/**
* 查询分账结果
*
* @param profitSharingQueryModel the profit sharing query model
* @return json node
*/
public JsonNode profitSharingQuery(ProfitSharingQueryModel profitSharingQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingQueryModel.setMchId(v3.getMchId());
profitSharingQueryModel.certPath(v3.getCertPath());
profitSharingQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingquery");
}
/**
* 添加分账接收方
*
* @param profitSharingAddReceiverModel the profit sharing add receiver model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharingAddReceiver(ProfitSharingAddReceiverModel profitSharingAddReceiverModel) {
ProfitSharingAddReceiverSModel profitSharingAddReceiverSModel = new ProfitSharingAddReceiverSModel();
ProfitSharingAddReceiverModel.Receiver receiver = profitSharingAddReceiverModel.getReceiver();
profitSharingAddReceiverSModel.setReceiver(MAPPER.writeValueAsString(receiver));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingAddReceiverSModel.setAppid(v3.getAppId());
profitSharingAddReceiverSModel.setMchId(v3.getMchId());
profitSharingAddReceiverSModel.certPath(v3.getCertPath());
profitSharingAddReceiverSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingAddReceiverSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver");
}
/**
* 删除分账接收方
*
* @param profitSharingRemoveReceiverModel the profit sharing remove receiver model
* @return json node
*/
@SneakyThrows
public JsonNode profitSharingRemoveReceiver(ProfitSharingRemoveReceiverModel profitSharingRemoveReceiverModel) {
ProfitSharingRemoveReceiverSModel profitSharingRemoveReceiverSModel = new ProfitSharingRemoveReceiverSModel();
ProfitSharingRemoveReceiverModel.Receiver receiver = profitSharingRemoveReceiverModel.getReceiver();
profitSharingRemoveReceiverSModel.setReceiver(MAPPER.writeValueAsString(receiver));
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingRemoveReceiverSModel.setAppid(v3.getAppId());
profitSharingRemoveReceiverSModel.setMchId(v3.getMchId());
profitSharingRemoveReceiverSModel.certPath(v3.getCertPath());
profitSharingRemoveReceiverSModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingRemoveReceiverSModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver");
}
/**
* 完结分账
*
* @param profitSharingFinishModel the profit sharing finish model
* @return json node
*/
public JsonNode profitSharingFinish(ProfitSharingFinishModel profitSharingFinishModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingFinishModel.setAppid(v3.getAppId());
profitSharingFinishModel.setMchId(v3.getMchId());
profitSharingFinishModel.certPath(v3.getCertPath());
profitSharingFinishModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingFinishModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish");
}
/**
* 查询订单待分账金额
*
* @param profitSharingOrderAmountQueryModel the profit sharing order amount query model
* @return json node
*/
public JsonNode profitSharingOrderAmountQuery(ProfitSharingOrderAmountQueryModel profitSharingOrderAmountQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingOrderAmountQueryModel.setMchId(v3.getMchId());
profitSharingOrderAmountQueryModel.certPath(v3.getCertPath());
profitSharingOrderAmountQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingOrderAmountQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingorderamountquery");
}
/**
* 分账回退
*
* @param profitSharingReturnModel the profit sharing return model
* @return json node
*/
public JsonNode profitSharingReturn(ProfitSharingReturnModel profitSharingReturnModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingReturnModel.setAppid(v3.getAppId());
profitSharingReturnModel.setMchId(v3.getMchId());
profitSharingReturnModel.certPath(v3.getCertPath());
profitSharingReturnModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingReturnModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn");
}
/**
* 回退结果查询
*
* @param profitSharingReturnQueryModel the profit sharing return query model
* @return json node
*/
public JsonNode profitSharingReturnQuery(ProfitSharingReturnQueryModel profitSharingReturnQueryModel) {
WechatPayProperties.V3 v3 = wechatV2Client.getWechatMetaBean().getV3();
profitSharingReturnQueryModel.setAppid(v3.getAppId());
profitSharingReturnQueryModel.setMchId(v3.getMchId());
profitSharingReturnQueryModel.certPath(v3.getCertPath());
profitSharingReturnQueryModel.signType(BaseModel.HMAC_SHA256);
return wechatV2Client.wechatPayRequest(profitSharingReturnQueryModel,
HttpMethod.POST,
"https://api.mch.weixin.qq.com/pay/profitsharingreturnquery");
}
}

View File

@@ -48,6 +48,8 @@ import org.springframework.util.IdGenerator;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
@@ -63,6 +65,7 @@ import java.security.cert.CertificateException;
*/
@Getter
public abstract class BaseModel {
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,13 +87,27 @@ public abstract class BaseModel {
private String sign;
@JsonIgnore
private String appSecret;
@JsonIgnore
private String certPath;
@JsonIgnore
private String signType;
public BaseModel appSecret(String appSecret) {
this.appSecret = appSecret;
return this;
}
public BaseModel certPath(String certPath) {
this.certPath = certPath;
return this;
}
public BaseModel signType(String signType) {
this.signType = signType;
return this;
}
/**
* Xml string.
*
@@ -99,7 +116,11 @@ public abstract class BaseModel {
@SneakyThrows
private String xml() {
String link = link(this);
this.sign = this.md5(link);
if (HMAC_SHA256.equals(signType)) {
this.sign = this.hmacSha256(link);
} else {
this.sign = this.md5(link);
}
return XML_MAPPER.writer()
.withRootName("xml")
.writeValueAsString(this);
@@ -120,6 +141,21 @@ public abstract class BaseModel {
return Hex.toHexString(md5Bytes).toUpperCase();
}
/**
* hmacSha256.
*
* @param src the src
* @return the string
*/
@SneakyThrows
private String hmacSha256(String src) {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(appSecret.getBytes(),"HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] bytes = sha256_HMAC.doFinal(src.getBytes(StandardCharsets.UTF_8));
return Hex.toHexString(bytes).toUpperCase();
}
/**
* 按照格式拼接参数以生成签名
*
@@ -130,14 +166,13 @@ public abstract class BaseModel {
@SneakyThrows
private <T> String link(T t) {
Assert.hasText(appSecret, "wechat pay appSecret is required");
return OBJECT_MAPPER
String link = OBJECT_MAPPER
.writer()
.writeValueAsString(t)
.replaceAll("\":\"", "=")
.replaceAll("\",\"", "&")
.replaceAll("\\{\"", "")
.replaceAll("\"}", "")
.concat("&key=").concat(this.appSecret);
.replaceAll("\\\\\"", "\"");
return link.substring(2, link.length() - 2).concat("&key=").concat(this.appSecret);
}
@@ -164,7 +199,7 @@ public abstract class BaseModel {
private RestTemplate getRestTemplateClientAuthentication(String mchId)
throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException,
KeyStoreException, KeyManagementException {
ClassPathResource resource = new ClassPathResource("wechat/apiclient_cert.p12");
ClassPathResource resource = new ClassPathResource(certPath == null ? "wechat/apiclient_cert.p12" : certPath);
char[] pem = mchId.toCharArray();

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Base profit sharing model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BaseProfitSharingModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
private String appid;
private String transactionId;
private String outOrderNo;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Base profit sharing receiver model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BaseProfitSharingReceiverModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
/**
* The type Multi profit sharing model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public class MultiProfitSharingModel extends ProfitSharingModel {
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
/**
* The type Multi profit sharing s model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public class MultiProfitSharingSModel extends ProfitSharingSModel {
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing add receiver model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingAddReceiverModel extends BaseProfitSharingReceiverModel {
private Receiver receiver;
/**
* The type Receiver.
*/
@Data
public static class Receiver {
/**
* 分账接收方类型.
* <p>
* MERCHANT_ID商户号mch_id或者sub_mch_id
* PERSONAL_OPENID个人openid
*/
private Type type;
/**
* 分账接收方帐号.
* <p>
* 类型是MERCHANT_ID时是商户号mch_id或者sub_mch_id
* 类型是PERSONAL_OPENID时是个人openid
*/
private String account;
/**
* 分账接收方全称.
* <p>
* 分账接收方类型是MERCHANT_ID时是商户全称必传当商户是小微商户或个体户时是开户人姓名
* 分账接收方类型是PERSONAL_OPENID时是个人姓名选传传则校验
*/
private String name;
/**
* 与分账方的关系类型.
* <p>
* 子商户与接收方的关系。
* 本字段值为枚举:
* SERVICE_PROVIDER服务商
* STORE门店
* STAFF员工
* STORE_OWNER店主
* PARTNER合作伙伴
* HEADQUARTER总部
* BRAND品牌方
* DISTRIBUTOR分销商
* USER用户
* SUPPLIER供应商
* CUSTOM自定义
*/
private RelationType relationType;
/**
* 自定义的分账关系.
* <p>
* 子商户与接收方具体的关系本字段最多10个字。
* 当字段relation_type的值为CUSTOM时本字段必填
* 当字段relation_type的值不为CUSTOM时本字段无需填写
*/
private String customRelation;
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing add receiver s model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingAddReceiverSModel extends BaseProfitSharingReceiverModel {
private String receiver;
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing finish model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingFinishModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
/**
* 商户分账单号.
* <p>
* 查询分账结果,输入申请分账时的商户分账单号; 查询分账完结执行的结果,输入发起分账完结时的商户分账单号
*/
private String outOrderNo;
/**
* 分账完结描述.
* <p>
* 分账完结的原因描述
*/
private String description;
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 单次分账请求按照传入的分账接收方账号和资金进行分账,同时会将订单剩余的待分账金额解冻给本商户。
* 故操作成功后,订单不能再进行分账,也不能进行分账完结。
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingModel extends BaseProfitSharingModel {
/**
* 分账接收方列表不超过50个json对象不能设置分账方作为分账接受方
*/
private List<Receiver> receivers;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing order amount query model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingOrderAmountQueryModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing query model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingQueryModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
/**
* 商户分账单号.
* <p>
* 查询分账结果,输入申请分账时的商户分账单号; 查询分账完结执行的结果,输入发起分账完结时的商户分账单号
*/
private String outOrderNo;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing remove receiver model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingRemoveReceiverModel extends BaseProfitSharingReceiverModel {
private Receiver receiver;
/**
* The type Receiver.
*/
@Data
public static class Receiver {
private Type type;
private String account;
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing remove receiver s model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingRemoveReceiverSModel extends BaseProfitSharingReceiverModel {
private String receiver;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing return model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingReturnModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
private String orderId;
private String outOrderNo;
private String outReturnNo;
private String returnAccountType;
private String returnAccount;
private String returnAmount;
private String description;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import cn.felord.payment.wechat.v2.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing return query model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingReturnQueryModel extends BaseModel {
/**
* 商户号.
* <p>
* 微信支付分配的商户号
*/
private String mchId;
/**
* 公众账号ID.
* <p>
* 微信分配的公众账号ID
*/
private String appid;
/**
* 微信分账订单号.
* <p>
* 原发起分账请求时,微信返回的微信分账单号,与商户分账单号一一对应。
* 微信分账单号与商户分账单号二选一填写
*/
private String orderId;
/**
* 商户分账单号.
* <p>
* 原发起分账请求时使用的商户系统内部的分账单号。
* 微信分账单号与商户分账单号二选一填写
*/
private String outOrderNo;
/**
* 商户回退单号.
* <p>
* 调用回退接口提供的商户系统内部的回退单号
*/
private String outReturnNo;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* The type Profit sharing s model.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ProfitSharingSModel extends BaseProfitSharingModel {
/**
* 分账接收方列表不超过50个json对象不能设置分账方作为分账接受方。
*/
private String receivers;
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
import lombok.Data;
/**
* The type Receiver.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@Data
public class Receiver {
/**
* 分账接收方类型.
* <p>
* MERCHANT_ID商户号mch_id或者sub_mch_id
* PERSONAL_OPENID个人openid
*/
private Type type;
/**
* 分账接收方帐号.
* <p>
* 类型是MERCHANT_ID时是商户号mch_id或者sub_mch_id
* 类型是PERSONAL_OPENID时是个人openid
*/
private String account;
/**
* 分账金额.
* <p>
* 单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
*/
private Integer amount;
/**
* 分账描述.
* <p>
* 分账的原因描述,分账账单中需要体现
*/
private String description;
/**
* 分账个人接收方姓名.
* <p>
* 可选项,在接收方类型为个人的时可选填,若有值,会检查与 name 是否实名匹配,不匹配会拒绝分账请求.
* 1、分账接收方类型是PERSONAL_OPENID时是个人姓名选传传则校验
*/
private String name;
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019-2021 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.v2.model.allocation;
/**
* The enum Relation type.
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public enum RelationType {
/**
* Service provider relation type.
*/
SERVICE_PROVIDER,
/**
* Store relation type.
*/
STORE,
/**
* Staff relation type.
*/
STAFF,
/**
* Store owner relation type.
*/
STORE_OWNER,
/**
* Partner relation type.
*/
PARTNER,
/**
* Headquarter relation type.
*/
HEADQUARTER,
/**
* Brand relation type.
*/
BRAND,
/**
* Distributor relation type.
*/
DISTRIBUTOR,
/**
* User relation type.
*/
USER,
/**
* Supplier relation type.
*/
SUPPLIER,
/**
* Custom relation type.
*/
CUSTOM
}

View File

@@ -0,0 +1,20 @@
package cn.felord.payment.wechat.v2.model.allocation;
/**
* The enum Type.
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
public enum Type {
/**
* 商户号mch_id或者sub_mch_id
*/
MERCHANT_ID,
/**
* 个人openid
*/
PERSONAL_OPENID
}

View File

@@ -202,6 +202,21 @@ public abstract class AbstractApi {
.build();
}
/**
* 构建Post请求对象.
*
* @param uri the uri
* @param params the params
* @return the request entity
*/
protected RequestEntity<?> Patch(URI uri, Object params) {
try {
return RequestEntity.patch(uri).header("Pay-TenantId", tenantId)
.body(mapper.writeValueAsString(params));
} catch (JsonProcessingException e) {
throw new PayException("wechat app pay json failed");
}
}
/**
* 对账单内容下载,非流文件。
*

View File

@@ -22,10 +22,7 @@ package cn.felord.payment.wechat.v3;
import cn.felord.payment.PayException;
import org.springframework.core.io.ClassPathResource;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.*;
import java.security.cert.X509Certificate;
/**
@@ -36,9 +33,16 @@ import java.security.cert.X509Certificate;
**/
public class KeyPairFactory {
private KeyStore store;
private static final KeyStore PKCS12_KEY_STORE;
static {
try {
PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12");
} catch (KeyStoreException e) {
throw new PayException(" wechat pay keystore initialization failed");
}
}
private final Object lock = new Object();
/**
* 获取公私钥.
@@ -48,23 +52,16 @@ public class KeyPairFactory {
* @param keyPass password
* @return the key pair
*/
public WechatMetaBean createPKCS12(String keyPath, String keyAlias, String keyPass) {
public WechatMetaBean initWechatMetaBean(String keyPath, String keyAlias, String keyPass) {
ClassPathResource resource = new ClassPathResource(keyPath);
char[] pem = keyPass.toCharArray();
try {
synchronized (lock) {
if (store == null) {
synchronized (lock) {
store = KeyStore.getInstance("PKCS12");
store.load(resource.getInputStream(), pem);
}
}
}
X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
PKCS12_KEY_STORE.load(resource.getInputStream(), pem);
X509Certificate certificate = (X509Certificate) PKCS12_KEY_STORE.getCertificate(keyAlias);
certificate.checkValidity();
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
PublicKey publicKey = certificate.getPublicKey();
PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);
PrivateKey storeKey = (PrivateKey) PKCS12_KEY_STORE.getKey(keyAlias, pem);
WechatMetaBean wechatMetaBean = new WechatMetaBean();
wechatMetaBean.setKeyPair(new KeyPair(publicKey, storeKey));
wechatMetaBean.setSerialNumber(serialNumber);

View File

@@ -18,6 +18,7 @@
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.v2.WechatAllocationApi;
import cn.felord.payment.wechat.v2.WechatPayRedpackApi;
import cn.felord.payment.wechat.v2.WechatPayTransfersApi;
import cn.felord.payment.wechat.v2.WechatV2Client;
@@ -177,4 +178,19 @@ public class WechatApiProvider {
return new WechatPayTransfersApi(wechatV2Client);
}
/**
* 微信支付分账基于V2
*
* @param tenantId the tenant id
* @return wechat allocation api
* @since 1.0.10.RELEASE
*/
public WechatAllocationApi allocationApi(String tenantId) {
WechatMetaBean wechatMeta = wechatPayClient.signatureProvider()
.wechatMetaContainer()
.getWechatMeta(tenantId);
WechatV2Client wechatV2Client = new WechatV2Client(wechatMeta);
return new WechatAllocationApi(wechatV2Client);
}
}

View File

@@ -384,7 +384,7 @@ public class WechatMarketingBusiFavorApi extends AbstractApi {
.expand(updateParams.getStockId())
.toUri();
updateParams.setStockId(null);
return Post(uri, updateParams);
return Patch(uri, updateParams);
})
.consumer(wechatResponseEntity::convert)
.request();

View File

@@ -91,6 +91,27 @@ public class WechatPayCallback {
}
/**
* 微信支付分账回调.
*
* @param params the params
* @param consumeDataConsumer the consume data consumer
* @return the map
* @since 1.0.10.RELEASE
*/
@SneakyThrows
public Map<String, ?> profitSharingCallback(ResponseSignVerifyParams params, Consumer<ProfitSharingConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.TRANSACTION);
ProfitSharingConsumeData consumeData = MAPPER.readValue(data, ProfitSharingConsumeData.class);
consumeDataConsumer.accept(consumeData);
Map<String, Object> responseBody = new HashMap<>(2);
responseBody.put("code", 200);
responseBody.put("message", "SUCCESS");
return responseBody;
}
/**
* 微信支付代金券核销回调.
*

View File

@@ -0,0 +1,77 @@
/*
*
* Copyright 2019-2020 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.model;
import cn.felord.payment.wechat.v2.model.allocation.Receiver;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 微信支付分账通知参数
*
* @author wangzecheng
* @since 1.0.10.RELEASE
*/
@Data
public class ProfitSharingConsumeData {
/**
* 直连商户号.
* <p>
* 直连模式分账发起和出资商户
*/
private String mchid;
/**
* 微信订单号.
* <p>
* 微信支付订单号
*/
private String transactionId;
/**
* 微信分账/回退单号.
*/
private String orderId;
/**
* 商户分账/回退单号.
* <p>
* 分账方系统内部的分账/回退单号
*/
private String outOrderNo;
/**
* 分账接收方.
* <p>
* 分账接收方对象
*/
private Receiver receiver;
/**
* 成功时间.
* <p>
* Rfc3339标准
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone = "GMT+8")
private LocalDateTime successTime;
}

View File

@@ -22,7 +22,7 @@ import cn.felord.payment.wechat.enumeration.RefundStatus;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.OffsetDateTime;
import java.time.LocalDateTime;
/**
* 微信支付退款结果通知解密
@@ -60,7 +60,7 @@ public class RefundConsumeData {
* 退款成功时间
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone = "GMT+8")
private OffsetDateTime successTime;
private LocalDateTime successTime;
/**
* 退款入账账户
*/

View File

@@ -23,7 +23,7 @@ import cn.felord.payment.wechat.enumeration.TradeType;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.OffsetDateTime;
import java.time.LocalDateTime;
import java.util.List;
/**
@@ -91,7 +91,7 @@ public class TransactionConsumeData {
* 支付完成时间 YYYY-MM-DDTHH:mm:ss+TIMEZONE
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone = "GMT+8")
private OffsetDateTime successTime;
private LocalDateTime successTime;
/**
* 在 1.0.0.RELEASE 直接返回了枚举字符串1.0.2.RELEASE 中变更为枚举
*

View File

@@ -20,7 +20,7 @@ package cn.felord.payment.wechat.v3.model.busifavor;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.OffsetDateTime;
import java.time.LocalDateTime;
/**
* 商家券领券事件回调通知解密
@@ -50,7 +50,7 @@ public class BusiFavorReceiveConsumeData {
* 发放时间 rfc 3339 yyyy-MM-ddTHH:mm:ss+TIMEZONE
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone = "GMT+8")
private OffsetDateTime sendTime;
private LocalDateTime sendTime;
/**
* 微信用户在appid下的唯一标识。
*/

View File

@@ -5,11 +5,11 @@
<parent>
<groupId>cn.felord</groupId>
<artifactId>payment-spring-boot</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
</parent>
<artifactId>payment-spring-boot-starter</artifactId>
<version>1.0.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,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.9.RELEASE</version>
<version>1.0.10.RELEASE</version>
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>