二次开发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
clr.AddReference('System')
from System.Net import HttpWebRequest, WebRequest
from System.IO import StreamReader
from System.Text import Encoding
def MakeHttpRequest(url, method="GET", data=None, headers=None):
try:
request = WebRequest.Create(url) # 创建请求
request.Method = method
# 设置请求头
if headers:
for key in headers.Keys:
request.Headers[key] = headers[key]
# POST请求添加数据
if method == "POST" and data:
bytesData = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytesData.Length
with request.GetRequestStream() as stream:
stream.Write(bytesData, 0, bytesData.Length)
# 获取响应
with request.GetResponse() as response:
with StreamReader(response.GetResponseStream()) as reader:
return reader.ReadToEnd()
except Exception as e:
this.View.ShowMessage(f"请求失败: {e.Message}")
return None
# 使用示例(在某个按钮点击事件中)
def ButtonClick(e):
url = "https://api.example.com/data"
result = MakeHttpRequest(url)
this.View.ShowMessage(f"响应结果: {result}")