热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

功能总结_微信服务商的分账功能总结

本文由编程笔记#小编为大家整理,主要介绍了微信服务商的分账功能总结相关的知识,希望对你有一定的参考价值。概要基于官方文档:服务商分账接口文档,根据我们自身的需求开发功能。此
本文由编程笔记#小编为大家整理,主要介绍了微信服务商的分账功能总结相关的知识,希望对你有一定的参考价值。

概要
基于官方文档:服务商分账接口文档 ,根据我们自身的需求开发功能。此文为开发后的总结和思考。

分析文档
先搞清楚官方接口能干嘛,不能干嘛。

一、能干(的功能)
1. 角色
服务商
子商户(特约商户)
2. 开通分账
(服务商联系运营开通产品白名单后,才可在产品中心看到此功能)
开通流程文档里已经很详细了。只要一步步按着操作就 ok 。
简单总结就是服务商首先有这个产品,邀请子商户授权同意。跟 服务商退款 授权流程一样。
服务商发出邀请后,子商户后台 消息中心 (其它路径我真的找不到)可看到该邀请的信息,进入输入允许分账金额的 最大比例 (例如 20%)以及可选择是否上传与服务商签订的协议。

3. API
文档提供了 6 个接口。主要是发起分账、查询分账结果、分账接收方添加/删除和完结分账几个功能。
其中的 请求单次分账 和 请求多次分账 ,我根据我们的场景选择了单次的,后面会讲到。完结分账 没有用到。所以我这次用到的只有其中 4 个。

4. 特点
增加了分账标识参数并且参数值为「Y」的订单,它们的金额会被冻结为「待分账资金」。冻结资金即暂时不可以挪为它用(比如提供给其它订单的退款金,这是不能的)。
分账之前,会在例如「20%」的资金里先扣除结算手续费之后,才是可分账的金额。
由 添加分账接收方 接口文档可知,接收方类型支持商户及个人微信。
二、不能干
发起分账请求后,没有回调通知分账的结果。类似 付款码支付API 。
必须跑的是子商户模式。
文档没有说明,发起分账请求后,多久能分账成功。根据实际经验,大概需要 1 分钟以内的时间。也因为这是时间的不确定性,我没有使用付款码支付API 那样的轮询处理查询结果的方式。这是两原因之一。
分账只能按照订单维度进行。1
分析需求
一、功能设置
每个子商户可决定是否使用分账、分账的最大金额,查看是否已达最大金额,设置隔「a」天分账一次( a <30)2,分账的比例「b」,合同图片,分账接收人列表;
每个分账接收人的设置,类型,帐号,名称,描述,最大可得金额,是否已达最大金额,分账比例「c」(可分账金额为订单金额 * (1 - 0.006) * b% * c%)。0.6% 为结算手续费;
商户除了用分账功能给服务商付费之外,也可给其合作的其它商户或个人进行分账。只需要把其它商户添加进分账接收人里。
二、分账的执行
定时任务,每天执行一次,查询是否有需要分账(最近分账记录至今超过「a」天)的商户(未超过最大金额)。
查询「a」天内的订单,分别执行分账。
以订单维度执行分账时,获取未达到最大金额的接收人,给接收人分账。
即将超过最大金额的商家,为了防止超过最大金额的分账订单,需要增加判断。判断此次分账的金额(订单金额 * 分账比例)是否大于剩余分账金额(最大 - 已分账金额),若大于,则分账金额替换为剩余的分账金额,继续执行分账,并且分账后更新商户「是否已达最大金额」为 true。
三、分账的记录
每笔订单执行一次分账操作就新增一条「分账记录表」的记录。
每一条分账记录对应多条「分账记录详情表」记录,与接受方一对一。
实际分账成功的金额需要根据「分账记录详情表」进行统计。
还需要「分账设置表」、「分账接收方记录表」。
开发
一、数据库字段设计
1. 分账设置表
mid 「商家 id」
is_sharing 「是否开启分账,0=否」
is_max 「是否已达最大金额,0=否」
max_amount 「分账最大金额」
shared_amount 「已分账的金额」
share_interval 「隔几天分账一次」
ratio 「分账比例」
compact_img 「合同图片地址」
其它
2. 分账接收方记录表
mid 「商家 id」
type 「分账接收方类型」
account 「分账接收方帐号」
name 「商户全称或个人姓名」
description 「分账的原因描述」
is_max 「是否已达最大金额,0=否」
max_amount 「分账最大可得金额」
ratio 「分账比例」
其它
3. 分账记录表
order_id 「订单id」
mid 「商家 id」
share_no 「分账的单号」
status 「分账结果」
close_reason 「关单原因」
其它
4. 分账记录详情表
record_id 「分账记录表的id」
receiver_id 「分账接收人表的id」
amount 「分账金额」
status 「分账结果」
fail_reason 「分账失败原因」
其它
二、接口对接(php7、TP5.0.24)
涉及详细逻辑的均为伪代码。

