1、目录NC二次开发概述1导论2综述2知识必备2开发环境搭建2MDE配置2Java运行环境配置3数据库安装4新建项目5启动项目5平台配置及升级5新建帐套6帐套升级6登录系统7新建用户8注册新模块8新建公司8定义集团本位币8新建公司账9注册功能节点9权限分配10单据开发10概述10功能注册10系统类型定义10单据类型定义10单据模板定义10PDM设计10导入PDM10增加单据模板10增加查询模板10设置默认模板10管理型单据开发示例10管理型单据列表界面10管理型单据卡片界面10UI端的类:10BS端的类10PUB端的类10编写代码10自定义按钮10界面数据获得与设置10参照配置10执行公式10初始
2、化数据和默认值设置10单据号自动生成10前台校验10后台校验10单据开发练习109投资理财业务需求109.0总体设计109.1投资理财申请单109.2投资理财办理单109.3投资理财结算单10流程开发10导论10综述10平台配置10业务类型定义10流程配置10配置参照查询的DMO类10VO对照注册10数据交换配置10代码配置10按钮配置10参照查询对应的DMO类10用于显示来源单据的UI类10数据交换类10数据交换扩展10联查上下游单据功能10联查典型调用10HLBillFinder这个类是用来查找上下游单据的类,10HLDataFinder类实现了具体数据查找算法10配置10练习10单据UI
3、架构10单据界面构10单据界面加载10单据数据加载10NC外部交换平台10导论10综述10手动发送数据10系统配置101、导入业务插件类配置102、单据信息配置103、交换规则配置104、数据文件10代码实现10腾创科技客户下载需求10需求概述10产品现状10需求分析10需求实现10NC平台里的状态10单据相关状态10操作状态10业务状态10扩展状态10按钮状态10VO状态与表格行状态10NC数据加锁概述10综述10同一单据加锁10关联单据加锁10NC V5系列WEBSERVICE开发10说明10详细配置10新建接口10新建实现类10生成WSDL文件10部署及相关说明10示例10报表开发10基
4、本概念10功能节点注册10报表模板初始化10列表头配置10功能节点默认模板设置10报表界面10代码开发10先了解一下IReportCtl接口10UI类10报表表体多页签实现10练习10数据库访问10JAVA读写Excel10NCV5代码结构规范10常用数据库表说明10常见问题解决办法101、审批流逐级弃审102、联查审批流显示金额字段103、跨模块创建对象104、自定义档案105、生成会计凭证106、查询框监听107、表体树实现108、后台任务配置109、从外系统导数据到NC业务系统1010、加载单据模板1011、NC外部交换平台初始化帐套信息1012、开发单据函数1013、表体右键菜单101
5、4、显示表体01015、联查凭证1016、汇率1017、文件下载1018、单表体界面的实现1019、初始化键值对下拉数据1020、点击按钮弹出单据界面1021、后台获得前台客户端相关信息1022、使用NC的公式对话框1023、NC中的表格绘制器10培训纲要10结束语10参考资料10延伸阅读10导论我和你一样曾经对NC一无所知,因为选择了这个工作,所以我决心要做好它。学习一个新的东西总要走不少弯路,学习有时候会很枯燥,让你对它的热情降低,你要不时的看看别的东西来调节下自己的口味。要学的东西很多,如何才能印象深刻呢,你要去理解,抓住事物的本质,在一个更高的层次上去看待。理解就像一个压缩工具可以将知
6、识压缩占用更少的大脑空间,这样你就会长期保持一种愉悦的心情。本文将带您进入NC的世界,你不要害怕,你完全有能力掌握它。首先我要提以下几个问题:1、 如何搭建NC开发环境2、 NC的UI的核心是什么?3、 如何在NC中开发应用读完本文你将会对你的工作更有信心。综述本文以ncv55版本讲述 nc-uap平台二次开发全过程,包括以下内容:开发环境搭建、功能节点注册、权限分配、单据开发以及单据UI架构知识必备NC-UAP平台是架构在J2EE平台上,UI界面均为Swing组件,采用oracle、sql server、db2 (oracle 数据库在应用中非常常用)这3种数据库作为后台存储。因此在学习NC
7、之前应该具备以下知识。1、 java编程语言基础2、 了解Swing组件构建界面3、 了解oracle 的安装,创建用户,表空间,以及基本的sql语法。4、 学习eclipse集成开发平台的使用开发环境搭建Eclipse 3.2,v55 的 nchome,v55的eclipse插件,oracle 10g数据库MDE配置将v55的eclipse插件放入plugins目录下,启动eclipse查看【首选项】,如下图,左边会出现我们需要的MDE选项,右边需要配置nchome和数据库的相关信息Java运行环境配置配置成nchome自带的,位于nchome的ufjdk目录需要导入tools.jar和pl
8、ugin.jar两个包数据库安装请参看UFIDA NC 5.5安装指南.htm新建项目这些都配置完后,新建MDE项目,会出现如下的目录结构client目录存放前台类;private目录里存放后台类;public里存放公共的类,供前后台使用启动项目第一次启动项目,右键选择项目,以调试的方式启动NC Middleware(NC中间件),中间件启动完成后再启动NC Client。以后启动直接可以从快捷菜单,如下图平台配置及升级项目启动后,登录界面如下以root用户登录,密码为空新建帐套新建一个帐套,关联一个数据源,并设置管理员。一个帐套只能对应一个数据源,我们可以建多个帐套,以不同的帐套登录系统相当
9、于对应了不同的数据库。帐套升级如下图,选择待安装的产品,进行数据库安装,【客户化】是必须安装的,里面带有二次开发需要的节点。登录系统选择新建的帐套,以管理员身份登录系统新建用户建立一个新用户,以后以此用户登录系统。如下图注册新模块注册一个新的模块需要在表 sm_codetocode 插入一条记录dispcodedrfunccodeisleafmoduletypepk_codetocodesubfunccodetsHL0HLN1ETHLH1,HLH3在新建公司账的时候,系统会读取此处的数据新建公司定义集团本位币新建公司账配置模块名显示为中文Nchome/langlib下增加一个et_sim_la
10、ngres.jar文件,采用ZIP压缩et_sim_langres.jar文件目录结构为langsimpchnfuncode,位于funcode的目录下有一个属性文件HL.properties(HL为功能节点),内容如下:DHL=进出口管理对于V502的nchome,该属性文件放置的位置为nchomeresourceslangsimpchnfuncode注册功能节点权限分配NC的权限管理是基于角色的,首先建立角色,对角色分配权限,然后将角色再分配给用户,那么用户就拥有了角色对应的权限,详细内容请参看红皮书。单据开发概述NC-UAP平台UI的核心内容是单据,单据泛指所有能表示为主子表关系的数据模
11、型对应为关系数据库的主子表关系,在NC系统里每个单据都有一个单据类型来标识单据的唯一性。最终系统通过该单据类型加载定义的单据模板来实现加载界面。从业务上来看,NC中有两类单据,一类称作基本档案,一类称作业务单据(通常也叫单据),这两类单据的动作在系统中的实现是不一样的,注意后续介绍。以下内容将简单的介绍如何开发单据界面。功能注册注册所有的可功能节点,包括虚功能节点,可执行功能节点。【对应文件名或控件名】:可执行功能节点时需注册,对应于单据的ui类名系统类型定义【模块名】:对应nchome/modules下面的一个目录名【相关节点编码】:对应于【功能注册】的节点编码【是否发送会计平台】:系统里存
12、在单据需要生成凭证,此字段需打钩单据类型定义【单据类型编码】:4位字符(varchar(4))【参照查询对应的后台类】:在开发流程时使用【审批流检查类】:有审批时需要。可设置为HYSuperDMO,需加包名单据模板定义可以手工的一个个字段增加到单据模板,也可以通过powerdesigner工具先设计表再导入表,然后生成单据模板。PDM设计字段命名规范 描述命名数据库类型NC数据对象备注主键字段pk开头或者c开头char(20)String日期类型d开头char(10)UFDate逻辑类型b开头char(1)UFBoolean整数/下拉i开头Integer/smallintInteger数值型n
13、开头decimal(20,8)UFDouble一般字符v开头varchar(100)String编码字段v开头varchar(30)String名称字段v开头varchar(100)String备注字段v开头varchar(256)String常用字段命名参看类:BillField该类里面的常用字段并没有按照上述规范命名,如果基于标准的UAP开发,我们只好遵循历史的字段命名,如果基于BUAP开发,我们可以按照新的命名规范,查看HLBillField类描述命名数据库类型NC数据对象备注公司pk_corpChar(4)String一般单据单据号vbillnoVarchar(30)String一般单
14、据单据类型pk_billtypeVarchar(4)String一般单据单据日期dbilldateChar(10)UFDate一般单据制单日期dmakedateChar(10)UFDate一般单据制单人voperatoridChar(20)String一般单据审批人vapproveidVarchar(30)String审批流需要审批日期dapprovedateChar(10)UFDate审批流需要审批批语vapprovenoteVarchar(256)String审批流需要单据状态vbillstatussmallintInteger审批流需要业务类型pk_busitypeChar(20)Str
15、ing流程需要上层单据类型vlastbilltypeVarchar(4)String流程需要上层单据号vlastbillcodeVarchar(30)String流程需要上层单据行IDvlastbillrowidVarchar(30)String流程需要上层单据IDvlastbillidVarchar(30)String流程需要上层单据行号vlastbillrownoVarchar(30)String流程需要源头单据类型vsourcebilltypeVarchar(4)String流程需要源头单据号vsourcebillcodeVarchar(30)String流程需要源头单据行IDvsour
16、cebillrowidVarchar(30)String流程需要源头单据IDvsourcebillidVarchar(30)String流程需要源头单据行号vsourcebillrownoVarchar(30)String流程需要PDM使用按照powerdesigner 软件后打开,新建一个physical data model选择面板上的表格,然后点击在空白的地方双击打开,录入数据库表名称、编码和字段General页签Columns页签,录入表的列,表的主键需要打上后面的勾Preview页签,查看建表脚本PDM插件自动生成TS、DR字段ts、dr字段是NC表结构里必须的字段。ts标识数据的产
17、生时间,由数据库自动生成(ts在数据的一致性校验起着至关重要的作用),dr字段标识数据是否逻辑删除,当dr=1时表明数据是删除状态的,当dr=0或者为空时,表示数据是有效的。在做数据库设计时,我们不需要在Columns页签里设计ts,dr字段,我们只需要给powerdesigner打上自动生成ts,dr的补丁即可。导入PDMPdm设计好了后,我们需要将它导入到NC平台,v5系列的平台只支持sql server 7.x类型的pdm的导入。所有我们需要切换下pdm的数据库选择sql server 7.x 确定,然后保存pdm即可增加单据模板增加后增加查询模板可以在单据模板初始化界面,模板操作菜单下
18、生成查询模板,然后去查询模板初始化节点找出来进行相关修改,也可以直接在查询模板初始化节点增加。查询模板是通过节点号来对应到具体的功能节点的。NC默认的查询,查询条件只支持表头条件。在查询模板初始化节点可查询到生成的查询模板查询条件的取值可以使用系统函数,带有#value#的为系统函数,列表如下:系统函数名称描述Sys_Account会计期间Sys_Year当前年份Sys_Month当前月份Sys_Date当前日期Sys_Operator当前操作员Sys_department当前部门Sys_CurrCorp当前公司Sys_daysBefore_i当前日期前i天Sys_monthsBefore_i
19、当前月前i月Sys_DeptWithChild当前部门及其下级门 设置默认模板对于单据模板,查询版,报表模板,打印模板,需要在此节点进行相应的分配点击分配按钮选择查询模板点击添加选择相应的节点,选择【默认模板】,选择【模板】然后确认。最后保存管理型单据开发示例开发一个单据,除了单据模板,查询模板的基本配置,需要开发的最基本的类只需要3个,分别是,控制类,事件处理类,界面UI类。但是实际的业务中可能还需要有相关的数据校验,所以就有了前台校验类、后台校验类。以下是开发主子(非多子表)管理型单据,包含了实际的业务处理管理型单据列表界面管理型单据卡片界面UI端的类:前台校验类:CheckUI,需要在单
20、据类型节点的自定义项3上配置类全名控制类:ClientCtrl事件处理类:ClientEH界面UI类 :ClientUI这4个类UAP平台都给我们提供了相应的基类去继承,具体查看UI工厂ClientCtrl类配置卡片界面按钮默认的系统按钮都是定义在IBillButton接口列表界面按钮单据类型这里的单据类型是定义在常量接口里的,统一管理单据VO类数组如果是业务单据(单据是用来录入日常业务数据的)需要配置业务动作类型业务动作类型定义在接口 IBusinessActionTypePLATFORM:平台类型,需要动作脚本(需要另外的java类,针对保存、删除、查询、审批、弃审等按钮的动作)BD:基本
21、档案类型,不需要动作脚本如果当前单据需要审批(即单据走审批流),则就存在一个单据状态。存在单据状态返回true,不存在返回falseClientEH类配置如果没有自定义事件处理,暂时不需要做任何配置,只需继承父类即可ClientUI类配置关联事件处理类关联控制类BS端的类如果单据动作是平台类型的,一些基本的事件东西需要动作脚本单据动作配置保存:WRITE删除:DELETE修改:EDIT提交:SAVE审批:APPROVE弃审:UNAPPROVE动作执行脚本单据动作脚本通过平台编译,生成的类在模块下的META-INF目录里子目录可以找到,把生成的类Copy放置在eclipse环境下的private
22、的nc.bs.pub.action包中保存:WRITEObject retObj =null;/#重要说明:生成的业务组件方法尽量不要进行修改#/方法说明:公共保存方法retObj = runClassComsave.BillSave, saveBill, nc.vo.pub.AggregatedValueObject:01;/#return retObj;删除:DELETE/#本脚本必须含有返回值,返回DLG和PNL的组件不允许有返回值#Object retObj =null;/方法说明:行业公共删除retObj =runClassCom delete.BillDelete, deleteB
23、ill, nc.vo.pub.AggregatedValueObject:01;/#return retObj;修改:EDIT/#本脚本必须含有返回值,返回DLG和PNL的组件不允许有返回值#Object retObj=null;return null;提交:SAVEObject retObj =null;/#重要说明:生成的业务组件方法尽量不要进行修改#/方法说明:公共提交方法retObj = runClassComstatus.BillCommit, commitBill, nc.vo.pub.AggregatedValueObject:01;/#return retObj;审批:APPR
24、OVE/#该组件为单动作工作流处理开始.不能进行修改#procActionFlow;/#该组件为单动作工作流处理结束.不能进行修改#Object retObj =runClassCom status.BillApprove, approveBill, nc.vo.pub.AggregatedValueObject:01; return retObj;弃审:UNAPPROVE/#本脚本必须含有返回值,返回DLG和PNL的组件不允许有返回值# procUnApproveFlow (vo); Object retObj=runClassCom status.BillUnApprove, unAppr
25、oveBill, nc.vo.pub.AggregatedValueObject:01; return retObj;结束:END/#本脚本必须含有返回值,返回DLG和PNL的组件不允许有返回值#Object retObj=runClassCom status.BillEnd, endBill, nc.vo.pub.AggregatedValueObject:01; return retObj;取消结束:UNEND/#本脚本必须含有返回值,返回DLG和PNL的组件不允许有返回值#Object retObj=runClassCom status.BillUnEnd, unEndBill, nc.
26、vo.pub.AggregatedValueObject:01; return retObj;PUB端的类编写代码要熟悉管理型单据的开发,管理型单据是最基础最常用的单据。详细内容见 UI工厂.pdf介绍。自定义按钮将系统按钮加入卡片界面,我们只需实现控制类的方法public int getCardButtonAry()return new intIBillButton.Save,/保存IBillButton.Edit,/修改 IBillButton.Cancel,/取消 IBillButton.Delete/删除事实上,每一个按钮对应这一个int 型的编码,系统预置按钮的编码在100以内,它们
27、都定义在IBillButton接口里。那么我们自定按钮的话,按钮的编码必需大于100,并且同一个单据的自定义按钮的编码不能重复。下面我们来实现一个自定义按钮“导入”自定义按钮实现步骤:步骤1、定义按钮编码接口:public interface IDefButton int Import = 101;步骤2、定义按钮VO,可以参照系统预置按钮的VO定义做public class ImprotBtnVO implements IBillButtonVOpublic final static String btnChinaName = 导入;/按钮中文名字public ImprotBtnVO ()s
28、uper();public nc.vo.trade.button.ButtonVO getButtonVO()ButtonVO btnVo = new ButtonVO();btnVo.setBtnNo(IDefButton. Import);/设置按钮编号btnVo.setBtnChinaName(btnChinaName);/设置按钮中文名字(按钮权限控/制时用到)btnVo.setBtnName(“导入”);/设置按钮的名字btnVo.setHintStr(“导入数据”);/设置按钮提示文字btnVo.setOperateStatus(new int IBillOperate.OP_NO
29、TEDIT,IBillOperate.OP_INIT );/设置按钮的可操作状态,系统会根据它/来设置按钮的可用状态btnVo.setBusinessStatus(null);/设置按钮的业务状态btnVo.setHotKey(I);/设置快捷健btnVo.setDisplayHotKey(Ctrl+I);btnVo.setModifiers(Event.CTRL_MASK);return btnVo;步骤3、将按钮加到控制类public int getCardButtonAry()return new intIDefButton. Import ;步骤4、在UI类里初始化按钮,需要覆盖下面方
30、法protected void initPrivateButton() ButtonVO improtBtnVO =(new ImprotBtnVO ().getButtonVO();addPrivateButton(improtBtnVO);/加入私有按钮上面定义的按钮只有操作状态,没有业务状态。系统中像增加,保存等按钮都没有业务状态,这些都属于普通按钮,另外的属于业务按钮,业务按钮要定义按钮的业务状态,这个状态也就是单据的默认的8种状态。和自定义普通按钮基本一样,只需加入私有按钮时,将addPrivateButton 换成addPrivateBusinessButton即可,业务按钮是需要
31、调用动作脚本的,单据是要走平台的,是存在单据状态的。所以要实现按钮事件还要生成动作脚本,后两项都是在控制类里设置的。界面数据获得与设置 对于NC系统的单据而言,数据分为两部分,一是界面数据,二是缓存数据。界面数据和缓存数据只有在非编辑状态下才是一样的,在修改状态下,界面数据和缓存数据是脱钩的。所以说修改状态下要获得单据数据的话,一定要从界面获得,这样保证了数据的同步。NC单据界面分为两种,一种是卡片界面,一种是列表界面。这两个界面是分开的。但是数据都是缓存在一个地方。界面上的数据则是放在不同组件上。所以从两种不同的界面上获得数据的方式也不一样。如果你想了解这两种界面的布局的话,可以参看文章加载
32、单据模板,该文里面画出了单据卡片、列表界面的结构图。了解了结构图,有助于开发人员深入了解单据界面的实现。卡片、列表界面的判断:在UI端有方法isListPanelSelected()返回true时,说明当前界面为列表界面,返回false时,说明当前界面为卡片界面。(1)卡片界面取值(一下都是从UI端取值,如果在事件处理端取值,首先获得UI对象):获得表头某字段的值:getBillCardPanel().getHeadItem(strKey).getValueObject() / strKey为字段编码 表头取值不分页签获得表体某字段的值:getBillCardPanel().getBodyVa
33、lueAt(rowIndex, strKey)/ rowIndex 为表体行索引 strKey 为字段编码 默认为第一个页签getBillCardPanel().getBillModel(tableCode).getValueAt(rowIndex, strKey)/获得表体某页签,某行,某个字段的值获得单据界面VO:getVo();/从缓存获得当前聚合VO,列表界面下也适用getVOFromUI();/从界面获得当前聚合VOgetBillCardPanel().getBillModel().getBodyValueVOs(bodyVOName);/获得表体vos,返回表体VO数组getBil
34、lCardPanel().getBillModel().getBodyValueRowVO(row, bodyVOName);/获得表体某行的VO获得表体选中行getBillCardPanel().getBillTable().getSelectedRow();getBillCardPanel().getBillTable().getSelectedRows();/多选模式下返回所有选中行getBillCardPanel().getBillTable(tableCode).getSelectedRow();getBillCardPanel().getBillTable().getSelecte
35、dRowCount();/选择的行数(1)列表界面取值获得表头某字段的值:getBillListPanel().getHeadBillModel().getValueAt(rowIndex, strKey)/获得表头某行某字段的值获得表体某字段的值:getBillListPanel().getBodyBillModel().getValueAt(rowIndex, strKey)/获得表体某行某字段的值 默认第一个页签getBillListPanel().getBodyBillModel(tableCode).getValueAt(rowIndex, strKey)/获得表体某页签某行某字段的
36、值获得单据界面VO:getBillListPanel().getBillValueVO(row, billVOName, headVOName, bodyVOName)/获得表头某一行对应的聚合VOgetBillListPanel().getHeadBillModel().getBodyValueVOs(bodyVOName)/获得表头所有VOgetBillListPanel().getHeadBillModel().getBodyValueRowVO(row, bodyVOName)/获得表头某一行的VO获得表头选中行getBillListPanel().getHeadTable().get
37、SelectedRow();getBillListPanel().getHeadTable().getSelectedRows();getBillListPanel().getHeadTable().getSelectedRowCount ();上面只列举了部分常用的方法,还有更多的方法请查阅相关的类参照配置参照是NC系统里特有的组件,它也是一种表现数据的形式,提高了用户的可操作性。参照分为三种类型,表格型参照、树型参照、树卡型参照。在这里并不打算讲述自定义这3种类型的参照如何实现,而是谈一谈,开发中使用参照出现的一些问题,如何去解决它。参照可以放在表头、表体、表尾。这都是在单据模板上配置的。
38、放在表头和表尾的情况是一样的。参照有3种显示:显示编码,显示名称,显示主键。默认情况下表头卡片界面下,参照显示为名称(这个是我们需要的),列表界面下参照显示为主键(这个不是我们希望的)。如果要列表界面下也显示名称的话,我们只能让该字段卡片显示,并且需要增加一个自定义字段,让它列表显示,还需要配置编辑或显示公式将名称带到自定义字段上。表体两种界面参照都显示为编码,如果要显示名称的话,同样需要增加自定义字段和配置公式。执行公式 公式可以放在代码里执行,也可以配置在单据模板上,让系统读取执行。公式分为两种,一种是编辑公式(当某个字段被编辑的时候,就会触发这个字段下的公式执行),另一种是显示公式(当某
39、个字段有值显示时,就会触发这个字段下的显示公式执行)例如下面公式:transpmodename-getColValue(transpmode,vname ,ctranspmode ,transpmode );transpmodename: 模板上的字段-:赋值号getColValue :取值函数transpmode :数据库里的表vname :数据库里的表的一个字段ctranspmode:数据库里的表的一个字段transpmode :模板上的字段上面的取值函数等价于:select vname from transpmode where ctranspmode= transpmodetransp
40、mode在公式解析的时候会替换为这个字段的值公式执行的结果被赋给字段transpmodename还有其它更多的函数可以查看NC单据模板初始化里面的公式配置。初始化数据和默认值设置初始化一般有两种:一是初始化监听,二是初始化界面的数据由于现有的单据监听事件不满足业务需求,我们需要增加其它的监听事件,因此需要初始化监听,需要覆盖下面的方法。下面都是UI端的方法protected void initEventListener() 另外,我们可能需要初始化参照、下拉。就需要覆盖下面的方法protected void initSelfData() getBillCardWrapper().initBod
41、yComboBox(tablecode, key, values, isWhithIndex);/初始化卡片表体下拉getBillCardWrapper().initHeadComboBox(key, values, isWhithIndex);/初始化卡片表头下拉getBillListWrapper().initBodyComboBox(tablecode, key, values, isWhithIndex);/初始化列表表体下拉getBillListWrapper().initHeadComboBox(key, values, isWhithIndex);/初始化列表表头下拉我们知道卡片、列表是两个不同的界面,所以初始化下拉的时候卡片、列表都要初始化。不然就不能正常显示数据了,设置下拉时,模板上对应字段的数据类型也必须为下拉,这样才能正确设置。另外,单据状态(vbillstatus)这个字段是下拉类型,不需要我们手动设置,由系统完成。事实上我们也可以在模板上设置下拉字段的值,在字段的高级属性