使用hiPrint代替odoo原生的打印功能
可以实现快速自定义修改打印模板,无需每次都调整打印模板
无论是表单分页还是各种需求,都能满足
目录
1 使用命令创建新的模块,无用的demo文件可以删除掉
2 新建“打印模板”,用于保存打印模板
1)编写打印模板模型
2)增加打印模板权限
3)增加打印模板视图和菜单
3 首次运行先安装模块
4 增加按钮,定制并保存模板
1)增加自定义按钮“定制模板”xml
2)增加自定义按钮事件js,点击按钮实现打开新的页面
3)增加引入自定义按钮事件js的xml
4)列表视图增加自定义按钮
5)引入以上2个文件
6)引入js,bootstrap,hiprint并引用
7)编写接口,用于打开模板编辑界面,并实现修改保存打印模板
8)编写打开的打印模板页面,在打印模板页面调用接口,实现修改保存打印模板
5 编辑并保存打印模板
1)勾选打印模板记录,点击定制模板
2)在模板设计页面设计打印模板,并保存
6 新建“打印数据”,用于模拟测试打印功能(类似新建“打印模板”,此处省略说明)
1)增加模型,增加权限,增加视图,增加菜单,增加数据
7 在需要进行打印的列表处增加打印按钮
1)增加自定义按钮“打印”xml
2)增加自定义按钮事件js,点击按钮实现打印
3)增加引入自定义按钮事件js的xml
4)列表视图增加自定义按钮
5)引入以上2个文件
8 勾选数据记录,并点击打印按钮即可
9 插件下载
1 使用命令创建新的模块,无用的demo文件可以删除掉
python odoo-bin scaffold hiprint
2 新建“打印模板”,用于保存打印模板
1)编写打印模板模型
2)增加打印模板权限
3)增加打印模板视图和菜单
class PrintTemp(models.Model):
_name = 'print.temp'
_order = 'name DESC'
_description = '打印模板'
_sql_constraints = [
('unique_code_print_temp', 'unique(code)', '编码需要唯一.'),
]
name = fields.Char(u'名称', copy=False, index=True, required=True)
code = fields.Char(u'编码', copy=False, index=True, default='/')
type = fields.Char('类型')
template = fields.Text('模板')
remark = fields.Char(string='备注')
def copy(self, default=None):
default = dict(default or {})
copied_count = self.search_count(
[('name', '=like', u"副本 {}%".format(self.name))])
if not copied_count:
new_name = u"副本 {}".format(self.name)
else:
new_name = u"副本 {} ({})".format(self.name, copied_count)
default['name'] = new_name
return super(PrintTemp, self).copy(default)
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
print_temp,print_temp,model_print_temp,,1,1,1,1
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="print_temp_tree_view">
<field name="name">print.temp.tree</field>
<field name="model">print.temp</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="code"/>
<field name="type"/>
<field name="remark"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="print_temp_form_view">
<field name="name">print.temp.form</field>
<field name="model">print.temp</field>
<field name="arch" type="xml">
<form delete="0">
<sheet>
<group>
<group>
<field name="code"/>
<field name="name" />
</group>
<group>
<field name="template"/>
<field name="type"/>
<field name="remark"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_print_temp">
<field name="name">打印模板</field>
<field name="res_model">print.temp</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<menuitem id="hiprint_menu" name="hiprint" web_icon="hiprint,static/description/icon.png" sequence="10"/>
<menuitem id="hiprint_print_temp" name="打印模板" parent="hiprint_menu" sequence="10" action="action_print_temp"/>
</data>
</odoo>
3 首次运行先安装模块
python odoo-bin -c odoo.conf -i hiprint
4 增加按钮,定制并保存模板
1)增加自定义按钮“定制模板”xml
2)增加自定义按钮事件js,点击按钮实现打开新的页面
3)增加引入自定义按钮事件js的xml
4)列表视图增加自定义按钮
5)引入以上2个文件
6)引入js,bootstrap,hiprint并引用
7)编写接口,用于打开模板编辑界面,并实现修改保存打印模板
8)编写打开的打印模板页面,在打印模板页面调用接口,实现修改保存打印模板
<?xml version="1.0" encoding="UTF-8"?>
<templates id="print_temp_button_template" xml:space="preserve">
<t t-extend="ListView.buttons" t-name="hiprint_print_temp_tree_view.buttons">
<t t-jquery="button.o_list_export_xlsx" t-operation="before">
<t t-if="widget.modelName=='print.temp'">
<button type="button" class="btn btn-primary o_list_button_custom">
定制模板
</button>
</t>
</t>
</t>
</templates>
odoo.define('add_print_temp_button', function (require) {
"use strict";
var ListController = require('web.ListController');
var ListView = require('web.ListView');
var viewRegistry = require('web.view_registry');
function renderGenerateButton() {
if (this.$buttons) {
var self = this;
this.$buttons.on('click', '.o_list_button_custom', function () {
console.info('click');
var actived_ids = []
var state = self.model.get(self.handle, {raw: true});
for (var i = 0; i < $('tbody .o_list_record_selector input').length; i++) {
if ($('tbody .o_list_record_selector input')[i].checked === true) {
actived_ids.push(state.res_ids[i]);
}
}
var ctx = state.context;
if(actived_ids.length > 0){
window.open("pt_custom/" + actived_ids[0], '_blank');
}
});
}
}
var ModelListController = ListController.extend({
willStart: function () {
var self = this;
//设置管理员权限组才看到按钮,可以按需修改
var ready = this.getSession().user_has_group('base.group_no_one')
.then(function () {
if (true) {
self.buttons_template = 'hiprint_print_temp_tree_view.buttons';
}
});
return Promise.all([this._super.apply(this, arguments), ready]);
},
renderButtons: function () {
this._super.apply(this, arguments);
renderGenerateButton.apply(this, arguments);
}
});
var ModelListView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Controller: ModelListController,
}),
});
//将tree视图的按钮注册到视图
viewRegistry.add('print_temp_tree', ModelListView);
});
<odoo>
<data>
<template id="button_js" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/hiprint/static/src/js/print_temp_button.js"/>
</xpath>
</template>
</data>
</odoo>
<!--增加js_class="print_temp_tree"-->
<record model="ir.ui.view" id="print_temp_tree_view">
<field name="name">print.temp.tree</field>
<field name="model">print.temp</field>
<field name="arch" type="xml">
<tree js_class="print_temp_tree">
<field name="name"/>
<field name="code"/>
<field name="type"/>
<field name="remark"/>
</tree>
</field>
</record>
'data': [
'security/ir.model.access.csv',
'views/print_temp_view.xml',
'views/menus_view.xml',
'static/src/xml/include_print_temp_button_js.xml',
],
'qweb': [
'static/src/xml/print_temp_button_template.xml',
]
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/hinnn.css"/>
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/hiprint.css"/>
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/print-lock.css"/>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/polyfill.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/jquery.minicolors.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/JsBarcode.all.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/qrcode.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/hiprint.bundle.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/jquery.hiwprint.js"></script>
<!--<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/socket.io.js"></script>-->
</xpath>
</template>
</odoo>
# -*- coding: utf-8 -*-
import logging
from odoo import http
from odoo.http import request
from odoo.tools import exception_to_unicode
import jinja2, sys, os
_logger = logging.getLogger(__name__)
class PrintCtrl(http.Controller):
_pt_custom = '/pt_custom/<int:id>'
_pt_find = '/pt_find/<int:id>'
_pt_save = '/pt_save/<int:id>'
_pd_list = '/pd_list'
@http.route(_pt_custom, type='http', auth='none', method=['GET', 'POST'], csrf=False)
def _pt_custom(self, **kw):
try:
if hasattr(sys, 'frozen'):
# When running on compiled windows binary, we don't have access to package loader.
path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views'))
loader = jinja2.FileSystemLoader(path)
else:
loader = jinja2.PackageLoader('odoo.addons.hiprint', "views")
env = jinja2.Environment(loader=loader, autoescape=True)
return env.get_template("customtemp.html").render({'id': kw.get("id")})
except Exception as e:
return exception_to_unicode(e)
@http.route(_pt_find, type='json', auth='none', methods=['GET', "POST"], csrf=False)
def pt_find(self, **kw):
result = {
'method': self._pt_find,
'code': 200,
'message': 'ok',
'data': {},
}
try:
id = kw.get('id', False)
code = kw.get('code', False)
if code:
print_temp = request.env['print.temp'].sudo().search([("code", "=", code)])
if print_temp:
result['data'] = {
'template': print_temp.template,
}
return result
if id:
print_temp = request.env['print.temp'].sudo().search([("id", "=", id)])
if print_temp:
result['data'] = {
'template': print_temp.template,
}
return result
except Exception as e:
request.env.cr.rollback()
result['code'] = 500
result['message'] = exception_to_unicode(e)
return result
return result
@http.route(_pt_save, type='json', auth='none', methods=["POST"], csrf=False)
def pt_save(self, **kw):
result = {
'method': self._pt_save,
'code': 200,
'message': 'ok',
'data': {},
}
try:
id = kw.get('id', False)
template = kw.get('template', False)
if id:
print_temp = request.env['print.temp'].sudo().search([("id", "=", id)])
print_temp.template = template
else:
result['code'] = 500
result['message'] = '缺少必要的参数'
return result
except Exception as e:
request.env.cr.rollback()
result['code'] = 500
result['message'] = exception_to_unicode(e)
return result
return result
@http.route(_pd_list, type='json', auth='user', methods=["POST"], csrf=False)
def pd_list(self, **kw):
result = {
'method': self._pd_list,
'code': 200,
'message': 'ok',
'data': {},
}
try:
result_data = []
ids = kw.get('ids', False)
if ids:
for id in ids:
# 改成逐行查询,一次查询会导致顺序不正确
record = request.env['print.data'].sudo().search([("id", "=", id)])
result_data.append({
'id': record.id,
'name': record.name,
'code': record.code,
})
result['data'] = {
'print_data': result_data,
'total': len(result_data),
}
else:
result['code'] = 500
result['message'] = '缺少必要的参数'
return result
except Exception as e:
request.env.cr.rollback()
result['code'] = 500
result['message'] = exception_to_unicode(e)
return result
return result
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/hinnn.css"/>
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/hiprint.css"/>
<link rel="stylesheet" href="/hiprint/static/src/js/hiprint/css/print-lock.css"/>
<link rel="stylesheet" href="/hiprint/static/src/js/bootstrap-3.4.1-dist/css/bootstrap.min.css"/>
<script type="text/javascript" src="/hiprint/static/src/js/jquery/jquery-1.12.4.min.js"></script>
</head>
<body>
<layout class="layout hinnn-layout hinnn-layout-has-sider height-100-per" style="background:#fff;">
<content class="hinnn-layout-content" style="border-left:1px solid #e8e8e8;">
<div class="container-fluid height-100-per print-content">
<div class="row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-3 col-md-2" style="padding-right:0px;">
<div class="rect-printElement-types hiprintEpContainer">
<ul class="hiprint-printElement-type">
<li>
<span class="title"><code>拖拽列表</code></span>
<ul>
<li>
<a class="ep-draggable-item" tid="testModule.text" style="">
<span class="glyphicon glyphicon-text-width" aria-hidden="true"></span>
<span class="glyphicon-class">文本</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.image" style="">
<span class="glyphicon glyphicon-picture" aria-hidden="true"></span>
<span class="glyphicon-class">图片</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.longText">
<span class="glyphicon glyphicon-subscript" aria-hidden="true"></span>
<span class="glyphicon-class">长文</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.tableCustom" style="">
<span class="glyphicon glyphicon-th" aria-hidden="true"></span>
<span class="glyphicon-class">表格</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.html">
<span class="glyphicon glyphicon-header" aria-hidden="true"></span>
<span class="glyphicon-class">html</span>
</a>
</li>
</ul>
</li>
<li>
<span class="title">辅助</span>
<ul>
<li>
<a class="ep-draggable-item" tid="testModule.hline" style="">
<span class="glyphicon glyphicon-resize-horizontal" aria-hidden="true"></span>
<span class="glyphicon-class">横线</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.vline" style="">
<span class="glyphicon glyphicon-resize-vertical" aria-hidden="true"></span>
<span class="glyphicon-class">竖线</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.rect">
<span class="glyphicon glyphicon-unchecked" aria-hidden="true"></span>
<span class="glyphicon-class">矩形</span>
</a>
</li>
<li>
<a class="ep-draggable-item" tid="testModule.oval">
<span class="glyphicon glyphicon-record" aria-hidden="true"></span>
<span class="glyphicon-class">椭圆</span>
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="col-sm-9 col-md-10">
<div class="hiprint-toolbar" style="margin-top:15px;">
<ul>
<li><a class="hiprint-toolbar-item" onclick="setPaper('A3')">A3</a></li>
<li><a class="hiprint-toolbar-item" onclick="setPaper('A4')">A4</a></li>
<li><a class="hiprint-toolbar-item" onclick="setPaper('A5')">A5</a></li>
<li><a class="hiprint-toolbar-item" onclick="setPaper('B3')">B3</a></li>
<li><a class="hiprint-toolbar-item" onclick="setPaper('B4')">B4</a></li>
<li><a class="hiprint-toolbar-item" onclick="setPaper('B5')">B5</a></li>
<li><a class="hiprint-toolbar-item"><input type="text" id="customWidth" style="width: 50px;height: 19px;border: 0px;" placeholder="宽/mm"/></a>
</li>
<li><a class="hiprint-toolbar-item"><input type="text" id="customHeight" style="width: 50px;height: 19px;border: 0px;" placeholder="高/mm"/></a>
</li>
<li><a class="hiprint-toolbar-item" onclick="setPaper($('#customWidth').val(),$('#customHeight').val())">自定义</a></li>
<li><a class="hiprint-toolbar-item" onclick="rotatePaper()">旋转</a></li>
<li>
<a id="save" class="btn hiprint-toolbar-item " style="color: #fff;background-color: #d9534f;border-color: #d43f3a;">保存模板</a>
</li>
</ul>
<div style="clear:both;"></div>
</div>
<div id="hiprint-printTemplate" class="hiprint-printTemplate" style="margin-top:20px;">
</div>
</div>
</div>
</div>
</div>
</div>
</content>
<sider class="hinnn-layout-sider" style="">
<div class="container height-100-per" style="width:250px;">
<div class="row">
<div class="col-sm-12">
<div id="PrintElementOptionSetting" style="margin-top:10px;"></div>
</div>
</div>
</div>
</sider>
</layout>
<div class="modal fade" id="alertModal" tabindex="-1" role="dialog" aria-labelledby="alertModalLabel">
<div class="modal-dialog modal-lg" role="document" style="width: 825px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<div class="prevViewDiv"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/custom_test/custom-etype-provider.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/polyfill.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/jquery.minicolors.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/JsBarcode.all.min.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/qrcode.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/hiprint.bundle.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/hiprint/plugins/jquery.hiwprint.js"></script>
<script type="text/javascript" src="/hiprint/static/src/js/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
<script>
var hiprintTemplate;
var printTemplateJson;
var printData = {
};
$(function() {
var settings = {
"url": "/pt_find/{{id}}",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/json",
},
"data": JSON.stringify({
"params": {}
}),
};
$.ajax(settings).done(function (response) {
console.log(response.result.data.template);
printTemplateJson = $.parseJSON($.parseJSON(response.result.data.template))
//初始化打印插件
hiprint.init({
providers: [new customElementTypeProvider()]
});
//hiprint.PrintElementTypeManager.build('.hiprintEpContainer', 'testModule');
//设置左侧拖拽事件
hiprint.PrintElementTypeManager.buildByHtml($('.ep-draggable-item'));
//console.info(printTemplateJson);
hiprintTemplate = new hiprint.PrintTemplate({
template: printTemplateJson,
settingContainer: '#PrintElementOptionSetting',
paginationContainer: '.hiprint-printPagination'
});
//打印设计
hiprintTemplate.design('#hiprint-printTemplate');
});
$('#save').click(function () {
var settings = {
"url": "/pt_save/{{id}}",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/json",
},
"data": JSON.stringify({
"params": {
"template": JSON.stringify(JSON.stringify(hiprintTemplate.getJson()))
}
}),
};
$.ajax(settings).done(function (response) {
if(response.result.code=='200'){
$('#alertModal .modal-body .prevViewDiv').html("保存成功")
$('#alertModal').modal('show')
}
else{
}
});
})
});
var setPaper = function (paperTypeOrWidth, height) {
if(paperTypeOrWidth!="" && height!="")
hiprintTemplate.setPaper(paperTypeOrWidth, height);
}
var rotatePaper = function () {
hiprintTemplate.rotatePaper();
}
</script>
</body>
</html>
5 编辑并保存打印模板
1)勾选打印模板记录,点击定制模板
2)在模板设计页面设计打印模板,并保存
6 新建“打印数据”,用于模拟测试打印功能(类似新建“打印模板”,此处省略说明)
1)增加模型,增加权限,增加视图,增加菜单,增加数据
7 在需要进行打印的列表处增加打印按钮
1)增加自定义按钮“打印”xml
2)增加自定义按钮事件js,点击按钮实现打印
3)增加引入自定义按钮事件js的xml
4)列表视图增加自定义按钮
5)引入以上2个文件
<?xml version="1.0" encoding="UTF-8"?>
<templates id="print_data_button_template" xml:space="preserve">
<t t-extend="ListView.buttons" t-name="hiprint_print_data_tree_view.buttons">
<t t-jquery="button.o_list_export_xlsx" t-operation="before">
<t t-if="widget.modelName=='print.data'">
<button type="button" class="btn btn-warning o_list_button_print">
打印
</button>
</t>
</t>
</t>
</templates>
odoo.define('add_print_data_button', function (require) {
"use strict";
var ListController = require('web.ListController');
var ListView = require('web.ListView');
var viewRegistry = require('web.view_registry');
var Dialog = require('web.Dialog');
var core = require('web.core');
var _t = core._t;
function renderGenerateButton() {
if (this.$buttons) {
var self = this;
this.$buttons.on('click', '.o_list_button_print', function () {
var actived_ids = []
var state = self.model.get(self.handle, {raw: true});
for (var i = 0; i < $('tbody .o_list_record_selector input').length; i++) {
if ($('tbody .o_list_record_selector input')[i].checked === true) {
actived_ids.push(state.res_ids[i]);
}
}
$.ajax({
"url": "/pt_find/0",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/json",
},
"data": JSON.stringify({
"params": {
"code": "打印模板1"
}
}),
}).done(function (resp) {
$.ajax({
"url": "/pd_list",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/json",
},
"data": JSON.stringify({
"params": {
"ids": actived_ids
}
}),
}).done(function (response) {
if(JSON.stringify(response.result.data) != "{}"){
var printTemplateJson = $.parseJSON($.parseJSON(resp.result.data.template));
hiprint.init({});
var hiprintTemplate = new hiprint.PrintTemplate({
template: printTemplateJson,
settingContainer: '#PrintElementOptionSetting',
paginationContainer: '.hiprint-printPagination'
});
hiprintTemplate.print(JSON.parse(JSON.stringify(response.result.data.device_device)));
}
else{
console.info(response.result);
}
});
});
});
}
}
var ModelListController = ListController.extend({
willStart: function () {
var self = this;
//设置管理员权限组才看到按钮,可以按需修改
var ready = this.getSession().user_has_group('base.group_no_one')
.then(function () {
if (true) {
self.buttons_template = 'hiprint_print_data_tree_view.buttons';
}
});
return Promise.all([this._super.apply(this, arguments), ready]);
},
renderButtons: function () {
this._super.apply(this, arguments);
renderGenerateButton.apply(this, arguments);
}
});
var ModelListView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Controller: ModelListController,
}),
});
//将tree视图的按钮注册到视图
viewRegistry.add('print_data_tree', ModelListView);
});
<odoo>
<data>
<template id="include_print_data_button_js" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/hiprint/static/src/js/print_data_button.js"/>
</xpath>
</template>
</data>
</odoo>
8 勾选数据记录,并点击打印按钮即可
9 插件下载
https://download.csdn.net/download/u010520912/89520006