Python插件
调试
- 表单类插件:this.View.ShowMessage("调试信息")
- 服务类插件:raise Exception("调试信息")
链接
官方 | 社区 | |
---|---|---|
表单插件 | 表单插件 | 表单插件 |
列表插件 | 列表插件 | 列表插件 |
服务插件 | 服务插件 | 服务插件 |
动态表单插件 | 动态表单插件 | |
单据转换插件 | 单据转换插件 | 单据转换插件 |
表单插件
请求第三方系统(GET请求)
以"某测试单据" -> 增加"某测试按钮" -> 请求"第三方系统"为例
签出"某测试单据"
菜单 -> 编辑 -> 批量编辑字段属性 -> 表单插件 -> 注册Python脚本 -> 输入脚本名(随便输)-> 贴入以下代码 -> 确定
保存"某测试单据"并签入
# 引入clr运行库
import clr
# 添加对cloud插件开发的常用组件的引用
clr.AddReference("System")
clr.AddReference("System.Web.Extensions")
clr.AddReference("Kingdee.BOS")
clr.AddReference("Kingdee.BOS.Core")
# 导入cloud基础库中的常用实体对象(分命名空间导入,不会递归导入)
import sys
from System import *
from System.Collections.Generic import *
from System.Threading import *
from System.IO import *
from System.Net import *
from System.Text import *
from System.Security.Cryptography import *
from System.Web.Script.Serialization import *
from System.Collections.Generic import Dictionary
def BarItemClick(e):
if e.BarItemKey == "TXF_tbButton":
test = get("https://www.baidu.com")
this.View.ShowMessage(test)
def get(url):
req = WebRequest.Create(url)
req.Method = "GET"
rsp = req.GetResponse()
stream = rsp.GetResponseStream()
reader = StreamReader(stream, Encoding.GetEncoding("utf-8"))
result = reader.ReadToEnd()
return result
选择未审核或禁用的基础数据(字段设置)
import clr
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.ServiceHelper')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from System import *
from System.Data import *
from Kingdee.BOS.App.Data import *
from Kingdee.BOS.ServiceHelper import *
def BeforeSetItemValueByNumber(e):
key = str(e.BaseDataFieldKey.ToUpper())
if (key == "F_UZOE_BASE"):
e.IsShowUsed = False # 允许选择禁用的数据
e.IsShowApproved = False # 允许选择未审核的数据
e.Filter = ""
def BeforeF7Select(e):
key = str(e.FieldKey.ToUpper())
if (key == "F_UZOE_BASE"):
e.IsShowUsed = False
e.IsShowApproved = False
默认员工基础资料的数据为当前登录用户(sql查询)
import clr
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.ServiceHelper')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from System import *
from System.Data import *
from Kingdee.BOS.App.Data import *
from Kingdee.BOS.ServiceHelper import *
empId = 0
def OnInitialize(e):
userID = str(this.Context.UserId)
sqlGetEmpId = (""" select E.FID, E_L.FNAME, P.FPERSONID, U.FUSERID, U.FNAME
from T_SEC_USER U
inner join t_BD_Person P ON (u.FLINKOBJECT = P.FPERSONID)
inner join T_HR_EmpInfo E ON (P.FPERSONID = E.FPERSONID)
left join T_HR_EmpInfo_L E_L ON (E.FID = E_L.FID AND E_L.FLOCALEID = 2052)
where U.FUserId ={0} """).format(userID)
global empId
ds = DBServiceHelper.ExecuteDataSet(this.Context, sqlGetEmpId)
tab = ds.Tables[0]
empId = tab.Rows[0]["FID"] if tab.Rows.Count > 0 else 0
def AfterCreateNewData(e):
global empId
this.Model.SetItemValueByID("F_UZOE_Base", empId, 0)
判断是新增还是修改(保存)
# 引入clr运行库
import clr
# 添加对cloud插件开发的常用组件的引用
clr.AddReference("System")
clr.AddReference("System.Web.Extensions")
clr.AddReference("Kingdee.BOS")
clr.AddReference("Kingdee.BOS.Core")
from System import *
from System.Collections.Generic import *
from System.Threading import *
from System.IO import *
from System.Net import *
from System.Text import *
from System.Security.Cryptography import *
from System.Web.Script.Serialization import *
from System.Collections.Generic import Dictionary
def BarItemClick(e):
# 与 this.View.Model.GetValue("Id") 等效
if this.View.Model.DataObject["Id"] == 0:
this.View.ShowMessage('新增')
else:
this.View.ShowMessage('修改')
文本、基础资料获取值与设置值
基础资料需要设置引用属性
# 引入clr运行库
import clr
# 添加对cloud插件开发的常用组件的引用
clr.AddReference("System")
clr.AddReference("System.Web.Extensions")
clr.AddReference("Kingdee.BOS")
clr.AddReference("Kingdee.BOS.Core")
from System import *
from System.Collections.Generic import *
from System.Threading import *
from System.IO import *
from System.Net import *
from System.Text import *
from System.Security.Cryptography import *
from System.Web.Script.Serialization import *
from System.Collections.Generic import Dictionary
def BarItemClick(e):
if e.BarItemKey == "UZOE_tbButton":
# 文本获取和设置值
test = this.View.Model.GetValue('F_UZOE_Text').ToString()
this.View.Model.SetValue('F_UZOE_Text', test + '增加点内容')
# 基础资料获取和设置值,以部门为例
try:
departmentName = str(this.View.Model.GetValue('F_UZOE_Base')['Name'])
this.View.ShowMessage(departmentName)
except BaseException as e:
# 没有选部门,默认一个部门,先找到对应的组织,再查部门内码
# select * from T_ORG_ORGANIZATIONS_L
# SELECT FDEPTID FROM T_BD_DEPARTMENT where FUSEORGID=1
this.View.Model.SetValue('F_UZOE_Base', 112233)
this.View.ShowMessage('默认部门')
值更新事件
需要在字段上勾选"即时触发更新时间"
def DataChanged(e):
if e.Field.Key.ToUpperInvariant() == 'XXX':
# e.Row可以指定到具体的明细行
aaa = this.View.Model.GetValue("aaa", e.Row)
if str(aaa) = '123':
this.View.Model.SetValue("bbb", 1, e.Row)
列表插件
- 列表菜单新增一个按钮,按钮标识为:UZOE_tbButton_Batch_Update
- 找到需要批改的字段,在"功能控制"中设置允许批改
- 操作列表增加修改操作并在其他控制中设置权限项
- 列表插件中注册Python插件(保存的时候可能会报Python脚本存在语法错误,找不到"Kingdee.BOS.ServiceHelper",忽略)
import clr
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.ServiceHelper')
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.Bill.PlugIn import *
from Kingdee.BOS.Core.Permission import *
from Kingdee.BOS.ServiceHelper import *
def BarItemClick(e):
if e.BarItemKey == "UZOE_tbButton_Batch_Update":
businessObj = BusinessObject()
formId = str(this.View.BillBusinessInfo.GetForm().Id)
businessObj.Id = formId
if this.ListView.CurrentSelectedRowInfo == None:
this.View.ShowErrMessage("请选择需要批改的行")
return
param = BillShowParameter()
param.FormId = FormIdConst.BD_BulkEdit
this.View.ShowForm(param)
点击列表菜单打开外链
import clr
clr.AddReference('mscorlib')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
from Kingdee.BOS.Core.Bill.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.Args import *
from Kingdee.BOS.JSON import *
from Kingdee.BOS.Util import *
from System import *
def BarItemClick(e):
if e.BarItemKey in ["按钮标识"]:
# 直接打开
# this.View.AddAction("ShowWebURL", 'https://www.baidu.com')
# 方式二:弹窗打开Url地址
webobj = JSONObject()
webobj["source"] = 'https://www.baidu.com'
webobj["height"] = 600
webobj["width"] = 800
webobj["isweb"] = True
webobj["title"] = "百度一下"
this.View.AddAction("ShowKDWebbrowseForm", webobj)
this.View.SendDynamicFormAction(this.View)
服务插件
请求第三方系统(POST请求)
以"审核通过"后请求"第三方系统"为例
操作列表 -> 找到"审核" -> 编辑 -> "其他控制"页签 -> 服务插件 -> 注册Python脚本 -> 输入脚本名(随便输)-> 贴入以下代码 -> 确定
# 引入clr运行库
import clr
# 添加对cloud插件开发的常用组件的引用
clr.AddReference('System')
clr.AddReference("System.Web.Extensions")
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
# 导入cloud基础库中的常用实体对象(分命名空间导入,不会递归导入)
import sys
from System import *
from System.Data import *
from System.Collections.Generic import *
from System.Threading import *
from System.IO import *
from System.Net import *
from System.Text import *
from System.Security.Cryptography import *
from System.Web.Script.Serialization import *
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
# 加载指定字段到实体中,因为我们加载的时候只取到部分重要的数据包,可能会有一部分数据没加载进去,通过该事件确保我们需要的字段被加载进来
def OnPreparePropertys(e):
e.FieldKeys.Add("BillNo")
e.FieldKeys.Add("Date")
e.FieldKeys.Add("DocumentStatus")
e.FieldKeys.Add("SAL_OUTSTOCKENTRY")
# 操作执行后(事务内)事件,在操作处理完毕,未提交事务前触发
# 获取的数据是修改后的数据,可以抛出异常回滚事务
def EndOperationTransaction(e):
try:
DBId = str(this.Context.DBId)
# 正式环境
if DBId == 'aa2022119f1bbd':
url = 'https://www.baidu.com?token=aabbcc'
else:
url = 'https://beta.baidu.com?token=eeffgg'
d = dict()
for billObj in e.DataEntitys:
d['code'] = str(billObj["BillNo"])
d['goods_delivery_time'] = str(billObj["Date"])
d['status'] = str(billObj["DocumentStatus"])
d['order_code'] = list()
# 如果字段是一个基础资料类型,我们会获取到一个DynamicObject,需要进一步获取它的名称或编码等
# 需要在引用属性中设置相关的字段,如:Number、Name等
d['xxx_code'] = billObj['xxx']['Number']
for detailInfo in billObj['SAL_OUTSTOCKENTRY']:
d['order_code'].append({"order_code" : str(detailInfo["SOORDERNO"])})
res = post(url, d)
if str(res['code']) == '0':
print('success')
else:
print('fail')
except BaseException as e:
pass
def post(url, data):
req = WebRequest.Create(url)
req.Method = "POST"
buf = Encoding.GetEncoding("UTF-8").GetBytes(Json().encode(data))
req.Accept = "application/json"
req.ContentType = "application/json; charset=UTF-8"
req.ContentLength = buf.Length
stream = req.GetRequestStream()
stream.Write(buf, 0, buf.Length)
stream.Close()
res = req.GetResponse()
reader = StreamReader(res.GetResponseStream(), Encoding.GetEncoding("utf-8"))
returnData = Json().decode(reader.ReadToEnd())
reader.Close()
res.Close()
return returnData
自定义验证器
import clr
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
from System import *
from System.Data import *
from System.Collections.Generic import List
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Log import *
from Kingdee.BOS.Core.Validation import *
def OnAddValidators(e):
extMoProducTypeValidator = ExtMoProducTypeValidator()
extMoProducTypeValidator.EntityKey = "FBillHead"
extMoProducTypeValidator.TimingPointString = ",Save"
e.Validators.Add(extMoProducTypeValidator)
class ExtMoProducTypeValidator(AbstractValidator):
def Validate(self, dataEntities, validateContext, ctx):
for bill in dataEntities:
billId = str(bill["Id"])
entryData = bill.DataEntity["TreeEntity"]
l = []
for entryInfo in entryData:
seq = entryInfo["Seq"]
if seq in l:
errorInfo = ValidationErrorInfo(" ", billId, bill.DataEntityIndex, bill.RowIndex, billId, "明细表体存在分录行号重复,不允许保存", "", ErrorLevel.Error)
validateContext.AddError(None, errorInfo)
else:
l.append(seq)
提示信息
def AfterExecuteOperationTransaction(e):
# 这里获取单据数据包方式和前面一样
for billObj in e.DataEntitys:
billId = billObj["Id"] # 单据ID
billNo = billObj["BillNo"] # 单据编号
# 追加自定义提示信息,参考如下
result = OperateResult()
result.SuccessStatus = True
# result.Name = "关键字"
# result.PKValue = "单据ID"
# result.Number = "单据编号"
result.Message = "提示信息"
this.OperationResult.OperateResult.Add(result)
DynamicObject数据包赋值
for rObj in entity:
# 物料Id
matId = 1001
# --------------------------------------------------------
# 根据物料Id获取物料数据包,使用字段标识(服务插件)
matFld = this.BusinessInfo.GetField("FMaterialId")
# 根据物料Id获取物料数据包,使用字段标识(表单插件)
# matFld = this.View.BillBusinessInfo.GetField("FMaterialId")
matObj = BusinessDataServiceHelper.LoadSingle(this.Context, matId, matFld.RefFormDynamicObjectType)
# --------------------------------------------------------
# 注意:对资料类型的字段赋值时,需要2行代码,既要给实体里面资料ID赋值,也要给资料数据包赋值
rObj["MaterialId_Id"] = matId # 物料Id赋值
rObj["MaterialId"] = matObj # 物料数据包赋值
# 如果是表单插件,修改完实体数据包之后,要执行UpdateView刷新界面,界面才会显示更新后的数据
this.View.UpdateView("FBillNo") # 刷新部分字段,如:单据编号
this.View.UpdateView("FPOOrderEntry") # 刷新整个单据体
执行操作后刷新字段
以保存操作为例
操作列表 -> "保存" -> 编辑 -> 操作后刷新字段 -> 配置相关字段 -> 确定
获取自增ID
import clr
clr.AddReference('Kingdee.BOS.ServiceHelper')
from Kingdee.BOS.ServiceHelper import *
# 单据种子
# 获取表的种子值=获取表的自增Id=获取表的自增主键值,每获取一次,种子值就会加1,以确保主键值不会重复产生
# 种子值不是来自于当前数据表,而是来自于一个单独的种子表,一个数据表对应一个种子表,种子表名通常为数据表名的首字母t改为z
# 例如,数据表T_SAL_OUTSTOCKTRACE对应的种子表名为Z_SAL_OUTSTOCKTRACE
seqValue = DBServiceHelper.GetSequenceInt32(this.Context, 'T_SAL_OUTSTOCKTRACE', 1)[0]
# 基础资料种子
# 所有的基础资料的主表(单据头表)都是统一使用同一个种子表:Z_BAS_ITEM,基础资料的其它表则仍然使用各自的种子表
seqValue = DBServiceHelper.GetSequenceInt32(this.Context, 'T_BAS_ITEM', 1)[0]
常用属性和方法
Context上下文对象
this.Context.UserId # 当前用户ID
this.Context.UserName # 当前用户名称
this.Context.UserPhone # 当前用户手机号
this.Context.CurrentOrganizationInfo.ID # 当前组织Id
this.Context.CurrentOrganizationInfo.Name # 当前组织名称
this.Context.DBId # 当前数据中心Id
this.Context.DataCenterNumber # 当前数据中心编码
this.Context.DataCenterName # 当前数据中心名称
this.Context.IpAddress # 客户端本机网络信息:IP、MAC等
this.Context.ClientType # 客户端类型
this.Context.ServiceType # 服务类型
判断是否是WebApi请求
请求方式 | this.Context.ClientType | this.Context.ServiceType | WebType.WebService | ClientType.WebApi |
---|---|---|---|---|
API | WebApi | WebService | WebService | WebApi |
浏览器 | Html | WebSite | WebService | WebApi |
客户端 | WPF | WebSite | WebService | WebApi |
# 判断是否是WebApi请求
if this.Context.ClientType == ClientType.WebApi:
pass
日期相关
# 当前日期
print(str(DateTime.Now.Date))
# 昨天
print(str(DateTime.Now.Date.AddDays(-5)))
# 字段转日期格式
Convert.ToDateTime(billObj["XXX_DATE"]).Date
# 示例
t1 = DateTime.Parse(str(time1)) # 要注意判断字段为空:time1=None的情况
t2 = DateTime.Parse(str(time2)) # 要注意判断字段为空:time2=None的情况
ts = t1 - t2 # 计算日期差
onlyDays = ts.Days # 整数相差天数,向下取整,例如,1天X小时,都是1天
totalDays = ts.TotalDays # double类型,精确的小数天数
AfterXDaysDate = str(t2.AddDays(x)) # t2加上x天之后的日期,若x为负数,则标识x天前的日期
View视图层对象(服务类的插件没有这个)
# View的常用属性
this.View.BillBusinessInfo # 单据的业务逻辑元数据,元数据包含的信息很多,下面列了一下常用的信息
this.View.BillBusinessInfo.GetBillNoField().FieldName # 单据编号字段名
this.View.BillBusinessInfo.GetBillStatusField().FieldName # 单据状态字段名
this.View.BillBusinessInfo.GetBillTypeField().FieldName # 单据类型字段名
this.View.BillBusinessInfo.GetForm().Id # 单据FormId
this.View.BillBusinessInfo.MainOrgField.FieldName # 主业务组织字段名
this.View.BillBusinessInfo.GetEntity("FBillHead").TableName # 单据头表名
this.View.BillBusinessInfo.GetEntity("实体标识").TableName # 实体主表名
this.View.BillBusinessInfo.GetEntity("实体标识").SplitTables # 实体所有拆分表
this.View.OpenParameter # 表单入口参数
this.View.OpenParameter.Status # 当前界面状态:0-新增 1-查看 2-修改
this.View.OpenParameter.GetCustomParameter("参数标识") # 获取单据打开传入的参数
this.View.ParentFormView # 获取父页面的View
this.View.ParentFormView.BillBusinessInfo.GetForm().Id # 父页面的FormId,用来判断单据是从哪里进来的②View的常用方法
# View的常用方法
this.View.GetFormTitle() # 获取单据标题
this.View.SetFormTitle(LocaleValue("新标题")) # 修改单据标题
this.View.GetFormOperation("操作代码") # 获取单据的一个操作实例对象
this.View.InvokeFormOperation("操作代码") # 触发单据的某个操作:保存、提交、审核、关闭等!
this.View.GetControl[控件类]("控件标识") # 获取单据上的控件:按钮、菜单等,可用来设置控件的状态(可见性,锁定性等)
this.View.InvokeFieldUpdateService("字段标识", 行号) # 触发字段值更新,单据头字段行号填0
# 触发实体服务规则,下面2行代码
obj = BOSActionExecuteContext(this.View)
this.View.RuleContainer.RaiseDataChanged("字段标识", 字段所在实体行数据包, obj) # 触发实体服务规则
# 显示3种提示信息
this.View.ShowMessage("绿色背景提示信息") # 显示正常提示信息
this.View.ShowWarnningMessage("黄色背景提示信息") # 显示警告提示信息
this.View.ShowErrMessage("红色背景提示信息") # 显示错误提示信息
# 刷新界面数据,修改实体数据包后需要刷新重新读取,必须传标识,不建议粗暴刷新整个单据
this.View.UpdateView("字段标识/单据体标识") # 刷新界面数据
Model单据数据模型
this.View.Model # 单据数据模型,很重要,单据的实体数据包获取从这里开始,结合上文
this.View.Model.DataObject # 单据的完整数据包,相当于前面讲的单据头实体数据包
this.View.Model.GetEntryCurrentRowIndex("单据体标识") # 获取单据体当前焦点行号
this.View.Model.GetEntryRowCount("单据体标识") # 获取单据体行数
this.View.Model.CreateNewEntryRow("单据体标识") # 为单据体新增一行
this.View.Model.BatchCreateNewEntryRow("单据体标识", x) # 批量为单据体新增x行
this.View.Model.InsertEntryRow("单据体标识", i) # 在第i行前插入1行
this.View.Model.DeleteEntryRow("单据体标识", i) # 删除第i行
this.View.Model.DeleteEntryData("单据体标识") # 清空整个单据体数据#获取第x行(单据头不传x)某字段的值,不同字段类型返回不同类型数据,参考第3篇讲解
this.View.Model.GetValue("字段标识", x) # 更新第x行(单据头不传x)某字段的值,不同字段类型赋值不同类型数据,参考第3篇讲解
this.View.Model.SetValue("字段标识", 字段值, 行号)
this.View.Model.SetItemValueByID("字段标识", "id", x) # 用资料内码id更新第x行资料字段的值
this.View.Model.SetItemValueByNumber("字段标识", "id", x) # 用资料编码更新第x行资料字段的值
ListView列表视图层对象
this.ListView.BillBusinessInfo.GetForm().Id # 当前列表对应的单据标识
this.ListView.OpenParameter # 列表入口参数
this.ListView.OpenParameter.HideListMenu = True # 隐藏列表菜单
this.ListView.OpenParameter.IsShowFilter = True # 打开列表自动弹出过滤框,默认为False
this.ListView.OpenParameter.IsShowQuickFilter = False # 是否显示快捷过滤
this.ListView.OpenParameter.FilterSchemeId # 当前过滤方案ID
this.ListView.OpenParameter.IsTrackBillList() # 是否上下查列表
# 获取自定义参数,可获取发布主控台的参数,例如,将不同单据类型发布成不同列表
this.ListView.OpenParameter.GetCustomParameter("参数标识")
this.ListView.SelectedRowsInfo # 当前列表上被选中的行记录,复选框勾选的记录集合
this.ListView.CurrentSelectedRowInfo # 当前列表上当前选择行数据,即焦点行
this.ListView.CurrentPageRowsInfo # 当前列表页所有单据的行信息
grid = this.View.GetControl[EntryGrid]("FList") # 获取列表表格控件对象
selectedRowIndexs = List[int]()
selectedRowIndexs.Add(1)
selectedRowIndexs.Add(3)
grid.SelectRows(selectedRowIndexs.ToArray())
grid.SetRowHeight(80) # 设置行高
ListModel列表数据模型
this.ListModel # 获取列表数据模型
selectedRowsInfo = this.ListView.SelectedRowsInfo
this.ListModel.GetData(selectedRowsInfo) # 获取选中的数据
selectedRowsInfo.GetPrimaryKeyValues() # 获取选中行所有单据ID,字符串数组
selectedRowsInfo.GetEntryPrimaryKeyValues() # 获取所有选中行所有明细ID,字符串数组
this.ListModel.FieldKeyMap # 列表上显示的字段,其字段名 FieldName 和字段标识Key的对应关系
this.ListModel.FilterParameter # 列表过滤参数对象
this.ListModel.FilterParameter.CustomFilter # 列表过滤框实体数据包
this.ListModel.FilterParameter.FilterRows # 列表条件过滤行数据
this.ListModel.FilterParameter.FilterString # 列表条件过滤数据系统自动转换出的条件表达式
this.ListModel.GlobalParameter # 单据参数配置中配置的单据全局参数
this.ListModel.ParameterData # 用户参数实体数据包,选项菜单界面的配置数据
this.ListModel.Header # 列表表头对象
this.ListModel.Header.GetChilds() # 列表所有的列头集合
this.ListModel.Limit # 当前列表每页行数
this.ListModel.StartRow # 开始行索引,从0开始
this.ListModel.Refresh() # 刷新列表
this.ListModel.RefreshByFilter() # 根据过滤条件,重新取数,刷新列表
操作插件常用属性及方法
this.BusinessInfo.GetForm().Id #执行当前操作的单据FormId
this.BusinessInfo.GetBillNoField().FieldName #单据编号字段名
this.BusinessInfo.GetBillStatusField().FieldName #单据状态字段名
this.BusinessInfo.GetBillTypeField().FieldName #单据类型字段名
this.BusinessInfo.MainOrgField.FieldName #主业务组织字段名
this.BusinessInfo.GetEntity("FBillHead").TableName #单据头表名
this.BusinessInfo.GetEntity("实体标识").TableName #实体主表名
this.BusinessInfo.GetEntity("实体标识").SplitTables #实体所有拆分表
this.BusinessInfo.GetField("字段标识") #获取字段元素
this.FormOperation.Operation #当前执行的操作代码
this.FormOperation.OperationName.GetString(2052) #当前执行的操作中文名称
this.FormOperation.OperationId #当前执行的操作Id
this.FormOperation.PermissionItemId #当前操作绑定的权限项Id
this.FormOperation.ServicePlugins #当前执行操作下所有的操作服务插件集合
this.Option #当前操作执行时的选项参数,代码调用单据操作时,也可以通过此变量传入自定义参数
this.Option.ContainsVariable("参数标识") #判断是否存在某个参数,返回true或false
DIC=this.Option.GetVariables() #获取所有的参数,字典类型,根据参数标识获取
a=DIC["参数标识"] #获取某个参数
IsIgnoreWarning=DIC["IgnoreWarning"] #是否忽略警告提示,返回true或false
selectRows=DIC["_BillOperationSelectedRows_"] #如果是单据体行操作可以从这里获取选中行
for r in selectRows:
billId=r["PrimaryKeyValue"] #单据ID
billId=r["EntryPrimaryKeyValue"] #单据体分录ID,若为整单操作,此值为null
Json封装
在金蝶环境中运行的Python不能引入Python扩展,所以需要用到自定义JSON类
class Json:
def __init__(self):
pass
def __json_object(self, tokener):
obj = {}
if tokener.cur_token() != '{':
raise Exception('Json must start with "{"')
while True:
tokener.next()
tk_temp = tokener.cur_token()
if tk_temp == '}':
return {}
if not isinstance(tk_temp, str):
raise Exception('invalid key %s' % tk_temp)
key = tk_temp
tokener.next()
if tokener.cur_token() != ':':
raise Exception('expect ":" after "%s"' % key)
tokener.next()
val = tokener.cur_token()
if val == '[':
val = self.__json_array(tokener)
elif val == '{':
val = self.__json_object(tokener)
obj[key] = val
tokener.next()
tk_split = tokener.cur_token()
if tk_split == ',':
continue
elif tk_split == '}':
break
else:
if tk_split is None:
raise Exception('missing "}" at at the end of object')
raise Exception('unexpected token "%s" at key "%s"' % (tk_split, key))
return obj
def __json_array(self, tokener):
if tokener.cur_token() != '[':
raise Exception('Json array must start with "["')
arr = []
while True:
tokener.next()
tk_temp = tokener.cur_token()
if tk_temp == ']':
return []
if tk_temp == '{':
val = self.__json_object(tokener)
elif tk_temp == '[':
val = self.__json_array(tokener)
elif tk_temp in (',', ':', '}'):
raise Exception('unexpected token "%s"' % tk_temp)
else:
val = tk_temp
arr.append(val)
tokener.next()
tk_end = tokener.cur_token()
if tk_end == ',':
continue
if tk_end == ']':
break
else:
if tk_end is None:
raise Exception('missing "]" at the end of array')
return arr
def encode(self, data): # encode的兼容性有待调整且会数字化bool以及字符串化None
s = '{'
for k, v in data.items():
if type(v) is bool:
v = int(v)
elif v is None:
v = ''
# 兼容数组+字典场景
if type(v) is list:
temp = '['
for i in v:
temp = temp + self.encode(i) + ','
v = temp.rstrip(",") + ']'
if type(v) is str and (len(v) == 0 or v[0] not in '{['):
s = s + '"{0}":"{1}",'.format(k, v)
else:
s = s + '"{0}":{1},'.format(k, v)
return s.rstrip(",") + "}"
def decode(self, json_str):
tokener = Json.__Tokener(json_str)
if not tokener.next():
return None
first_token = tokener.cur_token()
if first_token == '{':
decode_val = self.__json_object(tokener)
elif first_token == '[':
decode_val = self.__json_array(tokener)
else:
raise Exception('Json must start with "{"')
if tokener.next():
raise Exception('unexpected token "%s"' % tokener.cur_token())
return decode_val
class __Tokener: # Tokener 作为一个内部类
def __init__(self, json_str):
self.__str = json_str
self.__i = 0
self.__cur_token = None
def __cur_char(self):
if self.__i < len(self.__str):
return self.__str[self.__i]
return ''
def __move_i(self, step=1):
if self.__i < len(self.__str):
self.__i += step
def __next_string(self):
outstr = ''
trans_flag = False
self.__move_i()
while self.__cur_char() != '':
ch = self.__cur_char()
if ch == '\\':
trans_flag = True
else:
if not trans_flag:
if ch == '"':
break
else:
trans_flag = False
outstr += ch
self.__move_i()
return outstr
def __next_number(self):
expr = ''
while self.__cur_char().isdigit() or self.__cur_char() in ('.', '+', '-'):
expr += self.__cur_char()
self.__move_i()
self.__move_i(-1)
if '.' in expr:
return float(expr)
else:
return int(expr)
def __next_const(self):
outstr = ''
while self.__cur_char().isalpha():
outstr += self.__cur_char()
self.__move_i()
self.__move_i(-1)
outstr = str(outstr).lower()
if outstr in ('true', 'false', 'null', 'none'):
return {'true': True, 'false': False, 'null': None, 'none': None}[outstr]
raise Exception('Invalid const "%s"' % outstr)
def next(self):
is_white_space = lambda a_char: a_char in ('\x20', '\n', '\r', '\t')
while is_white_space(self.__cur_char()):
self.__move_i()
ch = self.__cur_char()
if ch == '':
cur_token = None
elif ch in ('{', '}', '[', ']', ',', ':'):
cur_token = ch
elif ch == '"':
cur_token = self.__next_string()
elif ch.isalpha():
cur_token = self.__next_const()
elif ch.isdigit() or ch in ('.', '-', '+'):
cur_token = self.__next_number()
else:
raise Exception('Invalid symbol "%s"' % ch)
self.__move_i()
self.__cur_token = cur_token
return cur_token is not None
def cur_token(self):
return self.__cur_token
d = dict()
d['aaa'] = 'bbb'
d['ccc'] = ['ddd', 'eee']
d['fff'] = {"ggg": "hhh", "iii": {"jjj": "kkk", "lll": ["mmm", False, None], 'uuu': True, 'vvv': None}, "sss": False,
"ttt": None}
d['ooo'] = [111, +222, -333, 3.1415, 'ppp']
d['qqq'] = True
d['rrr'] = None
jsonData = Json().encode(d)
print(jsonData)
data = Json().decode(jsonData)
print(data)
错误日志
通常在应用对应的日期文件夹下
- C:\Program Files (x86)\Kingdee\K3Cloud\WebSite\App_Data\Log\2022-01-01
自定义错误日志
- 建议用Error(),如果用Info()的话,需要调整错误级别
- C:\Program Files (x86)\Kingdee\K3Cloud\WebSite\Web.config
- 搜索log4net的配置,要把Level的值从ERROR改为INFO或者ALL
- 需要重启IIS
import clr
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.Contracts')
clr.AddReference('Kingdee.BOS.ServiceHelper')
clr.AddReference('Kingdee.BOS.Log')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Orm import *
from Kingdee.BOS.Contracts import *
from Kingdee.BOS.App import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from System import *
from System.Data import *
from System.Text import *
from System.Collections import *
from Kingdee.BOS.App.Data import *
from System.Collections.Generic import List
from Kingdee.BOS.ServiceHelper import *
from Kingdee.BOS.Log import *
def AfterExecuteOperationTransaction(e):
try:
idList = List[object]()
idList.Add('123')
pkArray = idList.ToArray()
formID = this.BusinessInfo.GetForm().Id
meta = MetaDataServiceHelper.Load(this.Context, formID)
submitOption = OperateOption.Create()
# 自动提交配置忽略警告信息
submitOption.SetVariableValue("IgnoreWarning", True)
subResult = BusinessDataServiceHelper.Submit(this.Context, meta.BusinessInfo, pkArray, "Submit", submitOption)
if (subResult.IsSuccess == True):
auditOption = OperateOption.Create()
# 自动审核配置忽略警告信息
auditOption.SetVariableValue("IgnoreWarning", True)
auditResult = BusinessDataServiceHelper.Audit(this.Context, meta.BusinessInfo, pkArray, auditOption)
if (auditResult.IsSuccess == True):
return
auditErrorMessage = ''
for errMsg in auditResult.ValidationErrors:
auditErrorMessage += errMsg.Message
raise BaseException(auditErrorMessage)
subErrorMessage = ''
for errMsg in subResult.ValidationErrors:
subErrorMessage += errMsg.Message
raise BaseException(subErrorMessage)
except BaseException as ex:
# 记录Error日志到,C:\Program Files (x86)\Kingdee\K3Cloud\WebSite\App_Data\Log\{date}
Logger.Error('sal_order', 'submit_approval_error', KDException("?", str(ex)))