三月 29, 2011

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 簡述金流系統

網路改變了現代人很多的生活模式。論就原理,它不過是快速傳遞資訊而已,結果它可以把傳統語音訊號改成語音封包變成網路電話,而平面的郵購清單改成動態的網頁表單變成線上銷售,其實它的原理真的就只是能加快資訊傳輸的速度而已,但這「量變」卻造成「質變」。

金流也是。事實上,當各國央行放棄金本位制度後,所謂的貨幣就不過是個「數字」而已,美國聯準會可以搞 QE1, QE2, QE3 … 的原因,不是它美鈔可以印得比別人快,以 QE2 的規模 6000 億美元來看,美國印鈔局真有辦法在不到 1 年的時間印出 6000 億美元的鈔票嗎? 這還不算它本來就得應付的舊鈔換新鈔需求喔! 美鈔最大額不過是 100 元,印這個太慢了,所以它們印的是美國公債,隨便印都是 10 萬起跳的。當它們想要為金融體系注資時,就把當初發行的公債買回來就行了,而且還不用給現金,在資產負債表上掛帳就行了,可參閱聯準會買債券賺到784億美元

再以我們中央銀行為例,目前 3 千多億美金的外匯存底,真的是有實體資產放在央行的保險庫嗎? 當外資從紐約匯進 10 億美金,不過就是把某家銀行的美金數字換放到另一家銀行去就行了,根本不用搬真的錢進到台灣。所以金流根本就是資訊流,流通的資訊主要就是兩種,誰匯給誰以及匯多少。「誰匯給誰」關係『身份認證』這種事,而「匯多少」則部份與匯款人的額度也就是『身份認證』有關,剩下的部份就只是數字而已。

說起來金流還比通信網路簡單,至少它不需要使用者另外準備耳機及麥克風。以早期的資訊管理系統來說,會計系統通常是最早建置的,因為它們也只關乎數字。

金流系統聽起來這麼簡單,那我們會寫程式,會作資訊系統的人還不趕快來寫一套!

哈哈哈! 我就知道你不信我,金流系統如果怎麼簡單,怎麼沒聽說過那個大學沒畢業的有開發出來,到是有聽過沒畢業的人可以寫出社交網站; 但如果不簡單,怎麼天底下那麼多家銀行,幾乎每家都有金流系統,但也就那麼一個社交網站有著幾億人的使用者。

嘻! 這說法有沒有想到日近長安遠的故事。

原因不在程式難寫,而是『身份認證』太難。各位有聽過『軟體公司法』嗎? 乃規範軟體公司如何撰寫程式,收費標準以及沒事得接受政府檢查的法律,但是卻有銀行法及金管會,規範營業櫃台可放什麼,不可放什麼,能收取的利率上限為何,以及不定期與主管機關喝喝咖啡。

我們隨便寫個網站讓大家使用時,有沒有要使用者親自到公司櫃台辦理,而且還要帶雙證件及本人拍照喔! 沒有嘛! 因為銀行、信用卡公司都是特許行業,政府沒點頭,一般人是不能開的。你開公司時,在營業項目上面通常是高興拉多少就拉多少,開軟體公司能不能賣書? 可以! 能不能賣服飾? 可以! 但能不能寫個 H101021 商業銀行業? 我包你會被經辦人員白眼,嗆你一句:「請找個有正常腦袋的會計師幫你申請!」

於是乎,我們一般人寫金流系統,都需要找個代理人,幫我們作『身份認證』及『額度確認』的動作。那就是銀行提供的線上刷卡服務或是網路ATM系統,然而如果我們是跟玉山銀行(收單銀行)申請收款服務的,但消費者拿的是第一銀行(發卡銀行)的信用卡或是提款卡時,玉山銀行怎麼知道是真的卡還是假的? 它們得透過財金公司的金資系統作跨行查詢,信用卡則是透過信用卡組織像是 visamastercard 與發卡銀行查詢。

也因為金流系統真的只是數字交換而已,難作的『身份認證』及『額度開放』都被銀行、信用卡公司作完了,於是乎就有金流公司的誕生,它們整合 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 如何應用。

一月 24, 2011

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 使用 PayPal 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 的帳務管理系統中,看到消費者的付款紀錄。

一月 22, 2011

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 使用 PayPal Express Checkout 時,如何申請 API 簽章?

要使用 PayPal 作為收款工具時,除了申請它的帳戶(建議是商業帳戶)外,若使用的是 Express Checkout 收款機制,你還需為自己所寫的程式申請一組 API 簽章,包含「用戶名稱」、「密碼」、「簽名」。

申請方式很簡單,先登入 www.paypal.com ,看到個人的總覽頁面如下圖:



點選「我的業務設定」。



點選「立即開始」。



點選「為 PayPal 帳戶要求 API 電子簽章」。



選擇「申請 API 電子簽章」,並點選「同意並提交」。



抄下「API用戶名稱」、「API密碼」、「簽名」放到你的程式碼中,就可以呼叫 PayPal 的 Express Checkout API 了。

biggo.com.tw

A Django site.