Browse Source

[12.0][IMP] excel_import_export, excel_import_export_demo

Add report action feature and new examples
12.0
Kitti U 5 years ago
committed by OCA-git-bot
parent
commit
a66a12c957
  1. 1
      excel_import_export/__init__.py
  2. 9
      excel_import_export/__manifest__.py
  3. 4
      excel_import_export/controllers/__init__.py
  4. 53
      excel_import_export/controllers/main.py
  5. 1
      excel_import_export/models/__init__.py
  6. 42
      excel_import_export/models/common.py
  7. 39
      excel_import_export/models/ir_report.py
  8. 5
      excel_import_export/readme/HISTORY.rst
  9. 20
      excel_import_export/readme/USAGE.rst
  10. 88
      excel_import_export/static/src/js/report/action_manager_report.js
  11. 11
      excel_import_export/views/webclient_templates.xml
  12. 1
      excel_import_export_demo/__init__.py
  13. 8
      excel_import_export_demo/__manifest__.py
  14. 2
      excel_import_export_demo/readme/DESCRIPTION.rst
  15. 5
      excel_import_export_demo/readme/HISTORY.rst
  16. 14
      excel_import_export_demo/readme/USAGE.rst
  17. 4
      excel_import_export_demo/report_action/__init__.py
  18. 4
      excel_import_export_demo/report_action/partner_list/__init__.py
  19. BIN
      excel_import_export_demo/report_action/partner_list/partner_list.xlsx
  20. 10
      excel_import_export_demo/report_action/partner_list/report.xml
  21. 37
      excel_import_export_demo/report_action/partner_list/report_partner_list.py
  22. 43
      excel_import_export_demo/report_action/partner_list/report_partner_list.xml
  23. 29
      excel_import_export_demo/report_action/partner_list/templates.xml
  24. 13
      excel_import_export_demo/report_action/sale_order/report.xml
  25. BIN
      excel_import_export_demo/report_action/sale_order/sale_order_form.xlsx
  26. 36
      excel_import_export_demo/report_action/sale_order/templates.xml

1
excel_import_export/__init__.py

@ -3,3 +3,4 @@
from . import wizard
from . import models
from . import controllers

9
excel_import_export/__manifest__.py

@ -2,9 +2,9 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
{
'name': 'Excel Import/Export',
'summary': 'Base module for easy way to develop Excel import/export',
'version': '12.0.1.0.1',
'name': 'Excel Import/Export/Report',
'summary': 'Base module for developing Excel import/export/report',
'version': '12.0.1.0.2',
'author': 'Ecosoft,Odoo Community Association (OCA)',
'license': 'AGPL-3',
'website': 'https://github.com/OCA/server-tools/',
@ -22,8 +22,9 @@
'wizard/import_xlsx_wizard.xml',
'views/xlsx_template_view.xml',
'views/xlsx_report.xml',
'views/webclient_templates.xml',
],
'installable': True,
'development_status': 'alpha',
'development_status': 'beta',
'maintainers': ['kittiu'],
}

4
excel_import_export/controllers/__init__.py

@ -0,0 +1,4 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import main

53
excel_import_export/controllers/main.py

@ -0,0 +1,53 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
import json
import base64
import time
from odoo.addons.web.controllers import main as report
from odoo.http import content_disposition, route, request
from odoo.tools.safe_eval import safe_eval
class ReportController(report.ReportController):
@route()
def report_routes(self, reportname, docids=None, converter=None, **data):
if converter == 'excel':
report = request.env['ir.actions.report']._get_report_from_name(
reportname)
context = dict(request.env.context)
if docids:
docids = [int(i) for i in docids.split(',')]
if data.get('options'):
data.update(json.loads(data.pop('options')))
if data.get('context'):
# Ignore 'lang' here, because the context in data is the one
# from the webclient *but* if the user explicitely wants to
# change the lang, this mechanism overwrites it.
data['context'] = json.loads(data['context'])
if data['context'].get('lang'):
del data['context']['lang']
context.update(data['context'])
excel = report.with_context(context).render_excel(
docids, data=data
)[0]
excel = base64.decodestring(excel)
report_name = report.report_file
if report.print_report_name and not len(docids) > 1:
obj = request.env[report.model].browse(docids[0])
report_name = safe_eval(report.print_report_name,
{'object': obj, 'time': time})
excelhttpheaders = [
('Content-Type', 'application/vnd.openxmlformats-'
'officedocument.spreadsheetml.sheet'),
('Content-Length', len(excel)),
(
'Content-Disposition',
content_disposition(report_name + '.xlsx')
)
]
return request.make_response(excel, headers=excelhttpheaders)
return super(ReportController, self).report_routes(
reportname, docids, converter, **data
)

