ZH/Case-Study-01-Journal-02

From ADempiere
Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.

<返回中文首页> <返回本案例研究首页>

Noia 64 apps knode m.png

Contents

实施日志-02

2010年11月

2010-11-05

销售基础设置

  • 业务伙伴分组
    • 窗口:Business Partner Group
  1. 大客户组, VIP Customer Group
  2. 国内客户组, Domestic Customer Group
  3. 国外客户组, Foreign Customer Group
  4. 采购供应商组,Purchasing Supplier Group
  5. 外协供应商组, Outside Processing Supplier Group
  • 支付方式:
    • 窗口:Payment Term:
  1. 立即支付, Immediate
  2. Net 30,收货后30天支付.
  3. 50:50,立即支付50%, 余款30天内付清。50% Immediate - 50% in 30 days
  • 问候:
    • 窗口:Greeting:
    • 测试报表时发现{0}不能被自动替代,因此去掉{0}
  1. Dear, Dear {0}
  2. Mr, Mr {0}
  3. Ms, Ms {0}
  4. 尊敬的, 尊敬的 {0}


  • 销售区域
    • 窗口:Sales Region
  1. 国内
    1. 中国南方区
    2. 中国北方区
  2. 国外
    1. 亚洲
    2. 非洲
    3. 欧洲
    4. 北美洲
    5. 拉丁洲
    6. 大洋洲

讨论栏

2010-11-06

报表中文显示

  • 今天在职员的计算机浏览器对销售订单的报表进行测试,报表是以PDF格式生成的,打开后发现中文都显示为一个个方框。于是对服务器进行设置。

1. 首先检查使用中的JVM版本。

 $ java -version

2. 发现是OpenJDK。于是执行以下命令转为SunJDK。

 # update-alternatives --config java

3. 安装中文字体

 # aptitude install ttf-wqy-zenhei

4. 设置JVM中文字体

 # cd /usr/lib/jvm/java-6-sun/jre/lib/
 # mkdir fonts/fallback
 # ln -s /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc fonts/fallback/wqy-zenhei.ttf

5. 系统退出帐户重新登录即可,重新启动JBOSS。
6. 在职员的计算机再次进行测试,中文正常显示!

讨论栏

2010-11-07

销售模块实施分析

  • 昨天主要在对销售合同案例进行分析。

前期准备工作

  • 需整理数据清单
  1. 客户信息
  2. 产品信息
  • 需整理标准文档格式
  1. 销售合同-国内
  2. 销售合同-国外
  3. 生产通知
  • 需提供典型销售订单案例
  1. 大客户2个
  2. 国内客户2~3个
  3. 国外客户2~3个

几点感受

  1. 该公司销售合同格式尚未标准化,各种销售合同格式相似处大概只占65%。这给ERP界面定制、报表定制带来许多额外的分析整理工作。由此可见ERP实施与文档标准化息息相关。
  2. 要想贴近客户实际需求,需要对ADempiere ERP原有销售订单窗体进行比较大的改动,主要是增加窗体中的填写项目,相应地进行报表定制。

2Pack打包工具

  • 进行ERP实施的朋友可能会遇到这种情况,
    • 为了不让服务器设置得杂乱无章,先在自己的计算机上测试,测试完成后再应用到服务器上。
    • 或者利用晚上和周末在家中测试,第二天到公司后再应用在服务器上。
  • 由于一项项手工应用比较费事,因此希望能有一个实施打包的工具,在这方面2Pack应该能帮上忙。所以接下来几天会我研究2Pack这个工具。
  • 另外,曾经有位zimmer网友按照实施日志“增加Business Type下拉选项”的步骤一步一步进行实践。他踏实学习的精神打动了我。然而Zimmer遇到了点问题,没能实现下拉选择,有些遗憾。我想也可以把我的实施定制用2Pack打包上来给大家分享,这样也有助于Zimmer这样的网友更好地分析和解决问题。
  • 如果我们把目光放远一点,2Pack还可以是行业解决方案的打包工具和快速实施工具。
  • 相关链接:

讨论栏

2010-11-08

2Pack打包工具

  • 昨天看了动画教程"D_2PackHowto.7z",也动手测试了一下。
  • 2Pack的使用方法总结在这里:2Pack用户指南(英文)
  • 注意:PackIn的时候要选择zip文件,如果选择.tar.gz文件会报错。
  • 在数据库里执行的SQL语句应当是在SQL Statement选项,不过还没有进行测试。
  • 关于2Pack的几点疑问
  1. 以System Administrator角色登录系统,只能导出System下的内容,但是无法导出其它实体的内容,例如GardenWorld下面的Print Format。如果我想导出GardenWorld实体下面的Print Format,应当如何进行?
  2. 没有找到Menu选项,能否导出Menu?如果不能导出Menu的话,能否对2Pack进行二次开发以增加这个功能?
  • 解决方法
  1. Print Format的导出采用变通方法,进入数据库把ad_client_id由GardenAdmin改为System即可。
  2. Menu可以导出。通过Data选项进行。但是发现一个奇怪的现象,就是Summary Level的菜单项无法成功导入,其它菜单都成功导入了。
 SELECT * FROM ad_menu WHERE ad_menu_id=xxxxxxx(数字);
  • 发现存在几个问题:
  1. 在导出Process & Form、Print Format时,Report Access Role并没有一同导出,导致需要额外进行角色设置。
  2. 在导入Window, Tab & Field时,所设置的Process="MyProduct_V"并没有成功导入,还需要手工设置。

