cubes-doo/nestpay

Nestpay 电子商务集成

v2.1.2 2021-10-29 10:10 UTC

This package is auto-updated.

Last update: 2024-09-29 04:53:48 UTC


README

Nestpay 电子商务集成,与 Laravel 包一起发布

Latest Stable Version Total Downloads License

默认用法

安装

使用 composer 安装此包。

composer require cubes-doo/nestpay

为了使此包工作,您需要在数据库中创建名为 nestpay_payments 的表。此表用于存储有关支付的信息。

您可以通过导入示例 SQL 脚本来创建表

mysql -u root -p your_db_name < vendor/cubes-doo/nestpay/resources/nestpay_payments.sql

*如果您正在使用 Laravel,则有一个现成的迁移(请参阅下面的文档)

引导和配置

要使用的主要类是 \Cubes\Nestpay\MerchantService

实例化该类并传递配置参数

use Cubes\Nestpay\MerchantService;

//...

$nestpayMerchantService = new MerchantService([
    'clientId' => '********',
    'storeKey' => '********',
    'storeType' => '3D_PAY_HOSTING',
    'okUrl' => 'https://:8082/examples/success.php', //this could be configured later
    'failUrl' => 'https://:8082/examples/failed.php', //this could be configured later
    '3DGateUrl' => 'https://testsecurepay.eway2pay.com/fim/est3Dgate',

    //API
    'apiName' => '********',
    'apiPassword' => '********',
    'apiEndpointUrl' => 'https://testsecurepay.eway2pay.com/fim/api'
]);

使用现有的 PDO 实例设置与数据库的连接

$nestpayMerchantService->setPDO($pdo); //$pdo is instanceof \PDO

如果您想为 nestpay_payments 表指定其他名称,您需要传递另一个参数

$nestpayMerchantService->setPDO($pdo, 'your_table'); //'your_table' is name of the table for payments

配置 \Cubes\Nestpay\MerchantService 在成功支付或失败支付时该做什么

$merchantService->onFailedPayment(function ($payment) {
    //$payment is instance of \Cubes\Nestpay\Payment

    //send an email for failed payment attempt
    // $email = $payment->getProperty(\Cubes\Nestpay\Payment::PROP_EMAIL);
    // $customerName = $payment->getProperty(\Cubes\Nestpay\Payment::PROP_BILLTONAME);

})->onSuccessfulPayment(function($payment) {
    //$payment is instance of \Cubes\Nestpay\Payment

    //send an email for successful payment
    // $email = $payment->getProperty(\Cubes\Nestpay\Payment::PROP_EMAIL);
    // $customerName = $payment->getProperty(\Cubes\Nestpay\Payment::PROP_BILLTONAME);

    //do stuff related to the siccessfull payment
});

重要提醒!!! onSuccessfulPaymentonFailedPayment 可以通过两种方式触发

  • 当客户被重定向回您的页面时,通过调用 \Cubes\Nestpay\MerchantService::paymentProcess3DGateResponse(请参阅下面的文档)
  • 通过从您的 cron job 调用 \Cubes\Nestpay\MerchantService::paymentProcessOverNestpayApi(请参阅下面的文档)

因此,在处理成功或失败的支付时,请确保在处理程序中编写您的逻辑,如发送电子邮件或更改订单状态(这样您就不需要写两次)

用法

确认页面

您应该有一个确认页面,客户会从该页面重定向到银行卡处理器页面。

该页面应包含许多隐藏参数的表单。

使用 \Cubes\Nestpay\MerchantService::paymentMakeRequestParameters 方法生成必要的参数(HASH 参数和其他必要参数)

<?php 

