tbclla/laravel-revolut-business

Revolut商业版Open API的非官方Laravel包装器

v1.0 2020-04-18 13:14 UTC

This package is auto-updated.

Last update: 2024-09-19 20:22:43 UTC


README

Latest Stable Version License Build Status Scrutinizer Code Quality

Laravel-Revolut (Business)

Revolut商业版Open API的非官方Laravel包装器。
有关Revolut商家API的姐妹包可以在此处找到。

入门指南

阅读Revolut的官方文档,熟悉API和授权过程。

⚠️ 请在设置此包时使用沙盒账户,只有当您确认一切运行正常后,才切换到您的真实账户。

要求

  • Laravel >=5.8
  • PHP >=7.2

安装

通过Composer拉取此包。

composer require tbclla/laravel-revolut-business

服务提供者 & 门面

如果您已禁用Laravel的自动发现功能,请将服务提供者和门面添加到您的config/app.php

'providers' => [
    // ...
    tbclla\Revolut\Providers\RevolutServiceProvider::class,
],

'aliases' => [
    // ...
    'Revolut' => tbclla\Revolut\Facades\Revolut::class,
]

配置

安装包后,发布配置文件。

php artisan vendor:publish --provider "tbclla\Revolut\Providers\RevolutServiceProvider"

现在您可以在config/revolut.php下配置此包。

访问过期

根据官方文档,自由职业者计划上的企业必须在90天内在API中明确授权访问其账户。如果这适用于您的企业,请将'expire_api_access'设置为true

凭证

将以下密钥添加到您的.env文件中,因为大多数配置值都是从那里读取的。
您将在设置API访问时完成缺失的值。

REVOLUT_SANDBOX=true
REVOLUT_PRIVATE_KEY=
REVOLUT_REDIRECT_URI=
REVOLUT_CLIENT_ID=

令牌存储

令牌可以存储在数据库或缓存中。

缓存

当使用'cache'存储时,您可以可选地定义一个driver。如果设置为null,将使用您应用程序的默认缓存驱动程序(config/cache.php > default)。

数据库

当使用'database'存储时,当您运行迁移时,将自动包含所需的表的迁移。此表名可以在配置中自定义。

运行php artisan migrate以创建表。

设置API访问

请按照Revolut关于如何设置API访问的文档中的步骤1和2操作。

步骤1 - 生成一对公钥/私钥

完成Revolut说明中的步骤1以生成密钥对。
❗将私钥路径添加到您的.env作为REVOLUT_PRIVATE_KEY

步骤2 - 上传您的公钥

按照Revolut的步骤2上传您新创建的公钥并提供重定向URI。
⚠️您不需要为这个重定向URI创建路由或控制器,此包将处理它。
❗将此重定向URI添加到您的.env作为REVOLUT_REDIRECT_URI

Revolut现在已为您创建了一个客户端ID。
❗将此客户端ID添加到您的.env作为REVOLUT_CLIENT_ID

步骤 3 - 签署 JWT

跳过此步骤,此包将在需要时为您生成 JWT。
您可以通过以下 artisan 命令生成 JWT 来验证您已正确配置一切。可选地,您可以使用 --public 标志传递匹配的公钥路径,以验证 JWT。

php artisan revolut:jwt

php artisan revolut:jwt --public /Path/to/publickey.cer

步骤 4-7

您不必完成任何剩余步骤!
相反,使用以下 artisan 命令开始授权,并按照生成的链接操作。

php artisan revolut:authorize

为了减轻 CSRF 攻击,通过 Revolut 的网页界面请求授权代码与 Laravel-Revolut 不兼容。有关授权过程的更多信息,请参阅此处

完成

现在,访问和刷新令牌已被存储在您定义的令牌存储中。此包现在将使用此访问令牌,直到它过期,并通过刷新令牌从 Revolut 请求新的一个。

要验证您的应用程序已被授权,您可以使用以下 artisan 命令检索访问令牌。

php artisan revolut:access-token

使用 API

要使用客户端,您可以通过外观访问其方法,或者从 Laravel 的服务容器中解析它。

use tbclla\Revolut\Client;
use tbclla\Revolut\Facades\Revolut;

$revolut = resolve(Client::class);
$revolut->account()->details('11d79893-2703-489f-96e9-7946d9aba8b7');
// or simply
Revolut::account()->details('11d79893-2703-489f-96e9-7946d9aba8b7');

账户

请参阅Revolut 的文档

获取所有账户

$accounts = Revolut::account()->all();

获取一个账户

Revolut::account()->get('ac57ffc9-a5cb-4322-89d2-088e8a007a97');

获取账户详情