讨论栏

一楼

导出menu其实没有什么意义,因为menu的节点位置怎么都得再次确定,很难保证所有的节点位置都保持一致的,你设置过几次menu就知道了

打印格式没有用过,我一直认为adempiere系列中的报表(除了财务报表)很垃圾,所以使用的都是jasperreports的扩展,建议你也不要使用打印格式。

--2010年11月08日 aoslee

二楼

谢谢aoslee的建议!

关于Menu,既然用了2Pack,就希望能一切自动进行,不必劳神手工操作。

我接下来会布署JasperReports。利用ADempiere自身Report功能来设置复杂报表的确比较费事。

--Peanut

三楼

> 利用ADempiere自身Report功能来设置复杂报表的确比较费事。

其實如果你善用 StoredProcedure (Oracle/PostgresDB)

可以讓 Master/Detail(兩階或是三階/四階統計表)簡單串接.

以下簡單案例 :


-- Function: adempiere.t_rj_productbp(numeric)
-- DROP FUNCTION adempiere.t_rj_productbp(numeric);
CREATE OR REPLACE FUNCTION adempiere.t_rj_productbp(p_ad_pinstacne_id numeric)
  RETURNS numeric AS
$BODY$
DECLARE
        cur_parameter       record;
        cur_1               record;
	v_resultstr         VARCHAR (2000);
        v_message           VARCHAR (2000);
        v_result            numeric  := 1;
        v_record_id         numeric;
        v_ad_user_id        numeric;
        p_date              date;
        p_date_to           date;
        p_c_bpartner_id     numeric; 
        p_c_bpartner_id_to  numeric;
        p_m_product_id      numeric;
        p_m_product_id_to   numeric;
        v_nextno            numeric;
        p_pdvalue_x         VARCHAR (40);
        p_pdvalue           VARCHAR (40);
        p_pdvalue_to        VARCHAR (40);
        p_bpvalue_x         VARCHAR (40);
        p_bpvalue           VARCHAR (40);
        p_bpvalue_to        VARCHAR (40);
