接第四种支付方式,Tigshop开源商城 PaymentService 扩展点
一套 tigshop 单商户原本只开了微信、支付宝、线下转账三种支付。这次要接一个区域性的聚合支付通道算店里第四种付款方式。趁这次把支付这块的扩展点从头走了一遍结构其实挺规整照着现有通道加就行。先看现有的支付实现都在php/app/service/admin/pay/src/下面一个通道一个类php/app/service/admin/pay/src/ ├── WechatPayService.php ├── AliPayService.php ├── PayPalService.php ├── YaBanPayService.php └── YunPayService.php它们都继承同一个抽象基类php/app/service/admin/pay/PayService.php。打开基类看一眼就知道每个通道必须实现哪几个方法// php/app/service/admin/pay/PayService.phpabstractclassPayService{abstractpublicfunctionpay(array$order):array;// 下单返回前端拉起支付的参数abstractpublicfunctionrefund(array$order):array;// 退款abstractpublicfunctionnotify():array;// 支付异步回调abstractpublicfunctionrefund_notify():array;// 退款异步回调// getNotifyUrl / getReturnUrl 这些通用方法基类已经给了}所以加新通道本质就是照着现有的类再写一个把这四个抽象方法按新通道的 SDK 实现出来。第一步写一个新的支付类新建php/app/service/admin/pay/src/MyPayService.php继承PayService?phpnamespaceapp\service\admin\pay\src;useapp\service\admin\pay\PayService;classMyPayServiceextendsPayService{publicfunctionpay(array$order):array{// 调用新通道 SDK 下单回调地址用基类的 getNotifyUrl()// 组装并返回前端拉起支付需要的参数return[];}publicfunctionnotify():array{// 1. 验签失败直接返回失败不动订单// 2. 校验金额和订单号// 3. 校验通过后调 PaymentService::paySuccess() 把订单标记为已支付return[];}publicfunctionrefund(array$order):array{return[];}publicfunctionrefund_notify():array{return[];}}notify里第三步别自己写更新订单的逻辑直接复用PaymentService::paySuccess($pay_sn, $transaction_id)。这个方法已经处理了订单状态、发货短信、卡券分配、成长值这一整套自己重写一遍很容易漏。第二步让它出现在可用支付列表里C 端拿可用支付方式走的是PaymentService::getAvailablePayment()。看它的实现就明白了它是按后台配置开关一个个判断的// php/app/service/admin/pay/PaymentService.phppublicfunctiongetAvailablePayment(string$typeorder):array{$payment[];$config$this-getConfig();if(!empty($config[useWechat])$config[useWechat]1){$payment[]wechat;}if(!empty($config[useAlipay])$config[useAlipay]1){// ...$payment[]alipay;}// paypal / yabanpay / yunpay / offline 各有一段return$payment;}要让新通道能被选到就在这里加一段读一个自己的配置开关useMypayif(!empty($config[useMypay])$config[useMypay]1){$payment[]mypay;}第三步在支付分发处加分支这一步是我一开始漏掉的。加完上面两步前端能看到mypay这个选项但点下去没反应。翻代码才发现真正调pay()的地方在php/app/api/controller/order/Pay.php它是用switch ($pay_type)硬分发的// php/app/api/controller/order/Pay.phpswitch($pay_type){casewechat:$resapp(WechatPayService::class)-pay($pay_params);break;casealipay:$resapp(AliPayService::class)-pay($pay_params);break;// yabanpay / yunpay ...}所以新通道要在这个switch里补一个casenotify()和refund_notify()那两个 switch 也一样各加一个casemypay:$resapp(MyPayService::class)-pay($pay_params);break;tigshop 现在就是这么写死分发的别指望只加个类就能自动接上三处 switch 都得改到。第四步后台配置新通道的 appid、密钥、商户号这些加到支付配置项里让运营在后台填别写死在代码里。配置读取走的就是getConfig()和上面useMypay那个开关一套。回调这块单独说几句回调 URL 一定要公网可达本地调不通十有八九就是这个测试拿内网穿透顶一下。notify()里验签和金额校验一步都不能省这是资金安全的红线。上线前用小额真实走一遍完整链路下单、支付、看回调有没有真的把pay_status改成 1。光看前端弹出支付成功不算数得回pay_log表确认状态确实变了才算这通道接通了。