本篇接着SAP资产负债表实现方案探索 - 基于 Excel-DNA 自定义函数方法 这篇博文,继续介绍通过 VBA 编写自定义函数来实现资产负债表的方法。在上一篇文章中,整体解决方案的思路可以分为两个步骤:(1)SAP 提供 Restful Service,允许外部获取 json 格式的科目余额表;(2) Excel 通过自定义函数从 Restful Service 中获取所需要的数据。

因为上一篇已经介绍了在 SAP 中如何提供 SAP Restful 服务,这里就不重复了,直接从在 Excel 中通过 VBA 自定义函数开始。

将 VBA 自定义函数放到加载宏中

为了实现自定义函数的复用,可以将自定义的函数放到加载宏 (add-in) 中,方法是将 Excel 文件另存为 Excel 加载宏,Excel 加载宏的扩展名为 xlam。


在每台 PC 上都有默认的 Excel 加载宏位置,放在默认位置的加载宏能在「Excel加载宏」对话框中显示,放在其他位置的加载宏能通过浏览的方式找到并加载。默认位置:C:\Users\UserName\AppData\Roaming\Microsoft\AddIns

Excel 通过 VBA 使用 Restful Service 需要解决两个问题:1)发送和接收 Http 请求,可以使用 Microsoft WinHTTP Service 5.1 这个库来实现,之前的博文有讲解过。本例因为只涉及到 Get 请求,可以使用 Excel 的 WebService 函数;2)第二个问题是对 json 数据的解析,我使用了 github 上一个开源的代码:VBA-tools/VBA-JSON: JSON conversion and parsing for VBA。

有了上面的准备工作,编写 BsItemAmount 函数用于从 SAP 获取报表项余额:

Public Const BaseUrl As String = "http://sapecc6:8000/sap/zrfc/"Public Enum amtTypeEnumYEAR_BEGIN = 1PERIOD_BEGIN = 2PERIOD_DEBIT = 3PERIOD_CREDIT = 4PERIOD_NET = 5CLOSING = 6
End EnumPublic Function BsItemAmount(companyCode As String, year As String, period As String, fsItem As String, amountType As amtTypeEnum) As DoubleDim jsonData As StringDim url As StringDim parsedDict As DictionaryDim rv As Double ' 返回值url = BaseUrl & "Z_BS_BALANCES?COMPANYCODE=" & companyCode & "&FISCALYEAR=" & year & "&FISCALPERIOD=" & periodjsonData = Application.WorksheetFunction.WebService(url)Set parsedDict = JsonConverter.parseJson(jsonData)Dim val As DictionaryFor Each val In parsedDict("FS_BALANCES")If val("FSITEM") = fsItem ThenIf amountType = amtTypeEnum.YEAR_BEGIN Thenrv = val("YR_OPENBAL")ElseIf amountType = amtTypeEnum.PERIOD_BEGIN Thenrv = val("OPEN_BALANCE")ElseIf amountType = amtTypeEnum.PERIOD_DEBIT Thenrv = val("DEBIT_PER")ElseIf amountType = amtTypeEnum.PERIOD_CREDIT Thenrv = val("CREDIT_PER")ElseIf amountType = amtTypeEnum.PERIOD_NET Thenrv = val("PER_AMT")ElseIf amountType = amtTypeEnum.CLOSING Thenrv = val("BALANCE")End IfExit ForEnd IfNextBsItemAmount = rv
End Function

我们先对代码的功能做一个大致说明,后面再展开讲解关键的细节。上面这段代码做了两件事,先用 Excel 内置的 WebService 函数获取 SAP Restful service 的值,返回值为 json 字符串,然后通过 JsonConverter 对 json 字符串进行解析。 Json 字符串中的对象 (也就是花括号包括的部分)解析为 Dictionary,将 Json 字符串中的数组 (也就是方括号包括的部分) 解析为 Collection。

使用加载宏中的自定义函数

打开一个新的 Excel 工作簿,切换到「开发工具」页签,点击「Excel加载项」


从弹出对话框中选择合适的加载宏,如果加载宏不在默认位置,点击浏览按钮选择目标文件。


然后就可以愉快地使用自定义函数了(类别为:用户定义)

Restful Service 加载到 Excel 的方法

在写上面函数的时候,发现 VBA 在调试 Dictionary 或者 Collection 的时候挺不直观的,为了方便自己查看数据,就想着将数据导出到 Excel 工作表中。数据导出大体可以用两种方法。

方法一:基于解析的 Collection 和 Dictionary 写入工作表,代码如下:

