手把手程式實作分享系列:Python串接第三方金流 綠界XDjango

Walter Chiu
Bandai的機器學習筆記
16 min readFeb 10, 2022

何謂第三方金流

廣義來說,在一樁交易過程中,除了買賣雙方外,透過第三方來代收、代付金流,就可稱之為第三方支付。

第三方金流主要功能就是,先向顧客代收交易金額,等交易完全成功,例如是顧客收到貨品確認沒問題,才撥款給電商平台,而第三方金流也不是免費的,錢經過了它的手,怎麼有不收過路費的道理呢 XD,所以就有 手續費 的存在拉,關於手續費和服務內容,也就是各家第三方金流所競爭的關鍵。

由於我們是串用綠界的服務,就貼一下他們的金流小知識,分享給大家,如果有興趣的可以點進去看一下。

舉例來說

第三方金流就是你在電商網頁(博客來、蝦皮等等)上,進行結帳時會跳轉到一個要你輸入信用卡卡號的頁面,像下圖,要求你 填入卡號 或 選擇其他付款方式 的頁面,這就是第三方金流的服務。

今天要來串接的第三方金流廠商是 綠界,除了綠界還有其他廠商,像是藍新、paypel等等….反正很多,使用綠界就也沒想太多,反正品牌大,有線上支援的服務,我在串接的時候就狂寄信問他們。顆顆

綠界-台灣最早的第三方金流

我們是使用 pyhton X django當作後端嘛,綠界有提供 Python SDK,可以省去我們很多麻煩。

綠屆第三方支付,支援以下支付方式

  • 信用卡(一次付清、分期付款)
  • 網路ATM
  • ATM櫃員機
  • 超商代碼
  • 超商條碼
  • Google Pay

除了支援 All in One 金流之外,還有提供 物流整合服務,包含超商(全家、7–11、萊爾富)取貨付款,還有黑貓、宅配通,還有提供 電子發票的服務,算是相當完整,但手續費也不低 XD,文章下面有 2020 年 3 月的手續費表格截圖供參考。

先來註冊綠界

驗證完 → 填寫基本資料,到目前的步驟沒什麼問題,就是基本的註冊會員,下一步的收款設定比較麻煩

收款設定

這步驟需要決定,你是什麼商店、你賣哪些商品、提供身分或公司證明

公司戶跟個人戶我都有用過,但公司戶要給的資料超多超麻煩,所以後來我走個人戶的審核。

到這邊,已經可以接收非信用卡的收款了,如果要開通 接受信用卡收款 的功能、提領 的功能,需要另外由系統驗證證件,需要 2~3 個工作天的驗證流程。這邊要跟大家分享,這些審核資料是人工閱,所以有時候會很慢也可以會失誤,他前幾次給我認證失敗,我就寄信跟他們講,我明明都有按規定給予文件,然後什麼都沒改,我就通過了……

設定提領帳戶

全部申請及審核完成後,長這樣

建立收款連結

如果只是簡單的需要收款,可以直接透過「建立收款連結」,就可以產生一組 網址QR code,像是 https://p.ecpay.com.tw/XXXX 這樣的一串網址,而你只要把這組網址 或 QR code,轉貼到顧客看的到的地方(可能是你的文章或者是個人網頁等等),顧客就可以點進去網址,使用刷卡或超商付款等等的方式,透過各種方式給你錢 !

實際建立收款連結的過程

進到綠界的管理後台,點建立收款連結,然後填資料,建立一個固定金額的商品,如果有很多項商品,就需要建立多筆連結,如果你有串 金流 SDK 就不用手動新增了,可以透過後端程式邏輯,把你原本就有的訂單系統結合 SDK,新增 商品 與 收款連結 的對應關係。

因為各種付款方式有金額範圍限制,如果要成功建立,記得要符合所有付款方式的最低限度

建立之後會得到一個連結、QR code,你只要把這串 網址 或 QR code 轉貼到 文章 或 私訊給你的顧客,他們就可以透過第三方金流來付款給你。

試著用「收款連結」來結帳看看

現在要模擬顧客刷卡的過程,自己結帳給自己 XD,點進去透過綠界產生的收款連結,就會跳轉到綠界的結帳頁面。

點下一步→ 填付款人的基本資料

填完基本資料後,選擇付款方式,符合各類付款方式的範圍,就可以選各種付款方式。

填完信用卡資訊後,就近到熟悉的手機驗證頁面,可以看到特約商店是 GreenWorld 綠界,相當於是我的信用卡付款給 綠界,由 綠界 代管,等整筆訂單交易成功,綠界 再把訂單的 31 元扣除手續費,再放到 綠界帳戶,需要的時候再申請 提領,將放在 綠界帳戶 的錢,匯款到個人/公司銀行帳戶。