BEGIN
 p_date              := null;
 p_date_to           := null;
 p_c_bpartner_id     :=0; 
 p_c_bpartner_id_to  :=0;
 p_m_product_id      :=0;
 p_m_product_id_to   :=0;
 FOR cur_parameter IN 
      SELECT i.record_, 
             i.ad_user_id, 
             i.parametername, 
             p.p_string,  p.p_string_to,
             p.p_number,  p.p_number_to,
             p.p_date  ,  p.p_date_to
        FROM adempiere.ad_pinstance i
 LEFT OUTER JOIN adempiere.ad_pinstance_para p ON( i.ad_pinstance_id = p.ad_pinstance_id)
       WHERE i.ad_pinstance_id = p_ad_pinstacne_id 
       ORDER BY p.SeqNo
 LOOP
      v_record_id  := cur_parameter.Record_id;
      v_ad_user_id := cur_parameter.ad_user_id;
      
      IF    (cur_parameter.parametername = 'DateOrdered'  ) THEN 
      p_date    := cur_parameter.p_date;   
      p_date_to := cur_parameter.p_Date_TO;  

      ELSIF (cur_parameter.parametername = 'C_BPartner_ID') THEN 
      p_c_bpartner_id    := cur_parameter.p_number;   
      p_c_bpartner_id_to := cur_parameter.p_number_to;

      ELSIF (cur_parameter.parametername = 'M_Product_ID' ) THEN 
      p_m_product_id     := cur_parameter.p_number; 
      p_m_product_id_to  := cur_parameter.p_number_to;

     -- ELSE
     -- DBMS_OUTPUT.put_line ('*** Unknown Parameter=' || P.parametername);
      END IF;
 END LOOP;
 BEGIN--將客戶內碼(ID)改為:客戶編號(Value)
    IF (p_c_bpartner_id > 0) THEN
        SELECT value
          INTO p_bpvalue
          FROM c_bpartner
         WHERE c_bpartner_id=p_c_bpartner_id;
    ELSE 
        p_bpvalue := '';
    END IF;
 EXCEPTION
    WHEN OTHERS THEN
        p_bpvalue := '';
    --	RAISE NOTICE '%',SQLERRM;
 END;
 BEGIN--將客戶內碼(ID)改為:客戶編號(Value)
    IF (p_c_bpartner_id_to > 0) THEN
        SELECT value
          INTO p_bpvalue_to
          FROM c_bpartner
         WHERE c_bpartner_id=p_c_bpartner_id_to;
    ELSE 
        p_bpvalue_to := '';
    END IF;
 EXCEPTION
    WHEN OTHERS THEN
        p_bpvalue_to := '';
    --	RAISE NOTICE '%',SQLERRM;
 END;
 BEGIN --將產品內碼(ID)改為:產品編號(Value)
    IF (p_m_product_id > 0) THEN
        SELECT value
          INTO p_pdvalue
          FROM m_product
         WHERE m_product_id=p_m_product_id;
    ELSE 
        p_pdvalue := '';
    END IF;
 EXCEPTION
    WHEN OTHERS THEN
        p_pdvalue := '';
    --	RAISE NOTICE '%',SQLERRM;
 END;
 BEGIN --將產品內碼(ID)改為:產品編號(Value)
    IF (p_m_product_id_to > 0) THEN
        SELECT value
          INTO p_pdvalue_to
          FROM m_product
         WHERE m_product_id=p_m_product_id_to;
    ELSE 
        p_pdvalue_to := '';
    END IF;
 EXCEPTION
    WHEN OTHERS THEN
        p_pdvalue_to := '';
    --	RAISE NOTICE '%',SQLERRM;
 END;
 if p_bpvalue > b_bpvalue_to then
    p_bpvalue_x  := p_bpvalue_to;
    p_bpvalue_to := p_bpvalue;
    p_bpvalue    := b_bpvalue_x;
 end if;
 if p_pdvalue > b_pdvalue_to then
    p_pdvalue_x  := p_pdvalue_to;
    p_pdvalue_to := p_pdvalue;
    p_pdvalue    := p_pdvalue_x;
 end if;
 --要用客戶編號 Value 區間篩選客戶(註:用客戶內碼 ID 將引發區段錯亂)
 FOR cur_1 IN 
      SELECT p.ad_client_id,p.ad_org_id,          
       p.m_product_id,
       p.value AS pdvalue,
       p.name AS pdname,
       b.c_bpartner_id,
       b.value AS bpvalue,
       b.name AS bpname
        FROM adempiere.m_product p
 LEFT OUTER JOIN adempiere.c_orderline ol ON( p.m_product_id = ol.m_product_id)
 LEFT OUTER JOIN adempiere.c_order o ON( ol.c_order_id = o.c_order_id)
 LEFT OUTER JOIN adempiere.c_bpartner b ON( o.c_bpartner_id = bp.c_bpartner_id)
       WHERE 1=1
       AND (p_pdvalue ='' OR p.value BETWEEN p_pdvalue AND p_pdvalue_to)
       AND (p_bpvalue ='' OR b.value BETWEEN p_bpvalue AND p_bpvalue_to)
       ORDER BY p.value,b.value
 LOOP
       v_nextno := adempiere.ad_sequence_next('T_RJ_ProductBP','Y');
       INSERT INTO adempiere.t_rj_productbp
      (ad_pinstance_id            ,--    numeric(10,0),
       t_rj_productbp_id          ,--    numeric(10,0),
       ad_client_id               ,--    numeric(10,0),
       ad_org_id                  ,--    numeric(10,0),
       isactive                   ,--    char(1),
       created                    ,--    date,
       createdby                  ,--    numeric(10,0),
       updated                    ,--    date,
       updatedby                  ,--    numeric(10,0),
       m_product_id               ,--    numeric(10,0),
       pdvalue                    ,--    varchar(30),
       pdname                     ,--    varchar(60),
       c_bpartner_id              ,--    numeric(10,0),
       bpvalue                    ,--    varchar(30),
       bpname                      --    varchar(60),
       )VALUES(
       p_ad_pinstance_id,       
       v_nextno,             
       cur_1.ad_client_id,       
       cur_1.ad_org_id,          
       'Y',SYSDATE,0,SYSDATE,0,
       cur_1.m_product_id,
       cur_1.pdValue,
       cur_1.pdName,
       cur_1.bpartner_id,
       cur_1.bpvalue,
       cur_1.bpname
       );
       END LOOP;
 RETURN 0;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION adempiere.t_rj_productbp(numeric) OWNER TO adempiere;

--Albert :: Skype: Adempiere/Compiere

四楼

谢谢Albertachen的详细补充!

JasperReports和iReport的优势是使报表设计的灵活、快捷、美观。还可以很方便地生成各种图表。

StoredProcedure看起来很强大,我将来会学习如何使用的。

--Peanut

2010-11-09

销售数据整理模板

今天与市场部的职员举行了一次会议,将客户信息、销售订单需要增加或变更的字段、字段值的选项都确定下来了。

这是数据整理模板(电子表格下载)。

以后会陆续增加采购、仓库等模块的模板。

讨论栏

2010-11-11

JasperReports报表

今天主要调试JasperReports和iReport。

  • JasperReports是一款报表打印组件,开放源代码并基于Java。
  • “iReport...用来以可视化的方式设计生成JasperReport所使用的报表格式文件。因为JasperReports本身并未提供很好的可视化报表设计工具,iReport的出现正好弥补了这个缺陷。”
  • --摘自裴贺先的《JasperReport 与 iReport 的配置与使用》。

友情提醒:ADempiere新近版本已经集成了JasperReports功能,在Adempiere的安装目录下以jasper可以搜索到两个jar包。所以安装了ADempiere了用户就不必另外安装JasperReports了。

iReport安装方法

以iReport-3.7.6和Linux操作系统为例

  1. 下载安装包 iReport-3.7.6.tar.gz
  2. 解压缩到文件夹: /opt/iReport-3.7.6
  3. 运行iReport:
$ cd /opt/iReport-3.7.6/bin
$ sh ireport

在ADempiere中应用JasperReports

  1. 在iReport里新建报表并预览通过。
  2. Adempiere的安装目录下新建报表文件夹,然后把*.jrxml文件复制过去。
  3. 以System Administrator的角色登录。
  4. 在窗体Report & Process里新建Report。并在Jaspert Report栏填写*.jrxml文件的路径。
  5. 在窗体Menu中把新建的Report添加到菜单中。
  6. 以GardenWorld Administrator的角色登录。
  7. 打开刚才新建的Report,就可以看到JasperReport了。