1. 获取分账签名
参考了 EasyWeChat3 源码里 生成签名 的方法:

//获取签名
private function getSign($params, $key)
{
ksort($params);
$params[‘key‘] = $key;
$sign = strtoupper(call_user_func_array(‘hash_hmac‘, [‘sha256‘, urldecode(http_build_query($params)), $key]));
$params[‘sign‘] = $sign;
return $params;
}

2. 生成带分账签名的参数

/**
* @param $mid int 商户的 id
* @param $moreParam array 更多的其它参数
* @param bool $isQuery
* @return array 返回带分账签名的参数
* @throws Exception
*/
private function getParamWithSign($mid, $moreParam, $isQuery = false)
{
//获取服务商及子商户配置信息
$payCOnfig= $this->payConfig;
//整理生成签名的参数
$params = [
‘mch_id‘ => $payConfig[‘mch_id‘],
‘sub_mch_id‘ => $subAppConfig[‘sub_mch_id‘],
‘appid‘ => $payConfig[‘appid‘],
‘sub_appid‘ => $subAppConfig[‘sub_app_id‘],
‘nonce_str‘ => uniqid(),
‘sign_type‘ => ‘HMAC-SHA256‘
];
if ($isQuery) { //「查询分账结果」无此参数,去除
unset($params[‘appid‘], $params[‘sub_appid‘]);
}
$params = array_merge($params, $moreParam);
//获取签名
$params = $this->getSign($params, $payConfig[‘key‘]);
return $params;
}


3. 封装发送分账相关请求
private function postXml($dataArray, $url, $cert = [])
{
$dataXml = $this->arrayToXml($dataArray, false); //数组转换成 xml 的方法,网上搜的
$res = HttpClient::curl_post($url, $dataXml, $cert); //关于 cUrl 我们自己封装的方法,也可使用扩展「guzzlehttp/guzzle」
$resArray = $this->xmlToArray($res); //转换方法
//返回结果预处理
if (array_key_exists("return_code", $resArray) &&
$resArray[‘return_code‘] == ‘FAIL‘) throw new Exception($resArray[‘return_msg‘]);
if (!array_key_exists("return_code", $resArray)
|| !array_key_exists("result_code", $resArray)) {
throw new Exception("接口调用失败!");
}
if ($resArray[‘result_code‘] != ‘SUCCESS‘) {
//日志记录了 ‘result_code 不等于「SUCCESS」的反馈
throw new Exception($resArray[‘err_code_des‘]);
}
return $resArray;
}

剩下的就简单了。

4. 简单示例
/** 删除分账接收人
* @param $mid int 商家的 id
* @param $receiver
* @return array|bool
*/
public function removeReceiver($mid, $receiver)
{
$params[‘receiver‘] = json_encode($receiver, JSON_UNESCAPED_UNICODE);
$dataArray = $this->getParamWithSign($mid, $params);
$url = ‘https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver‘; // 接口 url
return $this->postXml($dataArray, $url);
}

5. 发起分账需要双向证书
可在封装的 cUrl 方法中设置证书,参考如下:

curl_setopt_array($curl, [
CURLOPT_SSLCERT => $cert[‘cert_path‘], // 客户端证书,用于双向认证
CURLOPT_SSLCERTTYPE => $cert[‘cert_type‘], // 证书的类型。支持的格式有"PEM" (默认值), "DER"和"ENG"。
CURLOPT_SSLKEY => $cert[‘key_path‘], // 客户端私钥的文件路径
CURLOPT_SSLKEYTYPE => $cert[‘key_type‘], // 客户端私钥类型,支持的私钥类型为"PEM"(默认值)、"DER"和"ENG"。
CURLOPT_KEYPASSWD => $cert[‘key_password‘], // 客户端私钥密码,私钥在创建时可以选择加密。
]);

其中,◆ API证书调用或安装需要使用到密码,该密码的值为微信商户号(mch_id)4 里的「商户号」为服务商商户号。证书和密钥为两个 .pem 文件的路径。

三、逻辑处理
以下为根据需求开发的业务逻辑,仅为我的梳理总结。