最後結帳成功

到綠界後台檢查訂單狀況

在綠界的後台可以查詢每一筆訂單,包括 消費者姓名手機email付款方式付款狀態等等,也可以決定是否 退款

被扣了 5 元,在國內使用 信用卡一次付清 的手續費是 2.75%,因為 31 元的 2.75% 低於最低手續費 5 元,所以就被收了 5 元,對於小額收款的電商平台來說,這是一個很大的抽成。

以我這一筆 31 元的訂單來講,就相當於是 16% 的手續費,非常高。

退款,在綠界後台也能處理取消訂單

因為是使用信用卡付款,還沒請款時,退款相對簡單,如果是已經請款了 或 客戶用的是別種結帳方式,那就要我們自己處理退款,也就是錢已經到綠界了,綠界是不會幫忙處理退款的,你需要用另外的帳戶來退款給顧客。

這個功能大家一定要會,因為測試的時候,我覺得還是要拿自己信用卡全部跑一次流程,會比較安心。

到這邊,已經瞭解綠界的操作流程了,再來就是後端Server 串接 第三方金流SDK 的部分。

Python 串接 綠界 All in One 金流 SDK

好拉,我們要進入正題了!用Pyhton 跟djnago 來串綠界的金流服務。

綠界提供 PHP、Java、Ruby、Node.js、C#(.Net) 和 Python,六種的程式語言的 SDK,而我們這篇使用的 Python 的 All in One SDK,在官方提供的 Github 上,除了有 SDK 之外,還有數個 sample codes,我們這邊參考的是 sample_create_order_ALL.py 這個 sample code。

導入 SDK

首先需要先把 All in One SDK 放到 Django 專案底下

參考 sample code 來使用 SDK

原本 sample code 長這樣,落落長,而我們真的需要修改的地方,用註解的方法標註,真正的修改方法需要參考官方文件,我寫文章時所參考的文件版本是 5.1.47 (2020-02-10)

sample_create_order_ALL.py 複製下來,並重新命名為 ecpay_testing.py,放在 shop/ 底下 (和 views.py 同層級),且把整個用一個叫做 main 的 function 包起來。

p.s 我在medium上不好寫code。大家去這邊抓來改。 連結

要改的地方:

  1. 用main 包起來
  2. “/path/to/ecpay_payment_sdk.py”的相對位置
  3. 把OrderResultURL的參數 改成空白,或者改成自己想要的網站(我這邊卡了一下…..)***然後這邊如果要用自己的網頁要特別注意***,綠界Sdk這個參數後面是POST,如果直接寫網址是會出錯的,我這邊是帶到自己後端的api 然後跳轉url網址。
  4. 測試環境下,MerchantID , HashKey, HashIV不用改,要在正式環境處理的話記得改。
