autepos/ai-payment

AiPayment 是 Laravel 的统一支付接口。

dev-main 2023-06-18 16:06 UTC

This package is auto-updated.

Last update: 2024-09-18 18:58:58 UTC


README

AiPayment 是 Laravel 的统一支付接口,简化了支付机制,允许您实现可嵌入的 UI 组件,以便将敏感支付数据的处理委托给支付提供商,以确保安全。您可以在支付交易期间保持客户在您的应用程序中,而不必处理他们的敏感支付详情。

AiPayment 的理想流程中,在服务器端开始支付初始化,生成在前端完成支付交易所需输出的。然后,通过提供商的 webhook 或直接由前端通知服务器支付完成。由于无法信任前端的通知,服务器会联系提供商以正式确认支付状态。Stripe Intent 作为提供商完全实现了这些功能。

以下是在 AiPayment 中支付提供的突出功能:

  • 将敏感数据处理的委托给提供商
  • 将支付分成多个支付
  • 使用多个提供商进行单个订单的支付(例如,离线/现金 + Stripe + 等)
  • 全额或部分退款交易
  • 保存支付方式以供重复使用
  • ping 提供商以验证集成状态
  • 动态更改支付提供商配置
  • 动态在实时和测试模式之间切换
  • 多租户支持
  • 自定义支付提供商。

安装

composer require autepos/ai-payment
php artisan migrate

使用方法

为了与支付提供商安全交互,请使用支付服务。要获取支付服务,通过容器构建它,以便自动解析其依赖项。

$paymentService=app(\Autepos\AiPayment\PaymentService::class)

初始化

初始化完整的订单支付操作

/**
 * @var \Autepos\AiPayment\Providers\Contracts\Orderable 
 */ 
$order=new Order;

//
$config=[
    'test_publishable_key'=>'...',
    'test_secret_key'=>'...'
    'webhook_secret'=>'...',
]
$livemode=false;
$paymentResponse = $paymentService->provider('stripe_intent')
                                ->config($config,$livemode)
                                ->order($order)
                                ->init();

支付响应对象包含完成前端支付所需的所有详细信息。因此,可以将 $paymentResponse 序列化并返回到前端。初始化操作记录在事务模型中,可以从响应对象中访问。

$transaction=$paymentResponse->getTransaction();

就是这样。或者,您可以初始化部分/分割订单支付操作

$paymentResponse = $paymentService->provider('stripe_intent')
                                ->config($config)
                                ->order($order)
                                ->init(100);

此外,收银员也可以代表客户初始化支付。

/**
 * @var \Illuminate\Contracts\Auth\Authenticatable
 */ 
$cashier=\App\Models\Admin::find(1);

//
$paymentResponse = $paymentService->provider('stripe_intent')
                                    ->config($config)
                                    ->order($order)
                                    ->cashierInit($cashier);

收费

支付初始化后,下一步是创建收费。

$paymentResponse = $paymentService->config($config)
                                    ->charge($transaction);//$transaction may be returned during init above

收银员也可以代表客户创建收费。

$paymentResponse = $paymentService->config($config)
                                    ->cashierCharge($cashier,$transaction);

退款

成功的收费可以退款。

$paymentResponse = $paymentService->config($config)
                                    ->refund($cashier,$transaction);

同步交易

本地收费数据(即交易)可以与提供商持有的相应数据同步。

$paymentResponse = $paymentService->config($config)
                                    ->syncTransaction($transaction);

常规操作

运行设置脚本

$simpleResponse = $paymentService->provider('stripe_intent')
                                    ->config($config)
                                    ->up();

运行设置脚本的逆操作

$simpleResponse = $paymentService->provider('stripe_intent')
                                    ->config($config)
                                    ->down();

ping 提供商

$simpleResponse = $paymentService->provider('stripe_intent')
                                    ->config($config)
                                    ->ping();

监听交易事件

交易记录在 Eloquent 模型 \Autepos\AiPayment\Models\Transaction 中。因此,您可以正常监听事件。此外,每次保存交易时,都会触发 \Autepos\AiPayment\Events\OrderableTransactionsTotaled 事件。此事件包含有关相关可订购项目和从所有适用交易中汇总的当前总金额的信息。您可以监听这些事件来更新相应的可订购项目。

class OnOrderableTransactionsTotaled
{
    use \App\Models\Order;

    /**
     * Handle the event.
     */
    public function handle(OrderableTransactionsTotaled $event)
    {
        $order=Order::find($event->orderable_id);
        $order->total_paid=$event->total_paid;
        $order->save();
    }
}

提供商客户

支付提供商可以实现一个客户,如下所示检索

