Openbravo开发手册

时间:2024-03-27 19:24:46

简介

Openbravo是一款面向中小企业的纯WEB方式的可扩展的ERP软件。她包括了基本的CRM(客户关系管理)、BI(商业智能)和一系列如采购、库存、项目、生产销售和财务管理等功能。适用于物流、服务和生产制造等多个行业。

Openbravo可以定制以支持特定行业的功能和业务流程。

Opnebravo的许可证允许合作伙伴和开发者选择是否将自已的工作以开源许可证还是以私有许可证的方式发布。我们鼓励合作伙伴和开发者以开源的方式与别人共享开发成果,也为Openbravo提供新的内容。本手册的目的是给大家为客户定制新的功能提供指导。

开发概述

以下列出了在Openbravo开发中使用的模型驱动开发方法的主要概念:

  • 应用字典:集中存放了定义的窗口、页签和字段的表。
  • 应用菜单:程序左边的主菜单。
  • Callout(类似于触发器):用户操作一个窗口时系统响应的动作。例如可以增加或减少可见的字段,或者根据输入系统的信息填定订单。
  • 表单:手工制作的可以输入、修改或删除的窗口。不同于标准窗口,表单允许复杂数据的输入和在多个位置输入数据。
  • MVC(模型-视图-控制器):将应用程序的数据、用户界面和流程分离的一种架构。在Openbravo中MVC是这样实现的:
    • 模型部份是用Openbravo的SqlC实现的。通过一个有标准SQL语句和参数的XML文件实现。其中的参数是可选或必须的,可以很容易的生成SQL语句。
    • 视图部份是用Openbravo开发的XmlEngine实现的。XmlEngine是可以从一个XML/HTML格式的模板生成XML/HTML文档的工具。
    • 控制器是从HttpBaseServlet继承的子类。这些Servlet处理读取数据,使用SQLC生成的类与数据库交互和使用XmlEngine提供输出。
  • 报表:显示从表中检索出来的数据或以预定义的格式和可视化的交互方式进行查询。以pdf或html的方式显示请求的信息是一种简捷的方式。报表可以用户希望的方式进行定制,通常用于展示全局形势或总结。
  • 标准窗口:可以输入、修改和删除数据的自动生成的窗口。窗口中的信息是由Openbravo按系统中的数据生成的。
  • 窗口:应用程序用于管理数据的屏幕。可以进行插入、更新或删除数据的操作。Openbravo中有两种窗口:标准窗口和表单。一个窗口可能会包含多个页签。

开发方法

Openbravo是构建Openbravo ERP的开发平台。正如架构总览中解释的开发可以理解为两层。

应用程序字典。它存储了应用程序的所有窗口、表、列、进程、报表和它们的关系。用户只要可以很方便的通过定义一个窗口、数据元素和报表并在应用程序字典中注册就可以增加一个新的功能,而无需一行代码。大部份的Openbravo代码是从应用程序字典中自动生成的。

模型/视图/控制器。当工作在这个层级时是可以通过Openbravo MVC开发框架完成任何改变的。无论如何一个工具或功能不能通过数据字典调整时,都可以在MVC这个层级实现。这通常意味着要开发一个新的JAVA类。

组织开发工作

在开始开发一个新的功能时必须清楚什么东西必须完成。下面几点对组织你的开发工作会有所帮助:

  • 应该提供哪些功能。必须清楚哪些功能要实现。
  • 尽量简单。保持设计尽量简单并且能很好的与不同组件进行交互。
  • 定义你的数据模型。需要添加哪些表、列、关系和索引来存储数据以实现想要的功能。
  • 定义用户界面。用户如何使用新的功能。按工业标准的可用性指南组织可视化的元素。
  • 定义报表。考虑哪些数据和你的用户有关和如何最好的呈现在报表中。

标识符命名标准

数据字典命名制定一个清晰和固定的标准对于ERP系统是非常关键的。按照这个命名标准就能保证Openbravo ERP的新版本不会因为与客户开发时使用的数据字典元素同名而产生冲突。

当自定义开发时,在每一个新的数据字典元素前加上CUS_的前缀。例如,当为一个名为ACME的公司进行客户定制时,在数据字典元素名前加上CUS_ACM的前缀。

当开发一个垂直功能时,加上这个市场名前加上VER_的前缀。例如,为房地产市场开发时使用VER_REA的前缀。

数据库元素

命名新的表时加上特定的开发时的前缀。例如你需要为ACME客户定制开发时需要增加一个DOCUMENT的表时你应该将该表命名为CUS_ACM_DOCUMENT。这些表的字段可以按照字段命名转换(AD_CLIENT_ID,IsActive,Name,Descriptioin等)。

当在已有的表中增加新的字段时需要加上特定的开发时的前缀。

其他的数据库对象(存储过程,触发器等)也要加上开发时的前缀。

数据字典的注册IDs是由序列按开发时的顺序生成的,因而不会出现重复的IDs。数据字典中的实体名都应加上一定的前缀。

MVC目录

命名目录时加上特定的前缀。建议建立一个独立的包。(org\openbravo\erpCommon\cus_myPackage)。

