ZH/Case-Study-01-Journal-21

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

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

实施日志-21-普通报表


2010-11-04

关联报表

产品物料明细报表
  • 今天主要测试了ADempiere的关联报表功能,这个报表的制作有点繁杂,想参照测试的新手建议从最简单的报表修改开始。
  • 本测试参照HumanFlash的动画教程进行,见HumanFlash/Part8/D.Customizing Reports/4.Create New Reports(Document Lines)。
  • 测试时遇到一个小问题,就是报表头与报表明细重迭了,后来发现是Print Format当中的Header Margin没有设置。设置为120后就不重迭了。

SQL语句

  • SQL语句如下:
  • MyProduct_V
CREATE OR REPLACE VIEW MyProduct_V AS
SELECT
 p.M_Product_ID AS MyProduct_V_ID,
 p.AD_Client_ID,
 p.AD_Org_ID,
 p.isActive,
 p.created,
 p.createdby,
 p.updated,
 p.updatedby,
 'en_US' AS AD_Language,
 p.M_Product_ID,
 p.value,
 p.name,
 p.M_Product_Category_ID,
 uom.UoMSymbol,
 tax.name AS TaxCategory,
 rl.name AS ProductType,
 p.volume,
 p.weight,
 p.upc,
 p.sku
FROM M_Product p
INNER JOIN C_UoM uom ON ( uom.C_UoM_ID = p.C_UoM_ID )
INNER JOIN C_TaxCategory tax on (tax.C_TaxCategory_ID = p.C_TaxCategory_ID)
INNER JOIN AD_Ref_List rl ON ( rl.value = p.ProductType AND rl.AD_Reference_ID =270);
  • MyProduct_VT
CREATE OR REPLACE VIEW MyProduct_VT AS
SELECT
 p.M_Product_ID AS MyProduct_V_ID,
 p.AD_Client_ID,
 p.AD_Org_ID,
 p.isActive,
 p.created,
 p.createdby,
 p.updated,
 p.updatedby,
 pt.ad_language AS AD_Language,
 p.M_Product_ID,
 p.value,
 pt.name,
 p.M_Product_Category_ID,
 uomt.UoMSymbol,
 taxt.name AS TaxCategory,
 rlt.name AS ProductType,
 p.volume,
 p.weight,
 p.upc,
 p.sku
FROM M_Product p
INNER JOIN M_Product_Trl pt ON (pt.M_Product_ID = p.M_Product_ID )
INNER JOIN C_UoM uom ON ( uom.C_UoM_ID = p.C_UoM_ID )
INNER JOIN C_UoM_Trl uomt ON (uomt.c_uom_id = uom.c_uom_id)
INNER JOIN C_TaxCategory tax ON (tax.C_TaxCategory_ID = p.C_TaxCategory_ID)
INNER JOIN C_TaxCategory_Trl taxt ON (tax.C_TaxCategory_ID = taxt.C_TaxCategory_ID)
INNER JOIN AD_Ref_List rl ON ( rl.value = p.ProductType AND rl.AD_Reference_ID =270)
INNER JOIN AD_Ref_List_Trl rlt ON ( rlt.AD_Ref_List_ID = rl.AD_Ref_List_ID );
  • MyProductLine_V
CREATE OR REPLACE VIEW MyProductLine_V AS
SELECT
 pb.AD_Client_ID,
 pb.ad_org_id,
 pb.isactive,
 pb.created,
 pb.createdby,
 pb.updated,
 pb.updatedby,
 'en_US' AS AD_Language,
 pb.M_Product_ID,
 pb.BomQty,
 pb.Line,
 pb.Description,
 p.value,
 p.name AS BOMProduct,
 uom.UoMSymbol,
 rl.name AS BomType
FROM M_Product_BOM pb
INNER JOIN M_Product p ON (pb.M_ProductBOM_ID = p.m_product_id)
INNER JOIN c_uom uom ON ( uom.c_uom_id = p.c_uom_id )
INNER JOIN ad_ref_list rl ON ( rl.value = pb.bomtype AND rl.ad_reference_id =279);
  • MyProductLine_VT
CREATE OR REPLACE VIEW MyProductLine_VT AS
SELECT
 pb.AD_Client_ID,
 pb.ad_org_id,
 pb.isactive,
 pb.created,
 pb.createdby,
 pb.updated,
 pb.updatedby,
 pt.AD_Language AS AD_Language,
 pb.M_Product_ID,
 pb.BomQty,
 pb.Line,
 pb.Description,
 p.value,
 pt.name AS BOMProduct,
 uomt.UoMSymbol,
 rlt.name AS BomType
FROM M_Product_BOM pb
INNER JOIN M_Product p ON (pb.M_ProductBOM_ID = p.m_product_id)
INNER JOIN M_Product_trl pt ON (pt.M_Product_ID = p.m_product_id)
INNER JOIN c_uom uom ON ( uom.c_uom_id = p.c_uom_id )
INNER JOIN c_uom_trl uomt ON ( uomt.c_uom_id = uom.c_uom_id )
INNER JOIN ad_ref_list rl ON ( rl.value = pb.bomtype AND rl.ad_reference_id =279)
INNER JOIN ad_ref_list_trl rlt ON ( rlt.ad_ref_list_id =  rl.ad_ref_list_id);

讨论栏

一楼-不建议用View写报表

  • 不建議一開始就偷懶用 View 來寫報表.
  • 因為當資料是 : 萬筆*萬筆*萬筆 JOIN, 時資料庫會很慢很慢.
  • 這是我們在大量資料的公司實際上線後的基本教條.嚴禁用 View 寫報表,除非他沒有 Join.
  • 建議使用資料庫 StoredProcedure 傳入參屬限制 JOIN 範圍.
  • ADempiere 近來的方向,將所有 StoredProcedure 幾乎都移除.請參考 Compiere 3.0之前的版本.
  • ADempiere 近來的方向,並不是以中大型企業大量資料每日千筆交易以上交易量.因此沒人討論到速度問題.
  • 我們的主要服務對象是在每日萬筆資料或千筆交易量的企業,我們大量使用 StoredProcedure.
  • 我們可能是唯一將 ADempiere 用於中大型企業, 所以我們仿效 SAP ECC6.0 架構大量使用 StoredProcedure.
  • --Albertachen

二楼

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-08

讨论-关于复杂报表

一楼-原有报表很垃圾

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

--2010年11月08日 aoslee

二楼-布署JasperReports

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

三楼-善用StoredProcedure

> 利用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

链接