$requestParameters = $nestpayMerchantService->paymentMakeRequestParameters([
    'amount' =>  123.45,
    'currency' => \Cubes\Nestpay\Payment::CURRENCY_RSD,
    'lang' => 'sr',
    //set transaction type to PreAuth or Auth
    \Cubes\Nestpay\Payment::PROP_TRANTYPE => \Cubes\Nestpay\Payment::TRAN_TYPE_PREAUTH,
    //this is email of the customer
    \Cubes\Nestpay\Payment::PROP_EMAIL => 'john.doe@example.com',
    
    //below are optional parameters
    \Cubes\Nestpay\Payment::PROP_INVOICENUMBER => '123456789', //must be numeric!!
    \Cubes\Nestpay\Payment::PROP_BILLTONAME => 'John Doe',\Cubes\Nestpay\Payment::PROP_BILLTOSTREET1 => 'BillToStreet1',
    \Cubes\Nestpay\Payment::PROP_BILLTOSTREET2 => 'BillToStreet2',
    \Cubes\Nestpay\Payment::PROP_BILLTOCITY => 'BillToCity',
    \Cubes\Nestpay\Payment::PROP_BILLTOSTATEPROV => 'BillToStateProv',
    \Cubes\Nestpay\Payment::PROP_BILLTOPOSTALCODE => 'BillToPostalCode',
    \Cubes\Nestpay\Payment::PROP_BILLTOCOUNTRY => 'RS',
    \Cubes\Nestpay\Payment::PROP_SHIPTOCOMPANY => 'ShipToCompany',
    \Cubes\Nestpay\Payment::PROP_SHIPTONAME => 'ShipToName',
    \Cubes\Nestpay\Payment::PROP_SHIPTOSTREET1 => 'ShipToStreet1',
    \Cubes\Nestpay\Payment::PROP_SHIPTOSTREET2 => 'ShipToStreet2',
    \Cubes\Nestpay\Payment::PROP_SHIPTOCITY => 'ShipToCity',
    \Cubes\Nestpay\Payment::PROP_SHIPTOSTATEPROV => 'ShipToStateProv',
    \Cubes\Nestpay\Payment::PROP_SHIPTOPOSTALCODE => 'ShipToPostalCode',
    \Cubes\Nestpay\Payment::PROP_SHIPTOCOUNTRY => 'RS',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA1 => 'DimCriteria1',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA2 => 'DimCriteria2',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA3 => 'DimCriteria3',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA4 => 'DimCriteria4',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA5 => 'DimCriteria5',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA6 => 'DimCriteria6',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA7 => 'DimCriteria7',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA8 => 'DimCriteria8',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA9 => 'DimCriteria9',
    \Cubes\Nestpay\Payment::PROP_DIMCRITERIA10 => 'DimCriteria10',
]);
?>
<html>
    <body>
        <pre>
            <code>
                <?php print_r($merchantService->getWorkingPayment());?>
            </code>
        </pre>
        <form method="post" action="<?php echo $merchantService->get3DGateUrl();?>">
            <?php foreach ($requestParameters as $key => $value) {?>
            <input type="hidden" name="<?php echo htmlspecialchars($key);?>"  value="<?php echo htmlspecialchars($value);?>">
            <?php }?>
            <input type="submit" value="Start payment">
        </form>
    </body>
</html>
?>

提交此表单后,客户会被重定向到 3D 网关银行卡处理页面,在该页面客户输入卡号、CVC 等。

结果页面

在输入卡详细信息后,客户会根据成功或失败的重定向回您的网站。

您应该调用 \Cubes\Nestpay\MerchantService::paymentProcess3DGateResponse 方法来处理 $_POST 参数。

成功页面

<?php
$payment = $nestpayMerchantService->paymentProcess3DGateResponse($_POST);
//DO NOT SEND EMAIL HERE OR DO SOME ACTION ON SUCCESSFUL PAYMENT, JUST SHOW RESULT!
//USE $nestpayMerchantService->onSuccessfulPayment INSTEAD!!!
//display results of the payment:
?>

<h1>Your payment <?php $payment->isSuccess() ? 'is successful' : 'has failed'?></h1>

失败页面

<?php
//second parameter (true) indicates that this processing is on fail url
$payment = $nestpayMerchantService->paymentProcess3DGateResponse($_POST, true); 

//display resultsu of the payment:
?>

<h1>Your payment <?php $payment->isSuccess() ? 'is successful' : 'has failed'?></h1>

通过 API 处理支付

当客户离开 3D 网关页面时,有可能他们不会重定向回您的网站(网络连接中断,客户关闭浏览器等)。

您应该在某个 cron job 中使用 \Cubes\Nestpay\MerchantService::paymentProcessOverNestpayApi 方法来通过 API 处理支付。

//$oid is the OID of some unprocessed payment (WHERE `processed` != 1)
$payment = $nestpayMerchantService->paymentProcessOverNestpayApi($oid); 

//DO NOT SEND EMAIL HERE OR DO SOME ACTION ON SUCCESSFUL PAYMENT!
//USE $nestpayMerchantService->onSuccessfulPayment INSTEAD!!!

通过 API 捕获支付(PostAuth)

对于两步支付(PreAuth 和 PostAuth),您应该使用 Nestpay API 来捕获成功支付的预留金额。

使用 \Cubes\Nestpay\MerchantService::postAuthorizationOverNestpayApi

//$oid is the OID of the payment
$result = $nestpayMerchantService->postAuthorizationOverNestpayApi($oid); 

如果您不想捕获全部金额,请传递第二个参数。

