devinweb/laravel-youcan-pay

Laravel的YouCanPay包,提供了一种简单的方式来实现最佳体验。

0.4.3 2023-07-01 13:30 UTC

This package is auto-updated.

Last update: 2024-09-15 21:18:40 UTC


README

Laravel YouCanPay

Latest Version on Packagist Total Downloads GitHub Actions Psalm

Laravel YouCanPay

简介

Laravel YouCanPay提供了一种轻松的体验,用于生成支付表单,并处理所有与支付相关的操作。

安装

您可以通过composer安装此包

composer require devinweb/laravel-youcan-pay

数据库迁移

LaravelYouCanPay包提供自己的数据库来管理不同步骤中的用户交易,迁移将创建一个新的transactions表来存储所有用户的交易。

php artisan migrate

如果您需要覆盖LaravelYouCanPay提供的迁移,您可以使用Artisan命令vendor:publish来发布它们

php artisan vendor:publish --tag="youcanpay-migrations"

配置

要发布配置文件,您可以使用以下命令

php artisan vendor:publish --tag="youcanpay-config"

然后您可以在config/youcanpay.php中找到配置文件

账单模型

如果您希望包根据用户模型管理交易,请将Billable特征添加到您的用户模型中。此特征提供各种方法来执行交易任务,例如创建交易、获取paidfailedpending交易。

use Devinweb\LaravelYouCanPay\Traits\Billable;

class User extends Authenticatable
{
    use Billable;
}

LaravelYouCanPay假定您的用户模型将是App\Models\User,如果您使用不同的用户模型命名空间,您应该使用方法useCustomerModel指定它。此方法通常应在AppServiceProvider类的boot方法中调用

use App\Models\Core\User;
use Devinweb\LaravelYouCanPay\LaravelYouCanPay;;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    LaravelYouCanPay::useCustomerModel(User::class);
}

如果您需要在每次交易中包都使用每个用户的计费数据,请确保在您的用户模型中包含一个getCustomerInfo()方法,该方法返回一个包含我们所需所有数据的数组。

/**
 * Get the customer info to send them when we generate the form token.
 *
 * @return array
 */
public function getCustomerInfo()
{
    return [
      'name'         => $this->name,
      'address'      => '',
      'zip_code'     => '',
      'city'         => '',
      'state'        => '',
      'country_code' => 'MA',
      'phone'        => $this->phone,
      'email'        => $this->email,
    ];
}

YouCanPay密钥

接下来,您应该在应用程序的.env中配置您的环境

# YouCanPay env keys
SANDBOX_MODE=
PRIVATE_KEY=
PUBLIC_KEY=
CURRENCY=MAD
SUCCCESS_REDIRECT_URI=
FAIL_REDIRECT_URI=

客户

检索客户

您可以使用findBillable方法通过您CanPay ID检索客户。此方法将返回账单模型的实例

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;

$user = LaravelYouCanPay::findBillable($order_id);

生成令牌

如果您需要从用户模型生成令牌,客户信息将直接从getCustomerInfo方法附加

$data= [
  'order_id' => '123',
  'amount' => 2000 // amount=20*100
];

$token = $user->getPaymentToken($data, $request);

如果您需要添加元数据,您可以使用

$data= [
  'order_id' => '123',
  'amount' => 2000 // amount=20*100
];

$metadata = [
  'key' => 'value'
];

$token = $user->getPaymentToken($data, $request, $metadata);

如果您需要从用户模型获取支付URL,您可以使用与以下相同参数的getPaymentURL方法。

$payment_url = $user->getPaymentURL($data, $request, $metadata);

生成支付URL

使用方法

在开始使用包之前,请确保使用正确的值更新您的config/youcanpay.php

令牌化

获取令牌ID

我们需要的第一步是创建一个基于凭据的令牌,使用您从YouCanPay仪表板获取的getId()方法。

注意
金额应该是* 100,例如,如果您的产品价格为20$,您应该发送
amount = 20*100 = 200,使用 currency='USD'

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;
use Illuminate\Support\Str;


public function tokenization(Request $request)
{
    $order_data = [
        'order_id' => (string) Str::uuid(),
        'amount' => 200
    ];

    $token= LaravelYouCanPay::createTokenization($order_data, $request)->getId();
    $public_key = config('youcanpay.public_key');
    $isSandbox = config('youcanpay.sandboxMode');
    $language = config('app.locale');


    // You can at this point share a lot of data with the front end,
    // the idea behind this is making the backend manage the environment keys,
    // we don't need to store the keys in many places.
    return response()->json(compact('token', 'public_key', 'isSandbox', 'language'));
}

