得益于 Python 的简洁以及 PyRFC 的加持,SAP 接口编程变得非常简单。本篇介绍如何使用 PyRFC 和 Flask 提供 Restful 服务,程序要实现的目标为:在 Excel 中通过 Restful Service 连接到 SAP系统,在 Excel 中创建科目余额表,报表功能与 SAP 事务码 F.08 类似。选择 Python 而非 用 ABAP 实现 Restful 服务,优点之一是对 SAP 没有侵入性。
需要要用到两个函数:
BAPI_GL_ACC_GETLIST
: 根据公司代码获取会计科目的清单BAPI_GL_ACC_GETPERIODBALANCES
: 获取会计科目在会计年度内各个月份的借方发生额、贷方发生额和余额,与 事务码 FAGLB03 类似
不熟悉两个函数用法的小伙伴,可以在 SAP 系统中用 SE37 来测试,了解函数的参数和返回值。
Restful API
新建一个项目,项目的文件结构如下:
首先,在 sap_system.py 文件中,使用一个 dict 存放连接到 SAP 系统的登录参数:
# 登录到SAP系统的参数
sap_conn_params = {
"user": "stone",
"passwd": "w123456",
"ashost": "192.168.44.100",
"sysnr": "00",
"lang": "EN",
"client": "001"
}
调用 SAP 函数的代码在 GL.py 文件中编写,PyRFC 自动管理 SAP 连接,不需要手动打开和关闭连接,但应该避免每个函数都创建一个连接对象,我将获取 SAP 连接的代码放在一个单独的函数中。
def get_sap_connection():
logon_params = sap_system.sap_conn_params
conn = pyrfc.Connection(**logon_params)
return conn
调用 BAPI_GL_ACC_GETLIST
返回 科目清单的方法:
class SAPGL(object):
def __init__(self) -> None:
self.sap_connection = get_sap_connection()
# OTHER CODES
def get_gl_acc_list(self, cocd, lang):
"""
获取会计科目清单
"""
conn = self.sap_connection
result = conn.call("BAPI_GL_ACC_GETLIST",
COMPANYCODE=cocd,
LANGUAGE=lang)
return result['ACCOUNT_LIST']
调用 BAPI_GL_ACC_GETPERIODBALANCES
函数获取某一个会计科目的在某一年度的借方发生额、贷方发生额和余额:
class SAPGL(object):
def get_acc_balances(self, cocd, gl_account, fiscal_year):
"""
获取会计科目在某一会计年度内按月份的发生额和余额
"""
conn = self.sap_connection
result = conn.call("BAPI_GL_ACC_GETPERIODBALANCES",
COMPANYCODE=cocd,
GLACCT=g_laccount,
FISCALYEAR=fiscal_year,
CURRENCYTYPE="10")
return result['ACCOUNT_BALANCES']
结合这两个函数,获取所有会计科目的科目余额:
def get_all_acc_balances(self, cocd, fiscal_year):
"""
获取所有会计科目在某一会计年度内按月份的发生额和余额
"""
# results for account balances
gl_acc_balances = []
# 获取所有会计科目
accounts = self.get_gl_acc_list(cocd, '1') # 1表示简体中文
# 遍历会计科目,获取每一个科目的发生额和余额
for item in accounts:
account = item.get('GL_ACCOUNT')
balances_in_year = self.get_acc_balances(cocd, account, fiscal_year)
for period_balance in balances_in_year:
gl_acc_balances.append(period_balance)
return gl_acc_balances
通过 Flask 提供三个 Web API:
# 会计科目列表
- /acclist/<cocd>
# 会计科目年度发生额和余额
- /accbal/<cocd>/<account>/<year>
-
# 根据公司代码获取所有会计科目的发生额和余额
- /balances/<cocd>/<year>
代码很直观:
from flask import Flask, request, make_response, jsonify
from SAP.GL import SAPGL
app = Flask(__name__)
@app.route("/")
def index():
return "index page"
@app.route("/accbal/<cocd>/<account>/<year>")
def get_acc_balances(cocd, account, year):
sap_gl = SAPGL();
acc_balances = sap_gl.get_ac_balances(str.upper(cocd), account, year)
return jsonify(acc_balances)
@app.route("/acclist/<cocd>")
def get_gl_acc_list(cocd):
sap_gl = SAPGL();
gl_list = sap_gl.get_gl_acc_list(str.upper(cocd), '1')
return jsonify(gl_list)
@app.route('/balances/<cocd>/<year>')
def get_all_acc_balances(cocd, year):
sap_gl = SAPGL();
balances = sap_gl.get_all_acc_balances(str.upper(cocd), year)
return jsonify(balances)
if __name__ == "__main__":
app.run()
Power Query 消费 Restful API
接下来,在 Excel 中通过消费这些 Restful Service,首先获取会计科目清单。对 Power Query 不熟悉的小伙伴请参考我之前写的 Power Query 系列。

Power Query 从网站获取的 json 格式数据,转换成表格基本都是下面要演示的几个步骤,首先将列表(List)转换为表:
然后点击表头的展开图标进行展开:
得到如下所示的结果:
在高级编辑器中查看对应的脚本:
将查询命名为 acclist,acclist 的结果不需要上载到 Excel 工作表,仅仅保留在 Power Query 中(上载的时候选择仅连接)。
用同样的方法从 URL : http://127.0.0.1:5000/balances/z900/2020 将所有科目的发生额和余额导入到 Power Query 作为第二个查询,将查询命名为 accbalances。因为 python 对 account balances 用的 dict 数据类型,dict 是没有顺序的,所以导入到 Power Query 后字段的顺序并不符合我们的需要,需要在 Power Query 的界面中做调整,并且删除不需要的字段。完成后界面如下:
我们可以看到,会计科目的借方发生额、贷方发生额和余额都有,但没有期初余额。期初余额字段可以在 Power Query 中添加计算字段得到。然后再通过合并查询的功能,从查询 acclist 中关联的方式获得会计科目的描述:
合并查询得到的是一个 table 类型的结构化字段,通过展开操作,选择 LONG TEXT 字段。将完成的查询上载到 Excel 工作表。
查询 accbalances 上载到 Excel 的工作表包含一个会计年度的数据,为了方便查看,将期间字段设为切片器,这样就做好了一个方便查看任意月份的科目余额表。