//$oid is the OID of the payment
//$amount should not be greated than the orginal amount reserved in PreAuth
$result = $nestpayMerchantService->postAuthorizationOverNestpayApi($oid, $amount); 

通过 API 取消支付

要取消支付,请使用 \Cubes\Nestpay\MerchantService::voidOverNestpayApi

//$oid is the OID of the payment
$result = $nestpayMerchantService->voidOverNestpayApi($oid); 

获取工作支付

如果您想获取最后处理的支付,请使用 \Cubes\Nestpay\MerchantService::getWorkingPayment

//$payment is instance of \Cubes\Nestpay\Payment 
$payment = $nestpayMerchantService->getWorkingPayment();

//get some of the payment properties
$email = $payment->getProperty(\Cubes\Nestpay\Payment::PROPERTY_EMAIL);

//for some important properties there are getters
$email = $payment->getEmail();

自定义保存支付信息

如果您希望使用其他方法来存储支付,您应该创建自己的 "数据访问对象"(DAO)类。您的 DAO 类必须实现 \Cubes\Nestpay\PaymentDao 接口

use \Cubes\Nestpay\PaymentDao;
use \Cubes\Nestpay\Payment;

class MyPaymentDao implements PaymentDao
{
    /**
     * Fetch payment by $oid
     * 
     * @return \Cubes\Nestpay\Payment
     * @param scalar $oid
     */
    public function getPayment($oid)
    {
        //return payment by oid
    }
    
    /**
     * Saves the payment
     * 
     * @param \Cubes\Nestpay\Payment $payment
     * @return \Cubes\Nestpay\Payment
     */
    public function savePayment(Payment $payment)
    {
        //save existing payment
    }

    /**
     * Creates new payment
     *
     * @param array $properties
     * @return \Cubes\Nestpay\Payment
     */
    public function createPayment(array $properties)
    {
        //create new payment
    }
}

\Cubes\Nestpay\MerchantService 使用您的 DAO 类

$nestpayMerchantService->setPaymentDao(new MyPaymentDao());

与 Laravel 框架(>=5.4)集成

cubes-doo/nestpay 内置 Laravel 包。

服务提供者类是 \Cubes\Nestpay\Laravel\NestpayServiceProvider

如果您使用的是 Laravel 版本 < 5.5,您必须手动包含服务提供者
<?php
//THIS IS config/app.php

return [
    
    //got to providers key
    // ...

    'providers' => [
        //...

        \Cubes\Nestpay\Laravel\NestpayServiceProvider::class
    ],

    'aliases' => [
        //...
        // optinally add alias for facade
        'Nestpay' => \Cubes\Nestpay\Laravel\Facade::class,
    ],
];

在使用 \Cubes\Nestpay\MerchantService 类之前,您应该 编辑您的 .env 文件

#add this to your .env file and set you clientID storeKey etc
NESTPAY_MERCHANT_CLIENT_ID=********
NESTPAY_MERCHANT_STORE_KEY=********
NESTPAY_MERCHANT_3DGATE_URL=https://testsecurepay.eway2pay.com/fim/est3Dgate
NESTPAY_MERCHANT_API_NAME=*******
NESTPAY_MERCHANT_API_PASSWORD=*******
NESTPAY_MERCHANT_API_ENDPOINT_URL=https://testsecurepay.eway2pay.com/fim/api

该包提供了 \Cubes\Nestpay\MerchantService 类,该类可以注入 Laravel 应用程序中的控制器和其他点

namespace App\Http\Controllers;

use \Cubes\Nestpay\MerchantService;

class TestController extends Controller
{
    public function index(MerchantService $merchantService)
    {

    }
}

您还可以使用外观或服务容器获取 \Cubes\Nestpay\MerchantService

//Using facade
\Nestpay::paymentProcess3DGateResponse($request->all());

//using service container with "nestpay" key
app('nestpay')->paymentProcessOverNestpayApi($nestpayPayment->oid);

对于未处理的支付(当客户意外地完成支付后未返回您的网站),还有可用的 artisan 命令

#this command will call Nestpay API to get payment result unprocessed payments
php artisan nestpay:handle-unprocessed-payments

Laravel 资源(配置、控制器、视图等)

尽管您可以手动将 Nestpay 服务集成到 Laravel 应用程序中,但此 Laravel 包包含您需要集成 Nestpay 系统的所有内容。

  1. 将包资源发布到您的 Laravel 应用程序
php artisan vendor:publish --provider="Cubes\\Nestpay\\Laravel\\NestpayServiceProvider"
  1. 自定义发布的配置文件 config/nestpay.php 以符合您的生产参数(在 .env 中保留测试参数)
