基于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. windows环境下搭建vue+webpack的开发环境

    前段时间一直在断断续续的看vue的官方文档,后来就慢慢的学习搭建vue的开发环境,已经有将近两周了,每到最后一步的时候就会报错,搞的我好郁闷,搁置了好几天,今天又接着搞vue的开发环境,终于成功了.我 ...

  2. iOS---A valid provisioning profile for this executable was not found

    把Target中的Code Signing Identity也设置成iPhone Develop就ok了,这样一切都说的通了,唯一不合理的就是在Project切换Code Signing Identi ...

  3. visual studio 2013 已停止运行 解决办法

    情况是这样,WINDOWS 8.1,双显卡笔记本,打开VS.NET 没几秒就提示 已停止运行,然后就关闭程序了,找了无数资料都没有解决 -------------------------------- ...

  4. Flink - state管理

    在Flink – Checkpoint 没有描述了整个checkpoint的流程,但是对于如何生成snapshot和恢复snapshot的过程,并没有详细描述,这里补充   StreamOperato ...

  5. Android 自定义spinner下拉框实现的实现

    请支持原创:http://blog.csdn.NET/geniuseoe2012/article/details/8723702 说到Android下拉框spineer,框架中虽有现成的控件,但实际效 ...

  6. NetworkReachable学习笔记

    一.基本知识 在需要联网的iPhone程序中,我们首先需要检查网络的状态,如果不能连接网络则告诉用户程序不能使用的原因是没有网络连接.在iPhone的SystemConfiguration框架里有提供 ...

  7. eclipse开发web应用程序步骤(图解)

    *运行环境(也就是服务器的选择) 环境搭建好之后开始编写web程序!然后右键->Run as -> Run on Server!

  8. Hadoop学习(1)-- 入门介绍

    Hadoop是Apache基金会开发的一个分布式系统基础架构,是时下最流行的分布式系统架构之一.用户可以在不了解分布式底层的情况下,在Hadoop上快速进行分布式应用的开发,并利用集群的计算和存储能力 ...

  9. std::sort引发的core

    #include <stdio.h> #include <vector> #include <algorithm> #include <new> str ...

  10. TCP和UDP协议的应用/参数查看

    TCP发送的包有序号,对方收到包后要给一个反馈,如果超过一定时间还没收到反馈就自动执行超时重发,因此TCP最大的优点是可靠.一般网页(http).邮件(SMTP).远程连接(Telnet).文件(FT ...