<?php
use app\common\model\WxSubMember;
use think\Controller;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
class WechatSub
{
/** 准备部分
* 1.文档(v3分账) https://pay.weixin.qq.com/docs/merchant/products/profit-sharing/apilist.html
* 2.商户号 munch_id
* 3.商户私钥--merchantPrivateKey--商户平台开可以下载
* 4.商户证书序列号--merchantCertSerialNo--商户平台可以下载
* 5.微信支付平台证书--自己在本地生成--具体步骤见其他控制器
* 6. sdk-- composer require wechatpay/wechatpay
* 7. 支付订单的是否需要传分账标识profit_sharing--true/false
*/
/**
* @return \WeChatPay\BuilderChainable
*/
public function getInstance(): \WeChatPay\BuilderChainable
{
$merchantId = '商户号';
// 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
$merchantPrivateKeyFilePath = '商户私钥的文件路径';
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 「商户API证书」的「证书序列号」
$merchantCertificateSerial = '证书序列号';
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
$platformCertificateFilePath = '自己生成的微信平台证书的路径';
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 从「微信支付平台证书」中获取「证书序列号」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
// 构造一个 APIv3 客户端实例
$instance = Builder::factory([
'mchid' => $merchantId,
'serial' => $merchantCertificateSerial,
'privateKey' => $merchantPrivateKeyInstance,
'certs' => [
$platformCertificateSerial => $platformPublicKeyInstance,
],
]);
// 加密敏感信息
$encryptor = static function (string $msg) use ($platformPublicKeyInstance): string {
return \WeChatPay\Crypto\Rsa::encrypt($msg, $platformPublicKeyInstance);
};
return $instance;
}
/**
* 特别注意
* 1.微信分账的订单在下单支付的时候 需要把订单的分账标识打开,在实际业务中可根据自身情况灵活控制
* 2.微信没有查询分账接收方这个接口,需要自己建表把分账接收方存起来
* 3.微信的分账产品开通容易但是提升额度比较困难,最大支持30的比例,30的意思是100元中最多有30元可以分出去,不是每个人最多30,若需要提高比例则要向微信提出书面申请
*/
private function getEncrypt($str)
{
//$str是待加密字符串
$public_key_path = $this->public_path() . 'static/cert/3.pem';
$public_key = file_get_contents($public_key_path);
$encrypted = '';
if (openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
//base64编码
$sign = base64_encode($encrypted);
} else {
throw new Exception('encrypt failed');
}
return $sign;
}
/**
* 添加分账接收方
*/
public function addWxMember($user)
{
// $user数组
$instance = $this->getInstance();
$resp = $instance->chain('v3/profitsharing/receivers/add')->post(
[
'debug' => false,
'json' => [
'appid' => 'wx7ac5a73893c2c6b8',
'type' => 'PERSONAL_OPENID',
'account' => $user['account'],
//'name' => $this->getEncrypt('name'), //如果给商户分账 这个name字段必传
'relation_type' => 'USER'
]
]
// 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
);
$response = json_decode($resp->getBody()->getContents(), true);
/**
* 返回数据示例
* "type" : "MERCHANT_ID",
* "account" : "example_account",
* "name" : "example_name",
* "relation_type" : "SERVICE_PROVIDER",
* "custom_relation" : "example_custom_relation"
*/
if ($response) {
// wx没有查询分账接收方这一接口,所以微信分账添加或删除接收方都需要自己存到数据库--(微信分账接收方表)
$data = [];
$data['account'] = $user['account'];
$data['type'] = 'PERSONAL_OPENID';
$data['createtime'] = time();
WxSubMember::create($data);
return true;
} else {
return false;
}
//halt(json_decode($resp->getBody()->getContents(), true), PHP_EOL);
//return $response;
}
/**
* 删除分账接收方
*/
public function deleteWxMember($user)
{
// 商户号
$instance = $this->getInstance();
// 发送请求 auth证书
$resp = $instance->chain('v3/profitsharing/receivers/delete')->post(
[
'debug' => false,
'json' => [
'appid' => $user['appid'],
'type' => $user['type'],
'account' => $user['openid'],
//'name' => $encryptor('a'),//如果是给商户进行分账时会用到这个
],
]
// 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
);
$response = json_decode($resp->getBody()->getContents(), true);
if ($response) {
WxSubMember::where('id', '=', $user['id'])->delete();
return true;
} else {
return false;
}
}
/**
* 分账
*/
public function subWx($orderInfo)
{
// 商户号
$instance = $this->getInstance();
//组装分账接收方数据
$data = [];
//业务逻辑部分,如果是多人请用二维数组
$aa = [
'type' => 'PERSONAL_OPENID',
'account' => '填写分账接收方的openid',
'amount' => 1,//单位是分
'description' => '完成首单返佣'
];
$data[] = $aa;
try {
$resp = $instance->chain('v3/profitsharing/orders')->post(
[
'debug' => false,
'json' => [
'appid' => 'wx7ac5a73893c2c6b8',
'transaction_id' => $orderInfo->wx_order_num,//微信订单号(微信官方生成的订单号)
'out_order_no' => '分账请求订单号',//内部分账单号,自己生成,用这个订单号查询分账是否完成
'receivers' => $data,
'unfreeze_unsplit' => true //如果为false,该笔订单剩余未分账的金额不会解冻回分账方商户,可以对该笔订单再次进行分账。
]
] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
);
} catch (\Throwable $e) {
halt($e->getMessage());
}
$result = json_decode($resp->getBody()->getContents(), true);
//halt(json_decode($resp->getBody()->getContents(), true), PHP_EOL);
if ($result) {
return true;
} else {
return false;
}
}
/**
* 查询分账结果
*/
public function getWxSubData($data)
{
//todo 待测
$instance = $this->getInstance();
$response = $instance->chain('v3/transactions/split/query')->get([
'transaction_id' => $data['transaction_id'],//支付订单号
]);
$result = json_decode($response->getBody(), true);
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
// 输出分账结果
echo "分账结果查询成功,分账单号:{$result['split_id']},分账金额:{$result['split_amount']}";
} else {
// 输出错误信息
echo "分账结果查询失败,错误代码:{$result['return_code']},错误信息:{$result['return_msg']}";
}
}
}
最后检测日期:2023/10/09