Revolut::account()->details('11d79893-2703-489f-96e9-7946d9aba8b7');

交易对方

获取所有交易对方

Revolut::counterparty()->all();

获取一个交易对方

Revolut::counterparty()->get('5435ff9e-bacd-430b-95c2-094da8662829');

删除一个交易对方

Revolut::counterparty()->delete('5435ff9e-bacd-430b-95c2-094da8662829');

创建一个交易对方

有关更多详细信息,请参阅Revolut 的文档

创建 Revolut 交易对方
Revolut::counterparty()->create([
    "profile_type" => "personal",
    "name" => "John Smith",
    "phone" => "+4412345678900"
]);
创建非 Revolut 交易对方
Revolut::counterparty()->create([
    "company_name" => "John Smith Co.",
    "bank_country" => "GB",
    "currency" => "GBP",
    "account_no" => "12345678",
    "sort_code" => "223344",
    "email" => "test@sandboxcorp.com",
    "address" => [
        "street_line1" => "1 Canada Square",
        "street_line2" => "Canary Wharf",
        "region" => "East End",
        "postcode" => "E115AB",
        "city" => "London",
        "country" => "GB"
    ]
]);

构建交易对方

有关构建器和如何使用它们的更多信息,请参阅此处

构建 Revolut 交易对方
$builder = Revolut::counterparty()->build();
$builder->profileType('personal')
$builder->name('John Doe')
$builder->phone('+4412345678900');
$builder->create();

构建器还提供了以下快捷方式以实现相同的结果

Revolut::counterparty()->build()->personal('John Doe', '+4412345678900')->create();

Revolut::counterparty()->build()->business('test@sandboxcorp.com')->create();
构建非 Revolut 交易对方
$counterparty = Revolut::counterparty()->build()
    ->bankCountry('GB')
    ->currency('GBP')
    ->accountNumber('12345678')
    ->sortCode('223344');

$counterparty->companyName('John Smith Co');

// or for an individual
$counterparty->individualName('John', 'Smith');

// The counterparty builder accepts the address as an array
$counterparty->address([
    "street_line1" => "1 Canada Square",
    "street_line2" => "Canary Wharf",
    "region" => "East End",
    "postcode" => "E115AB",
    "city" => "London",
    "country" => "GB"
]);

// Alternatively, the builder lets you build the address fluently
$counterparty->streetLine1('1 Canada Square')
    ->streetLine2('Canary Wharf')
    ->region('East End')
    ->postcode('E115AB')
    ->city('London')
    ->country('GB');

转账

请参阅Revolut 如何创建转账的文档

创建转账

Revolut::transfer()->create([
    "request_id" => "e0cbf84637264ee082a848b",
    "source_account_id" => "bdab1c20-8d8c-430d-b967-87ac01af060c",
    "target_account_id" => "5138z40d1-05bb-49c0-b130-75e8cf2f7693",
    "amount" => 123.11,
    "currency" => "EUR",
]);

构建转账

有关构建器和如何使用它们的更多信息,请参阅此处

$transfer = Revolut::transfer()->build()
    ->sourceAccount($sourceAccountId)
    ->targetAccout($targetAccountId)
    ->amount(231.20)
    ->reference('payroll'); // optional

// If you want to keep the request ID for your records, retrieve it from the builder
$requestId = $transfer->request_id;

$transfer->create();

付款

请参阅Revolut 如何创建付款的文档

创建付款

Revolut::payment()->create([
    "request_id" => "e0cbf84637264ee082a848b",
    "account_id" => "bdab1c20-8d8c-430d-b967-87ac01af060c",
    "receiver" =>[
        "counterparty_id" => "5138z40d1-05bb-49c0-b130-75e8cf2f7693",
        "account_id" => "db7c73d3-b0df-4e0e-8a9a-f42aa99f52ab"
    ],
    "amount" => 123.11,
    "currency" => "EUR",
]);

构建付款

有关构建器和如何使用它们的更多信息,请参阅此处

$payment = Revolut::payment()->build()
    ->account('bdab1c20-8d8c-430d-b967-87ac01af060c')
    ->receiver('5138z40d1-05bb-49c0-b130-75e8cf2f7693')
    ->amount(93.12)
    ->currency('USD')
    ->create();

安排付款

schedule() 方法接受与 create() 方法相同的数据,以及 ISO 日期作为其第二个参数。

Revolut::payment()->schedule($data, '2020-05-19');

取消安排的付款

Revolut::payment()->cancel('b63f30f0-62dc-4b6b-98cf-2a9a2e5ac981');

交易

获取所有交易

all() 方法接受一个可选的数组作为其第一个参数,用作过滤器。请参阅Revolut 的文档以获取可用过滤器的列表。

