綠界金流串接攻略

綠界金流串接攻略

這篇文章說明該如何利用套件來快速進行金流串接

實作方式很單純,拋送訂單資訊給綠界金流後,它會生成付款頁面給我們,長得像這樣 綠界金流串接攻略

付款時需要填入正確的手機號碼,因為等下驗證時會發送驗證碼給這個號碼

綠界金流串接攻略

因為測試環境還沒申請 SSL ,會出現這個錯誤提示,這是沒關係的,選擇 "仍要傳送" 才能完成付款

綠界金流串接攻略

當用戶付完款之後會轉址到指定路由,我們在該方法去完成訂單狀態的變更即可

前置準備

如果需要透過綠界來進行付款,是需要申請綠界帳號並且通過審核得到信用卡付款資格的。但如果只是想要練習串接測試的話,則不需要,這裡提供測試資料的金鑰

綠界金流串接攻略

實作流程

Step 1. 下載套件

開啟 Terminal ,輸入以下指令:

composer require tsaiyihua/laravel-ecpay

PS:需注意此套件支援 PHP 7.2 版本,Laravel 版本 6.0 以上

如果想參考綠界的技術文件,套件資料夾內有一份,路徑為 vendor/tsaiyihua/laravel-ecpay/documents/ecpay_gw_p110.pdf

Step 2. 環境設定

同樣在 Terminal ,輸入以下指令:

這將會在 config 資料夾裡頭加入一個名為 ecpay.php 的設定檔,但你無需進行任何修改

php artisan vendor:publish --tag=ecpay

修改 .env 檔案,在裡頭加入以下金鑰設定,我預設已經為你準備好了測試帳密,可先不修改直接使用。但如果要連正式環境,就記得要改成申請得到的金鑰了!

ECPAY_MERCHANT_ID=2000132
ECPAY_HASH_KEY=5294y06JbISpM5x9
ECPAY_HASH_IV=v77hoKGq4kWxNNIS
ECPAY_INVOICE_HASH_KEY=
ECPAY_INVOICE_HASH_IV=
ECPAY_SEND_FORM=

Step 3.修改訂單表格(非必須)

一般來說當付款完畢會需要儲存金流端所傳回的資料,因此有必要擴增訂單表格的欄位,以下給出一個建議訂單表格的欄位

//database\migrations\create_orders_table

public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('owner_id')->index(); //下單人
            $table->foreign('owner_id')->references('id')->on('users')->onDelete('cascade');
            $table->string('receiver', 10)->nullable(); //收件人姓名
            $table->string('receiverTitle', 10)->nullable(); //收件人頭銜
            $table->string('receiverMobile', 20)->nullable(); //收件人手機號碼
            $table->string('receiverEmail', 100)->nullable(); //收件人電子郵箱
            $table->string('receiverAddress', 100)->nullable(); //收件人地址
            $table->string('message', 500)->nullable(); //訊息
            $table->string('couponCode', 100)->nullable(); //優惠券序號
            $table->integer('subtotal')->default(0); //訂單金額
            $table->integer('shipCost')->default(0); //運費
            $table->string('status', 20)->default('create'); //訂單狀態,包含 create 建立 paid 已付款 done 已完成 canceled 已取消
            $table->string('pay_type', 100)->nullable(); //付款類型
            $table->string('trade_no', 100)->nullable(); //金流序號
            $table->timestamp('pay_at')->nullable(); //付款時間
            $table->string('reply_desc', 255)->nullable(); //回覆給客戶的訊息
            $table->string('type', 255)->default('normal'); //類型
            $table->timestamps();
        });
    }

Step 3.1.修改商品訂單中介表格(非必須)

//database\migrations\xxxx_xx_xx_xxxxxx_create_item_order_table.php

