基于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的模版。

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

模块结构:

__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还支持一些标签,比如,总页数,当前页数,数字大写转换,统计,等。

openerp模块收藏 基于Lodop的报表打印模块(转载)的更多相关文章

  1. openerp经典收藏 对象的预定义方法(转载)

    对象的预定义方法 原文:http://shine-it.net/index.php/topic,2159.15.html 每个OpenERP的对象都有一些预定义方法,这些方法定义在基类osv.osv中 ...

  2. 在DevExpress程序中使用条形码二维码控件,以及进行报表打印处理

    在很多业务系统里面,越来越多涉及到条形码.二维码的应用了,不管在Web界面还是WInform界面都需要处理很多物料相关的操作,甚至很多企业为了减少录入错误操作,为每个设备进行条形码.二维码的标签,直接 ...

  3. 关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出”

    问题:关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出” 办法:在容纳ReportViewer的窗体后台代码中,添加如下代码即可 protected override ...

  4. 介绍一种基于gulp对seajs的模块做合并压缩的方式

    之前的项目一直采用grunt来构建,然后用requirejs做模块化,requirejs官方有提供grunt的插件来做压缩合并.现在的项目切到了gulp,模块化用起了seajs,自然而然地也想到了模块 ...

  5. JS调用水晶报表打印翻页按钮事件

    默认的水晶报表打印按钮.翻页按钮太小,并且样式不好调整,考虑自己做一个按钮,然后调用水晶报表的按钮事件. 在实际操作中发现可以在.net按钮的服务器端事件中调用翻页方法: CrystalReportV ...

  6. 微软RDLC报表打印

    关于微软RDLC报表打印时文字拉伸问题(Windows server 2003 sp2) 最近我们开发的打印服务频频出现打印文字拉伸问题,客户意见络绎不绝,最为明显的是使用黑体加粗后 “2.0份” 打 ...

  7. 使用POI实现报表打印功能

    [版权申明:本文系作者原创,转载请注明出处] 文章出处:http://blog.csdn.net/sdksdk0/article/details/53393453 作者:朱培 ID:sdksdk0 这 ...

  8. python常用模块(模块和包的解释,time模块,sys模块,random模块,os模块,json和pickle序列化模块)

    1.1模块 什么是模块: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文 ...

  9. JavaSript模块规范 - AMD规范与CMD规范介绍 (转载lovenyf.blog.chinaunix.net)

    JavaSript模块化   在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?       模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题 ...

随机推荐

  1. Linux IPTABLES端口转发

    之前在Linux上用普通用户部署了一个Tomcat,然后将其server.xml中的端口配置为80端口,用普通用户运行就提示绑定端口失败(permission denied),google了一下,原来 ...

  2. 在IIS7.5中ASP.NET调用cmd程序拒绝访问决绝方法小记

    前言 昨天利用Github的Webhook实现自动部署站点,其中要调用命令行(cmd.exe)程序执行shell脚本. 在本地测试没有任何问题,部署到服务器之后,发现错误信息:访问拒绝. 问题 没有权 ...

  3. the king of fighter

    wim 学习部分摘自coolshell http://coolshell.cn/articles/5426.html 基本式 i → Insert 模式,按 ESC 回到 Normal 模式. x → ...

  4. 5ucms后台调用标签

    <%=Rs.Data(1,i)%>栏目 <%=Rs.Data(2,i)%>标题 <%=Rs.Data(3,i)%>推荐 <%=Rs.Data(4,i)%> ...

  5. ios辅助功能之voiceover实战

      一个元素朗读的内容可分为以下4个部分(4部分按先后顺序朗读) 1. Label:元素的标题 2. Value:元素的值(可选) 3. Traits:元素的特征,即类型,包含: 按钮/链接/搜索框/ ...

  6. requirejs自己的学习

    1.最新版本的RequireJS压缩后只有14K. 2.模块化,不在使用全局变量,都用块级作用域包装. 3.防止js加载阻止页面渲染. 4.避免出现多个javascript的标签.

  7. 释放C盘空间的27招优化技巧

    主要讲讲Windows操作系统在C盘空间不足的情况下,我们可以通过那些具体手段来增加C盘空间. 1.打开"我的电脑"-"工具"-"文件夹选项" ...

  8. CentOS6.5下安装MariaDB5.5.36

    yum groupinstall -y "Development Tools" yum install -y cmake openssl-devel zlib-devel yum ...

  9. PHP static静态局部变量和静态全局变量总结

    1.不会随着函数的调用和退出而发生变化,不过,尽管该变量还继续存在,但不能使用它.倘若再次调用定义它的函数时,它又可继续使用,而且保存了前次被调用后留下的值 2.静态局部变量只会初始化一次 3.静态属 ...

  10. javascript设计模式2

    接口:利 固化一部分代码 弊 丧失js的灵活性 在JavaScript中模仿接口 /* interface Composite{ function add(child); function remov ...