$transactions = Revolut::transaction()->all();

$filtered = Revolut::transaction()->all([
    'count' => 200,
    'type' => 'card_payment',
]);

根据官方文档,如果交易超过 90 天,则只能访问在过去 5 分钟内生成访问令牌的交易。为此,您可以通过将可选的布尔值作为第二个参数传递,来指示是否在发出请求之前强制客户端刷新访问令牌。

Revolut::transaction()->all([], true);

获取一个交易

get() 方法允许您通过其 ID 获取交易。如果您想通过其请求 ID 获取交易,可以使用 getByRequestId() 方法。

Revolut::transaction()->get($id);

Revolut::transaction()->getByRequestId($requestId);

付款草稿

获取所有付款草稿

Revolut::paymentDraft()->all();

获取一个付款草稿

Revolut::paymentDraft()->get($id);

删除一个付款草稿

Revolut::paymentDraft()->delete($id);

创建一个付款草稿

Revolut::paymentDraft()->create([
    "title": "Sample title",
    "schedule_for": '2020-05-29',
    "payments" => [
        [
            "currency" => "EUR",
            "amount" => 123,
            "account_id" => "db7c73d3-b0df-4e0e-8a9a-f42aa99f52ab",
            "receiver" => [
                "counterparty_id" => "5138z40d1-05bb-49c0-b130-75e8cf2f7693",
                "account_id" => "bdab1c20-8d8c-430d-b967-87ac01af060c"
            ],
        ]
    ]
]);

构建付款草稿

在构建付款草稿时,付款可以通过将付款数组传递给 payment() 方法或通过 addPayment() 方法添加单个付款来设置。

$date = now()->addDays(7)->format('Y-m-d');

$draft = Revolut::paymentDraft()->build()
    ->title('Sample title')
    ->schedule($date)
    ->payments($payments);

foreach ($employees as $employee) {
    $draft->addPayment($payment);
}

$draft->create()

汇率

获取汇率

get() 方法接受源货币和目标货币作为前两个参数。
您可以可选地传递一个第三个参数作为兑换金额,否则默认为1。

Revolut::rate()->get('EUR', 'CHF');

Revolut::rate()->get('USD', 'GBP', 143.23);

兑换

创建兑换

Revolut::exchange()->create([
    "from" => [
        "account_id" => "d56dd396-523b-4613-8cc7-54974c17bcac",
        "currency" => "USD",
        "amount" => 135.25
    ],
    "to": [
        "account_id" => "a44dd365-523b-4613-8457-54974c8cc7ac",
        "currency" => "EUR"
    ],
    "reference" => "Time to sell",
    "request_id" => Revolut::generateRequestId(),
]);

构建兑换

$exchange = Revolut::exchange()->build()
    ->reference('Time to sell')
    ->from('d56dd396-523b-4613-8cc7-54974c17bcac', 'USD', 135.25)
    ->to('a44dd365-523b-4613-8457-54974c8cc7ac', 'EUR');

$response = $exchange->create()

Web钩子

请参阅Revolut的文档了解Web钩子和可用事件。

创建Web钩子

Revolut::webhook()->create('https://mydomain.com/endpoint');

删除Web钩子

Revolut::webhook()->delete();

构建器

所有具有create()方法(除Web钩子外)的API资源也都有一个返回特定资源实例的tbclla\Revolut\Builders\Builderbuild()方法。构建器可以用来以更流畅的方式创建有时复杂的数据数组。

Revolut::counterparty()->build() // tbclla\Revolut\Builders\CounterpartyBuilder
Revolut::payment()->build() // tbclla\Revolut\Builders\PaymentBuilder
Revolut::paymentDraft()->build() // tbclla\Revolut\Builders\PaymentDraftBuilder
Revolut::transfer()->build() // tbclla\Revolut\Builders\TransferBuilder
Revolut::exchange()->build() // tbclla\Revolut\Builders\ExchangeBuilder

输出

所有构建器都使用toArray()方法以Revolut所需格式返回数据。
例如

Revolut::exchange()->build()
    ->from('d56dd396-523b-4613-8cc7-54974c17bcac', 'USD')
    ->to('a44dd365-523b-4613-8457-54974c8cc7ac', 'EUR', 735.23)
    ->reference('Off to France!')
    ->toArray();

将返回

[
    'from' => [
        'account_id' => 'd56dd396-523b-4613-8cc7-54974c17bcac',
        'currency' => 'USD'
    ],
    'to' => [
        'account_id' => 'a44dd365-523b-4613-8457-54974c8cc7ac',
        'currency' => 'EUR',
        'amount' => 735.23,
    ],
    'reference' => 'Off to France!',
    'request_id' => 'c60ec5b3-c5b9-4cea-936c-fa0306374df5'
]