获取需要分账的商户的配置,并关联查询已添加的分账接收方信息 => $configs;
foreach ($configs as $config) {
$this->toShareForOneSeller($config);
}
1
2
3
为单个商户的设定时间段内的订单发起分账
private function toShareForOneSeller(&$config)
{
//查询最新分账记录
$recordModel = new SellerProfitSharingRecord();
$lastRecord = $recordModel->getLastRecord($config[‘sid‘]);
//如果最新分账记录存在且时间超过设置时间,或记录不存在,则需要分账
$lastRecordDate = $lastRecord[‘create_time‘] ?? null;
$tillNow = time() - strtotime($lastRecordDate);
if (!$lastRecord || $tillNow > $config[‘share_date‘] * 86400) {
//查询更新并获取该商户的已分账金额
$recordModel->refreshSharedAmount($config[‘sid‘]); //用到「查询分账结果」的接口,查询后更新数据库
$sharedAmount = $recordModel->getSharedAmount($config[‘sid‘]);
//更新已分账金额
$cOnfigModel= new SellerProfitSharingConfig();
$configModel->updateSharedAmount($sharedAmount[‘seller‘], $config[‘sid‘]);
if ($config[‘max_amount‘] > $sharedAmount[‘seller‘]) { //未到达最大分账金额
//按时间间隔获取需要分账的订单信息
$orderModel = new Order();
$orderInfo = $orderModel->getOrderNeedShare($config);
if (!$orderInfo) return true; //因为需要使用计划任务定时执行,所以不需要抛出异常
foreach ($orderInfo as $order) {
$shareNo = ‘P01‘ . date(‘ymdHis‘) . rand(1000, 9999); //分账单号
$canShareAmount = bcmul($order[‘real_amount‘], $config[‘ratio‘] / 100, 2);
//判断该商户是否已达到最大分账金额
if ($config[‘max_amount‘] <$canShareAmount + $sharedAmount[‘seller‘]) {
$canShareAmount = bcsub($config[‘max_amount‘], $sharedAmount[‘seller‘], 2);
}
// 0.6% 的结算手续费
$serviceCharge = bcmul($order[‘real_amount‘], 0.006, 2);
$canShareAmount = $canShareAmount - $serviceCharge;
//新增记录及处理分账
$res = $recordModel->addRecordWithSharing($order, $shareNo, $canShareAmount, $sharedAmount, $config);
if ($res) $sharedAmount[‘seller‘] = bcadd($sharedAmount[‘seller‘], $canShareAmount, 2);
}
} else {
//更新商家分账状态为已到达最大分账金额
$configModel->updateToIsMax($config[‘sid‘]);
}
}
return true;
}

四、计划任务批量处理
crontab 定时执行上述逻辑方法。

文档里的分账接口 - 常见问题 的注意事项 ??

注意事项 - 分账资金的冻结期默认是30天 ??

一个开源的微信非官方 SDK ??

使用API证书 ??
————————————————


推荐阅读
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本文详细介绍了如何在云服务器上配置Nginx、Tomcat、JDK和MySQL。涵盖从下载、安装到配置的完整步骤,帮助读者快速搭建Java Web开发环境。 ... [详细]
  • 本文详细介绍了虚拟专用网(Virtual Private Network, VPN)的概念及其通过公共网络(如互联网)构建临时且安全连接的技术特点。文章探讨了不同类型的隧道协议,包括第二层和第三层隧道协议,并提供了针对IPSec、GRE以及MPLS VPN的具体配置指导。 ... [详细]
  • 2017-2018年度《网络编程与安全》第五次实验报告
    本报告详细记录了2017-2018学年《网络编程与安全》课程第五次实验的具体内容、实验过程、遇到的问题及解决方案。 ... [详细]
  • 本文介绍了如何在多线程环境中实现异步任务的事务控制,确保任务执行的一致性和可靠性。通过使用计数器和异常标记字段,系统能够准确判断所有异步线程的执行结果,并根据结果决定是否回滚或提交事务。 ... [详细]
  • 本文详细介绍了如何在不同操作系统和设备上设置和配置网络连接的IP地址,涵盖静态和动态IP地址的设置方法。同时,提供了关于路由器和机顶盒等设备的IP配置指南。 ... [详细]
  • 本文介绍如何在Spring Boot项目中集成Redis,并通过具体案例展示其配置和使用方法。包括添加依赖、配置连接信息、自定义序列化方式以及实现仓储接口。 ... [详细]
  • 利用Selenium与ChromeDriver实现豆瓣网页全屏截图
    本文介绍了一种使用Selenium和ChromeDriver结合Python代码,轻松实现对豆瓣网站进行完整页面截图的方法。该方法不仅简单易行,而且解决了新版Selenium不再支持PhantomJS的问题。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • 本文详细介绍了 phpMyAdmin 的安装与配置方法,适用于多个版本的 phpMyAdmin。通过本教程,您将掌握从下载到部署的完整流程,并了解如何根据不同的环境进行必要的配置调整。 ... [详细]
  • 本文详细介绍如何使用 Apache Spark 执行基本任务,包括启动 Spark Shell、运行示例程序以及编写简单的 WordCount 程序。同时提供了参数配置的注意事项和优化建议。 ... [详细]
  • 当unique验证运到图片上传时
    2019独角兽企业重金招聘Python工程师标准model:public$imageFile;publicfunctionrules(){return[[[na ... [详细]
author-avatar
陈婉恩上源
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有