后续测试

  1. 父子报表(Parent-Child report);
  2. 参数传递。主要是与销售订单当前记录的关联。

完成测试后就会用于销售订单的报表定制。

JasperReports相关链接

讨论栏

2010-11-13

销售订单下拉表

这两天对销售订单、客户信息的定制进行了梳理。

  1. 销售订单需要新增字段30个,其中下拉选项表17个。
  2. 客户信息需要新增字段6个,其中下拉选项表2个。

去除重复项,共需下拉选项表18个。

起初想到的办法是为每个下拉选项表建一个表格,这样要建18个表格,比较繁琐。后来发现可以利用Reference的List,这样就简单多了。

从这个角度来看,之前增加的业务类型(Business Type)也可以通过Reference来设定,不需要创建数据表C_Business_Type了。

Sales Order当中的Invoice Rule就是这样处理的:

DB Table:

 invoicerule character(1) NOT NULL

Referece:

 Name= C_Order InvoiceRule
 Validation Type=List Validation

AD Table:

 Name = InvoiceRule
 Reference = List
 Reference Key =C_Order InvoiceRule
  • 遇到的问题及解决方法:
  1. 设置Payment Term,要以“Role=TongjiAdmin,Client=Tongji, Orangization=*”登录。
  2. Payment Rule, Invoice Rule, Delivery Rule。起初发现这些下拉选表没有找到相应的窗体来修改,后来发现是在Reference窗体里更改的。

关于Boolean数据类型

我有个疑问,ADempiere数据表为什么不用Boolean数据类型,而是用character(1)?

例如C_Order数据表当中的字段isactive:

 isactive character(1) NOT NULL DEFAULT 'Y'::bpchar

讨论栏

2010-11-23

实施栏

讨论栏

一楼

我知道::你已經卡住了!! 無法繼續往前實施!!

ADempiere 是技術與管理結合於一身者的 ERP !!

從 SVN 下載 Source code 重新編譯

從客戶訂單 到 出貨

從廠商訂單 到 收貨

你完整跑一圈了嗎!!

ADempiere PostGres 版本一直都有問題!!

Convert_PostgreSQL

完全正確嗎 ?

transaction 控管對嗎 ?

-- Albertachen

二楼

谢谢Albertachen大人的关心!

这段时间主要在忙几个事情。一个是ADempiere中文翻译校对,一个是Reference设置内容的批量导入,同时还有工作上的其他杂事。

  • ADempiere中文翻译校对:
    • 由于ADempiere ERP目前版本的中文翻译存在很多问题。首先是翻译率不高(翻译比例为75%)。而且大量存在错误翻译、术语不统一的现象,存在翻译质量问题的条目比例达30%以上。
    • 在ADempiere中文社区各位朋友的支持下,经过近六天的努力,已经推出第六个校对版本。ADempiere 3.6.0LTS版本共有条目13872个, 未翻译条目 439个, 翻译比例已经达到96%。同时翻译质量已经得到很大的提高,低质量翻译条目比例已经控制在5%以内。
    • 关于中文翻译校对的进展,见ADempiere 中文翻译项目
  • Reference设置内容的批量导入,见2010-11-24的实施日志。
  • 我知道::你已經卡住了!! 無法繼續往前實施!!
    • 由于目前实施范围主要集中在进销存领域,基本不涉及财务和生产,这一阶段卡住的可能性比较小。
    • 如果一旦卡住了,我一定会向各位专家虚心求教! :-)
  • ADempiere 是技術與管理結合於一身者的 ERP !!
    • 你说的对。我梦想有一天ERP能成为一个傻瓜式的工具,到那时我们才能真正地获得解放。
    • 就像傻瓜数码相机一样,只要把握好主要的几个原则,非专业人士就能在大多数场合拍摄出漂亮的相片。

--Peanut Blake

2010-11-24

Reference设置内容的批量导入

背景

  • 由于Reference的设置内容比较多,而且还要加入中文翻译,因此希望能有一个批量导入的方法。
    • 方法一:写XML文件,利用PackIn工具导入。
    • 方法二:写SQL语句依次插入。INSERT INTO ... (...) VALUES ( ... )。
    • 方法三:写Script脚本导入。
    • 方法四:维护一个基础数据库,再从这个数据库导入到ADempiere的PostgreSQL数据库。
    • 方法五:利用Import File Loader窗口导入。
    • 方法六:利用Pentaho Data Integration ( Kettle )工具进行导入。
  • 方案选择:
    • 一开始我选择了方法四,因为实施过程中变动比较多。
    • 后来发现方法四方案不佳,于是采用了Pentaho Data Integration + SQL语句 的综合方案,见“2010-11-27”的实施内容。--Peanut 于2010年11月27日补充。
    • 这几天重新查看了Import File Loader,发现还有一个方案可供选择:“Import File Loader + SQL语句” 的综合方案,不过比PDI方案多了一项工作——将电子表格另存为.CSV文件。--Peanut 于2010年12月03日补充。

探索

方法四:维护一个基础数据库,再从这个数据库导入到ADempiere的PostgreSQL数据库。

之前在Windows操作系统下用MS Access进行过数据的导入导出。MS Access同一个数据库可以同时进行自建表格、连接至PostgreSQL(通过ODBC或JDBC)、连接至EXCEL电子表格文件,这样就可以非常方便地进行导入和更新了。