存储过程语法

  • 作为存储过程参数的变量名前加上p_的前缀
  • 变量名前加v_的前缀
  • 游标名前加c_的前缀

目录结构

Openbravo ERP的目录结构从逻辑上区分了核心组件(XmlEngine,SQLC,HttpBaseServlet)和WAD(应用程序字典向导)与ERP本身的结构(表单,报表,call-outs,下拉列表,工作流,流程等)。

主树结构

AppsOpenbravo
   |-attachment   
   |-build
   |-config
   |-database
   |-docs
   |-legal
   |-lib
   |-src
   |-srcAD
   |-srcClient
   |-src-core
   |-src-db
   |-src-trl
   |-src-trl
   |-src-wad
   |-web
   |-WebContent
      |-src-loc

build编译好的类会被复制到这个目录中

AppsOpenbravo
   |-build
      |-classes
         |-org
            |-openbravo
               |-authentication
                  |-basic
                  |-lam
               |-base
                  |-secureApp
               |-erpCommon
               |-erpReports
               |-erpWindows
      |-javasqlc
         |-src
         |-srcAD

config包含了各种配置和日志文件

AppsOpenbravo
   |-config
      |-Format.xml
      |-log4j.lcf
      |-Openbravo.properties
      |-setup-properties-linux.bin
      |-...

database包含模型数据(结构:表,约束,存储过程和触发器),示例数据(如产品,业务伙伴等)和XML格式的源数据(窗口和页签)。

AppsOpenbravo
   |-database
      |-lib
      |-model
         |-functions
         |-sequences
         |-tables
         |-triggers
         |-views
      |-sampledata
      |-sourcedata

docsOpenbravo的API文档,由Javadoc生成。

legal许可证文档。

lib编译时需要的库。

AppsOpenbravo
   |-lib
      |-openbravo-core.jar
      |-openbravo-trl.jar
      |-openbravo-wad.jar
      |-openbravo.war
      |-...

openbravo-core.jar,openbravo-trl.jar和openbravo-wad.jar是执行ant compile.complete时必须的。编译的结果是一个名为openbravo.war的文件,需要将其复制到应用服务器的webapps目录下。

srcOpenbravo ERP的源代码:表单,报表,call-outs,combos,工作流,流程等。

AppsOpenbravo
   |-src
      |-org
         |-openbravo
            |-base
            |-erpCommon
               |-ad_actionButton
               |-ad_background
               |-ad_callouts
               |-ad_combos
               |-ad_forms
               |-ad_help
               |-ad_process
               |-ad_reports
               |-ad_tasks
               |-ad_workflow
               |-businessUtility
               |-info
               |-reference
               |-security
               |-utility
               |-ws
            |-erpReports

前缀ad_表示应用程序字典。字典名的结尾说明了它的意思。ad_reportserpReport的区别在于在应用程序中存取报表的方式不同。如果是通过菜单调用的报表应该放在ad_reports,另一方面,有些窗口在工具栏上有一个打印的按钮,通过这种方式调用的报表应该放在erpReports

srcAD保存了通过应用程序字典自动生成的代码。

srcClient存放为自已应用程序开发的代码,不是给其他客户。

src-core核心组件的源代码: XmlEngine (视图层), SQLC (模型层), HttpBaseServlet (控制器)和连接池。

AppsOpenbravo
   |-src-core
      |-src
         |-org
            |-openbravo
               |-base
                  |-HttpBaseServlet.java
                  |-HttpBaseUtils.java
               |-data
                  |-Sqlc.java
               |-database
                  |-ConnectionPool.java
               |-xmlEngine

src-db创建dbmanager.jar文件需要的源代码。

AppsOpenbravo
   |-src-db
      |-src
         |-org
            |-openbravo
               |-ddlutils

src-trl翻译器的源代码。

AppsOpenbravo
   |-src-db
      |-src
         |-org
            |-openbravo
               |-translate

src-wadWAD的源代码。

AppsOpenbravo
   |-src-db
      |-src
         |-org
            |-openbravo
               |-wad


webCSS,Javascript的代码和图片及弹出窗口。

AppsOpenbravo
   |-images
   |-js
   |-popups
   |-skins

src-locMVC结构中的视图层元素结构:HTML,XML,FO和子报表。它们被放在不同的位置(每一种一个目录)。

AppsOpenbravo
   |-WebContent
      |-src-loc
         |-design
            |-org
               |-openbravo
                  |-base
                  |-erpCommon
                  |-erpReports
                  |-erpWindows
         |-es_ES
         |-xx_XX
         |-...

风格指南

为了代码的统一和清晰,我们建议按下面的指南进行编码。这个指南应用于Java,XML,HTML和PL/SQL。

逻辑比较

不要使用空格。

  • 不正确::

WHERE a = b

WHERE a= b

  • 正确::

WHERE a=b

逗号分隔列表

  • 不正确:

SELECT a,b,c

SELECT a ,b ,c

SELECT a , b , c

  • 正确:

SELECT a, b, c

圆括号中的空格

在函数中使用时:

  • 不正确:

SELECT max( c1 )

SELECT max (c1)

  • 正确:

SELECT max(c1)

在比较操作时:

  • 不正确:

if(i==0)

if( i==0)

  • 正确:

