openerp模块收藏 基于Lodop的报表打印模块(转载)

基于Lodop的报表打印模块

原文:http://shine-it.net/index.php/topic,7397.0.html

前段时间写了个小模块,来解决OE中报表打印不方便的问题。
借鉴了 @buke 兄的 openerp-web-pdf-preview-print 模块的部分代码。

介绍:
Lodop是一款优秀的国产打印控件(activeX): http://mtsoftware.v053.gokao.net/download.html
ActiveX只支持windows,所以本控件不适用linux,mac osx.

模块使用mako标签,html的模版。

我只贴代码,不加附件,这样各位会体会更深。

模块结构:
ila_rendered


__openerp__.py

程序代码: 
{
    "name": "Lodop控件报表",
    "category": "web",
    "description":
        """
        Lodop控件模块, 针对于报表。
        """,
    "version": "6.0.5.6",
    "depends": [],
    "js": ["static/lib/Lodop6.145/*.js", "static/js/*.js"],
    'active':True,
    'installable': True,
    'active': False,
    'application':False,
}

服务端的controller(没啥一样的,继续借鉴@buke):

程序代码: 
# -*- coding: utf-8 -*-


import openerp.addons.web.http as openerpweb
from openerp.addons.web.controllers.main import View

import urllib2
import simplejson
import base64
import time
import zlib
import cPickle
import hashlib


class LodopReport(View):
    _cp_path = "/web/lodop/report"
    POLLING_DELAY = 0.25

    @openerpweb.jsonrequest
    def index(self, req, action):
        action = simplejson.loads(action)
        report_srv = req.session.proxy("report")
        context = dict(req.context)
        context.update(action["context"])
        report_data = {}
        report_ids = context["active_ids"]
        if 'report_type' in action:
            report_data['report_type'] = action['report_type']
        if 'datas' in action:
            if 'ids' in action['datas']:
                report_ids = action['datas'].pop('ids')
            report_data.update(action['datas'])
        report_id = report_srv.report(
            req.session._db, req.session._uid, req.session._password,
            action["report_name"], report_ids,
            report_data, context)
        report_struct = None
        while True:
            report_struct = report_srv.report_get(
                req.session._db, req.session._uid, req.session._password, report_id)
            if report_struct["state"]:
                break
            time.sleep(self.POLLING_DELAY)

        report = base64.b64decode(report_struct['result'])
        return dict(report = report)

主要部分是js部分:

程序代码: 
openerp.fg_lodop = function(instance) {

    instance.web.ActionManager = instance.web.ActionManager.extend({

        init: function (parent, action) {
            this._super(parent);
            //activex的标签放在页面里。
            var obj_string = '<object style="width:0px;height:0px;" id="LODOP_OB" classid="clsid:2105C259-1E0C-4534-8141-A753534CB4CA" width=0 height=0><embed id="LODOP_EM" type="application/x-print-lodop" width=0 height=0 pluginspage="/fg_lodop/static/lib/lodop6.145/install_lodop32.exe"></embed></object>';
            $(obj_string).appendTo("body");
        },
        
        ir_actions_report_xml: function(action, options) {
            var self = this;
            instance.web.blockUI();
            return instance.web.pyeval.eval_domains_and_contexts({
                contexts: [action.context],
                domains: []
            }).then(function(res) {
                action = _.clone(action);
                action.context = res.context;
                var os = navigator.platform || "Unknown OS";
                linux = os.indexOf("Linux") > -1;
                mac = os.indexOf("Mac") > -1;

                self.rpc("/web/lodop/report", {
                    action: JSON.stringify(action)
                }).done(function(result) {
                    if(result.error){
                        instance.web.unblockUI();
                        self.dialog_stop();
                        return;
                    }
                    instance.web.unblockUI();
                    self.dialog_stop();
                    if(linux || mac) { 
                        //不支持linux, mac, 这点没考虑过。
                        report_window=window.open('','','width=600,height=500');
                        report_window.document.write(result.report);
                        report_window.focus();
                    }
                    else {
                        //do magic.
                        // 等会解释这个由来。
                        format_obj = action.attachment.split(',');

                        LODOP=getLodop(document.getElementById('LODOP'),document.getElementById('LODOP_EM'));  
                        LODOP.SET_LICENSES("","xxxxxx","","");  //不设置授权码照样可以打印。
                        LODOP.PRINT_INIT("FG ERP Order");
                        LODOP.SET_PRINT_PAGESIZE(1, 2300, 1390, 'fg_lodop_print_job'); //公司用的各种单据的打印纸都是统一规格,所以写死了。
                        
                        var tables = $.parseHTML(result.report);
                        $.each( tables, function( i, el ) {
                            if(el.nodeName == "TABLE"){
                                LODOP.ADD_PRINT_TABLE(format_obj[0],format_obj[1],format_obj[2], format_obj[3], el.outerHTML);
                                LODOP.NEWPAGE();
                            }
                        });
                        LODOP.PREVIEW();
                    }
                });
            });
        },
    });


};