现在Linux操作系统下用OpenOffice.org Base,也试图用同样的方法进行,但是发现OOo Base只能三选一,要么自建表格,要么连接至PostgreSQL,要么连接Calc电子表格文件。

因此在OOo Base下进行电子表格-->PostgreSQL数据库的数据导入更为复杂一些。

步骤

备注:由于本方案不佳,于是采用了Pentaho Data Integration + SQL语句 的综合方案,见“2010-11-27”的实施内容。

1. 在PostgreSQL新建base数据库。

同时新建ad_reference, ad_ref_list数据表。

注意:新建的数据表一定要设立主键,否则无法新增和编辑数据。


2. 安装OpenOffice.org与PostgreSQL的连接工具。

 #aptitude install openoffice.org-sdbc-postgresql

3. 在OpenOffice.org Base新建adempiere-base数据库。

a).选择Connect to an existing database;

b).选择postgresql;

c).在Datasource URL栏输入: host=host=localhost port=5432 dbname=base

d). 在user name栏输入:adempiere

这样就可以在OOo Base操作PostgreSQL数据库了。

4. 将电子表格中的数据导入到PostgreSQL。

a).打开电子表格,把数据整理好。

b).在OOo Calc中选择并复制要导入的数据。(即选择并复制单元格。)

c).在OOo Base中选择要导入的表格,执行“粘贴”,这时会出现数据导入对话框,这样数据就可以顺利插入到PostgreSQL了。

讨论栏

2010-11-27

数据导入

采用Pentaho方案

  • 在“2010-11-24”的实施日志中,数据导入选用了方案四-使用OOo Base来中转,后来发现这个方法存在两个问题:
  1. PostgreSQL的Base数据库向adempiere数据库导入数据不方便。
  2. 从电子表格到OOo Base数据库的数据粘贴也不方便。
  • 后来采取以下方法:
  1. 不另外建立数据库,直接在adempiere数据库中建立数据导入表。例如ii_reference, ii_ref_list, ii_column。
  2. 不再利用OOo Base来中转数据,使用Pentaho Data Integration(PDI)工具将数据从电子表格导入PostgreSQL数据库。
    • (使用PDI工具是来自于Robin的建议,感谢Robin的帮助!)

数据导入工具包

  1. 数据导入模板。电子表格格式。
  2. PDI导入模板。
  3. SQL语句。
  • 执行的功能包括:
  1. 新建Reference,包括ref_list及翻译。
  2. 在表格(即ad_Column)中完成名称、描述、翻译、Reference引用等设置。
  3. 在窗口(即ad_Field)中完成名称、描述、翻译等设置。

SQL语句操作风险

  • 整个导入过程对数据库直接进行SQL语句操作,风险很大。这次实施过程中就有过一次误操作:
--更新Window Field名字。
UPDATE ad_field SET "name" = ii_column.name 
FROM ii_column WHERE ( ii_column.ad_field_id = ad_field.ad_field_id ) ;

我不留神误写成:

UPDATE ad_field SET "name" = ii_column.name 
FROM ii_column WHERE ( ii_column.ad_tab_id = ad_field.ad_tab_id ) ;

执行完毕就悲剧了。幸好后来用了其它办法补救回来了。

  • 为了最大限度的降低风险:
  1. 将整个过程先在测试数据库当中执行完毕,确认无误后方可在正式数据库中执行。
  2. 在正式数据库中执行之前,必须将数据库备份好。

讨论栏

  • 在数据导入过程中遇到了一些问题,总结如下。

二次开发-为什么不能自顶向下

  • 为什么不能自顶向下进行设计? Window -> AD Table -> DB Table 一脉贯通。我的设想是:在Window当中增加一个字段,系统就应当可以在AD Table、DB Table、Reference进行一系列的自动设置。 --Peanut
  • 假设你要新建的字段是虚拟列 还要建数据库字段吗??在"表与列"窗口里有个同步列字段,是可以在数据库中创建数据库字段的。 --豪客
  • 即便是虚拟列,系统也应当可以自动判断,或者用户略作标识。 --Peanut
  • 这个我觉得是完全可行的,只不过Table的column有自己的一些设置,而且可以在不同的窗口重用。另外,频繁地更新数据库表可能也会有比较大的风险吧?而且像virtual column我看好像在数据库里也是对应了相应的列的,是要保存数据的。---徐浣泽
  • 嗯,频繁地更新数据库表的确存在风险。不过我想可以设置一个“生成数据库表”按钮,当Window窗口设计经过一系列修改基本定型后,点击这个按钮执行即可,这样可以避免频繁更新数据库表。--Peanut

直观编辑Window界面的工具

  • 为什么没有工具直观地编辑Window界面?现在要比较费劲地在ad_field表当中设置Sequence、Same Line等字段。--Peanut
  • 直观? 我们做了一个不需要加几个配置字段,或者以外挂的实现。一个设计器,但是是公司的,希望有时间做个开源的。--豪客

