金蝶云星空供应链销售管理模块在2021年11月发布的补丁中新增了国际电子面单功能,但早期版本未及时更新支持的物流公司。为解决此问题,提供了一种不升级系统而采用Python编译C#代码的二开方法,通过注册Python插件和编写C#代码动态扩展物流公司选项,如添加顺丰和中通,并展示了实施步骤和效果截图。
金蝶云星空供应链领域销售管理模块在2021年11月04日发布的补丁 PT-146894 [7.7.0.202111] 中添加了国际电子面单功能,通过菜单‘获取电子面单(国际)’可进入操作界面,其功能界面如下图1-1所示:
图1-1
在 PT-146911 [8.0.0.202205] 之前的版本中,国际电子面单中的物流公司能选择的只有dhl, fedex, jet,后续快递100添加了新的物流公司,而金蝶云星空没有及时同步更新,导致一些国际物流公司不能输入(后续PT-146915 [8.0.0.202206]版本将支持新的物流公司)。如果客户不想升级,可参照本论坛,本文介绍一种用Python编译C#代码的二开方法处理相关逻辑。首先打开BOSIDE,在获取电子面单界面中注册Python插件,如下图1-2所示:
图1-2
其中的Python代码如下所示:
clr.AddReference('System') clr.AddReference('Kingdee.BOS') from System import AppDomain from System.IO import FileInfo from System.Reflection import Assembly from System.Reflection import BindingFlags from System.CodeDom.Compiler import CompilerParameters from Microsoft.CSharp import CSharpCodeProvider from Kingdee.BOS.Core.Util import MD5Compute from Kingdee.BOS.Cache import KCacheManagerFactory refDlls = ''' Kingdee.BOS Kingdee.BOS.App Kingdee.BOS.App.Core Kingdee.BOS.Business.DynamicForm Kingdee.BOS.Business.PlugIn Kingdee.BOS.BusinessEntity Kingdee.BOS.Contracts Kingdee.BOS.Core Kingdee.BOS.DataEntity Kingdee.BOS.Model Kingdee.BOS.OrmEngine Kingdee.BOS.ServiceHelper Kingdee.BOS.Web Kingdee.K3.Core Kingdee.K3.SCM.Sal.Business.PlugIn log4net Newtonsoft.Json System System.configuration System.Core System.Data System.Data.DataSetExtensions System.Web System.Xml ''' code = ''' using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Orm.DataEntity; using Kingdee.BOS.ServiceHelper; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.K3.SCM.Sal.Business.PlugIn; namespace Kingdee.K3.SCM.Custom.BusinessPlugin { public class CustomGuoJiGetKuaidiBillEdit : AbstractDynamicFormPlugIn { public override void AfterDoOperation(AfterDoOperationEventArgs e) { base.AfterDoOperation(e); this.View.ShowErrMessage("测试代码 CustomGuoJiGetKuaidiBillEdit:" + e.Operation.Operation.ToUpperInvariant()); //以上只是一个测试代码 } static CustomGuoJiGetKuaidiBillEdit() { if (GetKuaidiBillEdit.INTERNATIONAL_COMPANY_CODES != null) { GetKuaidiBillEdit.INTERNATIONAL_COMPANY_CODES.AddRange(new List<string>() { "shunfeng", "zhongtong" }); } } } } ''' def CompileCode(code, refDlls): refAsmNames = filter(lambda y: y != '', map(lambda x: x.strip(), refDlls.split())) try: kcmgr = KCacheManagerFactory.Instance.GetCacheManager('PyCodeGeneratorCache', 'PyCodeGeneratorCache') except: return None cacheKey = MD5Compute().MDString(code + '-'.join(refAsmNames)) if(kcmgr.Get(cacheKey) is not None): return kcmgr.Get(cacheKey) cSharpCodePrivoder = CSharpCodeProvider({'CompilerVersion':'v4.0'}) codeCompiler = cSharpCodePrivoder.CreateCompiler() compilerParameters = CompilerParameters() compilerParameters.GenerateExecutable = False; compilerParameters.GenerateInMemory = True; for refAsmName in refAsmNames: asms = filter(lambda asm: asm.GetName().Name == refAsmName, AppDomain.CurrentDomain.GetAssemblies()) if(len(asms) > 0): compilerParameters.ReferencedAssemblies.Add(FileInfo(asms[0].CodeBase.Substring(8)).DirectoryName.Replace('\\', '/')+'/' + refAsmName + '.dll') else: try: compilerParameters.ReferencedAssemblies.Add(FileInfo(Assembly.Load(refAsmName).CodeBase.Substring(8)).DirectoryName.Replace('\\', '/') + '/' + refAsmName + '.dll'); except: pass compilerResults = codeCompiler.CompileAssemblyFromSource(compilerParameters, code); if (compilerResults.Errors.HasErrors): raise Exception('\r\n'.join(map(lambda err: err.ErrorText, compilerResults.Errors))) compiledAsm = compilerResults.CompiledAssembly; kcmgr.Put(cacheKey, compiledAsm) return compiledAsm assembly = CompileCode(code, refDlls) csPlugin = assembly.CreateInstance('Kingdee.K3.SCM.Custom.BusinessPlugin.CustomGuoJiGetKuaidiBillEdit') if assembly is not None else None def getPlugIn(): csPlugin.SetContext(this.Context, this.View) return csPlugin def AfterDoOperation(e): getPlugIn().AfterDoOperation(e)
注:以上代码不要直接通过论坛复制,要使用附件中的代码,上面的Python脚本会先申明一个refDlls和code变量,refDlls为C#项目引用,这个code变量里面是一个完整的C#代码块(包含了using指令,命名空间,类,方法等),后面的Python逻辑定义了动态编译功能,最终通过定义Python方法AfterDoOperation并在里面调用了code 变量中的同名C#方法,以下图2-1和2-2为Python重要脚本相关截图。
图2-1
图2-2
这种方法优点是只需要写C#代码,不需要懂太多Python语法,客户可以用类似方法自定义二开插件逻辑。以下图2-3是二开效果图,可以看到顺丰和中通已经能够在国际电子面单界面中选择了:
图2-3
PythonCompileCSharp.zip(1.58KB)
推荐阅读