1
excel_import_export/models/__init__.py

@ -6,3 +6,4 @@ from . import xlsx_export
from . import xlsx_import
from . import xlsx_template
from . import xlsx_report
from . import ir_report

42
excel_import_export/models/common.py

@ -180,28 +180,28 @@ def xlrd_get_sheet_by_name(book, name):
raise ValidationError(_("'%s' sheet not found") % (name,))
def isfloat(input):
def isfloat(input_val):
try:
float(input)
float(input_val)
return True
except ValueError:
return False
def isinteger(input):
def isinteger(input_val):
try:
int(input)
int(input_val)
return True
except ValueError:
return False
def isdatetime(input):
def isdatetime(input_val):
try:
if len(input) == 10:
dt.strptime(input, '%Y-%m-%d')
elif len(input) == 19:
dt.strptime(input, '%Y-%m-%d %H:%M:%S')
if len(input_val) == 10:
dt.strptime(input_val, '%Y-%m-%d')
elif len(input_val) == 19:
dt.strptime(input_val, '%Y-%m-%d %H:%M:%S')
else:
return False
return True
@ -209,18 +209,18 @@ def isdatetime(input):
return False
def str_to_number(input):
if isinstance(input, str):
if ' ' not in input:
if isdatetime(input):
return parse(input)
elif isinteger(input):
if not (len(input) > 1 and input[:1] == '0'):
return int(input)
elif isfloat(input):
if not (input.find(".") > 2 and input[:1] == '0'): # 00.123
return float(input)
return input
def str_to_number(input_val):
if isinstance(input_val, str):
if ' ' not in input_val:
if isdatetime(input_val):
return parse(input_val)
elif isinteger(input_val):
if not (len(input_val) > 1 and input_val[:1] == '0'):
return int(input_val)
elif isfloat(input_val):
if not (input_val.find(".") > 2 and input_val[:1] == '0'):
return float(input_val)
return input_val
def csv_from_excel(excel_content, delimiter, quote):

39
excel_import_export/models/ir_report.py

@ -0,0 +1,39 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class ReportAction(models.Model):
_inherit = "ir.actions.report"
report_type = fields.Selection(selection_add=[("excel", "Excel")])
@api.model
def render_excel(self, docids, data):
if len(docids) != 1:
raise UserError(
_('Only one id is allowed for excel_import_export'))
xlsx_template = self.env['xlsx.template'].search(
[('fname', '=', self.report_name), ('res_model', '=', self.model)])
if not xlsx_template or len(xlsx_template) != 1:
raise UserError(
_("Template %s on model %s is not unique!" %
(self.report_name, self.model)))
Export = self.env['xlsx.export']
return Export.export_xlsx(xlsx_template, self.model, docids[0])
@api.model
def _get_report_from_name(self, report_name):
res = super(ReportAction, self)._get_report_from_name(report_name)
if res:
return res
report_obj = self.env['ir.actions.report']
qwebtypes = ['excel']
conditions = [
('report_type', 'in', qwebtypes),
('report_name', '=', report_name),
]
context = self.env['res.users'].context_get()
return report_obj.with_context(context).search(conditions, limit=1)

