diff --git a/report_csv/README.rst b/report_csv/README.rst index db923a947..3bf42ab53 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 d6a1c3e0b..eb5a8a921 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 4a5ad6adf..01982668b 100644 --- a/report_csv/models/ir_report.py +++ b/report_csv/models/ir_report.py @@ -10,6 +10,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, report_ref, docids, data): @@ -17,7 +25,11 @@ class ReportAction(models.Model): report_model_name = "report.%s" % report_sudo.report_name report_model = self.env[report_model_name] return report_model.with_context( - active_model=report_sudo.model + **{ + "active_model": report_sudo.model, + "encoding": self.encoding, + "encode_error_handling": self.encode_error_handling, + } ).create_csv_report(docids, data) @api.model 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 fa278c7bb..ae198ff89 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 3436347f4..67644cd95 100644 --- a/report_csv/tests/test_report.py +++ b/report_csv/tests/test_report.py @@ -6,6 +6,7 @@ from io import StringIO from unittest import mock from odoo import http +from odoo.exceptions import UserError from odoo.tests import common from odoo.tools import mute_logger @@ -70,6 +71,18 @@ class TestReport(common.TransactionCase): 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.report_name, 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.report_name, self.docs.ids, {}) + class TestCsvReport(common.HttpCase): """ 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 + + + + + + + + +