红皮书-1.0自定义技术新一代云ERP解决方案2目录一.前言.4二.自定义项引用节点展现.52.1.实现方式..52.2.需要产品组配合的工作.52.2.1.预制脚本.52.2.2.程序中向bd_defused表中插入数据.6三.自定义项引用校验..73.1.单据或档案自定义项使用了统计型自定义项后的检查分析.73.1.1.应用场景.73.1.2.解决方案.83.2.总结:需要产品组配合的工作..103.2.1.提供预制脚本..103.2.2.删除以前版本中在bd_ref_relation表中预置的脚本..10四.自定义项使用后的显示..114.1.通用情况.114.2.特殊情况和特殊需求.114.3.工具类设计.124.4.工具类使用说明.124.4.1.卡片界面引用自定义项的显示.124.4.2.列表界面引用自定义项的显示.134.4.3.管理界面引用自定义项的显示.134.5.使用举例.134.6.特殊情况的处理.134.6.1.查找自定义项的引用情况.14新一代云ERP解决方案34.6.2.初始化自定义项..144.6.3.显示引用了的自定义项.14五.自定义项使用后的打印..155.1.统计型自定义项打印涉及的修改..155.2.把统计型自定义项的主键翻译成名称的方法.155.3.使用举例.165.4.类图..17新一代云ERP解决方案4一.前言自定义项管理包括定义自定义项、引用自定义项及自定义项档案定义。主要解决系统业务单据中已有项目不能满足实际需要时,可以在系统中设置自定义项,并在单据中引用。U8cloud版从效率和易用性上有比较大的改变,具体体现在如下几个方面: 任何档案的自定义项都可以引用基本档案、自定义项档案。例如:存货管理档案的自定义项1可以引用自定义项档案、也可以引用任何基本档案(包括存货管理档案它自己)。 档案或单据的自定义项使用后,如果使用的是统计性自定义项,则保存的都是被引用档案的主键。例如:存货的自定义项1引用了客商管理档案,则存货的自定义项1中保存的是客商管理档案的主键。(以前保存的可能是主键、也有可能是名称)。 自定义项引用节点的展现方式的改变。我们提供了一些API或注册机制以帮助开发人员快速实现上述这些改变。本文的目的是对这些API或者注册机制进行详细的描述,以供开发人员参考。新一代云ERP解决方案5二.自定义项引用节点展现本章指的是自定项引用节点的界面展现方式的改变,着眼于实现U8cloud的如下新需求:修改该档案的展现方式。完全列表的方式不便于应用,修改为左边是进行自定义项引用的对象树(都是平级的)(如果可能按照产品模块构造树),右侧是该对象包含的自定义项列表。2.1.实现方式为了实现自定义项引用的展现方式,并且“按照产品模块构造树”,决定在bd_defused表中增加一个字段fun_code,其数据类型是varchar(60)。用来存储某功能节点所属模块的功能节点号。例如:客商档案和存货档案都是数据客户话的基本档案,所以客商和存货的自定义项引用在bd_defused表中的预制数据的fun_code的值都是“1008”(基本档案的功能节点号是1008)2.2.需要产品组配合的工作2.2.1.预制脚本凡是在安装盘中对表bd_defused进行预制数据的脚本都需要修改,添加对该表新加字段fun_code的初始值,其值是功能节点所属模块的功能节点号。例如:原预制脚本:insertintobd_defused(pk_defused,objcode,objname,defnum,freenum,pk_corp,ts,dr)values('secent00000000000001','secent','结算中心',20,0,null,'2001-09-1713:57:39',0)修改后预制脚本(由于“结算单位”是属于“基本档案”,其功能节点号是:1008):insertintobd_defused(pk_defused,objcode,objname,defnum,freenum,pk_corp,ts,dr,fun_code)values('secent00000000000001','secent','结算中心',20,0,null,'2001-09-1713:57:39',0,’1008’)新一代云ERP解决方案62.2.2.程序中向bd_defused表中插入数据现在只发现基本档案中的“项目档案”存在此种用法,如果还有其他产品组存在此种用法,请添加新加字段的预制值。新一代云ERP解决方案7三.自定义项引用校验本章讲的自定义项引用的校验主要指如下两方面:其一,自定义项引用节点修改某个自定义项的引用关系的校验:例如:客商档案的自定义项1引用了自定义项档案“明族”,并且在某条具体的客商档案数据中的自定项1保存了具体的某个民族(如:汉族),如果在自定项档案中又想把客商档案的自定义1修改为自定义项档案“学历”,这就会在客商档案表中导致错误数据,所以要做此校验。其二,就是删除校验。3.1.单据或档案自定义项使用了统计型自定义项后的检查分析自定义项档案部分的最新情况,也为了解决单据或档案的自定项使用了统计型自定义项后引用检查存在的问题(如果引用的是基本档案,则不能检查;检查的时候性能低下)。我们有了如下的解决方案:按需注册正确的引用脚本。3.1.1.应用场景A.定义一个统计型自定义项“AAAA”,让他引用“存货管理档案”B.在自定义项引用处,让客商管理档案的自定义项1,引用“AAAA”,此时在bd_ref_relation表中注册一条信息(如果修改成其他的统计型自定义项,也要相应的修改,如果修改成非统计型自定义项档案,择需要删除注册信息):主键引用表名引用字段名被引用表名被引用字段名Pk1客商管理档案客商管理档案的存货管理档案存货管理档案新一代云ERP解决方案8表def1表明主键名C.修改统计型自定义项“AAAA”,让他引用“民族”(自定义项档案),则修改B在表bd_ref_relation中插入的注册信息(如果已经被引用了的统计型自定义项也不能修改了,则不需要做此处理)主键引用表名引用字段名被引用表名被引用字段名Pk1客商管理档案表客商管理档案的def1自定义项档案表名自定义项项档案主键名3.1.2.解决方案为了实现上述引用场景,我们主要需要解决获取“引用表名”、“被引用表名”、“被引用字段名”的问题。(1)获取引用表名由于自定义项引用表中,只能知道某个选择的自定义项引用记录是属于哪个档案的(例如客商管理档案),具体哪个档案有哪几个表并不清楚,所以我们新加一个表:bd_defcsttblnme字段名字段含义字段含义pk_defcsttblnme主键,本表的主键pk_defused自定义项使用表主键,bd_defused表的主键,一个主键对应一个档案,例如,客商管理档案对应的主键是:sm000000000000000003新一代云ERP解决方案9tablename表名,某个档案对应的表名checkclassname在自定义项引用节点中,校验某自定义项引用是否可以修改的类,该类需要实现接口:nc.bs.bd.def.ICheckDefquoteCanChg如果此校验没什么特殊性,则不需要注册。例如:如果修改公司目录的自定义项,则交验规则其实就是根据selectcount(*)frombd_corpwheredef1isnotnullorrtrim(def1)<>’’这条语句返回值来判断,如果返回值为0,则认为公司目录还没有真正使用该自定义项,可以修改,否则,就不能修改了。这种情况下,就不需要注册了,自定义项提供了默认的实现(默认实现类是nc.bs.bd.def.DefaultChkDefquoteCanChg)。例如:项目管理档案的各个公司的自定义项可以引用不同的档案,这种情况下不是一条普通语句就能判断是否可以修改,就需要注册交验该字段。fieldclassname如果在bd_defquote表中注册的字段名和实际表中的字段名不一致,需要注册一个类,该类实现如下接口nc.bs.bd.def.IRegistFieldContrastTableField我们需要在安装盘中提供这个表的预制数据。需要产品组提供本表的预制脚本。一个档案或单据,可能会牵涉到多个表,例如,供应链单据头,可能牵涉到多个表,则需要在此表中预制多条数据。(2)获取被引用表名和被引用字段名可以通过这个自定义项引用的自定义档案所对应的bdinfo中获取。新一代云ERP解决方案10(3)由此引起的其他变化自定义项定义处,统计型的自定义项定义,如果被引用,则不能修改(以前是提示“请谨慎修改!”);自定义项引用处,如果引用的是统计型自定义项定义,则判断该统计型自定义项定义是否参照了档案,如果没有,则报错“您引用的是统计型自定义项,请先关联档案后在引用!”(以前没有这种判断)3.2.总结:需要产品组配合的工作3.2.1.提供预制脚本本工作需要产品组做的事只有一件,就是提供表bd_defcsttblnme的预制脚本。这个预制脚本的形式如下(如果checkclassname字段和fieldclassname需要预置的话,):Insertintobd_defcsttblnme(pk_defcsttblnme,pk_defused,tablename,checkclassname,fieldclassname,dr,ts)values(‘BD000000000000000001’,’sm000000000000000003’,’bd_cubasdoc’,0,null,null’2006-06-0813:57:39’)3.2.2.删除以前版本中在bd_ref_relation表中预置的脚本由自定义项引用引起的一些在表bd_ref_relation中的预制脚本需要删除,这些脚本可以用如下一条语句来找出:select*frombd_ref_relationwhere(referencingtablecolumnlike'def_'orreferencingtablecolumnlike'def__')andreferencedtablename='bd_defdoc'新一代云ERP解决方案11四.自定义项使用后的显示本章介绍利用单据模板开发的单据或者档案使用了自定义项后的显示问题。具体介绍程序员经常使用的API。4.1.通用情况对于用单据模板来开发UI界面的单据(或基本档案)使用自定义项,一般都需要做如下几件事: 该单据的自定义项引用是否引用了自定义项定义; 如果引用了,根据自定义项定义的数据类型,在界面上显示不同的控件; 不同的数据类型,分别需要进行如下的处理:日期:日期参照备注:字符录入框(需要限定可录入长度,为100)统计:参照数字:数字录入框(需要判断小数位数和录入长度);4.2.特殊情况和特殊需求另外,在研究基本档案各个功能节点的自定义项引用情况发现有如下一些比较特殊的情况:单据模板上显示自定义项一般指的是在卡片界面、列表界面显示自定义项。同时卡片和列表的表头和表体都有可能有自定义项。表头自定义项和表体自定义项都可能来自多个自定义项引用,例如:存货管理档案的表头自定义项来自“存货管理档案”和“存货档案”、客商管理档案的自定义项来自“客商管理档案”和“客商档案”等。在项目支持过程中,有客户提出这样的需求:存货基本档案的自定义项即时引用了,也不是一定需要显示,只有集团用户登录的时候才需要显示。新一代云ERP解决方案124.3.工具类设计针对如上特殊情况和需求,对单据模板使用自定义项的UI,设计了如下一些工具类(类图):4.4.工具类使用说明4.4.1.卡片界面引用自定义项的显示如果是卡片界面需要显示引用的自定义项,则需要在加载界面时插入如下代码:String[]strDefObjs=newString[]{"结算单位"};String[]strPrefix=newString[]{"def"};newCardDefShowUtil(this.getBillCardPanel()).showDefWhenRef(strDefObjs,新一代云ERP解决方案13strPrefix,true);如果不想引用就显示,而是根据单据模板自定义项的设置情况进行显示,可以自己实现显示策略:实现接口IDefShowStrategyimpl(如果仅仅是根据单据模板原自定义项的显示情况来判断是否显示,可以使用该默认实现:nc.ui.trade.bill.DefaultDefShowStrategyByBillItem),得到具体实现的实例impl,然后用如下方式调用:newCardDefShowUtil(this.getBillCardPanel(),impl).showDefWhenRef(strDefObjs,strPrefix,true);4.4.2.列表界面引用自定义项的显示如果是列表界面,则用ListDefShowUtil,使用方法与1类似;4.4.3.管理界面引用自定义项的显示如果是管理界面,则用ManageDefShowUtil,是用方法与1类似;4.5.使用举例可以参照如下类:nc.ui.bd.invdoc.InvMandocUI存货管理档案nc.ui.bd.invdoc.InvBasDocUI存货基本档案nc.ui.bd.settle.SettleUnitUI结算单位nc.ui.bd.settle.SettleCenterUI结算中心4.6.特殊情况的处理如果用以上工具不能解决问题,可以按照如下步骤来分解处理自定义项引用后的现实问题。新一代云ERP解决方案144.6.1.查找自定义项的引用情况例如:IDefdefservice=(IDef)NCLocator.getInstance().lookup(IDef.class.getName());nc.vo.bd.def.DefVO[]defs=null;try{defs=defservice.queryDefVO("物料生产档案",getUnitCode());}catch(BusinessExceptione){Logger.error(e.getMessage(),e);}4.6.2.初始化自定义项例如:getBillListPanel().getBillListData().updateItemByDef(defs,"def",true);getBillCardPanel().getBillData().updateItemByDef(defs,"def",true);4.6.3.显示引用了的自定义项例如:SetDefVisuabled.getInstance().setDefVisuabled(getBillListPanel().getBillListData(),defs,"def",true);SetDefVisuabled.getInstance().setDefVisuabled(getBillCardPanel().getBillData(),defs,"def",true);如果需要按照策略进行显示,则可以实像接口nc.ui.trade.bill.IdefShowStrategy,得到具体实现类的实例impl(如果仅仅是根据单据模板原自定义项的显示情况来判断是否显示,可以使用该默认实现:nc.ui.trade.bill.DefaultDefShowStrategyByBillItem),用如下方式调用:SetDefVisuabled.getInstance(impl).setDefVisuabled(getBillListPanel().getBillListData(),defs,"def",true);SetDefVisuabled.getInstance(impl).setDefVisuabled(getBillCardPanel().getBillData(),defs,"def",true);新一代云ERP解决方案15五.自定义项使用后的打印统计型自定义项统一存主键后,由于打印模板的自定义项是主键,所以需要通过一定的方式把主键变成名称,以便于打印。5.1.统计型自定义项打印涉及的修改首先,要修改打印模板(默认自定义项是不打印的);其次,修改数据源,如果自定义项存的是主键,把它翻译成名称。5.2.把统计型自定义项的主键翻译成名称的方法原来的打印,一般都有一个数据源(继承nc.ui.pub.print.IdataSource的接口),我们就叫orign_datasource,我写了一个装饰类,用来给原来的数据源添加新功能(把统计型自定义项的主键翻译成名称的功能)。这个装饰类为nc.ui.trade.pub.PrtDefDealedDecorator,它也继承了nc.ui.pub.print.IdataSource接口,同时它把原来的数据源(orign_datasource)通过构造注入,从而达到增加需要的功能的要求。同时,该装饰类的构造还需要两个参数:nc.ui.trade.pub.IcheckIsDef接口的实现:用来判断某个属性是否是自定义项,有默认实现nc.ui.trade.pub.DefaultCheckIsDef,认为以def且长度小于等于5的表达式,认为以vdef且长度小于等于6的表达式,认为以cdef且长度小于等于6的表达式,认为以c.def且长度小于等于7的表达式开头的人为是自定义项;nc.ui.trade.pub.IgetDefCodeOrName接口的实现:用来获取统计型自定义项主键对应的名称。有默认实现nc.ui.trade.pub.DefaultGetDefCodeOrName,那些采用本套自定义项显示机制(参见第四章)的,可以使用默认实现。新一代云ERP解决方案165.3.使用举例存货管理档案的打印:………………………………………………………………orign_datasource//获取原来的数据源,认为原数据源变量名为orign_datasource/*为支持自定义打印需要添加的代码——begin*/IGetDefCodeOrNamegetdefcodeOrName=newDefaultGetDefCodeOrName(orign_datasource);//获得IgetDefCodeOrName接口的实现(此处采用默认实现)orign_datasource=newPrtDefDealedDecorator(newDefaultCheckIsDef(),getdefcodeOrName,orign_datasource);//创建装饰类的实例,此处采用IcheckIsDef接口的默认实现/*为支持自定义打印需要添加的代码——end*/……………………新一代云ERP解决方案175.4.类图图5-4自定义类图新一代云ERP解决方案18新一代云ERP解决方案NewGenerationofCloudERPSolution用友网络科技股份有限公司YonyouNetworkTechCo.Ltd.