現在商業網站幾乎都配有購物車,順便在自己的網站平台上銷售產品,但總是需要收錢才交貨或者先收到錢才出貨,這時候可以透過第三方支付來幫網站處理所有金流的事情,讓業主省心。

前置準備

先到 綠界API/SDK金流串接教學與下載 網頁,下載 PHP 版的 金流整合串接SDK完整版-全方位金流API技術文件檔案

若是使用 Localhost 本機測試,請參考 Ngrok – 讓你的 localhost 也有實際的 domain 對外使用 讓 Localhost 可以接收串接後返回資料。

引入SDK到Laravel中

將下載回來的 SDK 檔案放到 Laravel 專案中,例如: app\ECPaySDK 目錄中。

新增路由

//付款按鈕,收集所有資料,並傳送至綠界
Route::post('order/pay','OrderController@pay')->name('order.pay');
//返回資料
Route::post('order/paycallback','OrderController@paycallback');
//返回成功畫面
Route::get('order/paysuccess','OrderController@paysuccess');

修改 OrderController 中的 pay function (路由中的 POST)

//開頭上方記得導入 SDK 中的 ECPay_PaymentMethod class
use ECPay_PaymentMethod;

//中介層排除掉 paycallback 與 paysuccess 檢驗
public function __construct(){
    $this->middleware('auth', [
        'except' => [
            'paycallback', 'paysuccess'
        ]
    ]);
}

修改 app\Http\Middleware\VerifyCsrfToken.php 排除掉返回的 CSRF 檢驗,否則該資料將會因為沒有 CSRF 參數而被拒絕進入。

protected $except = [
    '/order/paycallback'
];

將 example\sample_Credit_CreateOrder.php 內容複製到 OrderController 中的 pay function 中。並做修改。

測試過程中發現,會報找不到 ECPay_PaymentMethod 的錯誤訊息。參考網路上文章得知是 PSR-4 對應 Class 問題。所以需去修改 composer.json ,在 autoload 中,classmap 段落中,將 app/ECPaySDK 目錄導引進來。

    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "classmap": [
            "database/seeds",
            "database/factories",
            "app/ECPaySDK"
        ]
    },

修改完成後,執行 composer dump-autoload 重新載入 composer 後就OK了。

composer dump-autoload

在宣告 $obj 時,記得要在 ECPay_AllInOne() 前方加一個反斜線 ( \ ),不然還是一樣找不到 class。

$obj = new \ECPay_AllInOne();