import importlib.util# 第一個需要修改的,就是 SDK 路徑
spec = importlib.util.spec_from_file_location(
"ecpay_payment_sdk", # SDK檔名不用改
"/path/to/ecpay_payment_sdk.py" # 改成 django app name/sdk name,# 以我把 SDK 放到 shop 為例,# 我就是改成 "shop/ecpay_payment_sdk.py"
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
from datetime import datetime
def main():
# 第二個需要修改的,商品資訊
order_params = {
'MerchantTradeNo': datetime.now().strftime("NO%Y%m%d%H%M%S"),
'StoreID': '',
'MerchantTradeDate': datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
'PaymentType': 'aio',
'TotalAmount': 2000, # 商品金額
'TradeDesc': '訂單測試', # 商品描述
'ItemName': '商品1#商品2', # 商品名稱,用井字號當分行
'ReturnURL': 'https://www.ecpay.com.tw/return_url.php', # 顧客填完付款資料後的跳轉頁面
'ChoosePayment': 'ALL', # 顧客的付費方式

# 結帳後,先導到 OrderResultURL,從綠界頁面跳回的頁面
# 如果沒有參數才會跳轉到 ClientBackURL
'ClientBackURL': 'https://www.ecpay.com.tw/client_back_url.php',
'ItemURL': 'https://www.ecpay.com.tw/item_url.php', # 商品資訊頁面
'Remark': '交易備註', # 備註文字
'ChooseSubPayment': '',

# 結帳成功/失敗後的結果頁面,告知顧客本次的結帳結果
'OrderResultURL': 'https://www.ecpay.com.tw/order_result_url.php',
'NeedExtraPaidInfo': 'Y',
'DeviceSource': '',
'IgnorePayment': '',
'PlatformID': '',
'InvoiceMark': 'N',
'CustomField1': '',
'CustomField2': '',
'CustomField3': '',
'CustomField4': '',
'EncryptType': 1,
}

extend_params_1 = {
'ExpireDate': 7, # 商品上架期限
'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php', #付款資訊頁面
'ClientRedirectURL': '', # 看完付款資訊,要重導到哪裡
}

extend_params_2 = {
'StoreExpireDate': 15,
'Desc_1': '',
'Desc_2': '',
'Desc_3': '',
'Desc_4': '',
'PaymentInfoURL': 'https://www.ecpay.com.tw/payment_info_url.php',
'ClientRedirectURL': '',
}

extend_params_3 = {
'BindingCard': 0,
'MerchantMemberID': '',
}

extend_params_4 = {
'Redeem': 'N',
'UnionPay': 0,
}

# 發票資訊
inv_params = {
# 'RelateNumber': 'Tea0001', # 特店自訂編號
# 'CustomerID': 'TEA_0000001', # 客戶編號
# 'CustomerIdentifier': '53348111', # 統一編號
# 'CustomerName': '客戶名稱',
# 'CustomerAddr': '客戶地址',
# 'CustomerPhone': '0912345678', # 客戶手機號碼
# 'CustomerEmail': 'abc@ecpay.com.tw',
# 'ClearanceMark': '2', # 通關方式
# 'TaxType': '1', # 課稅類別
# 'CarruerType': '', # 載具類別
# 'CarruerNum': '', # 載具編號
# 'Donation': '1', # 捐贈註記
# 'LoveCode': '168001', # 捐贈碼
# 'Print': '1',
# 'InvoiceItemName': '測試商品1|測試商品2',
# 'InvoiceItemCount': '2|3',
# 'InvoiceItemWord': '個|包',
# 'InvoiceItemPrice': '35|10',
# 'InvoiceItemTaxType': '1|1',
# 'InvoiceRemark': '測試商品1的說明|測試商品2的說明',
# 'DelayDay': '0', # 延遲天數
# 'InvType': '07', # 字軌類別
}

# 建立實體
ecpay_payment_sdk = module.ECPayPaymentSdk(
# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 商店ID
MerchantID='2000132',

# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 HashKey
HashKey='5294y06JbISpM5x9',

# 參考綠界後台->系統開發管理->系統界接設定,開發時有測試用的 HashIV
HashIV='v77hoKGq4kWxNNIS'
)

# 合併延伸參數
order_params.update(extend_params_1)
order_params.update(extend_params_2)
order_params.update(extend_params_3)
order_params.update(extend_params_4)

# 合併發票參數
order_params.update(inv_params)

try:
# 產生綠界訂單所需參數
final_order_params = ecpay_payment_sdk.create_order(order_params)

# 產生 html 的 form 格式
action_url = 'https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5' # 測試環境
# action_url = 'https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5' # 正式環境
html = ecpay_payment_sdk.gen_html_post_form(action_url, final_order_params)
# 最後產出 html,回傳回去顯示此 html
return html
except Exception as error:
print('An exception happened: ' + str(error))

views.py

導入 ecpay_testing.pymain()

from .ecpay_testing import main@csrf_exempt
def ecpay_view(request):
return HttpResponse(main())

urls.py

把這個測試頁面,綁在 ecpay/ 的網域底下,所以 urls.py 長這樣

urlpatterns = [
...
path('ecpay/', ecpay_view),
]

Djano 跑起來

$ python manage.py runserver

訪問 127.0.0.1:8000/ecpay/

進入到測試頁面

在結帳前,還會告知目前是測試環境

我最後就成功了,我搞了很久……祝大家都能順利完成。

單日心得總結

先跟大家說,以上的範例,全部都是純後端的走法,原理是用python去call綠界的post api然後跳轉他們的金流頁面。 驗證碼( CheckMacValue ) 已經都包好在sdk後面了,我在測試的時候,測試環境 跟正式環境 都ok

如果不是走sdk的路線,使用前端寫post 到綠界 api
(‘https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5') (https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5)

不管連線到測試環境或者 正式環境 都要傳送 驗證碼( CheckMacValue ) 給綠界,我嫌麻煩就沒繼續測試了。

(https://www.ecpay.com.tw/CascadeFAQ/CascadeFAQ_Qa?nID=4116&fbclid=IwAR1akY2jfRtMS6k7d4irBEABvzwFulIR93TK7lwitxTHIUBbBr7d-N5WQcY)

因為寫到一半,要解的問題爆炸多,如果有成功的朋友,也歡迎分享給我~一起討論 一下。

--

--

Walter Chiu
Bandai的機器學習筆記

台大電機博士候選人,主要學習電腦科學、資訊教育,關心各種時事議題,歡迎一起討論有趣的專題 dodo0095@hotmail.com