if (i==0)

for (i=0; i<n; i++)

SELECT INTO和INSERT INTO

如果超过8个字段:将其分为4个一组(为了易读性)。一行80个字符。这是比较灵活的规则。

SQL关键字

SQL的关键字要大写。

  • 不正确:

select * from AD_FIELD

  • 正确:

SELECT * FROM AD_FIELD (SELECT, UPDATE, 等)

编译程序

命令行编译任务

ant core.lib编译MVC框架的核心组件。它会生成openbravo-core.jar文件。

AppsOpenbravo
   |-lib
      |-openbravo-core.jar

ant wad.lib编译。它不会生成窗口,只是生成WAD本身而已。它会生成openbravo-wad.jar文件。

AppsOpenbravo
   |-lib
      |-openbravo-wad.jar

ant trl.lib编译翻译器。它会生成openbravo-trl.jar。

AppsOpenbravo
   |-lib
      |-openbravo-wad.jar

ant compile.complete编译整个程序。它会生成WAD的窗口和编译应用程序的源代码。它依赖于core.lib,wad.lib和trl.lib。

ant compile.complete.development编译整个应用程序并复制到tomcat的容器中。它会生成WAD的窗口和编译应用程序源代码。它依赖于core.lib,wad.lib和trl.lib。

ant compile -Dtab="xx,yy"生成指定的窗口(名称中包含xx或yy),编译修改过的源代码并且更新web.xml中的servlet-mapping。

ant compile.development -Dtab="xx,yy"生成指定的窗口(名称中包含xx或yy),编译修改过的源代码并且更新web.xml中的servlet-mapping。最后会将所有生成的类复制到tomcat的容器中。

ant setup调用设置数据库连接和应用程序路径的界面(是build.xml中的默认任务)。

ant war在lib目录下生成一个war文件:

AppsOpenbravo
   |-lib
      |-openbravo.war

ant deploy复制war文件到tomcat的webapps目录下。

ant installWebService安装Web Service到应用服务器的目录。

ant install.source会执行ant core.lib,ant wad.lib,ant trl.lib,ant compile.complete,ant installWebService和ant war任务。这个任务只用于安装。

开发环境

在开发环境中内容中手工拷贝的。我们不会生成war文件因为这比较耗时。

第一次编译过程是这样的:

ant core.lib
ant wad.lib
ant trl.lib
ant compile.complete.development

然后编译整个应用程序:

ant compile.complete.development

编译特定的窗口:

ant compile.development -Dtab="window name"

编译手工代码:

ant compile.development -Dtab=xx

为了编译时避免执行翻译的任务(对于这个阶段将时间花在这上面是没有必要的),可以在命令中添加一个参数:-Dtr=no

ant compile.development -Dtab="window name" -Dtr=no
ant compile.development -Dtab=xx -Dtr=no

生产环境

在生产环境下应用程序会打包在war文件中。这可以让我们对每一个应用程序设置正确的权限,但是我们必须将war文件发布到tomcat中,以使它能运行起来。

第一次编译的过程如下:

ant core.lib
ant wad.lib
ant trl.lib

编译整个应用程序:

ant compile.complete
ant war
ant deploy

编译指定的窗口:

ant compile -Dtab="window name"
ant war
ant deploy

编译手工代码:

ant compile -Dtab=xx
ant war
ant deploy

从源代码构建

这一节是如何从源代码构建的快速指南。你可以在 Build Openbravo from Sources看到完整的步骤。

安装Subversion

Subversion是一个源码控制工具,可以让开发者控制文件的版本。

构建前必须先安装Subverion。可以从这里下载:

http://subversion.tigris.org *

必须同时安装OpenSSL。

现在的源代码还不支持PostgreSQL只支持Oracle。 Openbravo 2.3 将会支持PostgreSQL。

从Subversion中检出源代码

安装好Subverion后运行如下代码:

svn co https://openbravo.svn.sourceforge.net/svnroot/openbravo/trunk AppsOpenbravo

将会创建AppsOpenbravo的目录,源代码保存的目录。

快速构建指南

从创建的subversion文件的目录运行如下命令:

ant -f build.xml.template setup

这个过程会配置安装参数。

  • build.xml 被创建
  • config目录下创建dbCon5.xml, XmlPool.xml, log4j.lcfuserconfig.xml
  • src 目录下创建 deploy.wsdd

使用Oracle数据库时所有这些文件都会被创建。如果使用PostgreSQL需要将dbCon5.xmlXmlPool.xml文件名修改为dbCon5_PostrgreSQL.xmlXmlPostgreSQL.xml

当参数按上面的方式配置好后,再运行下面的命令。

ant install.source

这个过程编译并生成应用程序的jar文件并在lib目录下生成openbravo.war文件。需要将些文件复制到$CATALINA_HOME/webapps 目录以发布应用。

集成开发环境

一些快速入门以Eclipse来开发Openbravo ERP,可以参考以下链接:

Openbravo数据模型

存储的数据库对象

某些情况不在Openbravo中的数据库对象(存储过程,函数和触发器)必须符合指定的规则才能使用。应用程序中存储过程时只能通过对应的AD_PInstance_ID来调用。存储过程也必须正确的管理AD_PInstance,设置返回值、设置有用的输出信息。在创建存储过程这一节会更详细的介绍如何开发一个存储过程。