/**
 * @var \Autepos\AiPayment\Providers\Contracts\ProviderCustomer
 */ 
$providerCustomer=$paymentService->provider('stripe_intent')
->config($config)
->customer();

提供商客户公开的方法允许使用支付提供商创建一个客户,以将本地账户详细信息链接起来。例如,为了创建 Stripe 客户端以链接本地用户,您可以执行以下操作

use \Autepos\AiPayment\Contracts\CustomerData;

$customerData=new CustomerData([
    'user_id'=>1,
    'user_type'=>'customer'
]);
$customerResponse=$providerCustomer->create($customerData);
$paymentProviderCustomer=$customerResponse->getPaymentProviderCustomer();

这就完成了。这将创建一个与新建的Stripe客户对象关联的本地记录。对象 $paymentProviderCustomer 是您的客户的新本地记录。这是一个稍后引入的Eloquent模型。您可以通过以下方式删除客户

$customerResponse=$providerCustomer->delete($paymentProviderCustomer);
if($customerResponse->success){
    // both local and Stripe records have been removed
}

支付提供商支付方式

支付提供商可以实现一个支付方式,如下所示检索

use \Autepos\AiPayment\Contracts\CustomerData;

$customerData=new CustomerData([
    'user_id'=>null,
    'user_type'=>'guest'
])

/**
 * @var \Autepos\AiPayment\Providers\Contracts\ProviderPaymentMethod
 */ 
$providerPaymentMethod=$paymentService->provider('stripe_intent')
->config($config)
->paymentMethod($customerData);

支付提供商支付方式公开的方法允许您为顾客保存支付方式,以便在未来付款中重复使用。要保存支付方式,您需要提供支付方式实现所需的所有数据。对于Stripe意图,所需的数据是支付方式ID。

$data=['payment_method_id'=>'pm_1LFRDP2eZvKYlo2C6NTvKmDS'];
$paymentMethodResponse=$providerPaymentMethod->save($data);
$paymentProviderCustomerPaymentMethod=$paymentMethodResponse->getPaymentProviderCustomerPaymentMethod();

请注意,API保存而不是创建新的支付方式。支付方式的创建可以由其他地方或前端处理。创建过程应获取保存支付方式所需的 $data 输入。如果创建处理需要服务器端初始化,可以使用 $providerPaymentMethodinit() 方法执行,该方法应作为响应对象的一部分返回所需的初始化数据。对于Stripe意图,如果不存在,将为底层 $customerData 创建客户。

对象 $paymentProviderCustomerPaymentMethod 是稍后引入的Eloquent模型。它存储了支付提供商的本地记录。主机应用程序可以直接访问此模型,在将来用于付款。例如,对于Stripe意图,您可以通过以下方式重复使用已保存的支付方式

$data=[
    'payment_provider_payment_method_id'=>$paymentProviderCustomerPaymentMethod->payment_provider_payment_method_id
    ];
$paymentResponse = $paymentService->provider('stripe_intent')
                                ->config($config,$livemode)
                                ->order($order)
                                ->init(null,$data);
$paymentResponse = $paymentService->charge($transaction);

if($paymentResponse->success){
    // payment was successful.
}

要删除支付方式,您可以使用 remove 方法

$paymentMethodResponse=$payment$providerPaymentMethod->remove($paymentProviderCustomerPaymentMethod);
if($paymentMethodResponse->success){
    // the record has been removed locally and at Stripe.
}

添加额外的支付提供商

定义支付提供商类,例如用于比特币支付

use Autepos\AiPayment\Providers\Contracts\PaymentProvider;

class BitcoinPaymentProvider extends PaymentProvider{
    ...
}

在服务提供商中注册支付提供商

$paymentManager=$this->app->make(\Autepos\AiPayment\Contracts\PaymentProviderFactory::class);
$paymentManager->extend('bitcoin', function($app){
    return $app->make(BitcoinPaymentProvider::class);
});

这就完成了,但如果您在Autepos中使用该提供商,您应该为其添加记录

$pm= new \Autepos\Models\PaymentMethod;
$pm->provider='bitcoin';// unique_provider_tag
$pm->provider_name='Name of provider';
$pm->name='Bitcoin';// What Customers will see
$pm->... e.g. delivery types etc
$provider->save();

测试

您应该适当地测试您的额外支付提供商。基本通用测试在命名空间下提供,\Autepos\AiPayment\Tests\ContractTests。您可以复制测试并修改它们,或在自己的测试中使用特性。您不必使用这些测试。如果您更喜欢使用特性,需要添加 createContract() 方法,该方法返回要测试的类。以下是一个测试支付提供商实现的示例