5
excel_import_export/readme/HISTORY.rst

@ -1,3 +1,8 @@
12.0.1.0.3 (2019-08-09)
~~~~~~~~~~~~~~~~~~~~~~~
* Add report action for report_type = 'excel'
12.0.1.0.2 (2019-08-07)
~~~~~~~~~~~~~~~~~~~~~~~

20
excel_import_export/readme/USAGE.rst

@ -39,3 +39,23 @@ This create report menu with criteria wizard. (example - excel_import_export_dem
3. Create report model as models.Transient, then define search criteria fields, and get reporing data into ``results`` field -- <report>.py
4. Create/Design Excel Template File (.xlsx), in the template, name the underlining tab used for report results -- <report_file>.xlsx
5. Create instruction dictionary for report in xlsx.template model -- templates.xml
**Note:**
Another option for reporting is to use report action (report_type='excel'), I.e.,
.. code-block:: xml
<report id='action_report_saleorder_excel'
string='Quotation / Order (.xlsx)'
model='sale.order'
name='sale_order.xlsx'
file='sale_order'
report_type='excel'
/>
By using report action, Odoo will find template using combination of model and name, then do the export for the underlining record.
Please see example in excel_import_export_demo/report_action, which shows,
1. Print excel from an active sale.order
2. Run partner list report based on search criteria.

88
excel_import_export/static/src/js/report/action_manager_report.js

@ -0,0 +1,88 @@
// Copyright 2019 Ecosoft Co., Ltd.
// License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
odoo.define("excel_import_export.report", function (require) {
"use strict";
var core = require("web.core");
var ActionManager = require("web.ActionManager");
var crash_manager = require("web.crash_manager");
var framework = require("web.framework");
var session = require("web.session");
var _t = core._t;
ActionManager.include({
_downloadReportExcel: function (url, actions) {
framework.blockUI();
var def = $.Deferred();
var type = "excel";
var cloned_action = _.clone(actions);
if (_.isUndefined(cloned_action.data) ||
_.isNull(cloned_action.data) ||
(_.isObject(cloned_action.data) && _.isEmpty(cloned_action.data)))
{
if (cloned_action.context.active_ids) {
url += "/" + cloned_action.context.active_ids.join(',');
}
} else {
url += "?options=" + encodeURIComponent(JSON.stringify(cloned_action.data));
url += "&context=" + encodeURIComponent(JSON.stringify(cloned_action.context));
}
var blocked = !session.get_file({
url: url,
data: {
data: JSON.stringify([url, type]),
},
success: def.resolve.bind(def),
error: function () {
crash_manager.rpc_error.apply(crash_manager, arguments);
def.reject();
},
complete: framework.unblockUI,
});
if (blocked) {
// AAB: this check should be done in get_file service directly,
// should not be the concern of the caller (and that way, get_file
// could return a deferred)
var message = _t('A popup window with your report was blocked. You ' +
'may need to change your browser settings to allow ' +
'popup windows for this page.');
this.do_warn(_t('Warning'), message, true);
}
return def;
},
_triggerDownload: function (action, options, type) {
var self = this;
var reportUrls = this._makeReportUrls(action);
if (type === "excel") {
return this._downloadReportExcel(reportUrls[type], action).then(function () {
if (action.close_on_report_download) {
var closeAction = {type: 'ir.actions.act_window_close'};
return self.doAction(closeAction, _.pick(options, 'on_close'));
} else {
return options.on_close();
}
});
}
return this._super.apply(this, arguments);
},
_makeReportUrls: function (action) {
var reportUrls = this._super.apply(this, arguments);
reportUrls.excel = '/report/excel/' + action.report_name;
return reportUrls;
},
_executeReportAction: function (action, options) {
var self = this;
if (action.report_type === 'excel') {
return self._triggerDownload(action, options, 'excel');
}
return this._super.apply(this, arguments);
}
});
});

11
excel_import_export/views/webclient_templates.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright 2019 Ecosoft Co., Ltd.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).-->
<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/excel_import_export/static/src/js/report/action_manager_report.js"/>
</xpath>
</template>
</odoo>