创建构建的资源

当您完成构建后,只需在构建器上调用create()方法即可。

Revolut::transfer()->build()
    ->sourceAccount('bdab1c20-8d8c-430d-b967-87ac01af060c')
    ->targetAccout('5138z40d1-05bb-49c0-b130-75e8cf2f7693')
    ->amount(231.20)
    ->create();

请求ID

Revolut要求某些请求包含一个唯一的request_id参数。

如果您使用构建器,请求ID将自动为您创建。您可以设置自己的请求ID,或从构建器获取现有的请求ID。

$builder = Revolut::exchange()->build()->requestId('my_own_request_id');

$requestId = $builder->request_id;

如果您没有使用构建器,您可以使用Revolut客户端上的静态generateRequestId()方法创建请求ID——这是构建器在底层使用的。此方法使用\Illuminate\Support\Str::Uuid()返回一个UUIDv4字符串。

use tbclla\Revolut\Client;

Client::generateRequestId();

令牌和授权

授权

根据RFC6749 10.12,此包实现了对redirect_uri的CSRF保护,并包含一个控制器来处理授权请求和后续响应,以强制执行此保护。

授权请求

由于控制器将需要一个有效的state参数,因此您不能使用Revolut的Web界面与该包一起授权您的应用程序。要授权您的应用程序,您必须从auth_route输入Revolut的Oauth流程。
您可以通过以下artisan命令获取URL。

php artisan revolut:authorize

如果您需要将用户重定向到Revolut的授权流程,您可以通过路由助手获取URL。auth_route是一个命名路由,其名称可在您的config/revolut.php文件中的auth_route.name下进行配置。您可以将一个可选的'after_success'参数传递给它,该参数将在授权完成后将用户重定向到指定位置。

$url = route('revolut-authorize');

$url = route('revolut-authorize', [
    'after_success' => route('home')
]);

return redirect($url);

要始终将用户重定向到授权流程,当您的应用程序未授权时,您可以捕获一个AppUnauthorizedException,该异常在没有任何有效的刷新令牌可用且您的应用程序需要重新授权时抛出。

use tbclla\Revolut\Exceptions\AppUnauthorizedException;

Route::get('/accounts', function () {
    try {
        return Revolut::account()->all();
    } catch(AppUnauthorizedException $e) {
        return redirect(route('revolut-authorization', [
            'after_success' => '/accounts'
        ]));
    }
});

授权响应

您的应用程序被授权后,Revolut将重定向您到您在创建API证书时设置的redirect URI。此redirect URI必须与config/revolut.php中设置的redirect_uri相匹配。

您不需要为这个redirect URI创建路由或控制器。

包含在此包中的授权控制器将验证响应的state参数的存在和有效性,如果接受,将交换响应的授权代码以获取访问令牌和刷新令牌。一旦收到并存储了这些令牌,控制器将重定向用户到指定位置。如果没有提供位置,则控制器将返回一个200响应。

令牌存储

本包将存储访问和刷新令牌到您的数据库或缓存中。授权代码永远不会被存储,而是立即交换为令牌。您可以在 config/revolut.php 文件中配置令牌驱动程序。

令牌加密

默认情况下,所有访问和刷新令牌在存储到您的数据库或缓存之前都会被加密。此包使用 Laravel 内置的加密工具 来加密您的令牌,因此请确保您在 config/app.php 中设置了一个强大的 key

清理过期令牌

缓存

存储在您的缓存中的令牌只在有效期内被记住,因此无需删除它们。如果您想从缓存中删除令牌,可以使用它们各自的键调用 forget()

// remove access token
Cache::forget('revolut_access_token');
// remove refresh token
Cache::forget('revolut_refresh_token');

数据库

如果您使用的是数据库令牌存储,可以使用以下 artisan 命令从数据库中删除过期的访问令牌和刷新令牌。

php artisan revolut:cleanup

您还可以在 App\Console\Kernel 类中安排此命令,以自动化此过程。

$schedule->command('revolut:cleanup')->daily();

从沙盒切换到真实账户

  • 更新您的 .env 文件,并将 REVOLUT_SANDBOX=false 设置。
  • 从数据库或缓存中清除任何沙盒令牌。
  • 更新您的 config/revolut.php,并将 encrypt_tokens 设置为 true(如果尚未设置)。
  • 通过访问账户设置 > API,列出将访问 API 的 IP 地址。
  • 重新授权您的应用程序。

许可证

本项目采用 MIT 许可证 - 请参阅 LICENSE.md 文件以获取详细信息。