跳出ping++退款的坑

贾华
• 阅读 5040

近期在项目的开发过程中,需要用到ping++的退款功能,由于使用的版本比官方提供的要低2个小版本,因此问题并不是很大。但是由于官方文档有些内容写的比较含蓄,因此遇到了一些问题。
我们可以通过如下的方式来获取SDK的版本:

>>> import pingpp
>>> pingpp.VERSION
'2.0.7'
>>> pingpp.api_version
'2.0.7'

在官方文档得说明中,我们可以看到这样3句代码:

import pingpp
pingpp.api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC'
ch = pingpp.Charge.retrieve('CH-ID')
re = ch.refunds.create(description='desc', amount=1)

入坑

在这里,我们看到我们先导入pingpp库,然后通过赋值的方式将其传入。然后我们通过pingpp得Charge类的retrieve方法获取给定ch_id,然后再根据其refunds属性得create方法传入关键字参数来实现退款的操作。
如果我们没有传入api_key,将得到1个AuthenticationError权限错误:

AuthenticationError: No API key provided. (HINT: set your API key using "pingpp.api_key = <API-KEY>"). You can generate
 API keys from the Ping++ web interface.  See https://pingxx.com for details, or email support@pingxx.com if you have a
ny questions.

在这里,我按照官方提供的方式进行赋值,直接就出现上面的情况了,让人比较纳闷。

出坑

下面我们来看下其实现的源码,在resource模块下的Charge类继承自3个类,分别为CreateableAPIResource, ListableAPIResource,UpdateableAPIResource。其源码如下:

class Charge(CreateableAPIResource, ListableAPIResource,
             UpdateableAPIResource):
    def refund(self, **params):
        ...

而这3个父类继承自APIResource类,而APIResource类继承自PingppObject类,它是1个Pingpp对象。

class CreateableAPIResource(APIResource):
    @classmethod
    def create(cls, api_key=None, **params):
        requestor = api_requestor.APIRequestor(api_key)
        url = cls.class_url()
        response, api_key = requestor.request('post', url, params)
        return convert_to_pingpp_object(response, api_key)

class APIResource(PingppObject):
    @classmethod
    def retrieve(cls, id, api_key=None, **params):
        instance = cls(id, api_key, **params)
        instance.refresh()
        return instance

    def refresh(self):
        self.refresh_from(self.request('get', self.instance_url()))
        return self
    @classmethod
    def class_name(cls):
        ...
        return str(urllib.quote_plus(cls.__name__.lower()))

    @classmethod
    def class_url(cls):
        cls_name = cls.class_name()
        return "/v1/%ss" % (cls_name,)

    def instance_url(self):
        ...
        extn = urllib.quote_plus(id)
        return "%s/%s" % (base, extn)

从上述代码,我们可以发现,我们还可以直接将api_key以关键字参数的形式传入到retrieve方法中。
我们调用Charge类的retrieve方法时,其会生成1个实例,然后调用该实例得refresh方法。而后调研该实例的refresh_from方法,使用get请求,而地址为该实例的url。
因此,最终的url地址为https://api.pingxx.com/v1/charges/,首先class_name方法返回Charge类名的小写名称,而后在class_url方法中进行组装后返回给instance_url方法。
而在调用request方法的过程中,我们会涉及到1个convert_to_pingpp_object方法,其将响应的内容转换为pingpp对象。
通过这种方式我们完成了官方文档中查询Charge对象的操作,即进行如下的操作:

GET https://api.pingxx.com/v1/charges/{CHARGE_ID}

因此,上面ch最终的结果为我们使用API调用后得到的JSON数据结果,而后我们通过ch的refunds属性得到这样1个对象:

 ...
   "refunds": {
    "url": "/v1/charges/ch_xxx/refunds", 
    "has_more": false,
    "object": "list",
    "data": [
      {
        ...
      }
    ]
  }

而这个转换的过程是在refresh_from函数中进行的:

def refresh_from(self, values, api_key=None, partial=False):
        ...
        for k, v in values.iteritems():
            super(PingppObject, self).__setitem__(
                k, convert_to_pingpp_object(v, api_key))

而后我们通过object属性获取到ch.refunds的结果为list。通过如下的方式我们得到的ch.refunds为1个ListObject:

def convert_to_pingpp_object(resp,api_key):
    klass_name = resp.get('object')
    if isinstance(klass_name, basestring):
       klass = types.get(klass_name, PingppObject)

这样,我们在create方法中传入的参数与API文档中创建Refund对象的参数一一对应了。而这些传入的参数将在调用api_requestor模块中得APIRequestor类时传入。其中,url为refund对象中的url属性,即上面的/v1/charges/ch_xxx/refunds
因此,第3行中的关键字参数description和amount正好对应官方文档中的说明。需要提示的是,description参数只能是最大255个unicode字符,不然又会出现一些问题。

总结

其实ping++的SDK是与其API接口对应的,如果你在使用SDK的过程中对其传入的参数不明确,可以查看API文档相应篇章中的说明。不然你会遇到ping++平台给你返回一些让你摸不着头脑的回复。

原文:

http://yuki-onna.github.io/jump-out-of-the-refund-of-ping++/

