需求背景
金蝶云星空的销售单据下推后,同步创建BOS单据工事依赖书
,工事依赖书
进行审核操作后,需要将部分数据明细,同步到其他三方平台。基于金蝶云星空的服务插件能力,实现以上功能。服务插件支持C#、Python,这里使用Python实现。Python在该系统中,是一种借壳执行的操作方式,故无法使用任何外部的import动作,只能引用内部的组件和实体对象。
开发方案
- 进入
金蝶云星空集成开发平台
,找到指定BOS单据的字段属性,确认好所需数据 - 开发python服务插件代码,注意字段的预加载
- 在指定的操作按钮(这里是[审核])中,注册服务插件
- 测试的数据中心执行成功后,再加入上机操作日志中
- 部署到正式数据中心
开发总结
- 开发组件引用(clr.AddReference) 和 实体对象导入(from XXX import *) 尽量多、全,不用考虑性能问题,避免从哪里复制过来的代码,因为引用和导入的遗漏导致方法无法使用报错
- 区分字段属性的
(标识)
、字段名
、绑定实体属性
,字段预加载事件@OnPreparePropertys 中使用的是(标识)
,DataEntitys取值中使用的是绑定实体属性
- 测试过程中,尽管加上[操作前确认提示]、[操作成功后提示],测试中就会有弹窗反馈,就可以知道有没有走到服务插件代码中;另外需要注意!服务插件重新编辑保存后,单据要关闭重新打开后才生效!
- 有部分数据处理,如实在无法理解到基础库实体对象的方法如何使用,可以尝试在python中使用内置函数解决;如一些基础的字符串转换、处理,无需import导入的动作(服务插件中不支持导入)
实体类型Entity中不存在名为XXX的属性,注意看下属性是归属于当前单据,还是由其他属性引用带入。如果是由其他属性(元素类型为:基础资料)引用,可以将该属性打印或者保存,观察下数据结构再进行获取
F_PVRH_BaseProperty_qtr = ("{0}").format(FEItem['F_PVRH_Base2']['Specification'])
写日志到上机操作日志控制台
log = LogObject() log.pkValue = bill_no + " start" # 唯一标志 log.Description = bill_no + " 推送开始" log.OperateName = "推送开始" log.ObjectTypeId = this.BusinessInfo.GetForm().Id # 操作的业务对象ID log.SubSystemId = this.BusinessInfo.GetForm().SubsysId # 子系统Id log.Environment = OperatingEnvironment.BizOperate # 操作员 LogServiceHelper.WriteLog(this.Context, log)
- 调试常用
- 表单类插件:this.View.ShowMessage("调试信息")
- 服务类插件:raise Exception("调试信息")
参考代码
# -*- coding: utf-8 -*-
# ******************* python服务插件@工事依赖书下推三方平台接口创建工单 *******************
import clr
# cloud插件开发组件引用
clr.AddReference('System')
clr.AddReference('System.Core')
clr.AddReference('System.Data')
clr.AddReference("System.Web.Extensions")
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.App.Core')
clr.AddReference('Kingdee.BOS.App.LogService')
clr.AddReference('Kingdee.BOS.Contracts')
clr.AddReference('Kingdee.BOS.DataEntity')
clr.AddReference('Kingdee.BOS.ServiceHelper')
clr.AddReference('Kingdee.BOS.ServiceFacade.Common')
clr.AddReference('Newtonsoft.Json')
import sys
# cloud基础库实体对象
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DependencyRules import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.Args import *
from Kingdee.BOS.Core.Metadata.FormElement import *
from Kingdee.BOS.Core.Log import *
from Kingdee.BOS.Log import *
from Kingdee.BOS.App.LogService import *
from System import *
from System.Data import *
from System.Threading import *
from System.Text import *
from System.Collections.Generic import *
from System.Linq import *
from System.IO import *
from System.Net import *
from System.Security.Cryptography import *
from System.Web.Script.Serialization import *
from System.Collections.Generic import Dictionary
from Kingdee.BOS.App.Data import *
from Kingdee.BOS.ServiceHelper import *
from Kingdee.BOS.Core.DynamicForm import *
from Kingdee.BOS.Core.Metadata.EntityElement import *
from Kingdee.BOS.Core.Metadata.FieldElement import *
from Kingdee.BOS.Orm.DataEntity import *
from Kingdee.BOS.ServiceFacade import *
from Kingdee.BOS.Util import *
from Newtonsoft.Json import *
from Newtonsoft.Json.Linq import *
sys.setdefaultencoding('utf-8')
# 字段预加载事件
def OnPreparePropertys(e):
# 预加载字段-单据头
e.FieldKeys.Add('FBillNo')
e.FieldKeys.Add('F_PVRH_Base3')
e.FieldKeys.Add('F_PVRH_Base') # 客户
e.FieldKeys.Add('F_PVRH_Text') # 联系人
e.FieldKeys.Add('F_PVRH_Text2') # 电话
e.FieldKeys.Add('F_PVRH_Text1') # 地址
# 预加载字段-单据体(明细信息)
e.FieldKeys.Add('F_PVRH_Base2')
e.FieldKeys.Add('F_PVRH_Qty')
e.FieldKeys.Add('F_PVRH_Text15')
e.FieldKeys.Add('F_PVRH_Text16')
e.FieldKeys.Add('F_PVRH_Remarks2')
# 执行操作事务后事件 AfterExecuteOperationTransaction
def AfterExecuteOperationTransaction(e):
first_bill_obj = e.DataEntitys[0]
bill_no = first_bill_obj['BillNo']
# 上机日志
LogObject1 = LogObject()
LogObject1.pkValue = bill_no + " start"
LogObject1.Description = bill_no + " 进入推送"
LogObject1.OperateName = "推送进入"
LogObject1.ObjectTypeId = this.BusinessInfo.GetForm().Id
LogObject1.SubSystemId = this.BusinessInfo.GetForm().SubsysId
LogObject1.Environment = OperatingEnvironment.BizOperate
LogServiceHelper.WriteLog(this.Context, LogObject1)
for billObj in e.DataEntitys:
F_PVRH_Base = ("{0}").format(billObj['F_PVRH_Base']['Name']) # 一些数据类型需要进入下一级抓取
F_PVRH_Base3 = ("{0}").format(billObj['F_PVRH_Base3']['Name'])
postParam = {
'FBillNo': billObj['BillNo'],
'F_PVRH_Base': tidyString(F_PVRH_Base),
'F_PVRH_Base3': tidyString(F_PVRH_Base3),
'F_PVRH_Text': tidyString(billObj['F_PVRH_Text']),
'F_PVRH_Text2': tidyString(billObj['F_PVRH_Text2']),
'F_PVRH_Text1': tidyString(billObj['F_PVRH_Text1']),
'F_PVRH_Remarks': tidyString(billObj['F_PVRH_Remarks']),
'FEntity': [],
}
FEntity = billObj['FEntity'] # 单据体(明细信息)
for FEItem in FEntity:
F_PVRH_Base2 = ("{0}").format(FEItem['F_PVRH_Base2']['Name'])
F_PVRH_BaseProperty_qtr = ("{0}").format(FEItem['F_PVRH_Base2']['Specification'])
postParam['FEntity'].append({
'F_PVRH_Base2': tidyString(F_PVRH_Base2),
'F_PVRH_Qty': FEItem['F_PVRH_Qty'],
'F_PVRH_Text15': tidyString(FEItem['F_PVRH_Text15']),
'F_PVRH_Text16': FEItem['F_PVRH_Text16'],
'F_PVRH_Remarks2': FEItem['F_PVRH_Remarks2'],
})
try:
postData = {
'type': 'k3_business_bill',
'data': postParam,
}
postData = JsonUtil.Serialize(postData)
post('https://xxx.com/api/push', postData)
except Exception as e:
error_message = str(e)
LogObject2 = LogObject()
LogObject2.pkValue = bill_no + " end"
LogObject2.Description = bill_no + " 结束推送,异常:" + error_message
LogObject2.OperateName = "推送异常"
LogObject2.ObjectTypeId = this.BusinessInfo.GetForm().Id
LogObject2.SubSystemId = this.BusinessInfo.GetForm().SubsysId
LogObject2.Environment = OperatingEnvironment.BizOperate
LogServiceHelper.WriteLog(this.Context, LogObject2)
finally:
LogObject2 = LogObject()
LogObject2.pkValue = bill_no + " end"
LogObject2.Description = bill_no + " 结束推送"
LogObject2.OperateName = "推送结束"
LogObject2.ObjectTypeId = this.BusinessInfo.GetForm().Id
LogObject2.SubSystemId = this.BusinessInfo.GetForm().SubsysId
LogObject2.Environment = OperatingEnvironment.BizOperate
LogServiceHelper.WriteLog(this.Context, LogObject2)
def post(url, postData):
bytes = Encoding.ASCII.GetBytes(postData)
webRequest = HttpWebRequest.Create(url)
webRequest.Method = 'POST'
webRequest.ContentType = 'application/json'
webRequest.Timeout = 1000 * 60 * 10
webRequest.ContentLength = bytes.Length
webRequest.GetRequestStream().Write(bytes, 0, bytes.Length)
webRequest.GetRequestStream().Flush()
webRequest.GetRequestStream().Close()
webResponse = webRequest.GetResponse()
streamReader = StreamReader(webResponse.GetResponseStream(), Encoding.GetEncoding('utf-8'))
result = streamReader.ReadToEnd()
return result
def get(url):
webRequest = HttpWebRequest.Create(url)
webRequest.Method = 'GET'
webResponse = webRequest.GetResponse()
streamReader = StreamReader(webResponse.GetResponseStream(), Encoding.GetEncoding('utf-8'))
result = streamReader.ReadToEnd()
return result
# 中文字符串转换成Unicode编码 避免在 Encoding.ASCII.GetBytes 方法中被转成乱码
def tidyString(s):
return s.encode('unicode_escape').decode('ascii') if isinstance(s, str) else s
参考资料
插件实战开发-新手入门教程-服务插件
【新手入门】插件实操【分享汇总】
Python开发
服务插件 代表性"e.DataEntitys"取值
服务插件如何遍历单据体明细,获取单据体明细行内码?
#使用技巧#Python插件调试技巧及常见报错分析(新手必看,老手看不上的 干货)原创
本文由 ben 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Dec 9, 2024 at 10:24 am