获取支付URL

独立集成,您可以使用方法getPaymentUrl()生成支付URL

$paymentUrl= LaravelYouCanPay::createTokenization($data, $request)->getPaymentURL();

然后您可以将该URL放在您的HTML页面上

<a href="{{ $paymentUrl }}">Pay Now</a>

客户信息

如果您需要在令牌化期间添加客户数据,请保留以下数组键(nameaddresszip_codecitystatecountry_codephoneemail)。您可以使用

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;

$customerInfo = [
  'name'         => '',
  'address'      => '',
  'zip_code'     => '',
  'city'         => '',
  'state'        => '',
  'country_code' => '',
  'phone'        => '',
  'email'        => '',
];

$token= LaravelYouCanPay::setCustomerInfo($customerInfo)->createTokenization($data, $request)->getId();

元数据

您可以使用元数据发送可以在响应后或在webhook中检索的数据。

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;

$customerInfo = [
  'name'         => '',
  'address'      => '',
  'zip_code'     => '',
  'city'         => '',
  'state'        => '',
  'country_code' => '',
  'phone'        => '',
  'email'        => '',
];

$metadata = [
  // Can you insert what you want here...
  'key' => 'value'
];

$token= LaravelYouCanPay::setMetadata($metadata)
                          ->setCustomerInfo($customerInfo)
                          ->createTokenization($data, $request)->getId();

生成支付表单

此时,我们从后端接收到令牌,所以在我们 blade 或任何其他 HTML 页面中,您可以在 head 中放置此脚本

<html>
  ...
  <head>
    <!--Add this line -->
    <script src="https://pay.youcan.shop/js/ycpay.js"></script>
  </head>
  ...
</html>

然后,要显示表单,您的逻辑将类似于以下代码

<script type="text/javascript">
  // Create a YouCan Pay instance.
  const ycPay = new YCPay(
    // String public_key (required): Login to your account.
    // Go to Settings and open API Keys and copy your key.
    "public_key",
    // Optional options object
    {
      formContainer: "#payment-card",
      // Defines what language the form should be rendered in, supports EN, AR, FR.
      locale: "en",

      // Whether the integration should run in sandbox (test) mode or live mode.
      isSandbox: false,

      // A DOM selector representing which component errors should be injected into.
      // If you omit this option, you may alternatively handle errors by chaining a .catch()
      // On the pay method.
      errorContainer: "#error-container",
    }
  );

  // Select which gateways to render
  ycPay.renderAvailableGateways(["CashPlus", "CreditCard"]);

  // Alternatively, you may use gateway specific render methods if you only need one.
  ycPay.renderCreditCardForm();

</script>

要开始支付,您需要一个操作,您可以使用按钮

document.getElementById("pay").addEventListener("click", function () {
  // execute the payment
  ycPay.pay(tokenId).then(successCallback).catch(errorCallback);
});

function successCallback(response) {
  //your code here
}

function errorCallback(response) {
  //your code here
}

有关更多信息,请查看此 链接

处理YouCanPay Webhooks

YouCan Pay 使用 webhook 通知您的应用程序当您的账户中发生事件时。Webhook 对于处理后端上的异步事件的反应非常有用,例如成功支付、失败支付、成功退款以及其他许多实时事件。Webhook 允许 YouCan Pay 通过 HTTPS 传输 JSON 有效负载将实时通知推送到您的应用程序。

Webhook 和 CSRF 保护

YouCanPay webhook 需要无障碍地到达您的 URI,因此您需要禁用 webhook URI 的 CSRF 保护,为此请确保将您的路径添加到应用程序的 App\Http\Middleware\VerifyCsrfToken 中间件中的异常数组中。

protected $except = [
   'youcanpay/*',
]

Webhook URL

为确保您的应用程序可以处理 YouCanPay webhook,请确保在 YouCanPay 控制面板中配置 webhook URL。默认情况下,该软件包包含一个内置的 webhook,使用 URL youcanpay/webhook,您可以通过在应用程序中使用 php artisan route:list 列出所有路由来找到它,该 webhook 验证接收到的有效负载相关的签名,并分配一个事件。

Webhook 中间件

