二次开发python插件
思路
(项目🔶-任务🟥-工作🔺)
建议用插件实现(插件捕获事件),不用实体规则
插件模式
通过插件来处理数据建立以一个无操作按钮
菜单事件
通过表单点击菜单 判断点击按钮表示 如: “XJPT_tbButton_2” 来执行内容
菜单点击
简单处理
import clr
#添加对cloud插件开发的常用组件的引用
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')
#clr.AddReference('Kingdee.BOS.KDSReportEntity')
#clr.AddReference('Kingdee.BOS.App.KDSService')
clr.AddReference('Newtonsoft.Json')
def BarItemClick(e):
""" 点击任意按钮 """
key=e.BarItemKey;
this.View.ShowMessage("欢迎回来 {0} ".format (key));
修改数据并刷新
import clr
import sys
clr.AddReference('System')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Newtonsoft.Json')
clr.AddReference('Kingdee.BOS.App')
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 Kingdee.BOS.JSON import *
from Newtonsoft.Json import JsonConvert
from System import *
import System
import System.IO
from Kingdee.BOS.App.Data import *
def getDt():
""" 获取事件 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj):
""" 显示对象内容 """
myLog("{0} {1} dir( obj ) {1} {2}\t".format(getDt(), '-'*10, type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type = {1} value = {2} ".format(i , type(cobj).__name__, cobj ))
def BarItemClick(e):
key=e.BarItemKey;
if(key !="XJPT_tbButton_2" ):
return
showObj(e)
showObj(this.View.Model.DataObject)
iD = this.View.Model.DataObject.Id
if(iD <= 0 ):
this.View.ShowMessage("未保存单据不能获取 {} ".format ( '' ));
else:
fsql="/*dialect*/ exec z_fxfph {0}".format(iD);
DBUtils.Execute(this.Context,fsql);
this.View.ShowMessage("完成操作 {0} ".format ( "" ));
this.View.InvokeFormOperation("Refresh")
myLog(" this.View.Model.DataObject.Id =={0} ".format(this.View.Model.DataObject.Id ))
def OnLoad(e):
#---------
myLog("{0}OnLoad e {0} {1}\t".format('-'*10, type(e).__name__))
for i in dir(e):
myLog("\t{}".format(i))
通用事件处理
import clr
import sys
clr.AddReference('System')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Newtonsoft.Json')
clr.AddReference('Kingdee.BOS.App')
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 Kingdee.BOS.JSON import *
from Newtonsoft.Json import JsonConvert
from System import *
import System
import System.IO
from Kingdee.BOS.App.Data import *
def getDt():
""" 获取事件 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj):
""" 显示对象内容 """
myLog("{0} {1} dir( obj ) {1} {2}\t".format(getDt(), '-'*10, type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type = {1} value = {2} ".format(i , type(cobj).__name__, cobj ))
#-----------------
def BeforeDoOperation(e):
showObj(e)
myLog("myLog:str(e.Operation) {0} , type = {1} value = {2} ".format(str(e.Operation), type(e.Operation).__name__, e.Operation ))
# 判断是否为提交操作
if type(e.Operation).__name__ != "Submit":
return
e.Cancel=True # 这个怎么写
raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
def BeforeSave(e):
showObj(e)
#e.Cancel=True # 这个怎么写
#raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
存储过程
alter PROCEDURE [dbo].[z_fxfph]--exec z_fxfph '100039'
@fid int
AS
BEGIN
update b set b.F_XJPT_PRICE1=g.FPRICE,b.F_XJPT_PRICE=g.FTAXPRICE
from T_AP_PAYABLE a
join T_AP_PAYABLEENTRY b on b.fid=a.fid
join T_AP_PAYABLE_LK c on c.fentryid=b.fentryid
join T_AP_PAYABLEENTRY i on i.fentryid=c.fsid
join T_AP_PAYABLE j on j.fid=c.fsbillid
join T_AP_PAYABLE_LK k on k.fentryid=i.fentryid
join T_STK_INSTOCKENTRY d on d.fentryid=k.fsid
join T_STK_INSTOCK e on e.fid=k.fsbillid
join T_STK_INSTOCKENTRY_LK f on f.fentryid=d.fentryid --and a.fbillno='AP00026516'
join T_PUR_POORDERENTRY_F g on g.fentryid=f.fsid
join T_PUR_POORDER h on h.fid=f.fsbillid
where a.FSETACCOUNTTYPE=3 and a.fid=@fid
end
exec z_fxfph '100039'
# 引入CLR运行库
import clr
# 添加插件开发必要组件
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
# 导入命名空间
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 Kingdee.BOS.App.Data import *
def AfterExecuteOperationTransaction(e):
try:
# 确保操作对象有效
if e.DataEntitys is None or e.DataEntitys.Count == 0:
this.View.ShowMessage("未获取到有效数据!")
return
# 遍历数据实体
for item in e.DataEntitys:
# 获取主键ID,注意字段名区分大小写(通常为"Id")
fid = str(item["Id"]) if "Id" in item and item["Id"] else None
if not fid:
this.View.ShowMessage("主键ID为空,无法执行操作!")
continue # 跳过当前项
# 方案1:安全参数化查询(推荐,若DBUtils支持)
# fsql = "/*dialect*/ EXEC z_fxfph @FID=?"
# params = (fid,)
# DBUtils.Execute(this.Context, fsql, params)
# 方案2:直接拼接(需防注入,确保fid安全)
fsql = "/*dialect*/ EXEC z_fxfph @FID='{}'".format(fid)
DBUtils.Execute(this.Context, fsql)
# 可选:记录执行日志
this.Logger.Info("成功执行存储过程,单据ID: {}".format(fid))
except Exception as ex:
# 异常处理
this.View.ShowMessage("执行出错: " + str(ex))
this.Logger.Error("插件执行错误", ex)
return
番外篇http请求
插件基于IronPython运行脚本,用python 请求http服务
import clr
#添加对cloud插件开发的常用组件的引用
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.DataEntity')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.App.Core')
#导入cloud基础库中的常用实体对象(分命名空间导入,不会递归导入)
#import sys
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.DependencyRules 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 System.Net import *
from System.Text import *
from System.IO import *
from Kingdee.BOS.App.Data import *
from System.Collections.Generic import List
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 *
import System
import System.IO
from Newtonsoft.Json import JsonConvert
def getDt():
""" 获取时间 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj,desc="obj"):
""" 显示对象内容 到log文件 """
myLog("{0} {1} dir( {2} ) {3} {1} \t".format(getDt(), '-'*10, desc ,type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type == {1} value == {2} ".format(i , type(cobj).__name__, cobj ))
#--------------------
butName="QINL_tbButton_send"
def BarItemClick(e):
dObj = this.View.Model.DataObject
#showObj(e,"按钮 BarItemClick {} 发货通知单 ".format( butName ) )
#showObj(dObj,"按钮 BarItemClick {} 发货通知单 ".format( butName ) )
key=e.BarItemKey;
if(key ==butName ):
发送无源单到通知系统()
def 无源明细检测():
""" 返回行号
SAL_DELIVERYNOTICEENTRY
"""
dObj = this.View.Model.DataObject
retLs = []
# 源头检测
for index, ent in enumerate(dObj.SAL_DELIVERYNOTICEENTRY):
#msg = "{}\n".format( JsonConvert.SerializeObject(ent.FEntity_Link) )
#myLog(msg)
if len( ent.FEntity_Link ) > 0:
continue
retLs.append(index+1)
return retLs
def 发送无源单到通知系统():
""" webhook发送 """
dObj = this.View.Model.DataObject
rowNum = 无源明细检测()
if len( rowNum ) > 0 :
ctx = "无原单 {} 第 {} 明细没有上游单据".format( dObj.BillNo, rowNum )
posturl='https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b913b6c0-9696-4cca-b555-329b3bcfde99'
body=''' {
"msgtype": "text",
"text": {
"content": "____text____"
}
}
'''
#this.View.ShowMessage('准备发送')
myLog("{0}: 无原单 : {1} {2} ".format(getDt(), butName, dObj.BillNo ))
msg=ToPost(posturl, body.replace("____text____", ctx) );
def ToPost(posturl,postdata):
result="";
try:
webRequest=HttpWebRequest.Create(posturl)
webRequest.Method="POST"
webRequest.ContentType="application/json"
data=Encoding.UTF8.GetBytes(postdata)
webRequest.ContentLength=data.Length
webRequest.GetRequestStream().Write(data,0,data.Length)
webRequest.GetRequestStream().Flush()
webRequest.GetRequestStream().Close()
webResponse=webRequest.GetResponse()
streamReader=StreamReader(webResponse.GetResponseStream(),Encoding.GetEncoding("utf-8"))
result=streamReader.ReadToEnd()
#return result
except Exception as e:
result=str(e)
finally:
return result