Public Sub DataToSheet(data As Collection, shtName As String)' data的类型为JsonConverter的parseJson()方法的返回值,而不是普通的CollectionDim sht As WorksheetSet sht = ActiveWorkbook.Sheets(shtName)Dim topLeftCell As RangeSet topLeftCell = sht.Range("A1")' 在第一行打印表头Dim firstRow As New DictionaryDim k As VariantDim col As IntegerSet firstRow = data.Item(1)col = 0 ' col indexFor Each k In firstRow.KeystopLeftCell.Offset(0, col) = CStr(k)col = col + 1Next' 打印line item的值Dim val As DictionaryDim row As Integer ' row indexrow = 0col = 0For Each val In dataFor Each k In val.KeystopLeftCell.Offset(row + 1, col) = val(k)col = col + 1Nextcol = 0row = row + 1Next
End Sub

测试代码:

Public Sub WriteToSheetTest(ByVal shtName As String)Dim jsonData As StringDim url As StringDim parsedDict As Dictionaryurl = BaseUrl & "Z_BS_BALANCES?COMPANYCODE=Z900&FISCALYEAR=2020&FISCALPERIOD=10"jsonData = Application.WorksheetFunction.WebService(url)Set parsedDict = JsonConverter.parseJson(jsonData)Dim data As New CollectionSet data = parsedDict("FS_BALANCES")Call DataToSheet(data, shtName)
End Sub

方法二:将数据加载到 ADODB.RecordSet,利用 VBA 中 Excel Range 提供的 CopyFromRecordSet() 将数据导入 Excel 工作表。代码如下:

Public Function DataToRecordSet(data As Collection) As ADODB.RecordsetDim rst As New ADODB.RecordsetDim firstRow As New DictionaryDim k As VariantSet firstRow = data.Item(1)
'    For Each k In firstRow.Keys
'        rst.Fields.Append k, adVarChar, 50, adFldMayBeNull
'    Nextrst.Fields.Append firstRow.Keys(0), adVarChar, 50, adFldKeyColumnrst.Fields.Append firstRow.Keys(1), adDoublerst.Fields.Append firstRow.Keys(2), adDoublerst.Fields.Append firstRow.Keys(3), adDoublerst.Fields.Append firstRow.Keys(4), adDoublerst.Fields.Append firstRow.Keys(5), adDoublerst.Fields.Append firstRow.Keys(6), adDoublerst.CursorType = adOpenKeysetrst.CursorLocation = adUseClientrst.LockType = adLockPessimisticDim val As DictionaryDim col As Integer' 加载数据rst.OpenFor Each val In datarst.AddNewcol = 0For Each k In val.Keysrst.Fields(col) = val(k)col = col + 1Nextrst.UpdateNextSet DataToRecordSet = rst
End Function

注释掉的代码提供了更通用的功能,但因为数据类型无法确定,都默认为 varchar,效果不好,就改为根据数据本身的类型来确定 RecordSet 字段的数据类型。

测试代码如下。 先编写一个函数来获取值:

Public Function GetRecordSet() As ADODB.RecordsetDim jsonData As StringDim url As StringDim parsedDict As Dictionaryurl = BaseUrl & "Z_BS_BALANCES?COMPANYCODE=Z900&FISCALYEAR=2020&FISCALPERIOD=10"jsonData = Application.WorksheetFunction.WebService(url)Set parsedDict = JsonConverter.parseJson(jsonData)Dim data As New CollectionSet data = parsedDict("FS_BALANCES")Dim rst As New ADODB.RecordsetSet rst = DataToRecordSet(data)Set GetRecordSet = rst
End Function

然后再将数据导出到工作表:

Public Sub ExportDataTest()Dim rst As New ADODB.RecordsetSet rst = StoneSAPFunctions.printModule.GetRecordSet' print headerDim col As IntegerFor col = 0 To rst.Fields.Count - 1Sheet1.Range("A1").Offset(0, col) = rst.Fields(col).NameNext' print line itemsrst.MoveFirstSheet1.Range("A2").CopyFromRecordset rst
End Sub

在 CopyFromRecordset() 方法前,需要调用 Recordset 的 MoveFirst() 方法,否则游标处在最后一行,只打印出最后一行。