实体-关系(ER)图

Openbravo的实体-关系数据库图展示了Openbravo整个的数据模型。它包括了Openbravo ERP的功能所使用的所有表和字段。

根据应用程序字典中的数据生成了文档。这些图按不同的主功能模块分成了几个章节。同一个表可能在不同的章节中出现但具体的描述只出现一次。这样做是为了强调某一个章节中主要的表与其他章节中表的关系。例子中展现了所有的关系但没有代表性的表不会出现在章节中。

创建存储过程

AD_PInstance和AD_PInstance_Para表

应用程序中调用存储过程都需要在表AD_PInstance中注册。表AD_PInstance_Para中存放了报表和流程窗口中相应的存储过程的参数的值。

表AD_PInstance:

  • AD_PInstance_ID:表的标识符。
  • AD_Process_ID:与在应用程序字典中存放存储过程信息的表AD_Process相关联的外键。
  • Record_ID:如果在窗口中调用存储过程,这一列存放当前记录的ID。
  • IsProcessing:存储过程在执行中时这一列为“Y”。有些存储过程会检查相关的存储过程是否正在运行。
  • AD_User_ID:调用存储过程的用户ID。
  • Result:存放存储过程运行的结果。
  • ErrorMsg:存放存储过程输出的信息。

表AD_PInstance_Para:

  • Parametername:对应于数据库列名的参数名称。
  • P_String和P_String_TO:当字段是文本框或列表框时插入的值。
  • P_Number和P_Number_TO:当字段是数字框或外键时插入的值。
  • P_Date和P_Date_TO:当字段是日期型时插入的值。
  • Info和Info_TO:

当参数定义为一个范围内的值而不是指定的一个值时用_TO的后缀。使用这个参数生成的弹出窗口会有两个标签为From和To的字段。之后可以按其中的值来过滤查询结果。

存储过程的输入参数

应用程序调用存储过程时仅传递一个参数到数据库,就是对应的AD_PInstance_ID。

我们需要一个中介存储过程来从应用程序或一个不同的存储过程来调用另一个存储过程。因为从一个存储过程调用另一个存储过程时是不知道AD_PInstance_ID的。可以参考C_Order_Post和C_Order_Post1。主存储过程调用时需要有足够的参数,包括AD_PInstance_ID。被调用的中介存储过程仅有一个关于AD_PInstance的参数。这个存储过程仅有一个到主存储过程的调用,其中除了AD_PInstance其余参数都是空的。在主存储过程中必须区分AD_PInstance是否为空来管理调用的结果和输出信息。

从AD_PInstance表中获取有用的信息

在存储过程的开始我们也许会想要从AD_PInstance和AD_PInstance_Para两个表中知道一些必须的信息保存到变量中。如果没有参数那么用SELECT就可以了。如果有多个参数那么可能需要使用游标。参见C_Debt_Payment_Create。

Record_ID存放窗口中当前的活动记录的ID(如当处理Order时的C_Order_ID)。如果存储过程中有Update或Insert子句,AD_User_ID可以用于验证用户权限。

AD_Update_PInstance存储过程

该存储过程用于更新AD_PInstance的状态。其他存储过程必须在开始和结束时调用该存储过程。

参数:

  • p_PInstance_ID:将要被更新的AD_PInstance_ID。
  • p_AD_User_ID:执行更新的AD_User_ID。
  • p_IsProcessing:存储过程的状态。
  • p_Result:存储过程的结果。
  • p_Message:存储过程的输出信息。

在开始调用时设置Processing='Y':

 AD_UPDATE_PINSTANCE(p_PInstance,NULL,'Y',NULL,NULL);

在结整调用或引发例外时需要设置Processing='N'和相应的执行结果和输出信息:

 AD_UPDATE_PINSTANCE(p_PInstance_ID,v_User,'N',v_Result,v_Message);

存储过程执行的结果有3种。按不同的结果会显示不同的包含输出信息的对话框。结果为0表示错误(红色对话框),1表示成功(绿色对话框)和2表示警告(黄色对话框)。如果输出信息是NULL将作为成功来处理。

例外和错误管理

存储过程的错误信息只能依靠对应的AD_PInstance的结果来管理。所以所有的例外必须被正确的处理。

当在存储过程中触发了RAISE_APPLICATION_ERROR的例外时,错误号被设置为-20000。同时你可以加上对该问题的错误描述。描述信息中可以使用存储在AD_Message表中的信息,只要将它的值放在@之间。也可以将多个字符串连接在一起。

例外块中必须能够区分两种不同情况:存储过程是被应用程序直接调用还是被其他存储过程调用的。通常这可以通过AD_PInstance_ID是否为NULL来区分。

