commit
bf683e17aa
|
@ -0,0 +1,117 @@
|
|||
===============
|
||||
Base report csv
|
||||
===============
|
||||
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/reporting-engine/tree/13.0-mig-report_csv/report_csv
|
||||
:alt: OCA/reporting-engine
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/reporting-engine-13-0-mig-report_csv/reporting-engine-13-0-mig-report_csv-report_csv
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
||||
:target: https://runbot.odoo-community.org/runbot/143/13.0-mig-report_csv
|
||||
:alt: Try me on Runbot
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module provides a basic report class to generate csv report.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
An example of CSV report for partners on a module called `module_name`:
|
||||
|
||||
A python class ::
|
||||
|
||||
from odoo import models
|
||||
|
||||
class PartnerCSV(models.AbstractModel):
|
||||
_name = 'report.report_csv.partner_csv'
|
||||
_inherit = 'report.report_csv.abstract'
|
||||
|
||||
def generate_csv_report(self, writer, data, partners):
|
||||
writer.writeheader()
|
||||
for obj in partners:
|
||||
writer.writerow({
|
||||
'name': obj.name,
|
||||
'email': obj.email,
|
||||
})
|
||||
|
||||
def csv_report_options(self):
|
||||
res = super().csv_report_options()
|
||||
res['fieldnames'].append('name')
|
||||
res['fieldnames'].append('email')
|
||||
res['delimiter'] = ';'
|
||||
res['quoting'] = csv.QUOTE_ALL
|
||||
return res
|
||||
|
||||
|
||||
A report XML record ::
|
||||
|
||||
<report
|
||||
id="partner_csv"
|
||||
model="res.partner"
|
||||
string="Print to CSV"
|
||||
report_type="csv"
|
||||
name="module_name.report_name"
|
||||
file="res_partner"
|
||||
attachment_use="False"
|
||||
/>
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/reporting-engine/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_csv%0Aversion:%2013.0-mig-report_csv%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* Creu Blanca
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Enric Tobella <etobella@creublanca.es>
|
||||
* Jaime Arroyo <jaime.arroyo@creublanca.es>
|
||||
* Rattapong Chokmasermkul <rattapongc@ecosoft.co.th>
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/reporting-engine <https://github.com/OCA/reporting-engine/tree/13.0-mig-report_csv/report_csv>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
|
@ -0,0 +1,3 @@
|
|||
from . import controllers
|
||||
from . import models
|
||||
from . import report
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright 2019 Creu Blanca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
{
|
||||
"name": "Base report csv",
|
||||
"summary": "Base module to create csv report",
|
||||
"author": "Creu Blanca, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/oca/reporting-engine",
|
||||
"category": "Reporting",
|
||||
"version": "13.0.1.0.0",
|
||||
"license": "AGPL-3",
|
||||
"external_dependencies": {"python": ["csv"]},
|
||||
"depends": ["base", "web"],
|
||||
"data": ["views/webclient_templates.xml"],
|
||||
"demo": ["demo/report.xml"],
|
||||
"installable": True,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
from . import main
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (C) 2019 Creu Blanca
|
||||
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from odoo.http import content_disposition, request, route
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
from odoo.addons.web.controllers import main as report
|
||||
|
||||
|
||||
class ReportController(report.ReportController):
|
||||
@route()
|
||||
def report_routes(self, reportname, docids=None, converter=None, **data):
|
||||
if converter == "csv":
|
||||
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"])
|
||||
csv = report.with_context(context).render_csv(docids, data=data)[0]
|
||||
filename = "{}.{}".format(report.name, "csv")
|
||||
if docids:
|
||||
obj = request.env[report.model].browse(docids)
|
||||
if report.print_report_name and not len(obj) > 1:
|
||||
report_name = safe_eval(
|
||||
report.print_report_name,
|
||||
{"object": obj, "time": time, "multi": False},
|
||||
)
|
||||
filename = "{}.{}".format(report_name, "csv")
|
||||
# When we print multiple records we still allow a custom
|
||||
# filename.
|
||||
elif report.print_report_name and len(obj) > 1:
|
||||
report_name = safe_eval(
|
||||
report.print_report_name,
|
||||
{"objects": obj, "time": time, "multi": True},
|
||||
)
|
||||
filename = "{}.{}".format(report_name, "csv")
|
||||
csvhttpheaders = [
|
||||
("Content-Type", "text/csv"),
|
||||
("Content-Length", len(csv)),
|
||||
("Content-Disposition", content_disposition(filename)),
|
||||
]
|
||||
return request.make_response(csv, headers=csvhttpheaders)
|
||||
return super(ReportController, self).report_routes(
|
||||
reportname, docids, converter, **data
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!--
|
||||
Copyright 2019 Creu Blanca
|
||||
License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
|
||||
-->
|
||||
<report
|
||||
id="partner_csv"
|
||||
model="res.partner"
|
||||
string="Print to CSV"
|
||||
report_type="csv"
|
||||
name="report_csv.partner_csv"
|
||||
file="res_partner"
|
||||
attachment_use="False"
|
||||
/>
|
||||
</odoo>
|
|
@ -0,0 +1,118 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * report_csv
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 12.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: report_csv
|
||||
#: code:addons/report_csv/models/ir_report.py:18
|
||||
#, python-format
|
||||
msgid "%s model was not found"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#. openerp-web
|
||||
#: code:addons/report_csv/static/src/js/report/qwebactionmanager.js:49
|
||||
#, python-format
|
||||
msgid "A popup window with your report was blocked. You may need to change your browser settings to allow popup windows for this page."
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model,name:report_csv.model_report_report_csv_abstract
|
||||
msgid "Abstract Model for CSV reports"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_abstract__display_name
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_partner_csv__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "HTML"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_abstract__id
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_partner_csv__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_abstract____last_update
|
||||
#: model:ir.model.fields,field_description:report_csv.field_report_report_csv_partner_csv____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "PDF"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.actions.report,name:report_csv.partner_csv
|
||||
msgid "Print to CSV"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "Py3o"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model,name:report_csv.model_ir_actions_report
|
||||
msgid "Report Action"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model.fields,field_description:report_csv.field_ir_actions_report__report_type
|
||||
msgid "Report Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "Text"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model.fields,help:report_csv.field_ir_actions_report__report_type
|
||||
msgid "The type of the report that will be rendered, each one having its own rendering method. HTML means the report will be opened directly in your browser PDF means the report will be rendered using Wkhtmltopdf and downloaded by the user."
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#. openerp-web
|
||||
#: code:addons/report_csv/static/src/js/report/qwebactionmanager.js:52
|
||||
#, python-format
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "XLSX"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "XML"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: selection:ir.actions.report,report_type:0
|
||||
msgid "csv"
|
||||
msgstr ""
|
||||
|
||||
#. module: report_csv
|
||||
#: model:ir.model,name:report_csv.model_report_report_csv_partner_csv
|
||||
msgid "report.report_csv.partner_csv"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1 @@
|
|||
from . import ir_report
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2019 Creu Blanca
|
||||
# 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=[("csv", "csv")])
|
||||
|
||||
@api.model
|
||||
def render_csv(self, docids, data):
|
||||
report_model_name = "report.%s" % self.report_name
|
||||
report_model = self.env.get(report_model_name)
|
||||
if report_model is None:
|
||||
raise UserError(_("%s model was not found" % report_model_name))
|
||||
return report_model.with_context(
|
||||
{"active_model": self.model}
|
||||
).create_csv_report(docids, data)
|
||||
|
||||
@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 = ["csv"]
|
||||
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)
|
|
@ -0,0 +1,3 @@
|
|||
* Enric Tobella <etobella@creublanca.es>
|
||||
* Jaime Arroyo <jaime.arroyo@creublanca.es>
|
||||
* Rattapong Chokmasermkul <rattapongc@ecosoft.co.th>
|
|
@ -0,0 +1 @@
|
|||
This module provides a basic report class to generate csv report.
|
|
@ -0,0 +1,38 @@
|
|||
An example of CSV report for partners on a module called `module_name`:
|
||||
|
||||
A python class ::
|
||||
|
||||
from odoo import models
|
||||
|
||||
class PartnerCSV(models.AbstractModel):
|
||||
_name = 'report.report_csv.partner_csv'
|
||||
_inherit = 'report.report_csv.abstract'
|
||||
|
||||
def generate_csv_report(self, writer, data, partners):
|
||||
writer.writeheader()
|
||||
for obj in partners:
|
||||
writer.writerow({
|
||||
'name': obj.name,
|
||||
'email': obj.email,
|
||||
})
|
||||
|
||||
def csv_report_options(self):
|
||||
res = super().csv_report_options()
|
||||
res['fieldnames'].append('name')
|
||||
res['fieldnames'].append('email')
|
||||
res['delimiter'] = ';'
|
||||
res['quoting'] = csv.QUOTE_ALL
|
||||
return res
|
||||
|
||||
|
||||
A report XML record ::
|
||||
|
||||
<report
|
||||
id="partner_csv"
|
||||
model="res.partner"
|
||||
string="Print to CSV"
|
||||
report_type="csv"
|
||||
name="module_name.report_name"
|
||||
file="res_partner"
|
||||
attachment_use="False"
|
||||
/>
|
|
@ -0,0 +1,2 @@
|
|||
from . import report_csv
|
||||
from . import report_partner_csv
|
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2019 Creu Blanca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
from io import StringIO
|
||||
|
||||
from odoo import models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import csv
|
||||
except ImportError:
|
||||
_logger.debug("Can not import csvwriter`.")
|
||||
|
||||
|
||||
class ReportCSVAbstract(models.AbstractModel):
|
||||
_name = "report.report_csv.abstract"
|
||||
_description = "Abstract Model for CSV reports"
|
||||
|
||||
def _get_objs_for_report(self, docids, data):
|
||||
"""
|
||||
Returns objects for csv report. From WebUI these
|
||||
are either as docids taken from context.active_ids or
|
||||
in the case of wizard are in data. Manual calls may rely
|
||||
on regular context, setting docids, or setting data.
|
||||
|
||||
:param docids: list of integers, typically provided by
|
||||
qwebactionmanager for regular Models.
|
||||
:param data: dictionary of data, if present typically provided
|
||||
by qwebactionmanager for TransientModels.
|
||||
:param ids: list of integers, provided by overrides.
|
||||
:return: recordset of active model for ids.
|
||||
"""
|
||||
if docids:
|
||||
ids = docids
|
||||
elif data and "context" in data:
|
||||
ids = data["context"].get("active_ids", [])
|
||||
else:
|
||||
ids = self.env.context.get("active_ids", [])
|
||||
return self.env[self.env.context.get("active_model")].browse(ids)
|
||||
|
||||
def create_csv_report(self, docids, data):
|
||||
objs = self._get_objs_for_report(docids, data)
|
||||
file_data = StringIO()
|
||||
file = csv.DictWriter(file_data, **self.csv_report_options())
|
||||
self.generate_csv_report(file, data, objs)
|
||||
file_data.seek(0)
|
||||
return file_data.read(), "csv"
|
||||
|
||||
def csv_report_options(self):
|
||||
"""
|
||||
:return: dictionary of parameters. At least return 'fieldnames', but
|
||||
you can optionally return parameters that define the export format.
|
||||
Valid parameters include 'delimiter', 'quotechar', 'escapechar',
|
||||
'doublequote', 'skipinitialspace', 'lineterminator', 'quoting'.
|
||||
"""
|
||||
return {"fieldnames": []}
|
||||
|
||||
def generate_csv_report(self, file, data, objs):
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright 2019 Creu Blanca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
import csv
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class PartnerCSV(models.AbstractModel):
|
||||
_name = "report.report_csv.partner_csv"
|
||||
_inherit = "report.report_csv.abstract"
|
||||
_description = "Report Partner to CSV"
|
||||
|
||||
def generate_csv_report(self, writer, data, partners):
|
||||
writer.writeheader()
|
||||
for obj in partners:
|
||||
writer.writerow({"name": obj.name, "email": obj.email})
|
||||
|
||||
def csv_report_options(self):
|
||||
res = super().csv_report_options()
|
||||
res["fieldnames"].append("name")
|
||||
res["fieldnames"].append("email")
|
||||
res["delimiter"] = ";"
|
||||
res["quoting"] = csv.QUOTE_ALL
|
||||
return res
|
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -0,0 +1,462 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
|
||||
<title>Base report csv</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: grey; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="base-report-csv">
|
||||
<h1 class="title">Base report csv</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0-mig-report_csv/report_csv"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0-mig-report_csv/reporting-engine-13-0-mig-report_csv-report_csv"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0-mig-report_csv"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module provides a basic report class to generate csv report.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
|
||||
<p>An example of CSV report for partners on a module called <cite>module_name</cite>:</p>
|
||||
<p>A python class</p>
|
||||
<pre class="literal-block">
|
||||
from odoo import models
|
||||
|
||||
class PartnerCSV(models.AbstractModel):
|
||||
_name = 'report.report_csv.partner_csv'
|
||||
_inherit = 'report.report_csv.abstract'
|
||||
|
||||
def generate_csv_report(self, writer, data, partners):
|
||||
writer.writeheader()
|
||||
for obj in partners:
|
||||
writer.writerow({
|
||||
'name': obj.name,
|
||||
'email': obj.email,
|
||||
})
|
||||
|
||||
def csv_report_options(self):
|
||||
res = super().csv_report_options()
|
||||
res['fieldnames'].append('name')
|
||||
res['fieldnames'].append('email')
|
||||
res['delimiter'] = ';'
|
||||
res['quoting'] = csv.QUOTE_ALL
|
||||
return res
|
||||
</pre>
|
||||
<p>A report XML record</p>
|
||||
<pre class="literal-block">
|
||||
<report
|
||||
id="partner_csv"
|
||||
model="res.partner"
|
||||
string="Print to CSV"
|
||||
report_type="csv"
|
||||
name="module_name.report_name"
|
||||
file="res_partner"
|
||||
attachment_use="False"
|
||||
/>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_csv%0Aversion:%2013.0-mig-report_csv%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Creu Blanca</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Enric Tobella <<a class="reference external" href="mailto:etobella@creublanca.es">etobella@creublanca.es</a>></li>
|
||||
<li>Jaime Arroyo <<a class="reference external" href="mailto:jaime.arroyo@creublanca.es">jaime.arroyo@creublanca.es</a>></li>
|
||||
<li>Rattapong Chokmasermkul <<a class="reference external" href="mailto:rattapongc@ecosoft.co.th">rattapongc@ecosoft.co.th</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0-mig-report_csv/report_csv">OCA/reporting-engine</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,88 @@
|
|||
// © 2019 Creu Blanca
|
||||
// License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
|
||||
odoo.define("report_csv.report", function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require("web.core");
|
||||
var ActionManager = require("web.ActionManager");
|
||||
var framework = require("web.framework");
|
||||
var session = require("web.session");
|
||||
var _t = core._t;
|
||||
|
||||
ActionManager.include({
|
||||
|
||||
_downloadReportCSV: function (url, actions) {
|
||||
var self = this;
|
||||
framework.blockUI();
|
||||
var type = "csv";
|
||||
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));
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var blocked = !session.get_file({
|
||||
url: url,
|
||||
data: {
|
||||
data: JSON.stringify([url, type]),
|
||||
},
|
||||
success: resolve,
|
||||
error: (error) => {
|
||||
self.call('crash_manager', 'rpc_error', error);
|
||||
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);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_triggerDownload: function (action, options, type) {
|
||||
var self = this;
|
||||
var reportUrls = this._makeReportUrls(action);
|
||||
if (type === "csv") {
|
||||
return this._downloadReportCSV(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.csv = '/report/csv/' + action.report_name;
|
||||
return reportUrls;
|
||||
},
|
||||
|
||||
_executeReportAction: function (action, options) {
|
||||
var self = this;
|
||||
if (action.report_type === 'csv') {
|
||||
return self._triggerDownload(action, options, 'csv');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
from . import test_report
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2019 Creu Blanca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
import logging
|
||||
from io import StringIO
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
try:
|
||||
import csv
|
||||
except ImportError:
|
||||
_logger.debug("Can not import csv.")
|
||||
|
||||
|
||||
class TestReport(common.TransactionCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
report_object = self.env["ir.actions.report"]
|
||||
self.csv_report = self.env["report.report_csv.abstract"].with_context(
|
||||
active_model="res.partner"
|
||||
)
|
||||
self.report_name = "report_csv.partner_csv"
|
||||
self.report = report_object._get_report_from_name(self.report_name)
|
||||
self.docs = self.env["res.company"].search([], limit=1).partner_id
|
||||
|
||||
def test_report(self):
|
||||
# Test if not res:
|
||||
self.env["ir.actions.report"]._get_report_from_name("TEST")
|
||||
report = self.report
|
||||
self.assertEqual(report.report_type, "csv")
|
||||
rep = report.render(self.docs.ids, {})
|
||||
str_io = StringIO(rep[0])
|
||||
dict_report = list(csv.DictReader(str_io, delimiter=";", quoting=csv.QUOTE_ALL))
|
||||
self.assertEqual(self.docs.name, dict(dict_report[0])["name"])
|
||||
|
||||
def test_id_retrieval(self):
|
||||
|
||||
# Typical call from WebUI with wizard
|
||||
objs = self.csv_report._get_objs_for_report(
|
||||
False, {"context": {"active_ids": self.docs.ids}}
|
||||
)
|
||||
self.assertEquals(objs, self.docs)
|
||||
|
||||
# Typical call from within code not to report_action
|
||||
objs = self.csv_report.with_context(
|
||||
active_ids=self.docs.ids
|
||||
)._get_objs_for_report(False, False)
|
||||
self.assertEquals(objs, self.docs)
|
||||
|
||||
# Typical call from WebUI
|
||||
objs = self.csv_report._get_objs_for_report(
|
||||
self.docs.ids, {"data": [self.report_name, self.report.report_type]}
|
||||
)
|
||||
self.assertEquals(objs, self.docs)
|
||||
|
||||
# Typical call from render
|
||||
objs = self.csv_report._get_objs_for_report(self.docs.ids, {})
|
||||
self.assertEquals(objs, self.docs)
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!--
|
||||
© 2019 Creu Blanca
|
||||
License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
|
||||
-->
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/report_csv/static/src/js/report/qwebactionmanager.js"/>
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
</odoo>
|
Loading…
Reference in New Issue