use Autepos\AiPayment\Tests\ContractTests\PaymentProviderContractTest;

class BitcoinPaymentProviderTest extends PHPUnit_TestCase
{
    use PaymentProviderContractTest;

    /**
     * Hook for PaymentProviderContractTest
     *
     * @return void
     */
    public function createContract():PaymentProvider{
        return new BitcoinPaymentProvider;
    }
}

这将运行 PaymentProviderContractTest 中定义的所有测试。您也可以覆盖 PaymentProviderContractTest 中的任何测试以修改它,并添加额外的测试

use Autepos\AiPayment\Providers\Contracts\PaymentProvider;
use Autepos\AiPayment\Tests\ContractTests\PaymentProviderContractTest;

class BitcoinPaymentProviderTest extends PHPUnit_TestCase
{
    use PaymentProviderContractTest;

    /**
     * Hook for PaymentProviderContractTest
     *
     * @return void
     */
    public function createContract():PaymentProvider{
        return new BitcoinPaymentProvider;
    }

    /**
     * Additional test
     */
    public function test_can_resolve_provider(){
        // test code
    }

    /**
     * Override the test_can_ping() from PaymentProviderContractTest.
     */
    public function test_can_ping(){
        // test code
    }
}

Eloquent 模型

由于以下都是纯Eloquent模型,您可以自由使用它们。

  • 交易:支付提供商应使用此模型管理交易。主机应用程序应使用此模型确定对可订购的所有付款。
  • PaymentProviderCustomer:支付提供商应将其远程保留的客户与该模型同步。主机应用程序可以使用该模型来管理支付提供商的客户的保存详情,例如 $paymentProviderCustomer->paymentMethods 提供保存支付方式的关联;
  • PaymentProviderCustomerPaymentMethod:支付提供商应将其远程保留的客户支付方式与该模型同步。主机应用程序可以通过此模型在关联到 PaymentProviderCustomer 时与注册客户的保存支付方式交互。

默认提供商

离线

这是离线支付。当需要在系统之外进行支付时使用。

// Retrieve instance with payment service
$paymentProvider=$paymentService->provider('offline');

现金

特定于现金的离线支付。

// Retrieve instance with payment service
$paymentProvider=$paymentService->provider('cash');

稍后支付

这是一个用于给客户提供支付稍后选项的非常简单的支付提供商实现。

// Retrieve instance with payment service
$paymentProvider=$paymentService->provider('pay_later');

Stripe意图

这提供了Stripe意图支付服务。

// Retrieve instance with payment service
$paymentProvider=$paymentService->provider('stripe_intent');

有关此支付提供商的安装信息,请参阅 Stripe意图

租户

租户功能已支持,但默认情况下是禁用的。您可以通过设置“ai-payment.tenancy”配置来启用租户,如下所示

....
/**
 * Payment provider
 */
'ai_payment'=>[
    'tenancy'=>[
        'enable_multi_tenant'=>true,
        'column_name'=>'tenant_id',
        'is_column_type_integer'=>true,
        'default'=>1,// Should be neural ID that does not belong to any client when tenancy is in use. If tenancy is not in use then all data is stored with this value.
        'global_scope_name'=>'simple_tenancy_tenant_id',// Eloquent global scope name for scoping related queries
    ]
],
...

即使启用了租户功能,某些支付提供者的实现可能也不支持它。默认支付提供者支持租户。

在与支付提供者或支付提供者模型(例如模型交易等)交互之前,您应该始终首先调用

\Autepos\AiPayment\Tenancy\Tenant::set('current_tenant_id');

或者,您也可以通过支付服务设置租户,如下所示

\Autepos\AiPayment\PaymentService::tenant('current_tenant_id');

Autepos的支付提供者Vue组件

每个支付提供者都应该提供两个视图组件。这些组件可以全局注册,以便可以通过Payment.vue/Refund.vue(或如果存在,PaymentService.vue/PaymentServiceRefund.vue)加载,即支付服务的Vue组件。其中一个组件用于处理支付,另一个用于退款。在Autepos Vue组件中可以找到这些组件的示例。

建议注册的支付处理组件名称应遵循以下约定:{provider}PaymentProvider,其中{provider}用Pascal大小写的唯一提供者标签/驱动器替换。例如,具有唯一标签/驱动器stripe_intent的Stripe意图应该将其组件注册为StripeIntentPaymentProvider

退款组件的注册名称应遵循类似的约定,唯一不同的是在末尾出现“退款”一词。因此,对于Stripe意图,我们将有,StripeIntentPaymentProviderRefund

测试

从命令行运行测试

php vendor/phpunit/phpunit/phpunit

composer test