二次开发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}")