Skip to main content

网站集成

本教程的源代码托管在github上。

您可以体验我们的Demo

这是一个简陋的电商网站,只有两个商品,但有丰富的支付渠道选择。

添加商品到购物车#

单击 add cart,将相关的商品添加到购物车中,可以添加多件。

提交订单#

单击 Checkout,将调用支付网关API并从客户处收集付款信息。

通过 webhook 获取支付结果#

一旦客户完成了付款,支付状态将通过 webhook 返回。


目录#


准备#

  • Python 3.7

    - 其他的Python3版本也可以,但是Python包版本可能会导致一些混淆,可能需要做一些小的更改

  • Ksher 沙箱账号

    - 申请沙箱账号,请联系 support@ksher.com

  • API_URL

    - 除了沙箱账号外,您还将收到一个API_URL:s[指定名称].vip.ksher.net

  • API_TOKEN

    - 使用给定的沙箱账号登录到API_URL并获得令牌。请参见 如何获取API令牌

安装#

在本节中,我们将安装所有的依赖并准备我们的环境。

步骤1: 克隆仓库#

git clone https://github.com/ksher-solutions/payment_demo_python

步骤2: 进入到克隆的源代码文件夹#

cd ./payment_demo_python

步骤3:创建虚拟环境并激活#

python -m venv ./venv
source ./venv/bin/activate

注意:如果你安装了多个Python环境,必须指定一个环境

python3 -m venv ./venv

步骤4:安装全部的依赖#

pip install -r requirements.txt

配置#

在我们可以运行之前,有一些参数需要进行配置。在这个演示中,我们使用了环境变量。这是一种防止将密钥暴露到源代码中并被他人观察的好方法,特别是在github中托管的开源软件。

我们已经为您提供了该模板文件:

cp env.example .env

您的 .env 文件现在应该如下所示:

export FLASK_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export FLASK_ENV=development
export STORE_LOCALE=th_TH
export STORE_CURRENCY=THB
export PREFERRED_URL_SCHEME=http
export SERVER_NAME=localhost:5000
export KSHER_API_BASE=https://s[UNIQUE_NAME].vip.ksher.net
export KSHER_API_TOKEN=token1234
export STORE_BASE_URL=https://315c0f6fc742.ngrok.io

关于一些配置参数的说明

  • FLASK_SECRET_KEY

    - 随机字符串将用作 Flask 程序的密钥

  • KSHER_API_BASE

    - 请求中指定的 Ksher API_URL

  • KSHER_API_TOKEN

    - 请求中指定的 Ksher API_TOKEN

  • SERVER_NAME

    - 此 Flask 程序的服务器URL,用于存储缓存

    - 在 heroku 或生产部署中,这将与STROE_BASE_URL相匹配

  • STORE_BASE_URL

    - 此 Flask 程序的服务器URL

    - 在 heroku 或生产部署中,这将与SERVER_NAME相匹配。当在 localhost 运行时,方便 webhook 测试,我们会把它设置为 ngrok

配置对象#

这里指定的配置参数将会加载到配置对象,之后将被加载到 Flask 应用的配置中。

from config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.logger.setLevel('INFO')
app.config.from_object(config_class)

运行演示程序#

在本节中,我们将向您展示如何在本地机器上运行此演示程序。我们还为您提供了如何在 Heroku 上运行演示程序。

在完成前面的所有部分(安装、配置)之后,现在是时候运行演示了。

要运行,只需执行以下命令

export FLASK_APP=app.py
python -m flask run

程序启动运行并监听 5000 端口,指定的服务是 App


系统概览#

系统概览可以在程序工厂中看到。

app.py文件中,它位于此演示程序的根目录中。

系统分为3个模块(或3个微服务):

  • Store

    - 管理店铺并添加商品到购物车

  • Checkout

    - 从购物车中创建订单,并重定向用户到 Khser 支付网关上付款,并在支付完成后返回

  • Webhook

    - 处理支付完成后从 Ksher 支付网关发送回的 webhook 通知