//file: config/nestpay.php
return [
    'merchant' => [/* the mercant configuration*/],
   
    //change this if you want to use some other class for payment model
    //Object of paymentModel class is going to be returned when calling MerchantService::getWorkingPayment
     'paymentModel' => \App\Models\NestpayPayment::class 
    //...
];
  1. 添加 Nestpay 路由
//file: routes/web.php

\Nestpay::routes();
  1. 将发布的订阅者添加到您的 \App\Providers\EventServiceProvider
//file: app/Providers/EventServiceProvider.php

    protected $subscribe = [
        'App\Listeners\NestpayEventsSubscriber',
    ];
  1. 自定义发布的迁移用于 nestpay_payment
//file: database/migrations/2020_03_27_144802_create_nestpay_payments_table.php

public function up()
    {
        Schema::create($this->tableName, function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->tinyInteger('processed')->default(0)->comment('1-processed; 0-not_processed');
            $table->char('oid', 64)->comment('Unique identifier of the order');

            // add your application specific fields like user_id or order_id etc..

            //DO NOT REMOVE ANY OF EXISTING COLUMNS!!!
  1. 自定义发布的模型 \App\Models\NestpayPayment
//file: app\Migrations\NestpayPayment

namespace App\Models;

use Cubes\Nestpay\Laravel\PaymentModel as Model;

class NestpayPayment extends Model
{
    protected $table = 'nestpay_payments';

    protected $fillable = [

        //DO NOT REMOVE ANY FILLABLES JUST ADD NEW ONE FOOUR APPLICATION
        'processed',
        'oid',
        'trantype', 
        //...
  1. 自定义控制器 \App\Http\Controllers\NestpayController
class NestpayController extends Controller
{
    ...

    //You should definitively start from this point
    //customize how to read amount, currenct customer email and other stuff from your application
    protected function getPaymentData()
    {
        //...
    }
}

重要提示!!! 您不应该在此控制器中向客户发送电子邮件或包含任何与成功支付相关的逻辑,因为支付也可以通过 nestpay::handle-unprocessed-payments artisan 命令处理!

请使用 NestpayEventsSubscriber 代替(请参阅下面的文档)。

重要提示!!! 动作的路由 NestpayController@successNestpayController@fail 必须排除 CSRF 令牌验证,通过编辑 VerifyCsrfToken 中间件排除这些操作的 URL

//file: app/Http/Middleware/VerifyCsrfToken.php

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        '/nestpay/success', //change this if you have customized routes
        '/nestpay/fail', //change this if you have customized routes
    ];
}
  1. 自定义视图脚本
resources   
│
└───views
│   │
│   └───vendor
│       │   
│       │───nestpay
│       |       │
│       |       │    confirm.blade.php
│       |       │    email.blade.php
│       |       │    result.blade.php

  1. nestpay::handle-unprocessed-payments 命令计划为每五分钟执行一次,以便可以在后台通过 Nestpay API 处理未处理的支付
//file: app/Console/Kernel.php

class Kernel extends ConsoleKernel
{
    //...

    
    protected function schedule(Schedule $schedule)
    {
        //...
        $schedule->command('nestpay::handle-unprocessed-payments')->everyFiveMinutes();
    }

    //...
  1. 自定义监听器 \App\Listeners\NestpayEventsSubscriber

重要提示!!!

这是最重要的自定义!!!

当支付处理时(无论是通过 NestpayController 还是 nestpay::handle-unprocessed-payments 命令),将触发以下事件

  • \Cubes\Nestpay\Laravel\NestpayPaymentProcessedSuccessfullyEvent - 对于成功支付
  • \Cubes\Nestpay\Laravel\NestpayPaymentProcessedFailedEvent - 对于失败事件

此时,您应该有一个已发布的订阅者 \App\Listeners\NestpayEventsSubscriber,该订阅者已配置为监听这些事件。

该类包含向客户发送必要邮件的逻辑,您只需添加当支付成功(当客户已付款)时的逻辑即可。

//file: app/Listeners/NestpayEventsSubscrber
class NestpayEventsSubscriber
{
    /**
     * Successfull payment
     */
    public function nestpayPaymentProcessedSuccessfullyEvent(NestpayPaymentProcessedSuccessfullyEvent $event) {
        $payment = $event->getPayment();

        //CUSTOMER HAS PAID, DO RELATED STUFF HERE

        //$payment is instanceof Eloquent Model which implements \Cubes\Nestpay\Payment interface

        //sending email
        \Mail::to(
            $payment->getProperty(Payment::PROP_EMAIL),
            $payment->getProperty(Payment::PROP_BILLTONAME)
        )->send(new NestpayPaymentMail($payment));
    }

    //...