網路改變了現代人很多的生活模式。論就原理,它不過是快速傳遞資訊而已,結果它可以把傳統語音訊號改成語音封包變成網路電話,而平面的郵購清單改成動態的網頁表單變成線上銷售,其實它的原理真的就只是能加快資訊傳輸的速度而已,但這「量變」卻造成「質變」。
金流也是。事實上,當各國央行放棄金本位制度後,所謂的貨幣就不過是個「數字」而已,美國聯準會可以搞 QE1, QE2, QE3 … 的原因,不是它美鈔可以印得比別人快,以 QE2 的規模 6000 億美元來看,美國印鈔局真有辦法在不到 1 年的時間印出 6000 億美元的鈔票嗎? 這還不算它本來就得應付的舊鈔換新鈔需求喔! 美鈔最大額不過是 100 元,印這個太慢了,所以它們印的是美國公債,隨便印都是 10 萬起跳的。當它們想要為金融體系注資時,就把當初發行的公債買回來就行了,而且還不用給現金,在資產負債表上掛帳就行了,可參閱聯準會買債券賺到784億美元。
再以我們中央銀行為例,目前 3 千多億美金的外匯存底,真的是有實體資產放在央行的保險庫嗎? 當外資從紐約匯進 10 億美金,不過就是把某家銀行的美金數字換放到另一家銀行去就行了,根本不用搬真的錢進到台灣。所以金流根本就是資訊流,流通的資訊主要就是兩種,誰匯給誰以及匯多少。「誰匯給誰」關係『身份認證』這種事,而「匯多少」則部份與匯款人的額度也就是『身份認證』有關,剩下的部份就只是數字而已。
說起來金流還比通信網路簡單,至少它不需要使用者另外準備耳機及麥克風。以早期的資訊管理系統來說,會計系統通常是最早建置的,因為它們也只關乎數字。
金流系統聽起來這麼簡單,那我們會寫程式,會作資訊系統的人還不趕快來寫一套!
哈哈哈! 我就知道你不信我,金流系統如果怎麼簡單,怎麼沒聽說過那個大學沒畢業的有開發出來,到是有聽過沒畢業的人可以寫出社交網站; 但如果不簡單,怎麼天底下那麼多家銀行,幾乎每家都有金流系統,但也就那麼一個社交網站有著幾億人的使用者。
嘻! 這說法有沒有想到日近長安遠的故事。
原因不在程式難寫,而是『身份認證』太難。各位有聽過『軟體公司法』嗎? 乃規範軟體公司如何撰寫程式,收費標準以及沒事得接受政府檢查的法律,但是卻有銀行法及金管會,規範營業櫃台可放什麼,不可放什麼,能收取的利率上限為何,以及不定期與主管機關喝喝咖啡。
我們隨便寫個網站讓大家使用時,有沒有要使用者親自到公司櫃台辦理,而且還要帶雙證件及本人拍照喔! 沒有嘛! 因為銀行、信用卡公司都是特許行業,政府沒點頭,一般人是不能開的。你開公司時,在營業項目上面通常是高興拉多少就拉多少,開軟體公司能不能賣書? 可以! 能不能賣服飾? 可以! 但能不能寫個 H101021 商業銀行業? 我包你會被經辦人員白眼,嗆你一句:「請找個有正常腦袋的會計師幫你申請!」
於是乎,我們一般人寫金流系統,都需要找個代理人,幫我們作『身份認證』及『額度確認』的動作。那就是銀行提供的線上刷卡服務或是網路ATM系統,然而如果我們是跟玉山銀行(收單銀行)申請收款服務的,但消費者拿的是第一銀行(發卡銀行)的信用卡或是提款卡時,玉山銀行怎麼知道是真的卡還是假的? 它們得透過財金公司的金資系統作跨行查詢,信用卡則是透過信用卡組織像是 visa 、 mastercard 與發卡銀行查詢。
也因為金流系統真的只是數字交換而已,難作的『身份認證』及『額度開放』都被銀行、信用卡公司作完了,於是乎就有金流公司的誕生,它們整合 WebATM 匯款、信用卡刷卡甚至超商繳費,只要你跟它們簽約,每年繳個閘道服務費,就提供 API 使用。而我們程式設計師只要知道傳什麼參數給它就成了。因為簡單,所以就得付出代價,每筆交易的手續費大概是花 2.8 ~ 3.4 % 之間,比買股票還貴,平平都是數字,轉 100 元扣 3 塊,轉 1000000000 扣 3 億,這不過是多 7 個零而已。
撰寫金流系統前,需要考慮的是『用誰的 API 』,有國內銀行、金流公司及 PayPal 等。
國內銀行:
通常你的公司帳戶開在那家銀行,就跟它們合作,好處是有關係有優惠,如果公司進出金額又大時,手續費會比較容易砍,而且消費者刷卡、匯款後,錢是馬上匯到公司戶頭。缺點是國內銀行的 API 不好用,不要以為它們的資本額動輒幾百億上下,寫的網站就比較厲害,這不見得。它們的本業是賺存放款利差,不是開軟體公司。或許我一竿子打翻一船人,非常歡迎提出反證,畢竟我沒看過國內所有銀行的 API 文件。因為不容易看得到,這一點我也覺得很奇怪,銀行居然會把 API 文件當作是機密,一定要簽約後,才能看到全貌,憑這一點,我就不想用銀行的系統了。
金流公司:
好處是它們的軟體實力比較好, API 考慮比較周延,付款種類較多,入帳管理系統也比較好用,有意見的話也比較有改進的空間。而缺點是金流公司一大堆,不要找到二流的,二流的收款是先到金流公司戶頭,之後再轉到你的公司戶頭,出問題,錢是要不回來的。或是網路頻寬不夠,消費者要刷卡時,苦苦等不到刷卡頁面。甚至盜賣消費者資料。
PayPal:
不須有公司登記,沒有建置費,可以跨國付款,軟體實力也是最高的,不只給個入帳管理系統,連帳務管理都有 API ,所以你高興還可以把帳務管理內建在自己的金流系統中,這樣你的會計就不用記兩組帳號、密碼,這邊登過來,那邊登過去了。缺點是它每筆交易收 3.4% + $10 TWD ,不算便宜。但是我們可以這樣想,公司不大時,用 PayPal 可以比較省成本,因為它少了上萬元的建置費,換算成 PayPal 手續費,大概可以抵上 1000 次,這對草創公司比較有利。另外還有一個不算缺點的缺點,它的 API 文件都是英文的,它沒有台灣辦公室,所以有程式問題要問,都得用英文問,像我就提了一個問題。
以我個人偏好來說,在小規模時,採用 PayPal 收款,大規模時,納入一流金流公司,而銀行則完全不考慮。
這篇文章一開頭其實只是想講如何使用 PayPal Express Checkout 機制收款,結果落落長,到現在都還沒講到初衷,所以請看下篇來了解 Express Checkout 如何應用。
若你不太了解什麼是金流系統,可以先去看「簡述金流系統」。
消費者在線上購買商品或勞務,所謂的付款其實只牽扯到兩件事:『身份驗證』及『確認額度』。但這兩件事都是特許公司如銀行或信用卡公司才能作的事。所以我們得透過中間人或中間人的中間人(金流公司)幫我們作到這兩件事,而我選的是 PayPal ,它是跨國的金流公司,我個人認為十分適合純網際網路公司使用。
從誰那裡匯多少錢到誰那裡? 有三個變數:『付款的人』、『付多少』及『收款人』。這『收款人』當然是我們自己的公司囉。在程式中設定收款帳戶只要設定『帳戶名稱(USERNAME)』、『密碼(PASSWORD)』及『簽名(SIGNATURE)」就行了,如何申請這三種資料請看我的另篇文章。
而『付多少』的設定變數名則為 AMT 。但在消費者刷卡時,要讓他明確地了解買的東西到底有什麼? 價錢是多少? 要刷多少錢? 我們得另外設定訂單的顯示變數。有商品名稱(L_NAME0)、商品描述(L_DESC0)、商品編號(L_NUMBER0)、購買數量(L_QTY0)、商品單價(L_AMT0)、所有商品小計(ITEMAMT)、運送及處理費用(SHIPPINGAMT)、稅金(TAXAMT)等。
這些變數後有帶 0 的表示它可以是多值,如果該筆訂單有第二項商品的話,就設定 L_NAME1 、 L_DESC1 、 L_NUMBER1 、 L_QTY1 、 L_AMT1 ,以此類推。
這些訂單顯示變數有幾項原則:
- ITEMAMT 必須等於 L_AMT0 * L_QTY0 + L_AMT1 * L_QTY1 + ... + L_AMTn * L_QTYn
- AMT 必須等於 ITEMAMT + SHIPPINGAMT + TAXAMT
違反這兩個原則, PayPal 會報錯的。
而『付款的人』部份就不是我們程式設計師該處理的,這部份交由 PayPal 自己與消費者確認卡號是否正確、與發卡銀行確認是否允許消費者刷該筆訂單的金額。等到 PayPal 作完『身份確認』及『額度確認』後,PayPal 會回傳一個 TOKEN ,告知我們消費者有能力消費該筆訂單,如果我們接受該筆交易,就以這個 TOKEN 回覆給 PayPal ,那它就幫我們刷下消費者的卡片了。之後就能在 PayPal 的帳務管理介面中看到消費者的付款紀錄。
上面的觀念了解了,我們這就進行程式的實作吧!
PayPal 的付款程序要經過 3 次的 API 呼叫,分別是 SetExpressCheckout, GetExpressCheckoutDetails, DoExpressCheckoutPayment 。
- SetExpressCheckout 是整理好一份訂單資訊供消費者瀏覽。
- GetExpressCheckoutDetails 是抓取當次交易的詳細資訊,但不包含消費者的卡號。
- DoExpressCheckoutPayment 要求 PayPal 對消費者進行刷卡動作,完成交易。
而消費者瀏覽網頁順序則是『我們的訂單頁面』=>『確定購買』=>『SetExpressCheckout』=>『PayPal 付款頁』=>『PayPal 確認頁』=>『GetExpressCheckoutDetails+DoExpressCheckoutPayment』=>『我們的購買成功頁面』。
我們自己所寫的『確定購買』程式中,會紀錄消費者的購買資訊,產生訂單編號,完成後執行 SetExpressCheckout API 呼叫動作。所謂的呼叫,其實不過就像是 html 中的 form submit 。很懶惰的作法是輸出一個如下的 html 表單,然後要求消費者自己手動按下送出鈕。
1 <form method="POST" action="https://api-3t.paypal.com/nvp">
2 <input type="hidden" name="USER" value="API_username_do_not_copy_me">
3 <input type="hidden" name="PWD" value=" API_password_do_not_copy_me">
4 <input type="hidden" name="SIGNATURE" value="API_signature_do_not_copy_me">
5 <input type="hidden" name="L_NAME0" value="test_product_name">
6 <input type="hidden" name="L_DESC0" value="test_description">
7 <input type="hidden" name="L_NUMBER0" value="test1">
8 <input type="hidden" name="L_QTY0" value="1">
9 <input type="hidden" name="L_AMT0" value="85">
10 <input type="hidden" name="ITEMAMT" value="85">
11 <input type="hidden" name="SHIPPINGAMT" value="10">
12 <input type="hidden" name="TAXAMT" value="5">
13 <input type="hidden" name="AMT" value="100">
14 <input type="submit" name="METHOD" value="SetExpressCheckout">
15 <input type="hidden" name="VERSION" value="63.0">
16 <input type="hidden" name="CURRENCYCODE" value="TWD">
17 <input type="hidden" name="PAYMENTACTION" value="Sale">
18 <input type="hidden" name="CANCELURL" value="http://www.YourCancelURL.com">
19 <input type="hidden" name="RETURNURL" value="http://www.YourReturnURL.com">
20 </form>
這裡有幾個地方要注意, form method 一定是 POST , form action 一定是 https://api-3t.paypal.com/nvp ,input name="METHOD" 的 value 一定是 SetExpressCheckout 。
VERSION 代表你呼叫的 API 版本是多少,版本號太小的 API ,可能會有些參數不支援。不過,以我使用的經驗,上面的參數都能跑在 53 ~ 63 之間。但能設得愈大愈好。
而 CURRENCYCODE 代表收取的幣別, TWD 代表新台幣, USD 代表美金,其他貨幣請參閱這裡。
PAYMENTACTION 的值有三種: Sale, Authorization, Order , Sale 表一般銷售,消費者要買,你一定賣; Authorization 表須確認的銷售,如消費者要買 Giant 的 TCR SL 3 車架,但貴公司沒建置庫存管理,所以消費者下單後,你得到大如足球場的倉庫去找,找得到就賣,找不到只好跟消費者 Say Sorry! Order 表須更長時間的確認銷售,像 Authorization 最多只會在帳務管理系統中等 3 天讓你按下請款鈕,但 Order 可以等到 29 天。
CANCELURL 是當消費者在 PayPal 付款頁中,反悔了,在他取消交易時, PayPal 會導引他回到你的網站。
RETURNURL 是當消費者在 PayPal 確認頁按下「立即付款」, PayPal 會導引他回到你的網站,理論上,這個網頁就是你執行 GetExpressCheckoutDetails + DoExpressCheckoutPayment 的地方。
從這個 html form 範例中,可以了解呼叫 SetExpressCheckout API 真的是非常簡單的事,只要把握正確的 name - value pair(nvp) 即可。
不過我們是 Python 程式設計師,怎麼能用 html form 這麼簡單的東西來呼叫 API ,當然要用 urllib 囉! 把下面的程式插到『確定購買』程式的最後面,這樣就不用消費者自己手動按送出鈕了。
1 from google.appengine.api import urlfetch
2 import urllib
3
4 string_hash = {
5 "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
6 "SIGNATURE": "API_signature_do_not_copy_me", "L_NAME0": "test_product_name",
7 "L_DESC0": "test_description", "L_NUMBER0": "test1", "L_QTY0": "1",
8 "L_AMT0": "85", "ITEMAMT": "85", "SHIPPINGAMT": "10", "TAXAMT": "5",
9 "AMT": "100", "METHOD": "SetExpressCheckout", "VERSION": "63.0",
10 "CURRENCYCODE": "TWD", "PAYMENTACTION": "Sale",
11 "CANCELURL": "http://www.YourCancelURL.com",
12 "RETURNURL": "http://www.YourReturnURL.com",
13 }
14 form_data = urllib.urlencode(string_hash)
15 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
16 payload=form_data,
17 method=urlfetch.POST,
18 headers={'Content-Type': 'application/x-www-form-urlencoded'},
19 deadline=10)
20
21 hash = {}
22 for i in result.content.split('&'):
23 k, v = i.split('=')
24 hash[k] = urllib.unquote(v)
25
26 redirect_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=%s' % hash['TOKEN']
27 return HttpResponseRedirect(redirect_url)
跑到 redirect_url 網址後,就是 PayPal 自己與消費者互動的網頁,等到消費者確定付款了,就會再轉回我們的 RETURNURL 程式。在 RETURNURL 頁面中,首先呼叫 GetExpressCheckoutDetails 得到該 token 所對應的付款資訊。然後再執行 DoExpressCheckoutPayment 即可完成信用卡刷卡動作。
1 # exec GetExpressCheckoutDetails
2 token = request.GET.get('token')
3 string_hash = {
4 "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
5 "SIGNATURE": "API_signature_do_not_copy_me", "METHOD": "GetExpressCheckoutDetails",
6 "VERSION": "63.0", "TOKEN": token,
7 }
8 form_data = urllib.urlencode(string_hash)
9 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
10 payload=form_data,
11 method=urlfetch.POST,
12 headers={'Content-Type': 'application/x-www-form-urlencoded'},
13 deadline=10)
14
15 hash = {}
16 for i in result.content.split('&'):
17 k, v = i.split('=')
18 hash[k] = urllib.unquote(v)
19
20 if hash['ACK'] != 'Success':
21 error_messages = []
22 for k, v in hash.items():
23 error_messages.append('%s: %s'%(k, v))
24 raise Exception(';\n'.join(error_messages))
25
26 # exec DoExpressCheckoutPayment
27 string_hash = {
28 "USER": "API_username_do_not_copy_me", "PWD": " API_password_do_not_copy_me",
29 "SIGNATURE": "API_signature_do_not_copy_me", "METHOD": "DoExpressCheckoutPayment",
30 "VERSION": "63.0", "TOKEN": token,
31 "AMT": "100", "CURRENCYCODE": "TWD",
32 }
33 form_data = urllib.urlencode(string_hash)
34 result = urlfetch.fetch(url='https://api-3t.paypal.com/nvp',
35 payload=form_data,
36 method=urlfetch.POST,
37 headers={'Content-Type': 'application/x-www-form-urlencoded'},
38 deadline=10)
39
40 hash = {}
41 for i in result.content.split('&'):
42 k, v = i.split('=')
43 hash[k] = urllib.unquote(v)
44
45 if hash['ACK'] != 'Success':
46 error_messages = []
47 for k, v in hash.items():
48 error_messages.append('%s: %s'%(k, v))
49 raise Exception(';\n'.join(error_messages))
50
51 return HttpResponseRedirect('http://www.YourThankURL.com/')
就這樣,你會在 PayPal 的帳務管理系統中,看到消費者的付款紀錄。
要使用 PayPal 作為收款工具時,除了申請它的帳戶(建議是商業帳戶)外,若使用的是 Express Checkout 收款機制,你還需為自己所寫的程式申請一組 API 簽章,包含「用戶名稱」、「密碼」、「簽名」。
申請方式很簡單,先登入 www.paypal.com ,看到個人的總覽頁面如下圖:
點選「我的業務設定」。
點選「立即開始」。
點選「為 PayPal 帳戶要求 API 電子簽章」。
選擇「申請 API 電子簽章」,並點選「同意並提交」。
抄下「API用戶名稱」、「API密碼」、「簽名」放到你的程式碼中,就可以呼叫 PayPal 的 Express Checkout API 了。