如果您需要在处理任何操作之前尝试验证 webhook 签名,则可以使用中间件 verify-youcanpay-webhook-signature,该中间件验证从 YouCanPay 接收到的有效负载相关的签名。

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class WebHookController extends Controller
{
    /**
     * Create a new WebhookController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('verify-youcanpay-webhook-signature');
    }
    //...
}

Webhook事件

LaravelYouCanPay 处理常见的 YouCanPay webhook 事件,如果您需要处理需要的事件,则可以监听由软件包分配的事件。

  • Devinweb\LaravelYouCanPay\Events\WebhookReceived

您需要注册一个可以处理事件的监听器

<?php

namespace App\Listeners;

use Devinweb\LaravelYouCanPay\Events\WebhookReceived;

class YouCanPayEventListener
{
    /**
     * Handle received Stripe webhooks.
     *
     * @param  \Devinweb\LaravelYouCanPay\Events\WebhookReceived  $event
     * @return void
     */
    public function handle(WebhookReceived $event)
    {
        if ($event->payload['event_name'] === 'transaction.paid') {
            // Handle the incoming event...
        }
    }
}

一旦您的监听器已被定义,您可以在应用程序的 EventServiceProvider 中注册它

<?php

namespace App\Providers;

use App\Listeners\YouCanPayEventListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Devinweb\LaravelYouCanPay\Events\WebhookReceived;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        WebhookReceived::class => [
            YouCanPayEventListener::class,
        ],
    ];
}

手动验证 webhook 签名

从 YouCanPay 接收到的 webhook 数据看起来像这样

[
  'id' => 'bbbb832c-dd13-4ce7-a642-6059885d9a7e',
  'event_name' => 'transaction.paid',
  'sandbox' => true,
  'payload' => [
    'transaction' => [
      'id' => 'fdd795ab-9f8a-4cf7-886c-dca9ce3ab6c0',
      'status' => 1,
      'order_id' => 'cc984e79-0de1-4e84-a654-74c102c3ba66',
      'amount' => '2000',
      'currency' => 'MAD',
      'base_currency' => NULL,
      'base_amount' => NULL,
      'created_at' => '2022-11-22T13:20:52.000000Z',
    ],
    'payment_method' => [
      'id' => 1,
      'name' => 'credit_card',
      'card' => [
        'id' => '2e42d52d-ab0a-4440-b1e2-9a41fb843dad',
        'country_code' => NULL,
        'brand' => NULL,
        'last_digits' => '4242',
        'fingerprint' => 'df276a45f62277bd43775616827f0718',
        'is_3d_secure' => false,
      ],
    ],
    'token' => [
      'id' => '811dd60e-4655-41da-b576-a1a537cda071',
    ],
    'event' => [
      'name' => 'transaction.paid',
    ],
    'customer' => [
      'id' => 'edc6fb6f-415f-4ac3-8b86-c70bead4770e',
      'email' => NULL,
      'name' => NULL,
      'address' => NULL,
      'phone' => NULL,
      'country_code' => NULL,
      'city' => NULL,
      'state' => NULL,
      'zip_code' => NULL,
    ],
    'metadata' => [],
  ],
]

但有趣的部分是在请求头中,您可以使用键 x-youcanpay-signature 找到签名值。

在处理任何逻辑或操作之前验证 webhook 签名。

<?php

namespace App\Http\Controllers;

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;
use Illuminate\Http\Request;

class YouCanPayWebhooksController extends Controller
{
    public function handle(Request $request)
    {
        $signature = $request->header('x-youcanpay-signature');
        $payload = json_decode($request->getContent(), true);
        if (LaravelYouCanPay::verifyWebhookSignature($signature, $payload)) {
            // you code here
        }
    }
}

手动验证 webhook 签名

验证具有与验证相同的影响,但验证会抛出一个异常,您可以在日志文件中检查它。

<?php

namespace App\Http\Controllers;

use Devinweb\LaravelYouCanPay\Facades\LaravelYouCanPay;
use Illuminate\Http\Request;

class YouCanPayWebhooksController extends Controller
{
    public function handle(Request $request)
    {
        LaravelYouCanPay::validateWebhookSignature($signature, $payload)

        // you code here
    }
}

命令

如果您需要清理挂起的交易,有一个命令

php artisan youcanpay:clean-pending-transactions

您可以将它添加到调度程序,以便每次运行命令,因此清理将是自动的,并且取决于在 youcanpay 配置文件中定义的 tolerance 值。

测试和测试卡

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关详细信息,请参阅 贡献

安全

如果您发现任何与安全相关的问题,请通过电子邮件 imad@devinweb.com 而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证(MIT)。请参阅 许可证文件 了解更多信息。

Laravel YouCanPay 模板

此软件包是使用 Laravel YouCanPay 模板 生成的。