From c75e7d169782a5801ee577ac68473dc885be8b6c Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Wed, 18 Jan 2023 08:49:07 +0630 Subject: [PATCH] [IMP] report_csv: add encoding option --- report_csv/README.rst | 18 ++++++++++ report_csv/__manifest__.py | 1 + report_csv/models/ir_report.py | 18 ++++++++-- report_csv/readme/CONFIGURE.rst | 9 +++++ report_csv/readme/CONTRIBUTORS.rst | 3 ++ report_csv/readme/USAGE.rst | 2 ++ report_csv/report/report_csv.py | 16 +++++++-- report_csv/static/description/index.html | 44 +++++++++++++++++------- report_csv/tests/test_report.py | 13 +++++++ report_csv/views/ir_actions_views.xml | 20 +++++++++++ 10 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 report_csv/readme/CONFIGURE.rst create mode 100644 report_csv/views/ir_actions_views.xml diff --git a/report_csv/README.rst b/report_csv/README.rst index 136642fae..15e598caa 100644 --- a/report_csv/README.rst +++ b/report_csv/README.rst @@ -35,6 +35,19 @@ This module provides a basic report class to generate csv report. .. contents:: :local: +Configuration +============= + +In case the exported CSV report should be encoded in another system than UTF-8, following +fields of the report record (*Settings > Technical > Reports*) should be populated accordingly. + +* Encoding: set an encoding system (such as cp932) +* Encode Error Handling: select 'Ignore' or 'Replace' as necessary. + + * 'Ignore': in case of an encoding error, the problematic character will be removed from the exported file. + * 'Replace': in case of an encoding error, the problematic character will be replaced with '?' symbol. + * Leaving the field blank: in case of an encoding error, the report generation fails with an error message. + Usage ===== @@ -77,6 +90,8 @@ A report XML record :: attachment_use="False" /> +Update encoding with an appropriate value (e.g. cp932) as necessary. + Bug Tracker =========== @@ -101,6 +116,9 @@ Contributors * Enric Tobella * Jaime Arroyo * Rattapong Chokmasermkul +* `Quartile `__: + + * Aung Ko Ko Lin Maintainers ~~~~~~~~~~~ diff --git a/report_csv/__manifest__.py b/report_csv/__manifest__.py index 0ee668415..e1e308459 100644 --- a/report_csv/__manifest__.py +++ b/report_csv/__manifest__.py @@ -10,6 +10,7 @@ "license": "AGPL-3", "depends": ["base", "web"], "demo": ["demo/report.xml"], + "data": ["views/ir_actions_views.xml"], "assets": { "web.assets_backend": [ "report_csv/static/src/js/report/qwebactionmanager.esm.js" diff --git a/report_csv/models/ir_report.py b/report_csv/models/ir_report.py index 47a7c412d..37f6a5c19 100644 --- a/report_csv/models/ir_report.py +++ b/report_csv/models/ir_report.py @@ -11,6 +11,14 @@ class ReportAction(models.Model): report_type = fields.Selection( selection_add=[("csv", "csv")], ondelete={"csv": "set default"} ) + encoding = fields.Char( + help="Encoding to be applied to the generated CSV file. e.g. cp932" + ) + encode_error_handling = fields.Selection( + selection=[("ignore", "Ignore"), ("replace", "Replace")], + help="If nothing is selected, CSV export will fail with an error message when " + "there is a character that fail to be encoded.", + ) @api.model def _render_csv(self, docids, data): @@ -18,9 +26,13 @@ class ReportAction(models.Model): 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 - ) + return report_model.with_context( + **{ + "active_model": self.model, + "encoding": self.encoding, + "encode_error_handling": self.encode_error_handling, + } + ).create_csv_report(docids, data) @api.model def _get_report_from_name(self, report_name): diff --git a/report_csv/readme/CONFIGURE.rst b/report_csv/readme/CONFIGURE.rst new file mode 100644 index 000000000..a0859d07d --- /dev/null +++ b/report_csv/readme/CONFIGURE.rst @@ -0,0 +1,9 @@ +In case the exported CSV report should be encoded in another system than UTF-8, following +fields of the report record (*Settings > Technical > Reports*) should be populated accordingly. + +* Encoding: set an encoding system (such as cp932) +* Encode Error Handling: select 'Ignore' or 'Replace' as necessary. + + * 'Ignore': in case of an encoding error, the problematic character will be removed from the exported file. + * 'Replace': in case of an encoding error, the problematic character will be replaced with '?' symbol. + * Leaving the field blank: in case of an encoding error, the report generation fails with an error message. diff --git a/report_csv/readme/CONTRIBUTORS.rst b/report_csv/readme/CONTRIBUTORS.rst index 1ee404f73..922a3262e 100644 --- a/report_csv/readme/CONTRIBUTORS.rst +++ b/report_csv/readme/CONTRIBUTORS.rst @@ -1,3 +1,6 @@ * Enric Tobella * Jaime Arroyo * Rattapong Chokmasermkul +* `Quartile `__: + + * Aung Ko Ko Lin diff --git a/report_csv/readme/USAGE.rst b/report_csv/readme/USAGE.rst index e5d9964cb..e6d22e382 100644 --- a/report_csv/readme/USAGE.rst +++ b/report_csv/readme/USAGE.rst @@ -36,3 +36,5 @@ A report XML record :: file="res_partner" attachment_use="False" /> + +Update encoding with an appropriate value (e.g. cp932) as necessary. diff --git a/report_csv/report/report_csv.py b/report_csv/report/report_csv.py index 0d9aeffdd..82fff5249 100644 --- a/report_csv/report/report_csv.py +++ b/report_csv/report/report_csv.py @@ -4,7 +4,8 @@ import logging from io import StringIO -from odoo import models +from odoo import _, models +from odoo.exceptions import UserError _logger = logging.getLogger(__name__) @@ -46,7 +47,18 @@ class ReportCSVAbstract(models.AbstractModel): 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" + encoding = self._context.get("encoding") + if not encoding: + return file_data.read(), "csv" + error_handling = self._context.get("encode_error_handling") + if error_handling: + return file_data.read().encode(encoding, errors=error_handling), "csv" + try: + return file_data.read().encode(encoding), "csv" + except Exception as e: + raise UserError( + _("Failed to encode the data with the encoding set in the report.") + ) from e def csv_report_options(self): """ diff --git a/report_csv/static/description/index.html b/report_csv/static/description/index.html index 28443266a..5f9c4446e 100644 --- a/report_csv/static/description/index.html +++ b/report_csv/static/description/index.html @@ -374,18 +374,33 @@ ul.auto-toc {

Table of contents

+
+

Configuration

+

In case the exported CSV report should be encoded in another system than UTF-8, following +fields of the report record (Settings > Technical > Reports) should be populated accordingly.

+
    +
  • Encoding: set an encoding system (such as cp932)
  • +
  • Encode Error Handling: select ‘Ignore’ or ‘Replace’ as necessary.
      +
    • ‘Ignore’: in case of an encoding error, the problematic character will be removed from the exported file.
    • +
    • ‘Replace’: in case of an encoding error, the problematic character will be replaced with ‘?’ symbol.
    • +
    • Leaving the field blank: in case of an encoding error, the report generation fails with an error message.
-

Usage

+

Usage

An example of CSV report for partners on a module called module_name:

A python class

@@ -423,9 +438,10 @@ class PartnerCSV(models.AbstractModel):
     attachment_use="False"
 />
 
+

Update encoding with an appropriate value (e.g. cp932) as necessary.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -433,23 +449,27 @@ If you spotted it first, help us to smash it by providing a detailed and welcome

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Creu Blanca
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose diff --git a/report_csv/tests/test_report.py b/report_csv/tests/test_report.py index cfaccc4ea..7d8cf02b3 100644 --- a/report_csv/tests/test_report.py +++ b/report_csv/tests/test_report.py @@ -3,6 +3,7 @@ import logging from io import StringIO +from odoo.exceptions import UserError from odoo.tests import common _logger = logging.getLogger(__name__) @@ -55,3 +56,15 @@ class TestReport(common.TransactionCase): # Typical call from render objs = self.csv_report._get_objs_for_report(self.docs.ids, {}) self.assertEqual(objs, self.docs) + + def test_report_with_encoding(self): + report = self.report + report.write({"encoding": "cp932"}) + rep = report._render_csv(self.docs.ids, {}) + str_io = StringIO(rep[0].decode()) + dict_report = list(csv.DictReader(str_io, delimiter=";", quoting=csv.QUOTE_ALL)) + self.assertEqual(self.docs.name, dict(dict_report[0])["name"]) + + report.write({"encoding": "xyz"}) + with self.assertRaises(UserError): + rep = report._render_csv(self.docs.ids, {}) diff --git a/report_csv/views/ir_actions_views.xml b/report_csv/views/ir_actions_views.xml new file mode 100644 index 000000000..d76fbeaf9 --- /dev/null +++ b/report_csv/views/ir_actions_views.xml @@ -0,0 +1,20 @@ + + + + ir.actions.report + ir.actions.report + + + + + + + + +