pay function

    //建立訂單與付款資料傳送至綠界
    public function pay(Request $request)
    {
        $id = $request->orderid;
        $order = OrderEloquent::findOrFail($id);
        $products = ProductOrderEloquent::where('order_id',$order->id)->get();

        $MerchantTradeNo = "ECPayTest".time();
        OrderEloquent::find($id)->update(['payMethod' => $MerchantTradeNo ]);

        /**
        *    ECPay Credit信用卡付款產生訂單範例
        */
        //載入SDK(路徑可依系統規劃自行調整)
        try {
            $obj = new \ECPay_AllInOne();

            //服務參數 (測試用參數)
            $obj->ServiceURL  = "https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5";    //服務位置
            $obj->HashKey     = '5294y06JbISpM5x9' ;                                            //測試用Hashkey,請自行帶入ECPay提供的HashKey
            $obj->HashIV      = 'v77hoKGq4kWxNNIS' ;                                            //測試用HashIV,請自行帶入ECPay提供的HashIV
            $obj->MerchantID  = '2000214';                                                      //測試用MerchantID,(有OTP) 2000132 (無OTP) 2000214
            $obj->EncryptType = '1';                                                            //CheckMacValue加密類型,請固定填入1,使用SHA256加密

            //基本參數(請依系統規劃自行調整)
            $obj->Send['ReturnURL']         = env('ECPay_CALL_BACK');                           //付款完成通知回傳的網址
            $obj->Send['ClientBackURL']     = env('ECPay_CALL_BACK_SUCCESS');                   //付款完成通知回傳的網址
            $obj->Send['MerchantTradeNo']   = $MerchantTradeNo;                                 //訂單編號
            $obj->Send['MerchantTradeDate'] = date('Y/m/d H:i:s');                              //交易時間
            $obj->Send['TotalAmount']       = $order->total;                                    //交易金額
            $obj->Send['TradeDesc']         = "good to drink" ;                                 //交易描述
            $obj->Send['ChoosePayment']     = ECPay_PaymentMethod::Credit ;                     //付款方式:Credit
            $obj->Send['IgnorePayment']     = ECPay_PaymentMethod::GooglePay ;                  //不使用付款方式:GooglePay

            //帶入訂單的商品資料並放入$obj->Send['Items']中
            foreach ($products as $product) {
                $items['Name'] = $product->product->name;
                $items['Price'] = $product->price;
                $items['Currency'] = '元';
                $items['Quantity'] = $product->qty;
                $items['URL'] = "dedwed";
                array_push($obj->Send['Items'], $items);
            }
            //訂單的商品資料
            // array_push($obj->Send['Items'], array('Name' => "歐付寶黑芝麻豆漿", 'Price' => (int)"2000",
            // 'Currency' => "元", 'Quantity' => (int) "1", 'URL' => "dedwed"));

            //Credit信用卡分期付款延伸參數(可依系統需求選擇是否代入)
            //以下參數不可以跟信用卡定期定額參數一起設定
            $obj->SendExtend['CreditInstallment'] = '' ;    //分期期數,預設0(不分期),信用卡分期可用參數為:3,6,12,18,24
            $obj->SendExtend['InstallmentAmount'] = 0 ;    //使用刷卡分期的付款金額,預設0(不分期)
            $obj->SendExtend['Redeem'] = false ;           //是否使用紅利折抵,預設false
            $obj->SendExtend['UnionPay'] = false;          //是否為聯營卡,預設false;

            //Credit信用卡定期定額付款延伸參數(可依系統需求選擇是否代入)
            //以下參數不可以跟信用卡分期付款參數一起設定
            // $obj->SendExtend['PeriodAmount'] = '' ;    //每次授權金額,預設空字串
            // $obj->SendExtend['PeriodType']   = '' ;    //週期種類,預設空字串
            // $obj->SendExtend['Frequency']    = '' ;    //執行頻率,預設空字串
            // $obj->SendExtend['ExecTimes']    = '' ;    //執行次數,預設空字串

            # 電子發票參數
            /*
            $obj->Send['InvoiceMark'] = ECPay_InvoiceState::Yes;
            $obj->SendExtend['RelateNumber'] = "Test".time();
            $obj->SendExtend['CustomerEmail'] = 'test@ecpay.com.tw';
            $obj->SendExtend['CustomerPhone'] = '0911222333';
            $obj->SendExtend['TaxType'] = ECPay_TaxType::Dutiable;
            $obj->SendExtend['CustomerAddr'] = '台北市南港區三重路19-2號5樓D棟';
            $obj->SendExtend['InvoiceItems'] = array();
            // 將商品加入電子發票商品列表陣列
            foreach ($obj->Send['Items'] as $info)
            {
                array_push($obj->SendExtend['InvoiceItems'],array('Name' => $info['Name'],'Count' =>
                    $info['Quantity'],'Word' => '個','Price' => $info['Price'],'TaxType' => ECPay_TaxType::Dutiable));
            }
            $obj->SendExtend['InvoiceRemark'] = '測試發票備註';
            $obj->SendExtend['DelayDay'] = '0';
            $obj->SendExtend['InvType'] = ECPay_InvType::General;
            */

            // dd($obj);
            //產生訂單(auto submit至ECPay)
            $obj->CheckOut();

        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }

paycallback function

    //綠界返回資料使用
    public function paycallback(Request $request)
    {
        $order = OrderEloquent::where('payMethod',$request->MerchantTradeNo)->update(['status' => '待出貨' ]);

        // 返回的資料格式與內容
        // {
        //     "CustomField1":null,
        //     "CustomField2":null,
        //     "CustomField3":null,
        //     "CustomField4":null,
        //     "MerchantID":"2000214",
        //     "MerchantTradeNo":"OrderTest1604538407",
        //     "PaymentDate":"2020\/11\/05 09:07:10",
        //     "PaymentType":"Credit_CreditCard",
        //     "PaymentTypeChargeFee":"26",
        //     "RtnCode":"1",
        //     "RtnMsg":"\u4ea4\u6613\u6210\u529f",
        //     "SimulatePaid":"0",
        //     "StoreID":null,
        //     "TradeAmt":"1058",
        //     "TradeDate":"2020\/11\/05 09:06:47",
        //     "TradeNo":"2011050906472347",
        //     "CheckMacValue":"73E2BE3C520ABD811CA12F1B2D0031ED5DE6DA79F19941249F6120BE501AFBD0"
        // }
    }

這個 function 主要用途就是處理返回來的資料,可以將其作紀錄或者改變訂單相關資料…等等。

paysuccess function

    //綠界畫面顯示付款成功返回商店時引導回來網址.
    public function paysuccess()
    {
        SESSION::put('success','付款成功');
        return Redirect::route('order.index');
    }

(由於 callback 是 post 方式返回,畫面實際上還是停留在綠界那邊,故需要提供綠界一個成功付款後返回本站的連結參數,當綠界通知付款成功,畫面上會有一個返回商店的按鈕。

$obj->Send['ClientBackURL']     = env('ECPay_CALL_BACK_SUCCESS');

實際測試

按下付款按鈕
輸入信用卡資訊及手機號碼
輸入手機驗證碼後,付款成功
返回後出現付款成功訊息,且訂單操作按鈕已被關閉並列出付款單號
至綠界後台查詢該筆資料是否正確傳入

Laravel ECPay Package

很多 Laravel 開發者替 ECPay 做了 Package,方便別人使用。

最後修改日期: 2020 年 11 月 5 日