关于窗口布局的疑问

  • 业务伙伴BPartner窗口的Logo页是在什么地方设置的?# 销售订单Sales Order窗口中的Delivery, Invoicing等可以收缩/展开的栏目是怎么设置的?--Peanut
  • 字段组。--aoslee
  • 这些都属于field group的内容,logo的field group是tab,而收缩/展开里面的那些叫Collapse。你zoom到filed group去看看就知道了。---徐浣泽
  • 感谢aoslee和徐浣泽的帮助!Logo页和Delivery收缩/展开都是利用“字段组”(Field Group)来实现的。有两个地方需要设置:
    • Field Group窗口。
    • Window, Tab & Field窗口中的Field Group字段。 --Peanut

关于“从数据库创建表”功能

  • 打开Table & Column窗口执行Create Columns from DB,不能直接引入数据库中的默认值,即Default Value或Default Logic。之前我用过一个月的GlobalQSS 3.6.1Branch, 我记得该版本是可以的,不知道是不是3.6.0LTS官方版本的Bug,或者说是GlobalQSS新增的功能?--Peanut
  • 有这个功能吗?我一般都是反着做,在AD先建好数据,然后再用AD在数据库中自动建表。建表的时候也有一些限制,比如无法自动帮你创建外键,需要手动创建,所以我想,Create Columns from DB这个功能可能也有一些不完善的地方吧。另外,即Default Value或Default Logic应该有一些自己独特的语法,支持除数据库的默认值之外更多的功能。--徐浣泽
  • 呵呵,我从来没有反着做过,下次测试一下。--Peanut

2010-11-29

实施栏

  • 今天主要工作:
  1. 对新增的销售字段进行排版。
  2. 导入客户资料
  3. 导入价格表
  4. 对帐户密码进行设置
  5. 对角色进行设置。主要通过菜单树(Menu)来控制。

菜单树Tree定制

  • 接下来要对角色权限进行设置。我的想法是通过菜单树(Tree)来控制。
  • 现成的方法是在Tree Maintenance窗口中进行,但是一个个手工设置比较繁琐。
  • 于是希望能在数据库表中进行,找了半天没找到,最后发现是ad_treenodemm表。

讨论栏

2010-11-30

销售订单查询语句

说明

  • 为了用JasperReport创建销售订单,借助电子表格终于把SQL查询语句写好了,大概有146行。
  • 难点在于引用Reference和Table的地方比较绕,需要写JOIN ... ON ...。
  • 而且要费点功夫才能搞清楚ad_field表里的xxxx_id是指向哪个表的。 同时还有ad_column表里的ad_reference_id和ad_reference_value_id,也是有点费神的。

OOo Base存在问题

  • 另外发现OOo Base存在一些问题:
    • 首先是不稳定,主要是执行数据查询时有时会出现重复列,有时会出现记录显示不全。
    • 其次是Queries的Design View设计不完善。在SQL View界面下写稍微复杂一点的SQL语句,一旦转到Design View界面,会就把SQL语句改换掉,接着就是报错。
  • 于是我还是老老实实的用pgAdmin吧。:-)

SQL语句

SELECT 
 AD_Client_74.name AS "Client", 
 AD_Org_82.name AS "Organization", 
 C_Order.contractno AS "Contract No", 
 C_Order.DocumentNo AS "Document No", 
 ref49.name AS "Business Type", 
 C_Order.POReference AS "Order Reference", 
 C_Order.Description AS "Description", 
 C_DocType_57.name AS "Target Document Type", 
 C_Order.IsSelfService AS "Self-Service", 
 C_Order.issueddate AS "Issued Date", 
 C_Order.signedplace AS "Signed Place", 
 C_Order.DateOrdered AS "Date Ordered", 
 C_Order.DatePromised AS "Date Promised", 
 C_BPartner_110.name AS "Business Partner ", 
 C_BPartner_56.name AS "Invoice Partner", 
 C_BPartner_Location_73.name AS "Partner Location", 
 C_BPartner_Location_62.name AS "Invoice Location", 
 AD_User_75.name AS "User/Contact", 
 AD_User_61.name AS "Invoice Contact", 
 ref50.name AS "Delivery Rule", 
 ref43.name AS "Priority", 
 M_Warehouse_81.name AS "Warehouse", 
 C_Order.IsDropShip AS "Drop Shipment", 
 C_BPartner_111.name AS "Drop Shipment Partner", 
 C_BPartner_Location_66.name AS "Drop Shipment Location", 
 AD_User_60.name AS "Drop Shipment Contact", 
 M_Shipper_80.name AS "Shipper", 
 ref42.name AS "Delivery Via", 
 ref51.name AS "Freight Cost Rule", 
 M_FreightCategory_77.name AS "Freight Category", 
 C_Order.FreightAmt AS "Freight Amount", 
 ref37.name AS "Packaging Provide", 
 ref36.name AS "Packaging Recycle", 
 ref54.name AS "Packing Standard", 
 ref38.name AS "Fumigation", 
 ref32.name AS "Mode of Shipment", 
 ref33.name AS "Place of Delivery", 
 C_Order.portofdestination AS "Port of Destination", 
 C_Order.portofshipment AS "Port of Shipment", 
 ref48.name AS "Time of Delivery Start Type", 
 ref47.name AS "Time of Delivery Day Type", 
 C_Order.timeofdelivery AS "Time of Delivery", 
 ref41.name AS "Invoice Rule", 
 M_PriceList_84.name AS "Price List", 
 C_Currency_78.name AS "Currency", 
 C_ConversionType_83.name AS "Currency Type", 
 AD_User_58.name AS "Sales Representative", 
 C_Order.IsDiscountPrinted AS "Discount Printed", 
 C_Charge_59.name AS "Charge", 
 C_Order.ChargeAmt AS "Charge amount", 
 ref103.name AS "Payment Rule", 
 C_PaymentTerm_76.name AS "Payment Term", 
 C_Order.PromotionCode AS "Promotion Code", 
 ref39.name AS "Invoice Type", 
 C_Order.paymentremitted AS "Payment Remitted", 
 ref45.name AS "Payment Method", 
 C_Project_72.name AS "Project", 
 C_Activity_71.name AS "Activity", 
 C_Campaign_69.name AS "Campaign", 
 AD_Org_63.name AS "Trx Organization", 
 C_ElementValue_65.name AS "User List 1", 
 C_ElementValue_64.name AS "User List 2", 
 C_Order.TotalLines AS "Total Lines", 
 C_Order.GrandTotal AS "Grand Total", 
 ref46.name AS "Document Status", 
 C_DocType_70.name AS "Document Type", 
 ref105.name AS "Document Action", 
 ref107.name AS "Posted", 
 C_Order.OrderType AS "Order Type", 
 C_OrderSource_79.name AS "Order Source", 
 ref55.name AS "Acceptance Method", 
 C_Order.advancepayment AS "Advance Payment ", 
 ref40.name AS "Advance Payment Required", 
 ref53.name AS "Contract Effective Way", 
 C_Order.priceisvaliddays AS "This price is valid for .. days", 
 ref31.name AS "Condition of Contact Invalidation", 
 ref34.name AS "Arbitration", 
 ref52.name AS "Installation Fee Payment Side", 
 C_Order.installationfeedetail AS "Installation Fee Detail", 
 ref44.name AS "Warranty Period", 
 ref35.name AS "After-sale Service", 
 C_Order.warrantystartdate AS "Warranty Start Date", 
 C_Order.warrantyenddate AS "Warranty End Date", 
 C_Order.AmountTendered AS "AmountTendered", 
 C_Order.AmountRefunded AS "AmountRefunded", 
 C_POS_68.name AS "POS Terminal" 