1
excel_import_export_demo/__init__.py

@ -3,3 +3,4 @@
from . import import_export_sale_order
from . import report_sale_order
from . import report_action

8
excel_import_export_demo/__manifest__.py

@ -1,7 +1,7 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
{'name': 'Excel Import/Export Demo',
{'name': 'Excel Import/Export/Report Demo',
'version': '12.0.1.0.0',
'author': 'Ecosoft,Odoo Community Association (OCA)',
'license': 'AGPL-3',
@ -15,6 +15,12 @@
'report_sale_order/templates.xml',
'import_sale_orders/menu_action.xml',
'import_sale_orders/templates.xml',
# Use report action
'report_action/sale_order/report.xml',
'report_action/sale_order/templates.xml',
'report_action/partner_list/report.xml',
'report_action/partner_list/templates.xml',
'report_action/partner_list/report_partner_list.xml',
],
'installable': True,
'development_status': 'alpha',

2
excel_import_export_demo/readme/DESCRIPTION.rst

@ -3,3 +3,5 @@ This module provide some example use case for excel_import_export
1. Import/Export Sales Order (import_export_sale_order)
2. Import New Sales Orders (import_sale_orders)
3. Sales Orders Report (report_sale_order)
4. Print Quoation / Order (.xlsx) (report_action/sale_order)
5. Run Partner List Report (report_action/partner_list)

5
excel_import_export_demo/readme/HISTORY.rst

@ -1,3 +1,8 @@
12.0.1.0.0 (2019-08-09)
~~~~~~~~~~~~~~~~~~~~~~~
* Add 2 new examples using report action, 1) sale_order 2) partner_list
12.0.1.0.0 (2019-02-24)
~~~~~~~~~~~~~~~~~~~~~~~

14
excel_import_export_demo/readme/USAGE.rst

@ -1,11 +1,19 @@
**Use Case 1:** Export/Import Excel on existing document
**Example 1:** Export/Import Excel on existing document
To test this use case, go to any Sales Order and use Export Excel or Import Excel in action menu.
**Use Case 2:** Import Excel Files
**Example 2:** Import Excel Files
To test this use case, go to Settings > Excel Import/Export > Sample Import Sales Order
**Use Case 3:** Create Excel Report
**Example 3:** Create Excel Report
To test this use case, go to Settings > Excel Import/Export > Sample Sales Report
**Example 4:** Printout Excel on existing document, using report action
To test this use case, go to any Sales Order and click print "Quotation / Order (.xlsx)".
**Example 5:** Run Partner List Report, using report action
To test this use case, go to menu Sales > Reporting > Partner List Report

4
excel_import_export_demo/report_action/__init__.py

@ -0,0 +1,4 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import partner_list

4
excel_import_export_demo/report_action/partner_list/__init__.py

@ -0,0 +1,4 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import report_partner_list

BIN
excel_import_export_demo/report_action/partner_list/partner_list.xlsx

10
excel_import_export_demo/report_action/partner_list/report.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<report id='action_report_partner_excel'
string='Partner List (.xlsx)'
model='report.partner.list'
name='partner_list.xlsx'
file='partner_list'
report_type='excel'
/>
</odoo>

37
excel_import_export_demo/report_action/partner_list/report_partner_list.py

@ -0,0 +1,37 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from odoo import models, fields, api
class ReportPartnerList(models.TransientModel):
_name = 'report.partner.list'
_description = 'Wizard for report.partner.list'
partner_ids = fields.Many2many(
comodel_name='res.partner',
)
supplier = fields.Boolean(
default=True,
)
customer = fields.Boolean(
default=True,
)
results = fields.Many2many(
'res.partner',
string='Results',
compute='_compute_results',
help='Use compute fields, so there is nothing store in database',
)
@api.multi
def _compute_results(self):
""" On the wizard, result will be computed and added to results line
before export to excel by report_excel action
"""
self.ensure_one()
domain = ['|', ('supplier', '=', self.supplier),
('customer', '=', self.customer)]
if self.partner_ids:
domain.append(('id', 'in', self.partner_ids.ids))
self.results = self.env['res.partner'].search(domain, order='id')

