昨天抱病撰文,终於在本机端将单笔资料透过ORM的方法,成功将新增的订单资料更新到Heroku Postgres资料库中(非常感动),今天我们要来完成剩下取得PayToken的最後一哩路。
先前已经做好create order的View,可以新增资料,还记得有一个关键的BackendURL
的参数是在我们呼叫API时会传入的参数吗?这个就是为了让永丰API知道到时候要将PayToken传回到哪里让我们接手进行处理。
这项功能其实在开发规格书中,是定义为「即时讯息通知」,老实说如果直接看名称,不是很容易理解其功用,以为是类似Push Notifcation,但完全不是。这个功能纯粹是永丰API会发送给尚未回报结案的TSNo,要传给他们PayToken。
文件说明如下:
STEP1:在「7.1 建立订单交易」有传送BackendURL且该订单「付款完成」或「指定预计自动请款」完成请款时则会 透过此通知传送讯息Token值给您,您收到後需回覆接收成功,如未回覆系统会每隔10分钟重新发送一次,直到失败5次後才会停止发送。
STEP2:接收到Token值後,请透过用「7.3 讯息查询服务」来确认订单付款是否成功或是失败。
因此我们要在这个让API回呼的URL中,除了实作接收这个PayToken的「即时讯息通知」外,还连带的要呼叫「讯息查询服务」才能得到付款的结果。
这个「即时讯息通知」是一个被动被叫用的网页,简单说,这是我方电商提供的API (只是这个API是别人订的规则),另一种说法是我们提供了一个Webhook给一开始的API,在完成某些事後可以回呼叫用通知我们。
这个Webhook,也就是上面称的BackendURL
,里面会传入的东西就只有两个属性的JSON。
{
"ShopNo":"NA0249_001",
"PayToken":"da1547c3d0d1649af5049125b0880c0e227f31e107cbf4f0995bed28d0f066c1"
}
所以我们在Django的View中,取得request参数时,虽然是一个POST的Method,但我们取用这个资料需要使用request.body
来拿到完整的JSON值。
先不论後面我们还需要做PayToken的查询,但我们要回覆永丰API一个固定的结案状态码,固定就是用JSON包装一个Status
属性,并回传S
。
{"Status": "S"}
简单在View中准备一个get_paytoken
,如下:
def get_paytoken(request):
if request.method == 'POST':
result_str = request.body
result_json = json.loads(result_str)
print(" --- PayToken Callback: {}".format(result_json))
update_order_by_paytoken(result_json)
resp_json = {"Status": "S"}
return HttpResponse(json.dumps(resp_json))
取得重要的PayToken後,接着就可以进行「讯息查询服务」了。这个需呼叫的API Function为OrderPayQuery
,他的输入的Message
值其实就是把刚刚BackendURL取回的JSON原封不动丢进去就行了。
但要呼叫的作法,需要和当初做OrderCreate
一模一样,该丢的API基础参数以及加解密流程全都需要重作一遍,今天先把流程讲完,这部份需要把可重覆使用的code整理过後,再来实作。
其中拿回的结果有很多属性,较为重要的有:
属性 | 说明 |
---|---|
APType | 讯息类型在这里应为PayOut,表示「付款结果」的通知 |
TSNo | 丰收款的交易号码,可以用此与资料库作关联,也可以用我们自己的订单编号。 |
Status | 处理状态S:处理成功 正常F:处理失败 错误 |
PayDate | 付款时间/请款时间, 例如:2021/9/30 22:32 格式 202109302232 。 |
我们可以写一个Model的方法来处理,
def update_order_by_paytoken(paytoken_json):
if paytoken_json:
pay_token = paytoken_json["PayToken"]
resp_json = SinopacAPI.query_by_paytoken(paytoken_json)
tsno = resp_json["TSNo"]
order_no = resp_json["OrderNo"]
status = resp_json["Status"]
order = Payment.objects.filter(order_no=order_no)
order.status = status
order.pay_token = pay_token
order.lm_time = datetime.now()
order.save()
print(" Update Order Successfully.")
else:
print(" Update Order Fail.")
若是我们的BackendURL有被API呼叫时,可建立一个PayToken的纪录Table以作为Log使用。
class PayToken(models.Model):
pay_token = models.CharField(max_length=100, null=True)
create_time = models.DateTimeField()
def create_new_paytoken(pay_token):
new_paytoken = PayToken()
new_paytoken.pay_token = pay_token
new_paytoken.create_time = datetime.now()
new_paytoken.save()
print("--- Create New PayToken")
并行在原本View的get_paytoken()中,加入create_new_paytoken(result_json["PayToken"])
,则可纪录PayToken被回呼的纪录。
def get_paytoken(request):
if request.method == 'POST':
result_str = request.body
result_json = json.loads(result_str)
print(" --- PayToken Callback: {}".format(result_json))
create_new_paytoken(result_json["PayToken"])
update_order_by_paytoken(result_json)
resp_json = {"Status": "S"}
return HttpResponse(json.dumps(resp_json))
今天先写到这儿,明天继续实作OrderPayCreate的加解密API全流程实作。
>>: IT 铁人赛 k8s 入门30天 -- day17 Run automated tasks with cron jobs
VS CODE安装好之後,就可以来认识HTML啦~ 开始写HTML前的步骤 首先,在桌面上新增一个资...
AJAX(上) ...
网格机器人改成一周开启一次就好,到周五机器人会自动关闭 ...
虽然各式各样的工具会导入到专案中来提高效率,但是浏览器能看懂得档案只有 HTML、CSS、JavaS...
-化名(Pseudonymization) 假名(Pseudonymized)数据可以通过添加信息...