public function up()
    {
        Schema::create('item_order', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('item_id')->nullable()->unsigned()->index(); 
            $table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
            $table->bigInteger('order_id')->nullable()->unsigned()->index(); 
            $table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
            $table->integer('quantity')->default(1);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::table('item_order', function (Blueprint $table) {
            $table->dropForeign(['item_id']);
            $table->dropForeign(['order_id']);
        });

        Schema::dropIfExists('item_order');
    }

Step 4.修改訂單模型(可選)

最好是把訂單表格可被修改的欄位都寫進 $fillable 屬性內,以免出現 MassAssignment 錯誤

//app\Models\Order.php

protected $fillable = ['owner_id', 'trade_no', 'pay_type', 'pay_at', 'status'];

//訂單所有商品關係函式
public function items()
{
     return $this->belongsToMany(Item::class);
}

//Mutator
public function getTitleAttribute(){
     $items = $this->items;
     $result = '';
     foreach ($items as $item) {
         $result = $result . $item->title . ',';
     }
     return $result;
}

Step 5. 修改路由檔

套件會為我們建立一些需要的路由,但因為我們希望付款完成後能通知我們來變更訂單狀態,所以需要新增 callback 路由

//routes\web.php

Route::namespace('App\Http\Controllers')->group(function(){
    ...
    Route::get('/checkout','SiteController@checkout');
    Route::post('/checkout/callback','SiteController@checkoutCallback');
    ...
});

Step 6.修改 VerifyCsrfToken 中介層

預設所有 Post 請求都需要附帶 Token 來防止跨站攻擊,但因為金流不會有我們的 Token ,所以要將提供給綠界轉址的路由予以除外才行

//app\Http\Middleware\VerifyCsrfToken.php

protected $except = [
   'checkout/callback'
];

Step 7.擴展控制器

控制器的邏輯你可根據自己需求來建立,以下提供一些基礎的結帳常見程式碼

//app\Http\Controllers\SiteController.php

use Carbon\Carbon;
use App\Models\Item;
use App\Models\Order;
use App\Models\OrderItem;
use Darryldecode\Cart\Cart;
use Illuminate\Http\Request;
use TsaiYiHua\ECPay\Checkout;
use Illuminate\Support\Facades\Log;

class SiteController extends Controller
{
    protected $checkout;

    public function __construct(Checkout $checkout)
    {
        $this->checkout = $checkout;
        $this->checkout->setReturnUrl(url('checkout/callback'));
    }

        //結帳路由方法
    public function checkout()
    {
       //建立訂單&明細
        $items_cart = \Cart::session(Auth::user()->id)->getContent();
        $order = Order::create([
            'owner_id' => Auth::user()->id
        ]);
        foreach ($items_cart as $item_cart) {
            ItemOrder::create(['order_id' => $order->id, 'item_id' => $item_cart->id, 'quantity' => $item_cart->quantity]);
        }

        //串接綠界金流做付款
        $formData = [
            'UserId' => Auth::user()->id, // 用戶ID , 非必須
            'MerchantTradeNo' => 'Goblin' . $order->id, //特店訂單編號
            'ItemDescription' => $order->title, //商品描述,可自己修改
            'ItemName' => 'Goblin Shop Items', //商品名稱,可自己修改
            'TotalAmount' => \Cart::session(Auth::user()->id)->getSubtotal(), //訂單總金額
            'PaymentMethod' => 'Credit', // ALL, Credit, ATM, WebATM
            'CustomField1' => $order->id, //自定義欄位1
            'CustomField2' => Auth::user()->id //自定義欄位2
        ];
        return $this->checkout->setPostData($formData)->send();
    }

    //綠界付完款轉址路由方法
    public function checkoutCallback(Request $request)
    {
       $userId = $request->CustomField2;
        \Cart::session($userId)->clear();
        $response = $request->all();
        $order = Order::find($response['CustomField1']);
        if ($response['RtnCode'] == 1) {
            if ($response['PaymentType'] == 'Credit_CreditCard') {
                $order->pay_type = 'credit';
            }
            $order->trade_no = $response['TradeNo']; //綠界訂單編號
            $order->pay_at = Carbon::createFromFormat('Y/m/d H:i:s',$response['PaymentDate']);
            $order->subtotal = $response['TradeAmt'];
            $order->status = 'paid';
            $order->save();
            Log::info('訂單編號' . $order->id . '付款成功');
        } else {
            Log::error('訂單編號' . $order->id . '付款失敗');
        }
        return redirect('/'); //返回首頁
    }
}

功能測試

以上改動完畢之後,就可以試看看功能能否正常執行

內部確認

可以開啟 log 檔看看是否有出現付款成功的訊息,路徑為 storage/logs/laravel.log

綠界金流串接攻略

外部確認

可以進到綠界的測試環境後台,看看所送出的訂單是否存在並完成了付款,網址為 https://creditvendor-stage.ecpay.com.tw/DumpAuth/Query

綠界金流串接攻略


分享這篇文章:

訂閱電子報,索取 Laravel 學習手冊

價值超過 3000 元,包含常用 Laravel 語法與指令!

一小時免費求職講座

3個應徵軟體工程師前該知道的秘訣

取得免費課程連結

Laravel 百萬年薪特訓營

從最基礎的 PHP 語法開始,包含所有你該知道的網頁基礎知識,連同 Laravel 從零開始一直到實戰,最後還將告訴你如何找好工作,讓你及早擁有百萬年薪