SAP资产负债表实现方案探索 - 基于 VBA 自定义函数方法相关推荐

  1. SAP资产负债表实现方案探索 - 基于 Excel-DNA 自定义函数方法

    早前曾基于 VBA 的 RFC 的方式从 SAP 获取数据,在 Excel 中自定义函数实现资产负债表,也把实现的过程在博文中进行了介绍:SAP接口编程之综合实例(一):资产负债表方案. 完成之后,对 ...

  2. VBA 自定义函数语法

    VBA 自定义函数语法 Sub subName( [(argList)] ) argList 为参数列表,一个函数允许声明多个参数,各个参数之间用逗号( , )隔开.参数声明语法如下文. '参数的语法 ...

  3. 微软函数 for vba自定义函数Function

    "XLAM"    支持WPS.Office 2007及以上版本. "XLA"    支持WPS.Office 2003及以上版本. 声明:必须具有VBA运行环 ...

  4. Excel·VBA自定义函数筛选单元格区域重复值

    贴吧提问<哪位大神知道要怎么实现?>,Excel内置函数使用比较麻烦,VBA字典实现比较直观 自定义函数UNIQUE_IF筛选单元格区域中的值,可以选择返回其中的唯一值或重复值,并用分隔符 ...

  5. 他山之石——VBA自定义函数

    VBA自定义函数自己是最近才开始使用的.其好处是可在工作表中直接调用,很方便. 这里,这位老师总结的很好,学习了! '1 什么是自定义函数?'在VBA中有VBA函数,我们还可以调用工作表函数,我们能不 ...

  6. 探索Julia(part10)--自定义函数

    学习笔记,仅供参考,有错必纠 参考自:Julia数据科学应用–Zacharias Voulgaris:官方文档 使用Julia-1.1.1 自定义函数 Functions 在Julia中,函数是将参数 ...

  7. VBA自定义函数TEXTJOIN CONCAT FILTER EVALUATE

    VBA是Office自带的,无需再安装.若使用WPS,需安装VBA插件:以下是实现代码.Office或WPS电脑端用户须已安装VBA且必须启用宏才能使用. 工作表TEXTJOIN函数实现代码: Fun ...

  8. 一个可以使用多个正则表达式进行多次尝试匹配、替换或提取的Excel VBA自定义函数(UFD)...

    该自定义函数可使用多个正则表达式对目标单元格进行多次匹配尝试,如匹配成功,将停止尝试匹配其他正则表达式,并且使用该正则表达式相对应的替换表达式进行替换,返回替换结果. 您可以直接下载包含该函数代码的X ...

  9. 探索Julia(part11)--自定义函数

    学习笔记,仅供参考,有错必纠 参考自:Julia数据科学应用–Zacharias Voulgaris:官方文档 使用Julia-1.1.1 自定义函数 元祖 Julia有一个称为元组的内置数据结构,它 ...

最新文章

  1. 如何理解“跳出率”,它对SEO有什么影响?
  2. Jenkins的关闭、重启
  3. SAP CAP 项目 cds watch 生成的 index.html 的模板位置和权限控制
  4. 后端获取的文本换行_前台带换行符的文本提交到后台,后台在前台显示换行
  5. Controller接口控制器(2)
  6. 保护公民信息安全 中国在行动
  7. 分治-寻找第k小的数
  8. [Ramda] Complement: Logic opposite function
  9. mysql如何进行宿舍分配_手把手教你做一个Jsp Servlet Mysql实现的学生宿舍管理系统...
  10. excel的表格数据转为数据库的dbf文件
  11. little VGL Visual Studio 模拟器仿真
  12. 教师对php作品评语通用,期末教师给学生的评语
  13. 解决错误:org.apache.ibatis.binding.BindingException
  14. sqlmap绕过空格过滤方法
  15. 欧姆龙PLC以太网与西门子WINCC通讯
  16. 物联网设备安全保护,需要这三道防线
  17. stormzhang的推荐!
  18. 世界各地的游戏都是如何分级的?哪个最严格?
  19. IDEA快捷键高清壁纸
  20. appium 等待的3中方式:强制等待、隐式等待、显示等待

热门文章

  1. swiper 轮播 多行多列 横向排列
  2. 亲民地理38期-江西极顶武功山(上)
  3. 关于python搞笑段子精选_你能讲一个让人瞬间爆笑的笑话吗?
  4. 转录组分析---Hisat2+StringTie+Ballgown使用
  5. linux dd if提示是目录,Linux dd 命令详解
  6. 继电器驱动设计方案及问题分析
  7. RecyclerView notifyDataSetChanged 导致图片闪烁的原因
  8. 1.3 项目经理的知识和技能
  9. 使用ipv6-test.com测试服务器域名是否支持IPV6
  10. 计算机exo乐谱,History钢琴简谱-数字双手-EXO