FROM C_Order 
 LEFT OUTER JOIN AD_Client AS AD_Client_74 ON (AD_Client_74.AD_Client_ID=C_Order.AD_Client_ID) 
 LEFT OUTER JOIN AD_Org AS AD_Org_82 ON (AD_Org_82.AD_Org_ID=C_Order.AD_Org_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref49 ON ((ref49.ad_reference_id=1001000) AND (C_Order.businesstype=ref49.value )) 
 LEFT OUTER JOIN C_DocType AS C_DocType_57 ON (C_DocType_57.C_DocType_ID=C_Order.C_DocTypeTarget_ID) 
 LEFT OUTER JOIN C_BPartner AS C_BPartner_110 ON (C_BPartner_110.C_BPartner_ID=C_Order.C_BPartner_ID) 
 LEFT OUTER JOIN C_BPartner AS C_BPartner_56 ON (C_BPartner_56.C_BPartner_ID=C_Order.Bill_BPartner_ID) 
 LEFT OUTER JOIN C_BPartner_Location AS C_BPartner_Location_73 ON (C_BPartner_Location_73.C_BPartner_Location_ID=C_Order.C_BPartner_Location_ID) 
 LEFT OUTER JOIN C_BPartner_Location AS C_BPartner_Location_62 ON (C_BPartner_Location_62.C_BPartner_Location_ID=C_Order.Bill_Location_ID) 
 LEFT OUTER JOIN AD_User AS AD_User_75 ON (AD_User_75.AD_User_ID=C_Order.AD_User_ID) 
 LEFT OUTER JOIN AD_User AS AD_User_61 ON (AD_User_61.AD_User_ID=C_Order.Bill_User_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref50 ON ((ref50.ad_reference_id=151) AND (C_Order.DeliveryRule=ref50.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref43 ON ((ref43.ad_reference_id=154) AND (C_Order.PriorityRule=ref43.value )) 
 LEFT OUTER JOIN M_Warehouse AS M_Warehouse_81 ON (M_Warehouse_81.M_Warehouse_ID=C_Order.M_Warehouse_ID) 
 LEFT OUTER JOIN C_BPartner AS C_BPartner_111 ON (C_BPartner_111.C_BPartner_ID=C_Order.DropShip_BPartner_ID) 
 LEFT OUTER JOIN C_BPartner_Location AS C_BPartner_Location_66 ON (C_BPartner_Location_66.C_BPartner_Location_ID=C_Order.DropShip_Location_ID) 
 LEFT OUTER JOIN AD_User AS AD_User_60 ON (AD_User_60.AD_User_ID=C_Order.DropShip_User_ID) 
 LEFT OUTER JOIN M_Shipper AS M_Shipper_80 ON (M_Shipper_80.M_Shipper_ID=C_Order.M_Shipper_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref42 ON ((ref42.ad_reference_id=152) AND (C_Order.DeliveryViaRule=ref42.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref51 ON ((ref51.ad_reference_id=153) AND (C_Order.FreightCostRule=ref51.value )) 
 LEFT OUTER JOIN M_FreightCategory AS M_FreightCategory_77 ON (M_FreightCategory_77.M_FreightCategory_ID=C_Order.M_FreightCategory_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref37 ON ((ref37.ad_reference_id=1001010) AND (C_Order.packagingprovide=ref37.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref36 ON ((ref36.ad_reference_id=1001011) AND (C_Order.packagingrecycle=ref36.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref54 ON ((ref54.ad_reference_id=1001001) AND (C_Order.packingstandard=ref54.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref38 ON ((ref38.ad_reference_id=319) AND (C_Order.fumigation=ref38.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref32 ON ((ref32.ad_reference_id=1001008) AND (C_Order.modeofshipment=ref32.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref33 ON ((ref33.ad_reference_id=1001009) AND (C_Order.placeofdelivery=ref33.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref48 ON ((ref48.ad_reference_id=1001002) AND (C_Order.timeofdeliverystarttype=ref48.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref47 ON ((ref47.ad_reference_id=1001003) AND (C_Order.timeofdeliverydaytype=ref47.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref41 ON ((ref41.ad_reference_id=150) AND (C_Order.InvoiceRule=ref41.value )) 
 LEFT OUTER JOIN M_PriceList AS M_PriceList_84 ON (M_PriceList_84.M_PriceList_ID=C_Order.M_PriceList_ID) 
 LEFT OUTER JOIN C_Currency AS C_Currency_78 ON (C_Currency_78.C_Currency_ID=C_Order.C_Currency_ID) 
 LEFT OUTER JOIN C_ConversionType AS C_ConversionType_83 ON (C_ConversionType_83.C_ConversionType_ID=C_Order.C_ConversionType_ID) 
 LEFT OUTER JOIN AD_User AS AD_User_58 ON (AD_User_58.AD_User_ID=C_Order.SalesRep_ID) 
 LEFT OUTER JOIN C_Charge AS C_Charge_59 ON (C_Charge_59.C_Charge_ID=C_Order.C_Charge_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref103 ON ((ref103.ad_reference_id=195) AND (C_Order.PaymentRule=ref103.value )) 
 LEFT OUTER JOIN C_PaymentTerm AS C_PaymentTerm_76 ON (C_PaymentTerm_76.C_PaymentTerm_ID=C_Order.C_PaymentTerm_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref39 ON ((ref39.ad_reference_id=1001015) AND (C_Order.invoicetype=ref39.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref45 ON ((ref45.ad_reference_id=1001007) AND (C_Order.paymentmethod=ref45.value )) 
 LEFT OUTER JOIN C_Project AS C_Project_72 ON (C_Project_72.C_Project_ID=C_Order.C_Project_ID) 
 LEFT OUTER JOIN C_Activity AS C_Activity_71 ON (C_Activity_71.C_Activity_ID=C_Order.C_Activity_ID) 
 LEFT OUTER JOIN C_Campaign AS C_Campaign_69 ON (C_Campaign_69.C_Campaign_ID=C_Order.C_Campaign_ID) 
 LEFT OUTER JOIN AD_Org AS AD_Org_63 ON (AD_Org_63.AD_Org_ID=C_Order.AD_OrgTrx_ID) 
 LEFT OUTER JOIN C_ElementValue AS C_ElementValue_65 ON (C_ElementValue_65.C_ElementValue_ID=C_Order.User1_ID) 
 LEFT OUTER JOIN C_ElementValue AS C_ElementValue_64 ON (C_ElementValue_64.C_ElementValue_ID=C_Order.User2_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref46 ON ((ref46.ad_reference_id=131) AND (C_Order.DocStatus=ref46.value )) 
 LEFT OUTER JOIN C_DocType AS C_DocType_70 ON (C_DocType_70.C_DocType_ID=C_Order.C_DocType_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref105 ON ((ref105.ad_reference_id=135) AND (C_Order.DocAction=ref105.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref107 ON ((ref107.ad_reference_id=234) AND (C_Order.Posted=ref107.value )) 
 LEFT OUTER JOIN C_OrderSource AS C_OrderSource_79 ON (C_OrderSource_79.C_OrderSource_ID=C_Order.C_OrderSource_ID) 
 LEFT OUTER JOIN ad_ref_list AS ref55 ON ((ref55.ad_reference_id=1001006) AND (C_Order.acceptancemethod=ref55.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref40 ON ((ref40.ad_reference_id=319) AND (C_Order.advancepaymentrequired=ref40.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref53 ON ((ref53.ad_reference_id=1001004) AND (C_Order.contracteffectiveway=ref53.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref31 ON ((ref31.ad_reference_id=1001005) AND (C_Order.conditionofcontactinvalidation=ref31.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref34 ON ((ref34.ad_reference_id=1001014) AND (C_Order.arbitration=ref34.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref52 ON ((ref52.ad_reference_id=1001016) AND (C_Order.installationfeepaymentside=ref52.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref44 ON ((ref44.ad_reference_id=1001012) AND (C_Order.warrantyperiod=ref44.value )) 
 LEFT OUTER JOIN ad_ref_list AS ref35 ON ((ref35.ad_reference_id=1001013) AND (C_Order.aftersaleservice=ref35.value )) 
 LEFT OUTER JOIN C_POS AS C_POS_68 ON (C_POS_68.C_POS_ID=C_Order.C_POS_ID) ;

讨论栏

  • 我觉得这样写报表还是比较繁琐的,不知道大家有没有更好的方法? --Peanut

链接

本系列链接

相关链接