文章目录
微信分账官方文档
微信分账相关参数配置
wx:
# 微信小程序appid
app-id: wxcbxxxxxxxxxxxx
# 商户号
mch-id: 167xxxxxxx
# 证书序列号
mch-serial-no: 7AA998xxxxxxxxxxxxxxxxxxxxxxxxxxx
# 小程序密钥
app-secret: 8cc13xxxxxxxxxxxxxxxxxx
# api密钥
api-key: toxxxxxxxxxxxxxxxxxxxx
# 退款通知回调地址
refund-notify-url: xxx
# 证书地址
key-path: /apiclient_key.pem
cert-path: /apiclient_cert.pem
cert-p12-path: /apiclient_cert.p12
msgDataFormat: JSON
相关配置参数获取方法
- 从这个链接进去获取相关配置
- 获取APPID
- 商户号获取位置
- 证书序列号和API秘钥获取位置
- 验签相关证书获取位置
- 验签证书直接放在 resources 目录下面
引入依赖
<!--WeChatPay-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
配置类properties
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "wx")
public class WxProperties {
/**
* 设置微信小程序的appid
*/
private String appId;
// /**
// * 设置微信小程序的Secret
// */
// private String appSecret;
/**
* 微信支付分配的商户号
*/
private String mchId;
/**
* 密钥文件的路径
*/
private String keyPath;
/**
* 商户证书的路径
*/
private String certPath;
/**
* 商户密钥,用于签名和验证
*/
private String apiKey;
/**
* 退款回调地址
*/
private String refundNotifyUrl;
/**
* 商户API证书序列号
*/
private String mchSerialNo;
/**
* 消息格式,XML或者JSON
*/
private String msgDataFormat;
}
配置类config
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.*;
/**
* 微信支付相关自动配置
* @author Ccoo
* 2024/3/24
*/
@Slf4j
@Configuration
public class WechatAutoConfiguration {
@Autowired
private WxProperties wxProperties;
@Autowired
private ResourceLoader resourceLoader;
private static final String CLASS_PATH = "classpath:";
/**
* 微信支付分账
* @param config Config
* @return ProfitsharingService
*/
@Bean
public ProfitsharingService profitsharingService(Config config){
ProfitsharingService service = new ProfitsharingService.Builder().config(config).build();
return service;
}
/**
* 微信支付对象
* @param config Config
* @return JsapiServiceExtension
*/
@Bean
public JsapiServiceExtension jsapiServiceExtension(Config config){
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
return service;
}
/**
* 自动更新证书
*
* @return RSAAutoCertificateConfig
*/
@Bean
public Config config() throws IOException {
String path = CLASS_PATH + wxProperties.getCertPath();
Resource resourceCert = resourceLoader.getResource(path);
X509Certificate certificate = getCertificate(resourceCert.getInputStream());
String merchantSerialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
String privatePath = CLASS_PATH + wxProperties.getKeyPath();
Resource resourcePrivate = resourceLoader.getResource(privatePath);
String privateKey = inputStreamToString(resourcePrivate.getInputStream());
return new RSAAutoCertificateConfig.Builder()
.merchantId(wxProperties.getMchId())
.privateKey(privateKey)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(wxProperties.getApiKey())
.build();
}
/**
* 微信回调对象
*
* @param config Config
* @return NotificationParser
*/
@Bean
public NotificationParser notificationParser(Config config) {
NotificationParser parser = new NotificationParser((NotificationConfig) config);
return parser;
}
/**
* 读取私钥文件,将文件流读取成string
*
* @param inputStream
* @return
* @throws IOException
*/
public String inputStreamToString(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
reader.close();
return stringBuilder.toString();
}
/**
* 获取证书 将文件流转成证书文件
*
* @param inputStream 证书文件
* @return {@link X509Certificate} 获取证书
*/
public static X509Certificate getCertificate(InputStream inputStream) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
cert.checkValidity();
return cert;
} catch (CertificateExpiredException e) {
throw new RuntimeException("证书已过期", e);
} catch (CertificateNotYetValidException e) {
throw new RuntimeException("证书尚未生效", e);
} catch (CertificateException e) {
throw new RuntimeException("无效的证书", e);
}
}
}
相关参数解释
- 可以在这个文档中心去看官方的解释
- 下面我给出了一些比较容易混淆的参数对应的解释
- appid - 公众账号ID
- 微信分配的服务商appid
- out_order_no - 商户分账单号
- 服务商系统内部的分账单号,在服务商系统内部唯一,
- 同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
- transaction_id - 微信订单号
- 微信支付订单号, 即微信支付成功之后由微信返回的唯一订单号
- order_id - 微信分账单号
- 微信分账单号,微信系统返回的唯一标识
- 这是微信分账之后微信服务器返回的分账账单唯一ID
- 这个微信分账单号和自己系统生成的
**out_order_no**
是等效的
- out_return_no - 商户回退单号
- 此回退单号是商户在自己后台生成的一个新的回退单号,在商户后台唯一
Controller控制器
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* @author Ccoo
* 2024/8/16
*/
@Api(tags = "分账接口(API-V3)")
@RestController
@RequestMapping("/profitsharing")
@RequiredArgsConstructor
public class SharingController {
private final SharingService sharingService;
/** 添加分账接收方 */
@ApiOperation(value = "添加分账接收方", notes = "添加分账接收方")
@PostMapping("/addReceiver")
public R<?> addReceiver(@ApiParam("接收方类型") @RequestParam String type,
@ApiParam("接收方账号") @RequestParam String account,
@ApiParam("与分账方的关系类型") @RequestParam String relationType) {
return sharingService.addReceiver(type, account, relationType);
}
/** 删除分账接收方 */
@ApiOperation(value = "删除分账接收方", notes = "删除分账接收方")
@PostMapping("/deleteReceiver")
public R<?> deleteReceiver(@ApiParam("接收方类型") @RequestParam String type,
@ApiParam("接收方账号") @RequestParam String account) {
return sharingService.deleteReceiver(type, account);
}
/** 单次分账请求 */
@ApiOperation(value = "单次分账请求", notes = "单次分账请求")
@PostMapping("/ordersSharing")
public R<?> ordersSharing(@ApiParam("微信订单号") @RequestParam String transactionId,
@ApiParam("分账描述") @RequestParam String description,
@ApiParam("是否解冻剩余未分资金(0是,1否)") @RequestParam String unfreezeUnsplit) {
return sharingService.ordersSharing(transactionId, description, unfreezeUnsplit);
}
/** 查询分账结果 */
@ApiOperation(value = "查询分账结果", notes = "查询分账结果")
@GetMapping("/sharingResult")
public R<?> sharingResult(@ApiParam("商户分账单号") @RequestParam String outOrderNo,
@ApiParam("微信订单号") @RequestParam String transactionId) {
return sharingService.sharingResult(outOrderNo, transactionId);
}
/** 请求分账回退 */
@ApiOperation(value = "请求分账回退", notes = "请求分账回退")
@PostMapping("/returnSharing")
public R<?> returnSharing(@ApiParam("微信分账单号") @RequestParam String orderId,
@ApiParam("回退商户号") @RequestParam String returnMchid,
@ApiParam("回退描述") @RequestParam String description){
return sharingService.returnSharing(orderId, returnMchid, description);
}
/** 查询分账回退结果 */
@ApiOperation(value = "查询分账回退结果", notes = "查询分账回退结果")
@GetMapping("/returnSharingResult")
public R<?> returnSharingResult(@ApiParam("商户回退单号") @RequestParam String outReturnNo,
@ApiParam("商户分账单号") @RequestParam String outOrderNo) {
return sharingService.returnSharingResult(outReturnNo, outOrderNo);
}
/** 解冻剩余资金 */
@ApiOperation(value = "解冻剩余资金", notes = "解冻剩余资金")
@PostMapping("/unfreeze")
public R<?> unfreeze(@ApiParam("微信订单号") @RequestParam String transactionId,
@ApiParam("商户分账单号") @RequestParam String outOrderNo,
@ApiParam("分账描述") @RequestParam String description) {
return sharingService.unfreeze(transactionId, outOrderNo, description);
}
/** 查询剩余待分金额 */
@ApiOperation(value = "查询剩余待分金额", notes = "查询剩余待分金额")
@GetMapping("/sharingAmountBalance")
public R<?> sharingAmountBalance(@ApiParam("微信订单号") @RequestParam String transactionId) {
return sharingService.sharingAmountBalance(transactionId);
}
/** 查询分账比例 */
@ApiOperation(value = "查询分账比例", notes = "查询分账比例")
@GetMapping("/sharingRatio")
public R<?> sharingRatio(@ApiParam("商户号") @RequestParam String mchId) {
return sharingService.sharingRatio(mchId);
}
/** 下载分账账单 */
@ApiOperation(value = "下载分账账单", notes = "下载分账账单")
@PostMapping("/downloadBill")
public R<?> downloadBill(@ApiParam("账单日期(格式YYYY-MM-DD)") @RequestParam String billDate,
@ApiParam("(选填)账单类型(不传默认为xlsx, 传GZIP则为压缩包)") String billType) {
return sharingService.downloadBill(billDate, billType);
}
}
Service接口层
import com.itheima.mp.domain.R;
/**
* @author Ccoo
* 2024/8/17
*/
public interface SharingService {
/**
* 添加分账接收方
* @param type 接收方类型
* @param account 接收方账号
* @param relationType 分账关系类型
* @return 结果
*/
R<?> addReceiver(String type, String account, String relationType);
/**
* 删除分账接收方
* @param type 接收方类型
* @param account 接收方账号
* @return 结果
*/
R<?> deleteReceiver(String type, String account);
/**
* 单次请求分账
* @param transactionId 微信订单号
* @param description 分账描述
* @param unfreezeUnsplit 是否解冻剩余未分资金
* @return 结果
*/
R<?> ordersSharing(String transactionId, String description, String unfreezeUnsplit);
/**
* 查询分账结果
* @param outOrderNo 商户分账单号
* @param transactionId 微信订单号
* @return 结果
*/
R<?> sharingResult(String outOrderNo, String transactionId);
/**
* 请求分账回退
* @param orderId 微信分账单号
* @param returnMchid 回退商户号
* @param description 回退描述
* @return 结果
*/
R<?> returnSharing(String orderId, String returnMchid, String description);
/**
* 查询分账回退结果
* @param outReturnNo 商户回退单号
* @param outOrderNo 商户订单号
* @return 结果
*/
R<?> returnSharingResult(String outReturnNo, String outOrderNo);
/**
* 解冻剩余资金
* @param transactionId 微信订单号
* @param outOrderNo 商户分账单号
* @param description 描述信息
* @return 结果
*/
R<?> unfreeze(String transactionId, String outOrderNo, String description);
/**
* 查询剩余待分金额
* @param transactionId 微信订单号
* @return 结果
*/
R<?> sharingAmountBalance(String transactionId);
/**
* 查询分账比例
* @param mchId 商户号
* @return 结果
*/
R<?> sharingRatio(String mchId);
/**
* 下载分账账单
* @param billDate 分账账单日期
* @param billType 分账账单类型
* @return 结果
*/
R<?> downloadBill(String billDate, String billType);
}
ServiceImpl实现层
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.profitsharing.model.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author Ccoo
* 2024/8/17
*/
@Service
@RequiredArgsConstructor
public class SharingServiceImpl implements SharingService {
private final ProfitsharingService profitsharingService;
private final WxProperties wxProperties;
public static final String TRUE_UNFREEZE_UNSPLIT = "0";
public static final String FALSE_UNFREEZE_UNSPLIT = "1";
/**
* 添加分账接收方
* @param type 接收方类型
* @param account 接收方账号
* @param relationType 分账关系类型
* @return 结果
* 商户发起添加分账接收方请求,建立分账接收方列表。后续可通过发起分账请求,将分账方商户结算后的资金,分到该分账接收方
* 商户需确保向微信支付传输用户身份信息和账号标识信息做一致性校验已合法征得用户授权
*/
@Override
public R<?> addReceiver(String type, String account, String relationType) {
AddReceiverRequest request = new AddReceiverRequest();
// 设置APPID
request.setAppid(wxProperties.getAppId());
// 设置分账接收方账号
request.setAccount(account);
// 设置分账接收方
if(SharingReceiverType.MERCHANT_ID.equals(type)){
request.setType(ReceiverType.MERCHANT_ID);
} else if (SharingReceiverType.PERSONAL_OPENID.equals(type)) {
request.setType(ReceiverType.PERSONAL_OPENID);
} else if (SharingReceiverType.PERSONAL_SUB_OPENID.equals(type)) {
request.setType(ReceiverType.PERSONAL_SUB_OPENID);
}
// 设置分账关系类型
if (SharingReceiverRelationType.SERVICE_PROVIDER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.SERVICE_PROVIDER);
} else if (SharingReceiverRelationType.STORE.equals(relationType)) {
request.setRelationType(ReceiverRelationType.STORE);
} else if (SharingReceiverRelationType.STAFF.equals(relationType)) {
request.setRelationType(ReceiverRelationType.STAFF);
} else if (SharingReceiverRelationType.STORE_OWNER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.STORE_OWNER);
} else if (SharingReceiverRelationType.PARTNER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.PARTNER);
} else if (SharingReceiverRelationType.HEADQUARTER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.HEADQUARTER);
} else if (SharingReceiverRelationType.BRAND.equals(relationType)) {
request.setRelationType(ReceiverRelationType.BRAND);
} else if (SharingReceiverRelationType.DISTRIBUTOR.equals(relationType)) {
request.setRelationType(ReceiverRelationType.DISTRIBUTOR);
} else if (SharingReceiverRelationType.USER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.USER);
} else if (SharingReceiverRelationType.SUPPLIER.equals(relationType)) {
request.setRelationType(ReceiverRelationType.SUPPLIER);
} else if (SharingReceiverRelationType.CUSTOM.equals(relationType)) {
request.setRelationType(ReceiverRelationType.CUSTOM);
}
try {
// 请求微信服务器添加分账接收方
AddReceiverResponse response = profitsharingService.addReceiver(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 删除分账接收方
* @param type 接收方类型
* @param account 接收方账号
* @return 结果
* 商户发起删除分账接收方请求。删除后,不支持将分账方商户结算后的资金,分到该分账接收方
*/
@Override
@Transactional
public R<?> deleteReceiver(String type, String account) {
DeleteReceiverRequest request = new DeleteReceiverRequest();
// 设置APPID
request.setAppid(wxProperties.getAppId());
// 设置分账接收方账号
request.setAccount(account);
// 设置分账接收方类型
if(SharingReceiverType.MERCHANT_ID.equals(type)){
request.setType(ReceiverType.MERCHANT_ID);
} else if (SharingReceiverType.PERSONAL_OPENID.equals(type)) {
request.setType(ReceiverType.PERSONAL_OPENID);
} else if (SharingReceiverType.PERSONAL_SUB_OPENID.equals(type)) {
request.setType(ReceiverType.PERSONAL_SUB_OPENID);
}
try {
// 请求微信服务器删除分账接收方
DeleteReceiverResponse response = profitsharingService.deleteReceiver(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 单次分账请求
*
* @return 结果
* 微信订单支付成功后,商户发起分账请求,将结算后的资金分到分账接收方
* 对同一笔订单最多能发起50次分账请求,每次请求最多分给50个接收方
* 此接口采用异步处理模式,即在接收到商户请求后,会先受理请求再异步处理,最终的分账结果可以通过查询分账接口获取
* 商户需确保向微信支付传输用户身份信息和账号标识信息做一致性校验已合法征得用户授权
*/
@Override
@Transactional
public R<?> ordersSharing(String transactionId, String description, String unfreezeUnsplit) {
CreateOrderRequest request = new CreateOrderRequest();
String outOrderNo = System.currentTimeMillis() + String.valueOf(new Random().nextInt(999999));
// 设置APPID
request.setAppid(wxProperties.getAppId());
// 设置微信订单号
request.setTransactionId(transactionId);
// 设置商户订单号
request.setOutOrderNo(outOrderNo);
List<CreateOrderReceiver> receivers = new ArrayList<>();
// 设置分账接收方, 可以为多个分账接收方, 这里测试只设置一个
CreateOrderReceiver receiver1 = new CreateOrderReceiver();
// 设置分账接收方类型
receiver1.setType("PERSONAL_OPENID");
// 设置分账接收方账号, 换成自己的接收方账号
receiver1.setAccount("oWBG560SZ8P_xxxxxxxxxxxxxx");
// 设置分账金额, 这里测试金额为1分, 默认最高只能分订单的30%
receiver1.setAmount(1L);
// 设置分账描述
receiver1.setDescription(description);
// 设置分账接收方列表
receivers.add(receiver1);
request.setReceivers(receivers);
// 设置是否解冻剩余资金
if (TRUE_UNFREEZE_UNSPLIT.equals(unfreezeUnsplit)) request.setUnfreezeUnsplit(Boolean.TRUE);
if (FALSE_UNFREEZE_UNSPLIT.equals(unfreezeUnsplit)) request.setUnfreezeUnsplit(Boolean.FALSE);
try {
// 请求微信服务器发起分账请求
OrdersEntity response = profitsharingService.createOrder(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 查询分账结果
* @param outOrderNo 商户分账单号
* @param transactionId 微信订单号
* @return 结果
* 发起分账请求后,可调用此接口查询分账结果
* 发起解冻剩余资金请求后,可调用此接口查询解冻剩余资金的结果
*/
@Override
@Transactional
public R<?> sharingResult(String outOrderNo, String transactionId) {
QueryOrderRequest request = new QueryOrderRequest();
// 1. 设置微信订单号
request.setTransactionId(transactionId);
// 2. 设置商户订单号
request.setOutOrderNo(outOrderNo);
try {
// 请求微信服务器查询分账结果
OrdersEntity response = profitsharingService.queryOrder(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 请求分账回退
* @param orderId 微信分账单号
* @param returnMchid 回退商户号
* @param description 回退描述
* @return 结果
* 如果订单已经分账,在退款时,可以先调此接口,将已分账的资金从分账接收方的账户回退给分账方,再发起退款。
* 分账回退以原分账单为依据,支持多次回退,申请回退总金额不能超过原分账单分给该接收方的金额
* 此接口采用同步处理模式,即在接收到商户请求后,会实时返回处理结果
* 对同一笔分账单最多能发起20次分账回退请求
* 退款和分账回退没有耦合,分账回退可以先于退款请求,也可以后于退款请求
* 此功能需要接收方在商户平台-交易中心-分账-分账接收设置下,开启同意分账回退后,才能使用
* 不支持针对“分账到零钱”的分账单发起分账回退。
* 分账回退的时限是180天。
*/
@Override
public R<?> returnSharing(String orderId, String returnMchid, String description) {
CreateReturnOrderRequest request = new CreateReturnOrderRequest();
// 生成商户回退单号
String outReturnNo = System.currentTimeMillis() + String.valueOf(new Random().nextInt(999999));
// 设置微信分账单号
request.setOrderId(orderId);
// 设置回退商户号
request.setReturnMchid(returnMchid);
// 设置商户回退单号
request.setOutReturnNo(outReturnNo);
// 设置回退金额, 这里测试金额为1分
request.setAmount(1L);
// 设置回退描述
request.setDescription(description);
try {
// 请求微信服务器发起分账回退请求
ReturnOrdersEntity response = profitsharingService.createReturnOrder(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 查询分账回退结果
* @param outReturnNo 商户回退单号
* @param outOrderNo 商户订单号
* @return 结果
* 商户需要核实回退结果,可调用此接口查询回退结果。
* 如果分账回退接口返回状态为处理中,可调用此接口查询回退结果
*/
@Override
public R<?> returnSharingResult(String outReturnNo, String outOrderNo) {
QueryReturnOrderRequest request = new QueryReturnOrderRequest();
// 1. 设置商户回退单号
request.setOutReturnNo(outReturnNo);
// 2. 设置商户订单号
request.setOutOrderNo(outOrderNo);
try {
// 请求微信服务器查询分账回退结果
ReturnOrdersEntity response = profitsharingService.queryReturnOrder(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 解冻剩余资金
* @param transactionId 微信订单号
* @param outOrderNo 商户分账单号
* @param description 描述信息
* @return 结果
* 不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给本商户
* 调用分账接口后,需要解冻剩余资金时,调用本接口将剩余的分账金额全部解冻给本商户
* 此接口采用异步处理模式,即在接收到商户请求后,优先受理请求再异步处理,最终的分账结果可以通过查询分账接口获取
*/
@Override
public R<?> unfreeze(String transactionId, String outOrderNo, String description) {
UnfreezeOrderRequest request = new UnfreezeOrderRequest();
// 1. 设置微信订单号
request.setTransactionId(transactionId);
// 2. 设置商户订单号
request.setOutOrderNo(outOrderNo);
// 3. 设置描述信息
request.setDescription(description);
try {
// 请求微信服务器发起解冻剩余资金请求
OrdersEntity response = profitsharingService.unfreezeOrder(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 查询剩余待分金额
* @param transactionId 微信订单号
* @return 结果
* 可调用此接口查询订单剩余待分金额
*/
@Override
public R<?> sharingAmountBalance(String transactionId) {
QueryOrderAmountRequest request = new QueryOrderAmountRequest();
// 设置微信订单号
request.setTransactionId(transactionId);
try {
// 请求微信服务器查询剩余待分金额
QueryOrderAmountResponse response = profitsharingService.queryOrderAmount(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 查询分账比例
* @param mchId 商户号
* @return 结果
*/
@Override
public R<?> sharingRatio(String mchId) {
QueryMerchantRatioRequest request = new QueryMerchantRatioRequest();
// 设置分账接收方商户号
request.setSubMchid(mchId);
try {
// 请求微信服务器查询分账比例
QueryMerchantRatioResponse response = profitsharingService.queryMerchantRatio(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
/**
* 下载分账账单
* @param billDate 分账账单日期
* @param billType 分账账单类型
* @return 结果
* 微信支付按天提供分账账单文件,商户可以通过该接口获取账单文件的下载地址。文件内包含分账相关的金额、时间等信息,供商户核对到账等情况
* 微信侧未成功的分账单不会出现在对账单中。
* 对账单中涉及金额的字段单位为“元”;
* 对账单接口只能下载三个月以内的账单。
* 账单文件包括明细数据和汇总数据两部分,每一部分都包含一行表头和若干行具体数据。
* 明细数据每一行对应一笔分账或一笔回退,同时每一个数据前加入了字符`,以避免数据被Excel按科学计数法处理。如需汇总金额等数据,可以批量替换掉该字符
*/
@Override
public R<?> downloadBill(String billDate, String billType) {
SplitBillRequest request = new SplitBillRequest();
// 1. 设置账单日期
request.setBillDate(billDate);
if(billType != null && !billType.isEmpty()){
// 2. 设置账单类型
request.setTarType(SplitBillTarType.GZIP);
}
try {
// 请求微信服务器下载分账账单
SplitBillResponse response = profitsharingService.splitBill(request);
return R.ok(response);
} catch (ServiceException e) {
return R.fail(e.getHttpStatusCode(), e.getErrorMessage());
}
}
}
常量类集合
- SharingReceiverType
/**
* @author Ccoo
* 2024/3/8
*/
public class SharingReceiverType {
/**
* 商户号
*/
public static final String MERCHANT_ID = "MERCHANT_ID";
/**
* 个人OpenID
*/
public static final String PERSONAL_OPENID = "PERSONAL_OPENID";
/**
* 个人SubOpenID
*/
public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID";
}
- SharingReceiverRelationType
/**
* @author Ccoo
* 2024/3/8
*/
public class SharingReceiverRelationType {
/**
* 服务商
*/
public static final String SERVICE_PROVIDER = "SERVICE_PROVIDER";
/**
* 门店
*/
public static final String STORE = "STORE";
/**
* 员工
*/
public static final String STAFF = "STAFF";
/**
* 店主
*/
public static final String STORE_OWNER = "STORE_OWNER";
/**
* 合作伙伴
*/
public static final String PARTNER = "PARTNER";
/**
* 总部
*/
public static final String HEADQUARTER = "HEADQUARTER";
/**
* 品牌方
*/
public static final String BRAND = "BRAND";
/**
* 分销商
*/
public static final String DISTRIBUTOR = "DISTRIBUTOR";
/**
* 用户
*/
public static final String USER = "USER";
/**
* 供应商
*/
public static final String SUPPLIER = "SUPPLIER";
/**
* 自定义
*/
public static final String CUSTOM = "CUSTOM";
}
- R 统一响应类
import java.io.Serializable;
/**
* 响应信息主体
*
* @author Ccoo
*/
public class R<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = 200;
/** 失败 */
public static final int FAIL = 500;
private int code;
private String msg;
private T data;
public static <T> R<T> ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(String msg)
{
return restResult(null, SUCCESS, msg);
}
public static <T> R<T> ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail()
{
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg)
{
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
}