# think-transfer **Repository Path**: goodbugood/think-pay ## Basic Information - **Project Name**: think-transfer - **Description**: fork 别人的,不知道 - **Primary Language**: PHP - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-05-19 - **Last Updated**: 2026-06-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 出款渠道对接 > 如果觉得 `think-withdraw` 不错,欢迎给个 star,谢谢。 ## 目录结构 ```php src/config/withdraw.php // 渠道配置文件,写好每个厂商的配置参数模版,记住是模版,不要把真实参数提交 src/dto/ // 接口数据传输对象 src/exception/ // 接口异常,不细分不需要再定义 src/extend/ // 接口扩展,你在对接时定义的工具类 src/provider/ // 接口服务提供者,一个厂商一个包,每个包里新建 `README.md` 文件,里面写厂商的接口文档 src/phpmate/ // 该目录下的文件未来将独立出去进行单独维护的,你不可以在此包下添加文件 ``` ## 使用方法 ```php // 1. 在你的 tp 项目下面安装 `yaoliyong/think-withdraw` 包 composer require yaoliyong/think-withdraw // 2. 构建 withdraw 策略业务 $configParams = [];// 服务商配置参数(参数请参考各个渠道的配置类公共属性);notifyUrl + channelId 用来配置回调地址,订单回调路由 = {notifyUrl}/channel/{channelId};签约回调路由 = {notifyUrl}/channel/{channelId}/type/h5Sign $WithdrawStrategy = WithdrawStrategyFactory::create('yunzhanghu', $configParams); $requestDto = new CreateOrderRequestDto(); // 省略Dto设置参数 $WithdrawStrategy->createOrder($requestDto); ``` ## 通知消息通道接入 `think-withdraw` 接收到代付平台通知后,会把不同平台的通知转换成统一的消息对象,再通过队列投递给业务项目。 ### 业务项目需要实现消息读取通道 ```php think\withdraw\channel\SignNotifyChannel // 签约状态通知 think\withdraw\channel\TransferOrderNotifyChannel // 代付订单状态通知 ``` ### 绑定通道实现 在 ThinkPHP 项目的 `app/provider.php` 里,把扩展接口绑定到自己的实现类: ```php \app\common\channel\transfer\SignNotifyChannelImpl::class, \think\withdraw\channel\TransferOrderNotifyChannel::class => \app\common\channel\transfer\TransferOrderNotifyChannelImpl::class, ]; ``` ### 告知代付平台你的通知地址 由于 transfer 服务接管了代付平台的通知,所以你不需要配置路由,书写 controller,只需要把地址告诉代付平台即可。 类型1: https://你的域名/plugin/transfer/notify/all-business/platform/{platform_code_and_app_id} 类型2: https://你的域名/plugin/transfer/notify/signStatus/platform/{platform_code_and_app_id} 1. platform_code_and_app_id 是平台码 + 应用 ID/商户 id,例如 `yunzhanghu_123456`。他是 transfer 服务读取你提供的配置参数,进行验签,解密的核心。 2. 提供那种类型的通知地址给上游,取决于上游的通知参数中是否包含业务方法。 ### ReadResult 返回值 ```php ReadResult::ack() // 已消费。若消息状态是终态,Job 会删除;非终态会继续延迟通知 ReadResult::retry(30, '我这边还没准备好,30 秒后再通知我') // 延迟指定秒数后重试 ReadResult::fail('我做业务更新失败了,请稍后再通知我') // 记录失败原因,并按退避延时重试 ReadResult::garbage('这不是我要的消息,你可以删除了') // 垃圾消息,直接删除 Job ``` ### 代付订单通知通道 ```php class TransferOrderNotifyChannelImpl implements TransferOrderNotifyChannel { public function read(Message $message): ReadResult { if (!$message instanceof TransferNotifyMessage) { return ReadResult::garbage('这不是我这个身份应该看到的消息'); } // 根据 platformCode + merchantOrderNo 定位本地订单 // 保存渠道订单号、状态、金额、税费、手续费、代付时间等字段 // 如果本地系统临时不可用,返回 ReadResult::retry() 或 ReadResult::fail() return ReadResult::ack(); } } ``` `TransferNotifyMessage` 常用字段: ```php $message->getPlatformCode(); // 平台码 $message->getMerchantOrderNo(); // 商户订单号 $message->getChannelOrderNo(); // 渠道/平台订单号 $message->getStatus(); // 统一代付状态 $message->getStatusDesc(); // 状态描述 $message->getAmount(); // 代付金额,Money|null $message->getActualAmount(); // 实际到账金额,Money|null $message->getIndividualIncomeTax(); // 个人所得税,Money|null $message->getValueAddedTax(); // 增值税,Money|null $message->getAdditionalTax(); // 附加税,Money|null $message->getFee(); // 服务费,Money|null $message->getTransferTime(); // 代付时间,LocalDateTime|null ``` ### 签约通知通道 ```php class SignNotifyChannelImpl implements SignNotifyChannel { public function read(Message $message): ReadResult { if (!$message instanceof SignNotifyMessage) { return ReadResult::garbage('你是不是发错了消息'); } // 根据 platformCode + idCardNo 定位本地签约记录 // 保存签约状态、状态描述、签约链接、合同文件地址 // 如果本地系统临时不可用,返回 ReadResult::retry() 或 ReadResult::fail() return ReadResult::ack(); } } ``` `SignNotifyMessage` 常用字段: ```php $message->getPlatformCode(); // 平台码 $message->getIdCardNo(); // 身份证号 $message->getStatus(); // 统一签约状态 $message->getStatusDesc(); // 状态描述 $message->getSignUrl(); // 签约链接 $message->getSignFileUrl(); // 签约合同文件下载地址 ``` ### 启动队列消费 通知消息会进入扩展统一的读取队列,业务项目需要启动队列监听: ```shell php think queue:listen --queue transfer:message:read ``` ## 测试 vendor/bin/phpunit --filter "XzbPayTest::testQueryBalance" --configuration phpunit.xml vendor/bin/phpunit --filter "XzbPayTest::testUserSign" --configuration phpunit.xml vendor/bin/phpunit --filter "XzbPayTest::testCreateOrder" --configuration phpunit.xml vendor/bin/phpunit --filter "XzbPayTest::testQueryOrder" --configuration phpunit.xml vendor/bin/phpunit --filter "XzbPayTest::testHandleCallbackOfWithdraw" --configuration phpunit.xml ## 问题排查 ### 日志 1. 如果是 `think-withdraw` 报错,日志写在 `runtime/log` 目录下 2. 如果正常的业务日志写在 `runtime/transfer/log` 目录下,如果你的 `config/log.php` 日志配置文件未配置 `transfer` 通道,业务日志写会写在 `runtime/log` 目录下。 要注意这两点区别。