Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 增加抖音支付 #1014

Merged
merged 27 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v3.7.9

### added

- feat: 新增抖音支付(#1014)

## v3.7.8

### added
Expand Down
140 changes: 116 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ yansongda/pay 100% 兼容 支付宝/微信/银联 所有功能(包括服务商
- 刷卡支付
- ...

### 抖音

- 小程序支付
- ...

### 银联

- 手机网站支付
Expand Down Expand Up @@ -146,7 +151,9 @@ class AlipayController

public function web()
{
$result = Pay::alipay($this->config)->web([
Pay::config($this->config);

$result = Pay::alipay()->web([
'out_trade_no' => ''.time(),
'total_amount' => '0.01',
'subject' => 'yansongda 测试 - 1',
Expand All @@ -157,7 +164,9 @@ class AlipayController

public function returnCallback()
{
$data = Pay::alipay($this->config)->callback(); // 是的,验签就这么简单!
Pay::config($this->config);

$data = Pay::alipay()->callback(); // 是的,验签就这么简单!

// 订单号:$data->out_trade_no
// 支付宝交易号:$data->trade_no
Expand All @@ -166,22 +175,22 @@ class AlipayController

public function notifyCallback()
{
$alipay = Pay::alipay($this->config);

Pay::config($this->config);
try{
$data = $alipay->callback(); // 是的,验签就这么简单!
$data = Pay::alipay()->callback(); // 是的,验签就这么简单!

// 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
// 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
// 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
// 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
// 4、验证app_id是否为该商户本身。
// 5、其它业务逻辑情况
} catch (\Exception $e) {
// $e->getMessage();
} catch (\Throwable $e) {
dd($e);
}

return $alipay->success();
return Pay::alipay()->success();
}
}
```
Expand Down Expand Up @@ -249,6 +258,8 @@ class WechatController

public function index()
{
Pay::config($this->config);

$order = [
'out_trade_no' => time().'',
'description' => 'subject-测试',
Expand All @@ -260,7 +271,7 @@ class WechatController
],
];

$pay = Pay::wechat($this->config)->mp($order);
$pay = Pay::wechat()->mp($order);

// $pay->appId
// $pay->timeStamp
Expand All @@ -269,17 +280,96 @@ class WechatController
// $pay->signType
}

public function notifyCallback()
public function callback()
{
$pay = Pay::wechat($this->config);

Pay::config($this->config);
try{
$data = $pay->callback(); // 是的,验签就这么简单!
} catch (\Exception $e) {
// $e->getMessage();
$data = Pay::wechat()->callback(); // 是的,验签就这么简单!
} catch (\Throwable $e) {
dd($e);
}

return $pay->success();
return Pay::wechat()->success();
}
}
```

### 抖音
```php
<?php

namespace App\Http\Controllers;

use Yansongda\Pay\Pay;

class DouyinController
{
protected $config = [
'douyin' => [
'default' => [
// 选填-商户号
// 抖音开放平台 --> 应用详情 --> 支付信息 --> 产品管理 --> 商户号
'mch_id' => '73744242495132490630',
// 必填-支付 Token,用于支付回调签名
// 抖音开放平台 --> 应用详情 --> 支付信息 --> 支付设置 --> Token(令牌)
'mch_secret_token' => 'douyin_mini_token',
// 必填-支付 SALT,用于支付签名
// 抖音开放平台 --> 应用详情 --> 支付信息 --> 支付设置 --> SALT
'mch_secret_salt' => 'oDxWDBr4U7FAAQ8hnGDm29i4A6pbTMDKme4WLLvA',
// 必填-小程序 app_id
// 抖音开放平台 --> 应用详情 --> 支付信息 --> 支付设置 --> 小程序appid
'mini_app_id' => 'tt226e54d3bd581bf801',
// 选填-抖音开放平台服务商id
'thirdparty_id' => '',
// 选填-抖音支付回调地址
'notify_url' => 'https://yansongda.cn/douyin/notify',
],
],
'logger' => [ // optional
'enable' => false,
'file' => './logs/alipay.log',
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
];

public function pay()
{
Pay::config($this->config);

$result = Pay::douyin()->mini([
'out_order_no' => date('YmdHis').mt_rand(1000, 9999),
'total_amount' => 1,
'subject' => '闫嵩达 - test - subject - 01',
'body' => '闫嵩达 - test - body - 01',
'valid_time' => 600,
'expand_order_info' => json_encode([
'original_delivery_fee' => 15,
'actual_delivery_fee' => 10
])
]);

return $result;
}

public function callback()
{
Pay::config($this->config);

try{
$data = Pay::douyin()->callback(); // 是的,验签就这么简单!
} catch (\Throwable $e) {
dd($e)
}

return Pay::douyin()->success();
}
}
```
Expand All @@ -292,7 +382,7 @@ namespace App\Http\Controllers;

use Yansongda\Pay\Pay;

class EpayController
class JsbController
{
protected $config = [
'jsb' => [
Expand Down Expand Up @@ -331,33 +421,35 @@ class EpayController

public function index()
{
Pay::config($this->config);

$order = [
'outTradeNo' => time().'',
'proInfo' => 'subject-测试',
'totalFee'=> 1,
];

$pay = Pay::jsb($this->config)->scan($order);
$pay = Pay::jsb()->scan($order);
}

public function notifyCallback()
{
$pay = Pay::jsb($this->config);
Pay::config($this->config);

try{
$data = $pay->callback(); // 是的,验签就这么简单!
} catch (\Exception $e) {
// $e->getMessage();
$data = Pay::jsb()->callback(); // 是的,验签就这么简单!
} catch (\Throwable $e) {
dd($e);
}

return $pay->success();
return Pay::jsb()->success();
}
}
```

## 代码贡献

由于测试及使用环境的限制,本项目中只开发了「支付宝」、「微信支付」、「银联」、「江苏银行」的相关支付网关。
由于测试及使用环境的限制,本项目中只开发了「支付宝」、「微信支付」、「抖音支付」、「银联」、「江苏银行」的相关支付网关。

如果您有其它支付网关的需求,或者发现本项目中需要改进的代码,**_欢迎 Fork 并提交 PR!_**

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"ext-libxml": "*",
"ext-json": "*",
"ext-bcmath": "*",
"yansongda/artful": "~1.1.0",
"yansongda/supports": "~4.0.9"
"yansongda/artful": "~1.1.1",
"yansongda/supports": "~4.0.10"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
Expand Down
4 changes: 4 additions & 0 deletions src/Exception/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class Exception extends \Exception

public const PARAMS_CALLBACK_REQUEST_INVALID = 9221;

public const PARAMS_DOUYIN_URL_MISSING = 9222;

/**
* 关于响应.
*/
Expand All @@ -57,6 +59,8 @@ class Exception extends \Exception

public const CONFIG_JSB_INVALID = 9404;

public const CONFIG_DOUYIN_INVALID = 9405;

/**
* 关于签名.
*/
Expand Down
20 changes: 20 additions & 0 deletions src/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Yansongda\Pay\Plugin\Wechat\V3\AddPayloadSignaturePlugin;
use Yansongda\Pay\Plugin\Wechat\V3\WechatPublicCertsPlugin;
use Yansongda\Pay\Provider\Alipay;
use Yansongda\Pay\Provider\Douyin;
use Yansongda\Pay\Provider\Jsb;
use Yansongda\Pay\Provider\Unipay;
use Yansongda\Pay\Provider\Wechat;
Expand Down Expand Up @@ -596,6 +597,7 @@ function verify_unipay_sign_qra(array $config, array $destination): void
function get_jsb_url(array $config, ?Collection $payload): string
{
$url = get_radar_url($config, $payload) ?? '';

if (str_starts_with($url, 'http')) {
return $url;
}
Expand Down Expand Up @@ -629,3 +631,21 @@ function verify_jsb_sign(array $config, string $content, string $sign): void
throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证江苏银行签名失败', func_get_args());
}
}

/**
* @throws InvalidParamsException
*/
function get_douyin_url(array $config, ?Collection $payload): string
{
$url = get_radar_url($config, $payload);

if (empty($url)) {
throw new InvalidParamsException(Exception::PARAMS_DOUYIN_URL_MISSING, '参数异常: 抖音 `_url` 参数缺失:你可能用错插件顺序,应该先使用 `业务插件`');
}

if (str_starts_with($url, 'http')) {
return $url;
}

return Douyin::URL[$config['mode'] ?? Pay::MODE_NORMAL].$url;
}
4 changes: 4 additions & 0 deletions src/Pay.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\Pay\Provider\Alipay;
use Yansongda\Pay\Provider\Douyin;
use Yansongda\Pay\Provider\Jsb;
use Yansongda\Pay\Provider\Unipay;
use Yansongda\Pay\Provider\Wechat;
use Yansongda\Pay\Service\AlipayServiceProvider;
use Yansongda\Pay\Service\DouyinServiceProvider;
use Yansongda\Pay\Service\JsbServiceProvider;
use Yansongda\Pay\Service\UnipayServiceProvider;
use Yansongda\Pay\Service\WechatServiceProvider;
Expand All @@ -23,6 +25,7 @@
* @method static Wechat wechat(array $config = [], $container = null)
* @method static Unipay unipay(array $config = [], $container = null)
* @method static Jsb jsb(array $config = [], $container = null)
* @method static Douyin douyin(array $config = [], $container = null)
*/
class Pay
{
Expand All @@ -46,6 +49,7 @@ class Pay
WechatServiceProvider::class,
UnipayServiceProvider::class,
JsbServiceProvider::class,
DouyinServiceProvider::class,
];

/**
Expand Down
5 changes: 4 additions & 1 deletion src/Plugin/Alipay/V2/AddRadarPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\Artful\Logger;
use Yansongda\Artful\Rocket;
use Yansongda\Supports\Collection;

use function Yansongda\Artful\get_radar_method;
use function Yansongda\Pay\get_alipay_url;
use function Yansongda\Pay\get_provider_config;

Expand All @@ -30,7 +32,8 @@ public function assembly(Rocket $rocket, Closure $next): Rocket
$payload = $rocket->getPayload();

$rocket->setRadar(new Request(
strtoupper($params['_method'] ?? 'POST'),
// 这里因为支付宝的 payload 里不包含 _method,所以需要取 params 中的
get_radar_method(new Collection($params)) ?? 'POST',
get_alipay_url($config, $payload),
$this->getHeaders(),
// 不能用 packer,支付宝接收的是 x-www-form-urlencoded 返回的又是 json,packer 用的是返回.
Expand Down
3 changes: 1 addition & 2 deletions src/Plugin/Alipay/V2/CallbackPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Yansongda\Artful\Logger;
use Yansongda\Artful\Rocket;
use Yansongda\Pay\Exception\InvalidSignException;
use Yansongda\Supports\Collection;

use function Yansongda\Artful\filter_params;
use function Yansongda\Pay\get_provider_config;
Expand All @@ -36,7 +35,7 @@ public function assembly(Rocket $rocket, Closure $next): Rocket

$value = filter_params($params, fn ($k, $v) => '' !== $v && 'sign' != $k && 'sign_type' != $k);

verify_alipay_sign($config, Collection::wrap($value)->sortKeys()->toString(), $params['sign'] ?? '');
verify_alipay_sign($config, $value->sortKeys()->toString(), $params['sign'] ?? '');

$rocket->setPayload($params)
->setDirection(NoHttpRequestDirection::class)
Expand Down
Loading