参考文章:

https://www.pingxx.com/api#api-r-new
https://www.pingxx.com/guidance/server/charge/refund
https://github.com/PingPlusPlus/pingpp-python/blob/2.0.7/example/refund.py

点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
springcloud1 升级到springcloud2所遇到的坑总结
目前项目的架构没有采用任何网关、采用nginx直连方式,因现在考虑加入软网关、并且采用springcloudgateway的支持、至此升级到2.0版本、在升级期间遇到了一些问题、看了不少官方文档、将目前所遇到的问题汇总如下。1:升级springcloud2先更改相应的maven相关的配置可参照:https://blog.csdn.net/qq
待兔 待兔
2年前
社区收藏缓存设计重构实战
一、背景社区收藏业务是一个典型的读多写少的场景,社区各种核心Feeds流都需要依赖用户是否收藏的数据判断,早期缓存设计时由于流量不是很大,未体现出明显的问题,近期通过监控平台等相关手段发现了相关的一些问题,因此我们针对这些问题对缓存做了重构设计,以保障收藏
她左右 她左右
4年前
uni-app - 实现热更新及时提醒用户更新
1.原因分析在小程序更新开发版本之后,用户本地并没有对之前版本的小程序进行删除,那么再进入小程序的时候的版本是不会发生变化的,这是由于发版是异步执行,因此新版本将会覆盖的比较慢,本质是小程序的启动方式分为两种,冷启动与热启动。冷启动:指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。热启动:指用户已经打开过某
风斗 风斗
4年前
Android 通知栏使用
不同版本通知栏的创建方式不尽相同,当前官方推荐使用NotificationCompat相关的API,兼容到Android4.0,但是部分新功能,比如内嵌回复操作,旧版本是无法支持的。一、设置通知内容//CHANNEL_ID,渠道ID,Android8.0及更高版本必须要设置NotificationCompat.Builde
Stella981 Stella981
3年前
Elasticsearch 5.5 入门必会之Java client(二)
前言由于本人一直从事Java方面研发,对Java也是尤其热爱,ES官方提供了Java的两种访问API的方式如下,当然,我选择了JavaAPI方式,因此我也开始了API踩坑之路(因为这个SDK文档看起来让人头痛,但是当我一步步理解深入的时候也发现挺简单的):JavaAPI\5.5\(https://www.oschin
Stella981 Stella981
3年前
GitHub Actions
使用GitHubActions发布版本时,获取触发的tag作为发布的版本号.方式一通过step获取tag,在需要使用的地方使用steps.get_version.outputs.VERSION,其中get_version是step的id.name:Release
Stella981 Stella981
3年前
CDH5.12.1添加spark2.2.0服务
最新的CDH安装包中spark版本为1.6,不过对于勇于尝鲜的同学,官方也提供了spark2的升级包,在CDH中spark1和spark2可以共存,但是由于scala版本的兼容性问题,建议只装一个版本。由于spark依赖于scala所以需要在每个节点安装scala,并配置好SCALA\_HOME并将$SCALA\_HOME/bin加入PATH中。Sca
Stella981 Stella981
3年前
NVR硬件录像机web无插件播放方案功能实现之相关接口注意事项说明
该篇博文主要用来说明EasyNVR硬件录像回放版本的相关接口说明和调用的demo;方便用户的二次开发和集成。软件根目录会包含接口文档的,因此,本文主要是对一些特定接口的说明和接口实现功能的讲解以及部分demo的展示说明;对应接口说明;支持设备类型由于获取NVR录像机的相关功能是通过SDK来实现功能的,因此,
Stella981 Stella981
3年前
Spring Boot 2.4 MacPorts 安装 CLI
很多时候我们都不一定能够用到Spring命令行工具的。但是SpringBoot的官方手册中有些这方面的内容和介绍,因此我们也在这里对这部分的内容进行了一些说明。Spring工具被用来初始化Spring项目和一些其他的工作,但Spring是基于Java的,因此很多东西需要自己配置环境。其实自己配置环境比使用环境配
Stella981 Stella981
3年前
DevOps世界中的软件开发
!(https://oscimg.oschina.net/oscnet/f40e68cbfe8148deb00f040b4e917a0a.jpg)在整个软件开发过程中,开发人员通常需要花费大量时间来修复错误和漏洞,以便一切按计划进行交付。但是,通过DevOps实践,可以更轻松地管理和保护这些问题。这是由于以下事实:使用DevOps实践的软
小万哥 小万哥
1年前
RSS 解析:全球内容分发的利器及使用技巧
RSS(ReallySimpleSyndication)是一种XML格式,用于网站内容的聚合和分发,让用户能快速浏览和跟踪更新。RSS文档结构包括&lt;channel&gt;和&lt;item&gt;元素,允许内容创作者分享标题、链接和描述。通过RSS,用户可以定制新闻源,过滤不相关信息,提高效率。RSS支持不同版本,如RSS0.91和RSS2.0,其中RSS2.0语法简单且广泛使用。RSS提高网站流量,适用于新闻、博客、日历等频繁更新的站点。RSS的历史始于1997年,至今仍无官方标准,但已成为内容共享的重要工具。