diff --git a/report_csv/__manifest__.py b/report_csv/__manifest__.py index 0aec029a4..d4d909afa 100644 --- a/report_csv/__manifest__.py +++ b/report_csv/__manifest__.py @@ -1,28 +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': '12.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, + "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": "12.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, } diff --git a/report_csv/controllers/main.py b/report_csv/controllers/main.py index f5c10980e..700a75a56 100644 --- a/report_csv/controllers/main.py +++ b/report_csv/controllers/main.py @@ -1,58 +1,55 @@ # Copyright (C) 2019 Creu Blanca # License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). -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 - 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) + 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'): + 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 = "%s.%s" % (report.name, "csv") + 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 = "%s.%s" % (report_name, "csv") + {"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 = "%s.%s" % (report_name, "csv") + {"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) - ) + ("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( diff --git a/report_csv/models/ir_report.py b/report_csv/models/ir_report.py index 7259f9dd4..9865cff75 100644 --- a/report_csv/models/ir_report.py +++ b/report_csv/models/ir_report.py @@ -1,33 +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 import _, api, fields, models from odoo.exceptions import UserError class ReportAction(models.Model): - _inherit = 'ir.actions.report' + _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_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) + 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() + 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) diff --git a/report_csv/report/report_csv.py b/report_csv/report/report_csv.py index 51d87d195..0d9aeffdd 100644 --- a/report_csv/report/report_csv.py +++ b/report_csv/report/report_csv.py @@ -1,22 +1,22 @@ # 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 -import logging _logger = logging.getLogger(__name__) try: import csv except ImportError: - _logger.debug('Can not import csvwriter`.') + _logger.debug("Can not import csvwriter`.") class ReportCSVAbstract(models.AbstractModel): - _name = 'report.report_csv.abstract' - _description = 'Abstract Model for CSV reports' + _name = "report.report_csv.abstract" + _description = "Abstract Model for CSV reports" def _get_objs_for_report(self, docids, data): """ @@ -34,11 +34,11 @@ class ReportCSVAbstract(models.AbstractModel): """ if docids: ids = docids - elif data and 'context' in data: - ids = data["context"].get('active_ids', []) + 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) + 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) @@ -46,7 +46,7 @@ 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' + return file_data.read(), "csv" def csv_report_options(self): """ @@ -55,7 +55,7 @@ class ReportCSVAbstract(models.AbstractModel): Valid parameters include 'delimiter', 'quotechar', 'escapechar', 'doublequote', 'skipinitialspace', 'lineterminator', 'quoting'. """ - return {'fieldnames': []} + return {"fieldnames": []} def generate_csv_report(self, file, data, objs): raise NotImplementedError() diff --git a/report_csv/report/report_partner_csv.py b/report_csv/report/report_partner_csv.py index 1fe897a82..904a2e2b5 100644 --- a/report_csv/report/report_partner_csv.py +++ b/report_csv/report/report_partner_csv.py @@ -1,25 +1,23 @@ # 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' + _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, - }) + 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 + res["fieldnames"].append("name") + res["fieldnames"].append("email") + res["delimiter"] = ";" + res["quoting"] = csv.QUOTE_ALL return res diff --git a/report_csv/tests/test_report.py b/report_csv/tests/test_report.py index 0bd53e8a4..84c9a112d 100644 --- a/report_csv/tests/test_report.py +++ b/report_csv/tests/test_report.py @@ -1,52 +1,53 @@ # Copyright 2019 Creu Blanca # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from io import StringIO -from odoo.tests import common 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.') + _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') + 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_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 + self.docs = self.env["res.company"].search([], limit=1).partner_id def test_report(self): report = self.report - self.assertEqual(report.report_type, 'csv') + 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']) + 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}}) + 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) + 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.docs.ids, {"data": [self.report_name, self.report.report_type]} ) self.assertEquals(objs, self.docs)