安装后,本模块将会替代系统默认的报表动作。

使用方法:

程序代码: 
<report auto="False" id="report_fg_sale_cust_order_html" model="fg_sale.cust.order"
                name="fg_sale.cust.order.html" rml="fg_sale/report/cust_order.html"
                string="定制单" report_type="mako2html" attachment="0mm,0mm,220mm,98mm"/>

因为需要确定打印的范围,所以借用了attachment这个属性----实在是不想修改系统的rng文件了。
* 这就是刚才代码 “format_obj = action.attachment.split(',');” 这一行的原因。


mako的html模版大概是这样的:

程序代码: 
# -*- coding: utf-8 -*-
            % for o in objects:
                % if o.state == 'review':
                    <table border="0" cellspacing="2" cellpadding="2" bordercolor="#000000" style="font-size:14px;width:850px;">
                      <thead>
                          <tr>
                            <td colspan="8" align="center">
                              <span style="font-size:18px;font-weight:bold;">定制清单  </span> ${ o.name }</td>
                          </tr>
                          <tr>
                              <td colspan="1"  height="18">客户名称: 
                                ${ o.partner_id.name }
                              </td>
                              <td colspan="3"  height="18">要求到货日期: ${ o.date_arrival_req or '' }</td>
                              <td colspan="4" height="18">
                                  交货日期: ${ o.date_delivery or '' }
                              </td>
                          </tr>
                          % if o.contact or o.phone or o.delivery_addr:
                          <tr>
                            <td colspan="1">联系人: ${ o.contact or '' }</td>
                            <td colspan="3">联系电话: ${ o.phone or '' }</td>
                            <td colspan="3">交货地址: ${ o.delivery_addr or '' }</td>
                          </tr>
                          % endif
                          <tr>
                            <td colspan="1">已付金额: ${ o.amount_paid or '' }</td>
                            <td colspan="3">付款方式: ${ o.amount_paid_method or '' }</td>
                            <td colspan="3">发票: 
                              % if o.invoice_type == 'common':
                              普通发票
                              % elif o.invoice_type == 'va':
                              增值发票
                              % else:
                              暂不开票
                              % endif
                            </td>
                          </tr>
                          <tr>
                            <td colspan="1">定制版面:  ${ o.client }</td>
                            <td colspan="3">运费承担方: ${ o.delivery_fee or '' }</td>
                            <td colspan="3">送货方式: ${ o.delivery_method or '' }</td>
                          </tr>
                          <tr height="18">
                             <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">品名</td>
                             <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">数量(只)</td>
                            <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">开票价</td>
                            <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">版费</td>
                            <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">已发货</td>
                            <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">小计</td>
                            <td style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" align="center">附注</td>
                          </tr>
                      </thead>
                      <tbody>
                          % for line in o.order_line:
                          <tr>
                              <td height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" >${ line.product_id.name }</td>
                              <td width="10%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;">${ line.product_uom_qty }</td>
                              <td width="10%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" >${ line.unit_price }</td>
                              <td width="10%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;">${ line.cust_price }</td>
                              <td width="10%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;">${ line.delivered and '是' or '否' }</td>
                              <td width="10%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;">${ line.subtotal_amount }</td>
                              <td width="20%" height="18" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;">${ line.note or '' }</td>
                            </tr>
                          % endfor
                      </tbody>
                      <tfoot>
                          <tr>
                            <td colspan="1" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;text-align:right;" tdata="allSum" format="#,##0.00" tindex="6">
                                共计: #
                            </td>
                            <td colspan="4" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" tdata="allSum" format="UpperMoney" tindex="6">
                                #
                            </td>
                            <td colspan="2" style="BORDER-COLLAPSE: collapse; BORDER:groove 1px;" tdata="subSum" format="#,##0.00">
                                本页小计: #
                            </td>
                          </tr>
                          <tr>
                              <td colspan="2">
                                开单人: ${ o['user_id']['name'] } &nbsp;&nbsp;
                                开单日期:${ o.date_order } 
                              </td>
                              <td colspan="4">
                                业务部确认: ${ o['confirmer_id']['name'] }&nbsp;&nbsp;
                                业务经办人:${ o.employee_id.name }
                              </td>
                              <td colspan="1" style="font-size:14px;height:18px;text-align:right;"><span tdata="pageNO" format="#">#</span>页-共<span tdata="pageCount" format="#">#</span></td>
                          </tr>
                      </tfoot>
                    </table>
            % endif
      % endfor

注意:
1. 模版只包含table标签,支持多table(多单打印)。
2. lodop的使用方法请参看其文档。


大功告成。

献丑了。如需改进,有问题请 @杨振宇_

 

lodop里,addprinttable方法可以把table里面 <theader>标签转为你说的,表头,tfoot标签转换为页脚。
tbody里,就是明细部分了,自动根据页面高度分页。

另外lodop还支持一些标签,比如,总页数,当前页数,数字大写转换,统计,等。

posted @ 2013-07-13 14:58 cnshen 阅读(...) 评论(...) 编辑 收藏