如果是由其他存储过程调用时引发的例外是由存在于AD_PInstance中的父存储过程处理的。但是这不适用于以上介绍的中介存储过程。因为中介存储过程中没有处理例外的块,所以还是由相应的AD_PInstance_ID的主存储过程来处理。在RAISE 之前可以使用DBMS_OUTPUT.PUT_LINE()用于调试。下面是被另外一个存储过程调用的存储过程中的例个块的例子:

 EXCEPTION
   WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE('ERROR MA_Standard_Cost_Sequence, sequence_ID '|| p_Sequence_ID || ', date ' || p_CalcDate || ' at ' ||v_ResultStr);
     RAISE;
 END Ma_Standard_Cost_Sequence;

如果存在AD_PInstance时例外必须要在AD_PInstance表中设置对应的信息。这条信息是由@ERROR=SQLERRM组成的,SQLERRM中是在RAISE_APPLICATION_ERROR或数据库抛出的的例外中的错误信息。然后是调用ROLLBACK,最后在AD_PInstance中更新错误信息并返回结果为0、显示错误信息的对话框。同时也可以使用DBMS_OUTPUT.PUT_LINE()用于测试。

 EXCEPTION
   WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE(v_ResultStr) ;
     v_ResultStr:= '@ERROR=' || SQLERRM; 
     DBMS_OUTPUT.PUT_LINE(v_ResultStr) ;
     ROLLBACK;
     AD_UPDATE_PINSTANCE(p_PInstance_ID, NULL, 'N', 0, v_ResultStr) ;
     RETURN;
 END MA_ProductionRun_Standard;

存储过程语法的建议

Openbravo支持Oracle和PostgreSQL数据库。

以下的一些建议可以使你的存储过程能同时在这两个数据库上运行或能够很容易的转换。这里假设你已经为Oracle与了代码但同时想让这些代码能在PostgreSQL上运行。

通用规则

以下一些内容能确保PL代码能正确地在其他数据库后台运行。

  • JOIN语句。用LEFT JOIN或RIGHT JOIN代替(+)
  • 在XSQL中使用问号(?)作为参数据占位符。如果参数时数值型使用TO_NUMBER(?),日期型使用TO_DATE(?)。
  • 不要使用GOTO语句,因为PostgreSQL不支持GOTO。
  • 使用COALESCE代替NVL
  • 使用CASE代替DECODE。如果CASE 表达式为NULL,如:
CASE WHEN variable IS NULL THEN X ELSE Y END
  • 如果变量的值是几个字符串连接起来的要用括号括起来
  • 用NOW()代替SYSDATE
  • PostgreSQL区分""和NULL,在检查空变量的时候要注意这一点
  • 使用子查询时要加上别名。
SELECT * FROM (SELECT 'X' FROM DUAL) A
  • 使用SELECT语句时总是使用AS
SELECT field AS field_name FROM DUAL
  • PostgreSQL中UPATE,INSERT,和DELETE语句中不支持别名。
  • PostgreSQL8.1不支持这样的UPDATE语句(但8.2已支持了)