def create_app(config_class=Config):
app = Flask(__name__)
app.logger.setLevel('INFO')
app.config.from_object(config_class)
app.register_blueprint(store)
app.register_blueprint(checkout)
app.register_blueprint(webhook)
# 添加内容安全策略,以加载本地内容或从Heroku开始的所有内容
Talisman(
app,
content_security_policy={
"default-src": "'unsafe-inline' 'self' *.amazonaws.com *.herokuapp.com *googleapis.com *.ksher.com"
},
)
return app

应用程序如何使用Ksher支付网关进行支付#

用户在订单提交页面中点击 check out 后,将执行以下方法向 Ksher 支付网关发出支付请求。

from ksherpay import Payment
@checkout.route("/charge", methods=["POST"])
def charge():
"""
Create an Order based on Checkout page and
make a payment request to Ksher Payment Gateway
"""
email = request.form.get("email")
api_url = current_app.config.get('KSHER_API_BASE')
api_token = current_app.config.get('KSHER_API_TOKEN')
myPayment = Payment(api_url,token=api_token)
store_base_url = current_app.config.get('STORE_BASE_URL')
cart = Cart()
order_id = myPayment.order.generate_order_id("Demo")
order_data = {
'amount': cart.total(), # ksher need cent unit
'merchant_order_id':order_id,
"channel_list": "linepay,airpay,wechat,promptpay,truemoney,card",
'note': f'customer email:{email}',
"redirect_url": f"{store_base_url}/orders/{order_id}/success",
"redirect_url_fail": f"{store_base_url}/orders/{order_id}/fail",
}
resp = myPayment.order.create(order_data)
if resp.status_code != 200:
return json.dumps({
"status_code":resp.status_code,
"error":resp.text
})
resp_data = resp.json()
redirect_url = resp_data['reference']
return redirect(redirect_url)

对以上代码的一些说明:

导入支付对象#

首先需要从 Ksher payment python sdk 导入支付对象

在这个演示程序中,我们已经将sdk放入根目录中。

在未来版本中,可以通过pip的方式安装sdk

from ksherpay import Payment

初始化支付对象#

api_url = current_app.config.get('KSHER_API_BASE')
api_token = current_app.config.get('KSHER_API_TOKEN')
myPayment = Payment(api_url,token=api_token)

创建订单#

我们从订单确认页和购物车中获取到必要的全部数据,并据此创建订单。

order_id 不一定要使用这种方式创建,你可以使用自己的方法生成order_id,同时要确保order_id的唯一性。

# Generate a unique order id by using the current time "YYYYMMDDTHHMMSS"
order_id = myPayment.order.generate_order_id("Demo")
order_data = {
'amount': cart.total(), # ksher need cent unit
'merchant_order_id':order_id,
"channel_list": "linepay,airpay,wechat,promptpay,truemoney,card",
'note': f'customer email:{email}',
"redirect_url": f"{store_base_url}/orders/{order_id}/success",
"redirect_url_fail": f"{store_base_url}/orders/{order_id}/fail",
}
resp = myPayment.order.create(order_data)

引导用户去支付#

如果订单创建成功。(Ksher 会返回 200

我们就可以使用响应回来的redirect_url参数引导用户去Ksher支付网关页面。

if resp.status_code != 200:
return json.dumps({
"status_code":resp.status_code,
"error":resp.text
})
resp_data = resp.json()
redirect_url = resp_data['reference']
return redirect(redirect_url)

应用程序如何知道支付已经完成#

当用户完成付款时,Ksher 将会根据创建订单时指定的redirect_url返回应用程序。

"redirect_url": f"{store_base_url}/orders/{order_id}/success",
"redirect_url_fail": f"{store_base_url}/orders/{order_id}/fail"

redirect_url 的实现如下

@checkout.route("/orders/<order_id>/<complete>")
def order(order_id,complete):
"""
Charge completion return URL. Once the customer is redirected
back to this site from the authorization page, we search for the
charge based on the provided `order_id`.
"""
return render_template(
"complete.html",
order_id=order_id,
complete=complete
)

根据重定向URL的配置,Ksher 会向webhook发送相关通知,参考文档