43
excel_import_export_demo/report_action/partner_list/report_partner_list.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="partner_list_wizard" model="ir.ui.view">
<field name="name">partner.list.wizard</field>
<field name="model">report.partner.list</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="partner_ids" widget="many2many_tags"/>
</group>
<group>
<field name="customer"/>
<field name="supplier"/>
</group>
</group>
<footer>
<button name='%(excel_import_export_demo.action_report_partner_excel)d'
type='action' string='Execute'
class='oe_highlight'/>
<button special='cancel'
string='Cancel'/>
</footer>
</form>
</field>
</record>
<record id='action_report_partner_list' model='ir.actions.act_window'>
<field name='name'>Partner List Report</field>
<field name='res_model'>report.partner.list</field>
<field name='view_type'>form</field>
<field name='view_mode'>form</field>
<field name='target'>new</field>
</record>
<menuitem id="menu_report_partner_list"
parent="sale.menu_sale_report"
action="action_report_partner_list"
name="Partner List Report"
/>
</odoo>

29
excel_import_export_demo/report_action/partner_list/templates.xml

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="partner_list_xlsx_template" model="xlsx.template">
<field name="res_model">report.partner.list</field>
<field name="fname">partner_list.xlsx</field>
<field name="name">Partner List Report Template</field>
<field name="description">Sample Partner List Report Template for testing</field>
<field name="input_instruction">
{
'__EXPORT__': {
1: {
'results': {
'A4': 'id',
'B4': 'name${value or ""}#{style=text}',
'C4': 'phone${value or ""}#{style=text}',
'D4': 'email${value or ""}#{style=text}',
}
}
},
}
</field>
</record>
<function model="xlsx.template" name="load_xlsx_template">
<value eval="[ref('partner_list_xlsx_template')]"/>
</function>
</odoo>

13
excel_import_export_demo/report_action/sale_order/report.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<report id='action_report_saleorder_excel'
string='Quotation / Order (.xlsx)'
model='sale.order'
name='sale_order_form.xlsx'
file='sale_order'
print_report_name="(object.state in ('draft', 'sent') and 'Quotation - %s' % (object.name)) or 'Order - %s' % (object.name)"
report_type='excel'
/>
</odoo>

BIN
excel_import_export_demo/report_action/sale_order/sale_order_form.xlsx

36
excel_import_export_demo/report_action/sale_order/templates.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_order_excel_template" model="xlsx.template">
<field name="res_model">sale.order</field>
<field name="fname">sale_order_form.xlsx</field>
<field name="name">Sale Order Template</field>
<field name="description">Sample Sales Order Template for testing</field>
<field name="input_instruction">
{
'__EXPORT__': {
'sale_order': {
'_HEAD_': {
'B2': 'partner_id.display_name${value or ""}#{align=left;style=text}',
'B3': 'name${value or ""}#{align=left;style=text}',
},
'order_line': {
'A6': 'product_id.display_name${value or ""}#{style=text}',
'B6': 'name${value or ""}#{style=text}',
'C6': 'product_uom_qty${value or 0}#{style=number}',
'D6': 'product_uom.name${value or ""}#{style=text}',
'E6': 'price_unit${value or 0}#{style=number}',
'F6': 'tax_id${value and ",".join([x.display_name for x in value]) or ""}',
'G6': 'price_subtotal${value or 0}#{style=number}@{sum}',
}
}
},
}
</field>
</record>
<function model="xlsx.template" name="load_xlsx_template">
<value eval="[ref('sale_order_excel_template')]"/>
</function>
</odoo>
Loading…
Cancel
Save