現在商業網站幾乎都配有購物車,順便在自己的網站平台上銷售產品,但總是需要收錢才交貨或者先收到錢才出貨,這時候可以透過第三方支付來幫網站處理所有金流的事情,讓業主省心。
前置準備
先到 綠界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,方便別人使用。