先前花了几天的时间,终於把每次API发送前的安全规定的细碎精工给搞定了,也开了篇幅写了一些关於十六进位转换与Base64的差异等的小专题後,接下来就可以再回到使用情境面,来看我们身为商家角色要为我们的电商平台顾客提供怎麽样的服务。
当我们顾客在选购商品服务到购物车後,确认为无时订单会在此时建立,接着就要进到电商交易买卖的重头戏--线上付款。
永丰银行APIs的服务就可以在这个阶段提供金流服务给客户,目前提供了两个线上付款的服务:
以上无论哪一种,在永丰API对应到的服务名称都是OrderCreate
提供转帐用的虚拟帐号给顾客,与信用卡刷卡、行动支付等比较起来,会是一个较不即时的行为。多半会给予顾客一定的期限,在顾客於一定时间内完成转帐付款之後,我们预期会由永丰API主动告知我们(电商平台)顾客已完成付款,并且我们会把相关的订单付款状态作更新。
阶段一:由我们呼叫永丰API
OrderCreate
API,并告知使用「虚拟帐号」服务。
BackendURL
的值,是为後续通知我们顾客付款状态的更新阶段二:消费者付款行为
5. 消费者可依期限内,透过其惯用的方法进行转帐付款 (可以是实体ATM、线上非约定转帐、线上WebATM…)
阶段三:永丰API端主动通知我们
6. 在永丰银行那端,只要在他所发出的虚拟帐号被缴款後,会有一个Mapping机制对应到当初我们传送的BackendURL
,因此会将该笔订单的付款状态查询代码(PayToken
)传到我们准备的接收网址。
阶段四:确认付款状态
7. 我们提供的网址若被永丰呼叫时,若能顺利取得传过来的PayToken
,当然要自行撰写程序去作好PayToken
的储存与管理工作。
8. 只要上面这个步骤有确实收到PayToken
,就要先在Response中回报「成功结案」给永丰API。 (不然永丰API会再继续发PayToken)。
9. 接下来就是要把刚刚的PayToken拿去问另一支API服务OrderPayQuery
来取得该PayToken对应到的付款状态细节。
10. 取得这些资讯後,我们应该要更新电商这笔订单的付款状态,让消费者可透过电商页来确认自己的付款状态确定也是一致的。
开发规格书中,针对建立订单交易的虚拟帐号,有以下的必填栏位:
参数名称 | 说明 | 我们的内容 |
---|---|---|
ShopNo | 商店号码 | NA0249_001 |
OrderNo | 订单编号 (由商店产生) | ex. A202109123456 (格式固定,但後六码随机动态产生) |
Amount | 订单总金额需补上小数2位**。所以如果是10元,则Amount是1000。 | 79900 注:是799元,当然可设计随机产生。 |
CurrencyID | 币别固定传入TWD |
TWD |
PrdtName | 收款名称最长60个中英文。 | ATM虚拟帐号收款 |
ReturnURL | 将顾客导回付款完成页面之网址 | https://127.0.0.1/sinopac/demoSite/payFinished/ (之後再实作) |
PayType | 收款方式ATM虚拟帐号的话,固定传入A 。 |
A |
ExpireDate | 付款截止日使用虚拟帐号为必填,若为2021/9/30,则填入20210930 | 执行日期+N天 |
程序实作上会先以验证与正确性为目标,主要把重点先放在发出request与取得response的结果符合预期为主,不会花太多时间在功能模组的设计,後面有时间再慢慢重构程序码。
所以我会先走一遍Hard code版的request资料,之後再把类似OrderNo、Amount、ExpiredDate等值以订单的产生器的方式作模拟,让每次的订单内容都可以有所不同以贴近真实的消费行为。
因此,一样的我们盘点「阶段一」的高阶逻辑後,可大约展出下面的实作关键
接着就可以开始来准备Python Code的实作了
import urllib
import hashlib
import requests
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
import datetime
from random import randrange
from datetime import date, timedelta, datetime
先引入我们会用到的module,由於我们会需要产生动态乱数的订单号码,所以会引入random
module,以及要实作付款到期日,所以也需引入datetime
module。
shop_no = "NA0249_001"
A1, A2, B1, B2 = "86D50DEF3EB7400E", "01FD27C09E5549E5", "9E004965F4244953", "7FB3385F414E4F91"
上面shop_no与A1~A4的值是固定的,因此就先hard code写在这里。
def bytes_xor_to_hexstring(ba1, ba2):
return bytes([a ^ b for a, b in zip(ba1, ba2)]).hex()
def get_hash_id():
ba_xor_A = bytes_xor_to_hexstring(bytes.fromhex(A1), bytes.fromhex(A2))
ba_xor_B = bytes_xor_to_hexstring(bytes.fromhex(B1), bytes.fromhex(B2))
return "{}{}".format(ba_xor_A, ba_xor_B).upper()
def get_new_nonce():
url = "https://sandbox.sinopac.com/QPay.WebAPI/api/Nonce"
req_param = {
"ShopNo": shop_no
}
response = requests.post(url=url, json=req_param).json()
return str(response["Nonce"])
def get_aes_iv(nonce):
return hashlib.sha256(nonce.encode('UTF-8')).hexdigest().upper()[-16:]
这边准备了几个function主要是将A1~A4 Hash代码进行运算,主要产生Hash ID用途。
另外还有先前最早呼叫的取得nonce值的API。
有了nonce值後,就可以产生AES加密所需要的IV值。
以上可参考之前的文章:
Day03 - [丰收款] 分析技术文件後,开始做个Nonce开胃菜吧!
Day04 - [丰收款] 金流API的起手式,每次沟通都机密
在进行message
的加密以及sign
安全签章之前,我们这次要模拟每次的订单交易资料都不相同,因此我们要把原本完全hard code的shop_data讯息内文,写一些function来动态产生资料。
明天再继续,先前是将shop_data完全以开发规格书中的资料进行验证,里面的值都是死的,包含nonce值也是固定的。接下来我们将提供较为模拟且每次会不相同的订单资料,然後来实际呼叫API。
<<: Day 09 - Design System x 实作 — Typography
>>: Day9 Android - Intent(换页)的基础上->A页面传值(bundle)至B页面
25 - Design Pattern(5) - Service Object Service 相对...
前言 过去总是羡慕具有设计、美术能力的朋友们,都能累积自己的作品集,并自豪地展现给大众。我的工作属於...
前言 这是本人第一次挑战铁人赛,虽然这篇幅水了不少文章,不过也终於让我写到完赛了 ✧*。 ٩(ˊᗜˋ...
之前我们在写 API 程序的时候,一开始使用写死在程序里的资料集合(List),这个方法虽然快速让我...
今天来介绍一个 Solidity 的另一个特别的东西 libraries。 下面来看看 librar...