Day16 - [丰收款] 取得PayToken的最後一哩路很慢长

昨天抱病撰文,终於在本机端将单笔资料透过ORM的方法,成功将新增的订单资料更新到Heroku Postgres资料库中(非常感动),今天我们要来完成剩下取得PayToken的最後一哩路。

只有拿到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的「即时讯息通知」外,还连带的要呼叫「讯息查询服务」才能得到付款的结果。

STEP1: 开个网址接口来处理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))

STEP2: 查询顾客付款状态

取得重要的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.")
       

纪录被API回呼纪录

若是我们的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))

https://ithelp.ithome.com.tw/upload/images/20211001/20130354y1PyEjiFaC.png

今天先写到这儿,明天继续实作OrderPayCreate的加解密API全流程实作。


<<:  成员 19 人:

>>:  IT 铁人赛 k8s 入门30天 -- day17 Run automated tasks with cron jobs

Day4 第一个HTML网页制作

VS CODE安装好之後,就可以来认识HTML啦~ 开始写HTML前的步骤 首先,在桌面上新增一个资...

AJAX(上)

AJAX(上) ...

2022/02/12 更新

网格机器人改成一周开启一次就好,到周五机器人会自动关闭 ...

[Day14] Webpack 入门 - 环境设定篇

虽然各式各样的工具会导入到专案中来提高效率,但是浏览器能看懂得档案只有 HTML、CSS、JavaS...

假名数据(Pseudonymized data)

-化名(Pseudonymization) 假名(Pseudonymized)数据可以通过添加信息...