gaooooge / easyhuifu
A PHP library for Huifu payments, onboarding, payouts, refunds, and reference data access.
v0.1.5
2026-04-13 02:34 UTC
Requires
- php: >=7.1.0
- huifurepo/dg-php-sdk: ^2.0
README
easyhuifu 是一个面向 PHP 的汇付能力封装包,用于统一管理配置、SDK 初始化、请求发送、响应解析及异常处理。
功能概览
- 交易支付下单
- 微信 APP 支付
- 支付宝支付(JS/正扫,可用于 APP 拉起支付宝)
- 支付查询
- 支付关单
- 延迟分账与交易确认
- 余额打款
- 扫码退款
- 个人进件
- 企业进件
- 业务开通
- 进件回显
- 进件档案快照持久化
- 联行号字典查询
- 汇付地区编码查询
目录结构
src/Application.php统一入口,负责组装配置、工厂和业务服务src/Config.php配置读取封装src/bootstrap.php汇付 SDK 自动加载兼容处理src/Foundation/BsPayClientFactory.phpSDK 初始化及客户端工厂src/Service/PayService.php交易支付服务src/Service/PayoutService.php余额打款服务src/Service/RefundService.php退款服务src/Service/EntryService.php进件与业务开通服务src/Contracts/*扩展接口定义src/Support/*默认支持组件与本地字典仓储data/*联行号与地区编码参考数据docs/THINKPHP_ADAPTER.mdThinkPHP 接入说明examples/*可复制示例
安装
1. 直接安装(推荐)
composer require gaooooge/easyhuifu:^0.1.5
2. 从 Git 仓库安装
在目标项目 composer.json 中增加:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/gaooooge/easyhuifu"
}
],
"require": {
"gaooooge/easyhuifu": "^0.1.5"
}
}
然后执行:
composer update gaooooge/easyhuifu
3. 本地 Path 联调
{
"repositories": [
{
"type": "path",
"url": "../easyhuifu"
}
],
"require": {
"gaooooge/easyhuifu": "^0.1.5"
}
}
初始化
use EasyHuifu\Application; $huifu = new Application([ 'sys_id' => '666600010000001', 'product_id' => '1234567890', 'rsa_private_key' => 'your-private-key', 'rsa_public_key' => 'huifu-public-key', 'upper_huifu_id' => '666600010000001', 'notify_url' => 'https://your-domain.com/payment/huifu/notify', 'prod_mode' => true, ]);
服务入口
$huifu->pay(); $huifu->payout(); $huifu->refund(); $huifu->split(); $huifu->entry(); $huifu->bankBranches(); $huifu->regions();
配置说明
必填配置
sys_id汇付系统号product_id产品号rsa_private_key商户私钥rsa_public_key汇付公钥
可选配置
upper_huifu_id上级汇付号;未传时默认回退sys_idmerchant_keySDK 内部实例标识;未传时自动生成prod_mode是否生产环境,默认truenotify_url默认支付回调地址ljh_data业务开通附加配置hxy_data业务开通附加配置
支付
支付下单
$pay = $huifu->pay()->miniApp([ 'amount' => 0.01, // 支付金额(元) 'goods_desc' => '订单支付', // 商品描述 'order_no' => 'M202603120001', // 业务订单号 'notify_url' => 'https://your-domain.com/payment/huifu/notify', // 支付回调地址 'sub_appid' => 'wx1234567890abcdef', // 微信子应用 appid 'sub_openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o', // 用户 openid ]);
也可以使用:
$huifu->pay()->create([...]); $huifu->pay()->jsPay([...]); $huifu->pay()->app([...]); // 微信 APP 或 APP 拉起支付宝 $huifu->pay()->alipay([...]); // 支付宝 JS 支付 $huifu->pay()->alipayNative([...]); // 支付宝正扫 $huifu->pay()->alipayApp([...]); // APP 拉起支付宝,别名同 alipayNative()
微信 APP 支付示例
$pay = $huifu->pay()->app([ 'amount' => 0.01, 'goods_desc' => '订单支付', 'order_no' => 'M202603120002', 'notify_url' => 'https://your-domain.com/payment/huifu/notify', 'sub_appid' => 'wx1234567890abcdef', ]);
支付宝 APP 拉起示例
$pay = $huifu->pay()->alipayApp([ 'amount' => 0.01, 'goods_desc' => '订单支付', 'order_no' => 'M202603120003', 'notify_url' => 'https://your-domain.com/payment/huifu/notify', 'subject' => '订单支付', ]);
说明:
alipayApp()默认走A_NATIVE- 返回结果里的
qr_code可交给移动端按支付宝 APP 拉起方案处理 - 如需自己控制参数,也可直接调用
app(['trade_type' => 'A_NATIVE', ...])
返回结果示例
[
'req_seq_id' => 'rQ20260312123000123456789012345678',
'req_date' => '20260312',
'huifu_id' => '666600010000001',
'resp_code' => '00000100',
'resp_desc' => '成功',
'trade_type' => 'T_MINIAPP',
'pay_info' => [
'package' => 'prepay_id=wx...',
'timeStamp' => '1710211200',
'nonceStr' => 'abc123',
'signType' => 'RSA',
'paySign' => 'xxxx',
],
'qr_code' => null,
'response' => [...],
]
支付参数
amount必填,支付金额notify_url必填;未传时读取初始化配置中的默认值goods_desc可选,商品描述,默认订单支付order_no可选,业务订单号;默认透传到remarkreq_seq_id可选,自定义请求流水号huifu_id可选,默认使用配置中的sys_idtrade_type可选;不传时根据pay_source推断pay_source可选;wx/wxapp/miniapp映射为T_MINIAPP,mp/jsapi映射为T_JSAPI,app映射为T_APP,alipay/native/appzfb映射为A_NATIVEsub_appid微信子应用appid;微信 APP 支付也可复用sub_openid微信子应用下用户openidwx_data可选,微信参数集合;支持数组或 JSON 字符串alipay_data可选,支付宝参数集合;支持数组或 JSON 字符串method_expand可选,统一下单接口扩展参数;传入后优先级高于wx_data/alipay_datasubject可选,支付宝交易标题;未传时回退goods_descbuyer_id可选,支付宝买家用户号;JS 支付场景常用delay_acct_flag可选,是否延迟分账,Y为开启,默认Nacct_split_bunch可选,延迟分账明细;支持数组或 JSON 字符串
延迟分账示例
$pay = $huifu->pay()->miniApp([ 'amount' => 0.01, // 支付金额(元) 'goods_desc' => '订单支付', // 商品描述 'order_no' => 'M202603120001', // 业务订单号 'notify_url' => 'https://your-domain.com/payment/huifu/notify', // 支付回调地址 'sub_appid' => 'wx1234567890abcdef', // 微信子应用 appid 'sub_openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o', // 用户 openid 'delay_acct_flag' => 'Y', // 开启延迟分账 'acct_split_bunch' => [ 'acct_infos' => [ [ 'div_amt' => '0.0030', // 分账金额 'huifu_id' => '666600010000002', // 分账接收方汇付号 ], [ 'div_amt' => '0.0020', // 分账金额 'huifu_id' => '666600010000003', // 分账接收方汇付号 ], ], ], ]);
说明:
delay_acct_flag = Y表示按延迟分账处理acct_split_bunch.acct_infos[*].huifu_id为分账接收方汇付号acct_split_bunch.acct_infos[*].div_amt为预分账金额- 该参数仅随支付请求一并提交,不代表最终分账已执行
支付查询
$query = $huifu->pay()->query([ 'org_req_seq_id' => 'rQ20260312123000123456789012345678', 'org_req_date' => '20260312', ]);
可用于查询的原始标识:
out_ord_idorg_hf_seq_idorg_req_seq_id
支付关单
$close = $huifu->pay()->close([ 'org_req_seq_id' => 'rQ20260312123000123456789012345678', 'org_req_date' => '20260312', ]);
打款
$result = $huifu->payout()->payToActor([ 'role_type' => 'supplier', // 主体类型 'actor_id' => 20001, // 主体 ID 'app_id' => 10000, // 应用 ID 'amount' => 88.00, // 打款金额(元) 'remark' => '供应商提现打款', // 业务备注 ]);
打款参数
amount必填,打款金额remark可选,备注huifu_id可选;直接指定收款主体汇付号role_type可选;未传huifu_id时建议传入actor_id可选;未传huifu_id时建议传入app_id可选,多应用场景下用于优先匹配进件档案out_huifu_id可选,默认使用sys_id
退款
$result = $huifu->refund()->scanPay([ 'huifu_req_seq_id' => 'rQ202603120001', // 原支付请求流水号 'transaction_id' => '0036000123456789', // 原支付全局流水号 'pay_time' => time(), // 原支付时间 ], 10.00, 'refund202603120001'); // 退款金额、退款单号
别名方法:
$result = $huifu->refund()->refund($order, 10.00, 'refund202603120001');
延迟分账确认
$confirm = $huifu->split()->confirm([ 'huifu_id' => '666600010000001', // 发起方汇付号 'org_req_seq_id' => 'rQ20260312123000123456789012345678', // 原支付请求流水号 'org_req_date' => '20260312', // 原支付请求日期 'pay_type' => 'ACCT_PAYMENT', // 交易类型 'acct_split_bunch' => [ 'acct_infos' => [ [ 'div_amt' => '0.0030', // 分账金额 'huifu_id' => '666600010000002', // 分账接收方汇付号 ], [ 'div_amt' => '0.0020', // 分账金额 'huifu_id' => '666600010000003', // 分账接收方汇付号 ], ], ], 'remark' => 'order split confirm', ]);
延迟分账确认查询
$query = $huifu->split()->confirmQuery([ 'huifu_id' => '666600010000001', 'org_req_seq_id' => 'rS20260312123500123456789012345678', 'org_req_date' => '20260312', ]);
延迟分账确认退款
$refundConfirm = $huifu->split()->confirmRefund([ 'huifu_id' => '666600010000001', 'org_req_seq_id' => 'rS20260312123500123456789012345678', 'org_req_date' => '20260312', 'acct_split_bunch' => [ 'acct_infos' => [ [ 'div_amt' => '0.0010', 'huifu_id' => '666600010000002', ], ], ], 'remark' => 'split confirm refund', ]);
进件
个人进件 + 业务入驻(组合调用)
$result = $huifu->entry()->openIndividual([ 'name' => '测试用户', // 姓名 'cert_no' => '3301xxxxxxxxxxxx', // 证件号 'mobile_no' => '13800000000', // 手机号 'cert_type' => '00', // 证件类型 'card_no' => '6222xxxxxxxxxxxx', // 结算银行卡号 'prov_id' => '310000', // 开户省编码 'area_id' => '310100', // 开户市编码 'bank_code' => '01050000', // 开户总行编码 'branch_code' => '105290071008', // 开户支行联行号 ]);
企业进件 + 业务入驻(组合调用)
$result = $huifu->entry()->openEnterprise([ 'reg_name' => '测试企业', // 企业注册名称 'license_code' => '9131xxxxxxxxxxxx', // 统一社会信用代码 'contact_name' => '张三', // 联系人姓名 'contact_mobile' => '13800000000', // 联系人手机号 'legal_name' => '张三', // 法人姓名 'legal_cert_no' => '3301xxxxxxxxxxxx', // 法人证件号 'bank_code' => '01050000', // 开户总行编码 'branch_name' => '中国建设银行上海张江支行', // 开户支行名称(可由系统解析联行号) ]);
说明:
openIndividual/openEnterprise默认执行“基础进件 + 业务入驻”。- 返回结果包含
huifu_id、basic_open、busi_open三部分。 - 企业银行卡场景可直接传
branch_code - 仅传
branch_name时,默认使用本地联行号字典解析 - 如需覆盖默认解析逻辑,可注入
branch_code_resolver
业务开通
$result = $huifu->entry()->openBusiness('6666000xxxxxxx', [ 'fee_rate' => '0.38', ]);
进件回显
$detail = $huifu->entry()->detailByActor([ 'role_type' => 'supplier', 'actor_id' => 20001, 'app_id' => 10000, ]);
联行号字典
$banks = $huifu->bankBranches()->getBankOptions('建设'); $branches = $huifu->bankBranches()->getBranchList([ 'head_bank_code' => '01050000', 'keyword' => '上海', 'page' => 1, 'pageSize' => 20, ]); $branchCode = $huifu->bankBranches()->resolveBranchCode('中国建设银行上海张江支行', '01050000'); $isValid = $huifu->bankBranches()->isValidBranchCode($branchCode); $branch = $huifu->bankBranches()->getByUnionCode($branchCode);
常用方法
getBankOptions($keyword = '', $limit = 200)查询银行选项getBranchList(array $params = [])分页查询支行列表resolveBranchCode($branchName, $bankCode = '')通过支行名称获取联行号isValidBranchCode($unionCode)校验联行号是否存在matchBranches($keyword, $bankCode = '', $limit = 20)模糊搜索支行getByUnionCode($unionCode)根据联行号反查支行信息
说明:
- 若同名支行命中多条且未传
bankCode,resolveBranchCode()返回空字符串 - 该行为用于避免歧义匹配
地区编码
$tree = $huifu->regions()->tree(); $provinceList = $huifu->regions()->getChildren(''); $cityList = $huifu->regions()->getChildren('310000'); $districtCode = $huifu->regions()->getCodeByName('浦东新区', 3, '310100');
适配器机制
支持通过第二个构造参数注入扩展服务:
$huifu = new Application($config, [ 'logger' => $logger, 'entry_repository' => $entryRepository, 'branch_code_resolver' => $branchCodeResolver, 'region_repository' => $regionRepository, ]);
可注入服务
logger自定义日志实现entry_repository自定义进件档案仓储branch_code_resolver自定义支行名称转联行号解析器region_repository自定义地区编码仓储
异常处理
所有服务统一抛出:
EasyHuifu\Exception\EasyHuifuException
建议在业务层统一捕获并转换为自身的异常类型或错误响应。
参考数据维护
scripts/export_reference_data.php 用于维护 data/ 目录下的参考数据文件,不属于运行时依赖。
导出联行号数据时需显式提供环境变量:
EASYHUIFU_DB_HOSTEASYHUIFU_DB_NAMEEASYHUIFU_DB_USEREASYHUIFU_DB_PASSEASYHUIFU_DB_PORTEASYHUIFU_DB_PREFIX
示例
请参考:
examples/native-php.phpexamples/README.mddocs/THINKPHP_ADAPTER.md
进件与入驻拆分说明
EntryService 现在提供两套调用方式:
- 仅进件(不要求银行卡参数)
entry()->basicOpenIndividual([...])entry()->basicOpenEnterprise([...])
- 进件+入驻(一体化,保持兼容)
entry()->openIndividual([...])entry()->openEnterprise([...])
说明:
basicOpen*只做基础进件,返回huifu_id和basic_open。open*会先调用basicOpen*,再调用openBusiness完成入驻。- 入驻阶段若涉及结算卡/代发配置,仍按
openBusiness参数规则传入(可在业务侧按需补充银行卡信息)。
仅进件示例(个人)
$basic = $huifu->entry()->basicOpenIndividual([ 'name' => '测试用户', // 姓名 'cert_no' => '3301xxxxxxxxxxxx', // 证件号 'mobile_no' => '13800000000', // 手机号 ]);
仅进件示例(企业)
$basic = $huifu->entry()->basicOpenEnterprise([ 'reg_name' => '测试企业', // 企业注册名称 'license_code' => '9131xxxxxxxxxxxx', // 统一社会信用代码 'reg_prov_id' => '310000', // 注册省编码 'reg_area_id' => '310100', // 注册市编码 'reg_district_id' => '310115', // 注册区县编码 'reg_detail' => '浦东新区xx路xx号', // 注册地址详情 'legal_name' => '张三', // 法人姓名 'legal_cert_no' => '3301xxxxxxxxxxxx', // 法人证件号 'contact_name' => '张三', // 联系人姓名 'contact_mobile' => '13800000000', // 联系人手机号 ]);
分步入驻示例(先进件后入驻)
$basic = $huifu->entry()->basicOpenIndividual([ 'name' => '测试用户', 'cert_no' => '3301xxxxxxxxxxxx', 'mobile_no' => '13800000000', ]); $busi = $huifu->entry()->openBusiness($basic['huifu_id'], [ 'settle_config' => [ 'settle_cycle' => 'T1', ], 'cash_config' => [ ['cash_type' => 'T1', 'fix_amt' => '0.00'], ], ]);
延迟分账交易确认说明(必读)
- 开启
delay_acct_flag = Y后,支付资金先进入延迟户,pay()->miniApp()/jsPay()仅是“预分账”,不会自动划转到分账接收方。 - 订单支付成功后,需要主动调用交易确认接口完成划转:
$huifu->split()->confirm([...])。 - 确认提交后可调用
$huifu->split()->confirmQuery([...])查询确认状态,建议在业务侧做重试与幂等。
接口映射(easyhuifu -> 汇付官方 SDK):
split()->confirm()->V2TradePaymentDelaytransConfirmRequestsplit()->confirmQuery()->V2TradePaymentDelaytransConfirmqueryRequestsplit()->confirmRefund()->V2TradePaymentDelaytransConfirmrefundRequest
当前状态:
- 以上 3 个接口已经在
easyhuifu中封装完成。 V2TradePaymentDelaytransConfirmrefundqueryRequest(确认退款查询)已封装,对应split()->confirmRefundQuery()。