UPDATE TABLE_NAME SET (A,B,C) = (SELECT X, Y, Z FROM ..

但下面的语句是可以的:

UPDATE TABLE_NAME SET A = (SELECT X FROM ..), B = (SELECT Y FROM .),C = (SELECT Z FROM ..)
  • PostgreSQL不支持在更新的字段中加上表名。
  • PostgreSQL不支持DELETE TABLE,可以使作DELETE FROM
  • PostgreSQL不支持在ORDER BY或GROUP BY中使用参数,如‘1’。而没有引号的数字是可以的。
  • PostgreSQL不支持CURRENT OF语句。
  • PostgreSQL不支持COMMIT。它会在BEGIN和END块间自动显示的提交。抛出例外时会产生ROLLBACK。
  • PostgreSQL不支持SAVEPOINT。可以用BEGIN,END和ROLLBACK完成同样的功能。
  • PostgreSQL不支持CONNECT。
  • PostgreSQL和Oracle都不支持用变量来指定表的字段名称。如使用v_IsProcessing替代IsProcessing。
  • PostgreSQL不支持EXECUTE IMMEDIATE...USING。可以使用SELECT和参数来完成相同的功能。
  • PostgreSQL在调用没有参数据函数时要加上括号。
  • DBMS.OUTPUT应该在一行内,以使自动翻译可用。
  • 在PostgreSQL中任何字符串与NULL连接都会产生一个NULL的字符串。建议用COALESCE或将变量初始化为‘’。
    • 注意:在Oracle中null||'a'结果是'a',而在PostgreSQL中结果是NULL,所以应使用coalesce(null,)||'a'。但时如果变量是Oracle的NVarchar类型时会引发ORA-12704:字符集不匹配的错误,这时可以这样做coalesce(to_char(myNVarCharVariable),)||'a'。

将以下语法

COALESCE(variable_integer, '') 

 COALESCE(variable_integer, 0)

来代替,以保证可以在PostgreSQL中也可以运行。

  • PostgreSQL执行SELECT FOR UPDATE是在表级而Oracle是在列级别。
  • PostgreSQL不支持带有三个参数的INSTR命令,可以使用SUBSTR。
  • 在Oracle中SUBSTR(text,0,Y)和SUBSTR(text,1,Y)的结果是相同的,但是PostgreSQL中不同。所以要使用SUBSTR(text,1,Y)。
  • PostgreSQL不支持这样<<LABEL>>的标签。
  • 在日期比较中默认的日期是1900.1.1或9999.12.31。
  • 如要将日期类型转换为文本型时要使用to_date函数和相应的掩码。

如:

COALESCE(movementdate, TO_DATE('01-01-1900', 'DD-MM-YYYY'))

游标

有两种使用游标的方法:FETCH子句和FOR循环。

Oracle中FETCH游标的声明:

CURSOR	Cur_SR IS

PostgreSQL中:

DECLARE Cur_SR CURSOR FOR

FOR循环中的游标格式:

TYPE RECORD IS REF CURSOR;
	Cur_Name RECORD;

这在Oracle和PostgreSQL中都可以使用。

数组

在Oracle中数组是这样定义的:

TYPE ArrayPesos IS VARRAY(10) OF INTEGER;
  v_pesos ArrayPesos;
v_dc2 := v_dc2 + v_pesos(v_contador)*v_digito;

但在PostgreSQL中是这样定义的:

v_pesos integer[];
v_dc2 := v_dc2 + v_pesos[v_contador]*v_digito;

ROWNUM

为了限制SELECT语句返回的行数,需要创建游标来读取记录。代码如下:

--Initialize counter
v_counter := initial_value;
--Create the cursor
FOR CUR_ROWNUM IN (SELECT CLAUSE)
LOOP
  -- Some sentences
  --Increment the counter
  v_counter := v_counter + 1;
  --Validate condition
  IF (v_counter = condition_value) THEN
    EXIT;
  END IF;
END LOOP;

%ROWCOUNT

SQL%ROWCOUNT不能直接在PostgreSQL中使用,而需要定义一个变量。如:

 GET DIAGNOSTICS rowcount := ROW_COUNT;

用上面定义的变量来替换SQL%ROWCOUNT。

%ISOPEN,%NOTFOUND

PostgreSQL不支持%ISOPEN和%NOTFOUND,但可以在存储过程内部定义一个boolean变量,然后当游标打开或关闭时手工去更新这个变量的值。

当定义表时,如果列名是关键字要用用引号引起来。如:

CREATE TABLE AD_TRACE
(
  "WHEN"  TIMESTAMP                   NOT NULL,
  NO      NUMERIC        DEFAULT 0    NOT NULL,
  WHAT    VARCHAR(2000)               NOT NULL
);

列WHEN用引号引起来以避免转到PostgreSQL后出现问题。

同样在约束、解发器、存储过程、视图和函数中也要这样处理。

函数

可以使用PERFORM和SELECT调用函数。因为PostgreSQL不支持默认参数,可以定义一个带有默认参数的重载函数。

另外如果要使自动翻译能正常工作,你应该遵循以下的建议:

  • AS和IS的左边不能有空格
  • 函数名不能用引号
  • 函数中,END前不能有空格。

存储过程

在PostgreSQL中有两种方法调用存储过程:

  • 变量名:=存储过程名(...)
  • 使用SELECT。这种方法用于存储过程返回多个参数时使用。

视图

PostgreSQL不支持可更新视图。如果要通过视图更新要创建一系列的规则。

在PostgreSQL中没有USER_TABLES和USER_TAB_COLUMNS。应该根据PostgreSQL的pg_class或pg_attribute表来创建。

触发器

触发器的规则如下:

  • 通常来说,父表中的触发器不应该修改子表中的列,因为子表中的触发器经常会参考父表中的数据,否则会引起mutating table的错误。
  • 触发器的名称不要用引号引起来,否则PostgreSQL会作为文本处理。
  • 所有的触发器都要有DECLARE在合法的注释前。
  • PostgreSQL不支持延迟计算值。如下面的语句在Oracle中可以运行但不能在PostgreSQL中运行:
IF INSERTING OR (UPDATING AND :OLD.FIELD = '') THEN

正确的方法是:

IF INSERTING THEN ... 
IF UPDATING THEN 
IF :OLD.NAME = '' THEN

PostgreSQL中总会有返回值。按不同的操作类型分别返回OLD(DELETE)或NEW(INSERT/UPDATE)。

如果使用自动翻译应注意:

  • 最后一个EXCEPTION的左边不能有空格。自动翻译者用最后一个EXCEPTION来设置返回值。
  • 最后一个END的左边不能有空格。缩排用于决定函数据结束。

序列数

PostgreSQL中的bigInts类型是18位的。将

sequence_name.NEXTVAL 

nextval("sequence_name") 

代替。如果是使用自动转换,这个会自动的修改。

命令

下面列出了从Oracle转换到PostgreSQL时要修改的语句:

Oracle PostgreSQL
SQLCODE SQLSTATE
RAISE; RAISE EXCEPTION ;
RAISE_APPLICATION_ERROR RAISE ERROR ;
DBMS.OUTPUT RAISE NOTICE '%'
ROWNUM LIMIT
MINUS EXCEPT
ISREFCURSOR REFCURSOR
EXECUTE IMMEDIATE EXECUTE
EXCEPTION NO_DATA_FOUND EXCEPTION DATA EXCEPTION
COMMIT  
ROLLBACK RAISE EXCEPTION

支持PostgreSQL8.3

为了支持PostgreSQL8.3,Openbravo2.40alpha已经调整了源代码。为了兼容这个版本的PostgreSQL,最大的修改是非字符数据不再自动转换为TEXT类型。

之前,如果提供一个非字符型的值给一个需要字符型参数的函数或一个操作时会自动转换为字符型,大部份(不是所有)的内建类型都是这样处理的。对于这种情况现在都需要进行显示的类型转换。例如,以下表达式之前是可以运行的:

substr(current_date, 1, 4)
23 LIKE '2%'

但现在会提示“函数不存在”或“操作不存在”的错误。需要进行显示的类型转换:

substr(current_date::text, 1, 4)
23::text LIKE '2%'

(当然你也可以使用CAST())。这样修改的原因是因为这些自动类型转换经常会引起一些无法预知的错误。如在以前的版本中,下面的表达式是语法正确的但运行的结果不是预期的:

current_date < 2017-11-17

这实际上是日期型与整型的比较,不应该拒绝这样的操作(现在已经是拒绝了)。但是在以前这样的表达式会转换成字符型与字符型比较。

但char(n)和varchar(n)仍然会自动转换成TEXT类型。尽管字符串连接(||)操作符仍然会进行自动类型转换,但至少其中一个操作符应该是字符型的。

因为以上的原因,PostgreSQL8.3在存储过程和数据库源代码文件中都要求进行显示的类型转换。这个大范围的修改已经在Openbravo2.4alpha中完成。例如,下面的表达式可以在Oracle/PostgreSQL中正确运行:

substr(TO_CHAR(current_date), 1, 4)
TO_CHAR(23) LIKE '2%'

Openbravo的源代码和存储过程中已经做了许多类型显示转换的操作以支持PostgreSQL8.3。主要的修改是:

  • 函数的类型转换:当在PostgreSQL中调用函数时,参数必须匹配。一个典型的例子是在XSQL文件中的AD_COLUMN_IDENTIFIER函数,在存储过程中也是同样处理的。
...
AD_COLUMN_IDENTIFIER(TO_CHAR('C_Invoice'), TO_CHAR(p.C_INVOICE_ID), TO_CHAR(?)) AS INVOICE
...
  • 操作时的类型转换:例如传递一个数字时作为标识符或日期到SQL语句:
...
  SELECT STDPRECISION 
  FROM C_CURRENCY 
  WHERE C_CURRENCY_ID = TO_NUMBER(?) 
  AND CREATED <= TO_DATE(?)
...

只要进行这些修改就可以兼容PostgreSQL。 Openbravo2.4alpha已经通过了与PostgreSQL8.3的可接受测试

修饰名称和描述内容的指南

说明内容的修辞指南

Openbravo在数据字典中的字段描述主要有两个目的:

  • 直接说明了字段如何使用的
  • 一些附加的信息

在阅读本节前,要知道在Openbravo ERP中已经有超过5000个的例子。强烈建议在需要时参考已存在的例子。

  • 时态:最好使用现在时,如果有必要可以使用过去时。
  • 人称:
    • Windows和Tabs:第二人称
    • 元素:第三人称(其实是要避免我,你,他或她都混在一起)
  • 单/复数:
    • Windows和Tabs:用复数
    • 元素:用单数
    • A/n vs The:当指一般的东西时用A,当指特定的东西时用The。
  • 仅用下面的某一项来描述Window/Tab的结构
    • View-仅用于某些只读的内容时
    • Create-当需要创建新的内容时使用,并且可以修改
    • Add-当一些内容之前已经输入过,但之后可以修改的情况
    • Edit-当需要修改信息时
    • Define-当需要在设置区域中输入数据,并且不是为了事务性的目的
    • Import-导入数据时
    • Translate-进行转换时

create和edit,add和edit,define和edit可以组合使用。

  • 描述的长度一般在20个单词左右

有一些词不允许在应用程序中作为描述使用。

Out In
Generate Create, Add, or Edit
Manage Create, Add, or Edit
Assign Create, Add, or Edit
Apply Create, Add, or Edit
Assign Create, Add, or Edit
Apply Create, Add, or Edit
New x (redundant)
Different x
Variety x
Various x
Period of time Time period
Given, Scheduled, Chosen (time period) Specified

命名的修辞指南

名称的修辞(如,名称,地址,城市)对于每条记录都是一样的。一般是用户或顾问使用这些名称。包括如下内容:列、元素名称、字段分组、字段名、列表、菜单、消息、过程、过程的参数、参考、表、页签、文本的接口和窗口。

可以参考The Data Model Resource Book by Silverston 这本书。

  • 可接受单复数
  • 大写关键字

在设置中,请使用单数。

  • 动词

Window或Tab的名称不要用动词开头 Processes总是以动词开头

  • 缩写

"Quantity"不缩写 "Number"一般缩写为"no." 一般不使用缩写

  • 做下面的操作时要慎重

名称中加入-,/,# 用"ed"结尾不能为了清楚,简单的区分产品而在应用程序中使用相关的单词。

  • 使用“Header"和"Line"作为Tab的名称

有时用户需要知道该用什么词:

Term Described Synonym
Set Group
Total (summary of all), final
Charge Expense or Expenditure
Planned Expected
Plan Strategy, Structure
Schedule Dates, Times
Setup Structure
Type Distinct characteristic
Date Period or time
Cost Charge
Amount Monetary sum
Quantity Number
Key Identification code
From/To Range (unless specified)
Price Value
Account Identification code
Number (no.) Specific number or code

有些单词不可以使用:

Out In
System Application
Group Category or Set
Rule Setup
"Is" x (no verb starters)

总的来说,Openbravo建议根据具体情况使用现有的描述。

使用数据字典进行Openbravo的开发

这一节介绍了如何使用应用程序字典(AD)来开发Openbravo ERP。我们将通过一个例子来一步一步的展示开发过程。这个例子包括一个新的文档注册功能和一些新的数据库元素,如窗口和报表。

扩展数据模型

首先,使用数据库管理工具建立一个新的表。(如用于PostgreSQL的pgAdmin IIIphpPgAdmin以及用于Oracle的Oracle SQL DeveloperToad)。使用安装时的数据库连接参数以正确的连接数据库实例。

在数据库中创建新的表

建立一个新的表CUS_DOCUMENTS包括这些字段AD_Client_ID, AD_Org_ID, IsActive, Created, CreatedBy, UpdatedUpdatedBy ,因为这些字段是安全认证所必须的。

Column name Type Length
CUS_DOCUMENTS_ID NUMBER 10
AD_CLIENT_ID NUMBER 10
AD_ORG_ID NUMBER 10
ISACTIVE CHAR 1
CREATED DATE  
CREATEDBY NUMBER 10
UPDATED DATE  
UPDATEDBY NUMBER 10
NAME CHAR 60
LASTEDITED DATE  
DOCSIZE NUMBER 15

在这个表中,即使NAME和LASTEDITED可以组成关键字,但也请使用另外一个字段作为唯一性的关键字如CUS_DOCUMENT_ID。按命名的规则,关键字时由表名加上"_ID"组成。

执行下面的SQL语句来建立CUS_DOCUMENT:

Oracle

CREATE TABLE CUS_DOCUMENTS
(
  CUS_DOCUMENTS_ID  NUMBER(10)			NOT NULL,
  AD_CLIENT_ID  NUMBER(10)			NOT NULL,
  AD_ORG_ID     NUMBER(10)			NOT NULL,
  ISACTIVE      CHAR(1 BYTE) DEFAULT 'Y'	NOT NULL,
  CREATED       DATE DEFAULT SYSDATE 	        NOT NULL,
  CREATEDBY     NUMBER(10)           	        NOT NULL,
  UPDATED       DATE DEFAULT SYSDATE 	        NOT NULL,
  UPDATEDBY     NUMBER(10)         	        NOT NULL,
  NAME	        NVARCHAR2(60)       	        NOT NULL,
  LASTEDITED    DATE           	                NOT NULL,
  DOCSIZE	NUMBER(15)			NOT NULL,
  CONSTRAINT "CUS_DOCUMENTS_KEY" PRIMARY KEY ("CUS_DOCUMENTS_ID")
);

PostgreSQL

CREATE TABLE cus_documents
(
  cus_documents_id  numeric(10)   NOT NULL,
  ad_client_id  numeric(10)   NOT NULL,
  ad_org_id     numeric(10)   NOT NULL,
  isactive      char(1)       NOT NULL   DEFAULT  'Y'::bpchar,
  created       timestamp     NOT NULL   DEFAULT  now(),
  createdby     numeric(10)   NOT NULL,
  updated       timestamp     NOT NULL   DEFAULT  now(),
  updatedby     numeric(10)   NOT NULL,
  name          varchar(60)   NOT NULL,
  lastedited    timestamp     NOT NULL   DEFAULT  now(),
  docsize       numeric(10)   NOT NULL,
  CONSTRAINT cus_documents_key PRIMARY KEY (cus_documents_id)
);

在Openbravo ERP中注册新的表

下面的步骤介绍如何在Openbravo ERP的应用程序字典中注册新建的表。首先,要以具有System Administrator角色的帐户登录系统。进入菜单Application Dictionary > Tables and Columns建立一条Name Cus_documents, Description Documents to be saved, Help/Comments Window used to register documents, DB Table Name CUS_DOCUMENTS, Data Access Level Client/Organization and Development Status Ready的新记录。


Openbravo开发手册
 窗口中的主要字段是:

  • Name 定义Openbravo ERP可以识别表的名称。
  • Description 简短的说明。
  • Help/Comments 帮助窗口中显示的内容。
  • DB Table name 数据库中的表名称。

Create columns from DB 按钮保存记录并且自动创建列实体。


Openbravo开发手册
 创建完成时,系统会提示有多少列被加到表中了。


Openbravo开发手册
 创建新窗口

编译新窗口

在Openbravo中增加新窗口的菜单

更新数据库的XML文件

用户消息

使用MVC开发Openbravo

基本工具

创建新的手工窗口(表单和报表)

创建callout

用JasperReport创建报表

使用JasperReport的报表模板

报表模板

子报表的用法

使用jasper文件

使用jrxml文件

报表中的JAVA

应用程序字典中的报表

使用JasperReport导出表格

国际化

安全

升级方法

协同开发

附录