diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 0915d8c3..166e89a4 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -7,7 +7,7 @@ name: pre-commit on: push: branches: "*.0" - pull_request: + pull_request_target: jobs: pre-commit: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e0cca51..0b82f519 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ exclude: | (?x) - + # We don't want to mess with tool-generated files .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|^eslint.config.cjs|^prettier.config.cjs| # Library files can have extraneous formatting (even minimized) diff --git a/attachment_s3/__manifest__.py b/attachment_s3/__manifest__.py index d98005e3..4ff545dc 100644 --- a/attachment_s3/__manifest__.py +++ b/attachment_s3/__manifest__.py @@ -15,5 +15,5 @@ }, "website": "https://github.com/camptocamp/odoo-cloud-platform", "data": [], - 'installable': False, + "installable": False, } diff --git a/attachment_s3/models/ir_attachment.py b/attachment_s3/models/ir_attachment.py index 416fc889..6cef8e42 100644 --- a/attachment_s3/models/ir_attachment.py +++ b/attachment_s3/models/ir_attachment.py @@ -23,7 +23,7 @@ _logger.debug("Cannot 'import boto3'.") -class S3BucketClientRegistry(object): +class S3BucketClientRegistry: bucket_dict = {} @classmethod @@ -131,9 +131,7 @@ def _store_file_read(self, fname): try: bucket = self._get_s3_bucket(name=s3uri.bucket()) except exceptions.UserError: - _logger.exception( - "error reading attachment '%s' from object storage", fname - ) + _logger.exception("error reading attachment '%s' from object storage", fname) return "" try: key = s3uri.item() @@ -164,7 +162,7 @@ def _store_file_write(self, key, bin_data): # TODO handle this on a better way try: if obj.content_length: - _logger.info('Skip uploading object %s, already exists', filename) + _logger.info("Skip uploading object %s, already exists", filename) return filename except Exception: pass @@ -173,9 +171,7 @@ def _store_file_write(self, key, bin_data): except ClientError as error: # log verbose error from s3, return short message for user _logger.exception("Error during storage of the file %s" % filename) - raise exceptions.UserError( - _("The file could not be stored: %s") % str(error) - ) from None + raise exceptions.UserError(_("The file could not be stored: %s") % str(error)) from None else: _super = super() filename = _super._store_file_write(key, bin_data) diff --git a/attachment_s3/s3uri.py b/attachment_s3/s3uri.py index a7054ebd..5bbe11a2 100644 --- a/attachment_s3/s3uri.py +++ b/attachment_s3/s3uri.py @@ -4,8 +4,7 @@ import re -class S3Uri(object): - +class S3Uri: _url_re = re.compile("^s3:///*([^/]*)/?(.*)", re.IGNORECASE | re.UNICODE) def __init__(self, uri): diff --git a/base_dynamic_message/__manifest__.py b/base_dynamic_message/__manifest__.py index 44904b87..234dcaf0 100644 --- a/base_dynamic_message/__manifest__.py +++ b/base_dynamic_message/__manifest__.py @@ -18,27 +18,25 @@ # ############################################################################## { - 'name': 'Dynamic Message', - 'version': "18.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Dynamic Message", + "version": "18.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "base", ], - 'depends': [ - 'base', + "data": [ + "security/res_groups.xml", + "security/ir.model.access.csv", + "views/ir_model_dynamic_message_views.xml", ], - 'data': [ - 'security/res_groups.xml', - 'security/ir.model.access.csv', - 'views/ir_model_dynamic_message_views.xml', - ], - 'demo': [ - ], - 'installable': True, - 'auto_install': False, - 'application': False, + "demo": [], + "installable": True, + "auto_install": False, + "application": False, } diff --git a/base_dynamic_message/models/ir_model_dynamic_message.py b/base_dynamic_message/models/ir_model_dynamic_message.py index 69ea03c7..9885c238 100644 --- a/base_dynamic_message/models/ir_model_dynamic_message.py +++ b/base_dynamic_message/models/ir_model_dynamic_message.py @@ -1,37 +1,42 @@ -from odoo import models, fields, api import ast import textwrap +from odoo import api, fields, models + class IrModelDynamicMessage(models.Model): - _name = 'ir.model.dynamic_message' - _description = 'ir.model.dynamic_message' + _name = "ir.model.dynamic_message" + _description = "ir.model.dynamic_message" name = fields.Char(required=True) description = fields.Text() - model_id = fields.Many2one('ir.model', required=True, ondelete='cascade') - model_name = fields.Char(related='model_id.model', string='Model Name') - line_ids = fields.One2many('ir.model.dynamic_message.line', 'dynamic_message_id', copy=True) - code = fields.Text(compute='_compute_code') - depends = fields.Char(compute='_compute_depends', store=True, readonly=False, required=True) - field_id = fields.Many2one('ir.model.fields', readonly=True, copy=False) + model_id = fields.Many2one("ir.model", required=True, ondelete="cascade") + model_name = fields.Char(related="model_id.model", string="Model Name") + line_ids = fields.One2many("ir.model.dynamic_message.line", "dynamic_message_id", copy=True) + code = fields.Text(compute="_compute_code") + depends = fields.Char(compute="_compute_depends", store=True, readonly=False, required=True) + field_id = fields.Many2one("ir.model.fields", readonly=True, copy=False) view_to_inherit_id = fields.Many2one( - 'ir.ui.view', compute='_compute_view_to_inherit', readonly=False, store=True, required=True) - view_id = fields.Many2one('ir.ui.view', readonly=True, copy=False) - alert_type = fields.Selection([('info', 'info'), ('warning', 'warning'), ('danger', 'danger')], required=True, default='info') + "ir.ui.view", compute="_compute_view_to_inherit", readonly=False, store=True, required=True + ) + view_id = fields.Many2one("ir.ui.view", readonly=True, copy=False) + alert_type = fields.Selection( + [("info", "info"), ("warning", "warning"), ("danger", "danger")], required=True, default="info" + ) - @api.depends('model_id') + @api.depends("model_id") def _compute_view_to_inherit(self): for rec in self: - rec.view_to_inherit_id = rec.env['ir.ui.view'].search( - [('type', '=', 'form'), ('model', '=', rec.model_id.model), ('mode', '=', 'primary')], limit=1) + rec.view_to_inherit_id = rec.env["ir.ui.view"].search( + [("type", "=", "form"), ("model", "=", rec.model_id.model), ("mode", "=", "primary")], limit=1 + ) - @api.depends('line_ids.code') + @api.depends("line_ids.code") def _compute_code(self): for rec in self: - sub_string = ''.join(rec.line_ids.filtered('code').mapped('code')) - sub_string = textwrap.indent(sub_string, prefix=' ') - field_name = 'x_dynamic_message_%i' % rec._origin.id or 0 + sub_string = "".join(rec.line_ids.filtered("code").mapped("code")) + sub_string = textwrap.indent(sub_string, prefix=" ") + field_name = "x_dynamic_message_%i" % rec._origin.id or 0 rec.code = """ for rec in self: messages = [] @@ -42,34 +47,34 @@ def _compute_code(self): rec['%s'] = "" %% "".join(["
  • %%s
  • " %% message for message in messages]) """ % (sub_string, field_name, field_name) - @api.depends('line_ids.domain') + @api.depends("line_ids.domain") def _compute_depends(self): for rec in self: dep_fields = [] - for line in rec.line_ids.filtered('domain'): + for line in rec.line_ids.filtered("domain"): domain = ast.literal_eval(line.domain) for element in domain: if type(element) is not tuple: continue # TODO deberiamos chequear que el campo sea sercheable (en smart search teniamos algo de esto) - if '.' in element[0]: - dep_fields.append(element[0].split('.')[0]) - elif element[0] != 'id': + if "." in element[0]: + dep_fields.append(element[0].split(".")[0]) + elif element[0] != "id": dep_fields.append(element[0]) - rec.depends = ','.join(list(set(dep_fields))) if dep_fields else False + rec.depends = ",".join(list(set(dep_fields))) if dep_fields else False def confirm(self): for rec in self: - field_name = 'x_dynamic_message_%i' % rec.id + field_name = "x_dynamic_message_%i" % rec.id field_vals = { - 'name': field_name, - 'field_description': 'Dynamic Message', - 'state': 'manual', - 'store': False, - 'ttype': 'html', - 'model_id': rec.model_id.id, - 'compute': rec.code, - 'depends': rec.depends, + "name": field_name, + "field_description": "Dynamic Message", + "state": "manual", + "store": False, + "ttype": "html", + "model_id": rec.model_id.id, + "compute": rec.code, + "depends": rec.depends, } if rec.field_id: rec.field_id.sudo().write(field_vals) @@ -77,17 +82,18 @@ def confirm(self): rec.field_id = rec.field_id.sudo().create(field_vals) view_vals = { - 'name': 'Dynamic Message for %s' % rec.model_id.name, - 'inherit_id': rec.view_to_inherit_id.id, - 'model': rec.model_id.model, - 'priority': 999, - 'arch_db': """ + "name": "Dynamic Message for %s" % rec.model_id.name, + "inherit_id": rec.view_to_inherit_id.id, + "model": rec.model_id.model, + "priority": 999, + "arch_db": """ -""" % (rec.alert_type, field_name, field_name), +""" + % (rec.alert_type, field_name, field_name), } if rec.view_id: rec.view_id.sudo().write(view_vals) @@ -96,11 +102,13 @@ def confirm(self): @api.ondelete(at_uninstall=True) def _delete_field_and_view(self): - self.mapped('field_id').sudo().unlink() - self.mapped('view_id').sudo().unlink() + self.mapped("field_id").sudo().unlink() + self.mapped("view_id").sudo().unlink() _sql_constraints = [ ( - 'unique_level_per_model', 'UNIQUE(model_id, alert_type, view_to_inherit_id)', - 'Debe haber un unico registro por modelo, vista heredada y tipo de alerta') + "unique_level_per_model", + "UNIQUE(model_id, alert_type, view_to_inherit_id)", + "Debe haber un unico registro por modelo, vista heredada y tipo de alerta", + ) ] diff --git a/base_dynamic_message/models/ir_model_dynamic_message_line.py b/base_dynamic_message/models/ir_model_dynamic_message_line.py index 3b7fb837..ce4d052a 100644 --- a/base_dynamic_message/models/ir_model_dynamic_message_line.py +++ b/base_dynamic_message/models/ir_model_dynamic_message_line.py @@ -1,19 +1,22 @@ -from odoo import models, fields, api import re +from odoo import api, fields, models + class IrModelDynamicMessageLine(models.Model): - _name = 'ir.model.dynamic_message.line' - _description = 'ir.model.dynamic_message.line' + _name = "ir.model.dynamic_message.line" + _description = "ir.model.dynamic_message.line" - dynamic_message_id = fields.Many2one('ir.model.dynamic_message', required=True, ondelete='cascade') + dynamic_message_id = fields.Many2one("ir.model.dynamic_message", required=True, ondelete="cascade") description = fields.Text() domain = fields.Char() - message = fields.Html(required=True,) - model_name = fields.Char(related='dynamic_message_id.model_id.model') - code = fields.Text(compute='_compute_code', store=True, readonly=False) + message = fields.Html( + required=True, + ) + model_name = fields.Char(related="dynamic_message_id.model_id.model") + code = fields.Text(compute="_compute_code", store=True, readonly=False) - @api.depends('message', 'domain') + @api.depends("message", "domain") def _compute_code(self): for rec in self: if rec.domain: @@ -34,7 +37,7 @@ def _compute_code(self): rec.code = """ if rec in rec.filtered_domain(%s): messages.append('%s') -""" % (domain, str(rec.message).replace('

    ', '').replace('

    ', '')) +""" % (domain, str(rec.message).replace("

    ", "").replace("

    ", "")) else: rec.code = False # code = self.filtered_domain(self.env['account.payment.method']._get_payment_method_domain(payment_method_code)) diff --git a/base_exception_ux/__manifest__.py b/base_exception_ux/__manifest__.py index d2c8cca0..b2884272 100644 --- a/base_exception_ux/__manifest__.py +++ b/base_exception_ux/__manifest__.py @@ -18,22 +18,20 @@ # ############################################################################## { - 'name': 'Base Exception UX', - 'version': "16.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'depends': [ - 'base_exception', + "name": "Base Exception UX", + "version": "16.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "depends": [ + "base_exception", ], - 'data': [ - ], - 'demo': [ - ], - 'installable': False, - 'auto_install': True, - 'application': False, + "data": [], + "demo": [], + "installable": False, + "auto_install": True, + "application": False, } diff --git a/base_exception_ux/models/base_exception_method.py b/base_exception_ux/models/base_exception_method.py index 1730adf1..baffe2f9 100644 --- a/base_exception_ux/models/base_exception_method.py +++ b/base_exception_ux/models/base_exception_method.py @@ -6,9 +6,11 @@ class BaseExceptionMethod(models.AbstractModel): _inherit = "base.exception.method" def _exception_rule_eval_context(self, rec): - time = wrap_module(__import__('time'), ['time', 'strptime', 'strftime', 'sleep', 'gmtime']) + time = wrap_module(__import__("time"), ["time", "strptime", "strftime", "sleep", "gmtime"]) eval_context = super()._exception_rule_eval_context(rec) - eval_context.update({ - 'time': time, - }) + eval_context.update( + { + "time": time, + } + ) return eval_context diff --git a/base_report_to_print_node/__manifest__.py b/base_report_to_print_node/__manifest__.py index 2523e277..9ebbe9c9 100644 --- a/base_report_to_print_node/__manifest__.py +++ b/base_report_to_print_node/__manifest__.py @@ -25,5 +25,5 @@ "license": "AGPL-3", "depends": ["base_report_to_printer"], "data": ["wizards/res_config_settings_view.xml"], - 'installable': False, + "installable": False, } diff --git a/base_report_to_print_node/models/ir_actions_report.py b/base_report_to_print_node/models/ir_actions_report.py index 79135872..fc24676a 100644 --- a/base_report_to_print_node/models/ir_actions_report.py +++ b/base_report_to_print_node/models/ir_actions_report.py @@ -1,5 +1,3 @@ - - from odoo import models diff --git a/base_report_to_print_node/models/printing_printer.py b/base_report_to_print_node/models/printing_printer.py index 653bda24..bcb8e951 100644 --- a/base_report_to_print_node/models/printing_printer.py +++ b/base_report_to_print_node/models/printing_printer.py @@ -20,7 +20,6 @@ class PrintingPrinter(models.Model): - _inherit = "printing.printer" print_node_printer = fields.Boolean(string="Print Node Printer?") @@ -71,13 +70,12 @@ def update_print_node_printers_status(self): printer.write(vals) def print_document(self, report, content, **print_opts): - """ Print a file + """Print a file Format could be pdf, qweb-pdf, raw, ... """ if len(self) != 1: _logger.error( - "Print Node print called with %s but singleton is expeted." - "Check printers configuration." % self + "Print Node print called with %s but singleton is expeted." "Check printers configuration." % self ) return super().print_document(report, content, **print_opts) @@ -96,13 +94,14 @@ def print_document(self, report, content, **print_opts): try: res = self._submit_job( - self.uri, options.get("format", "pdf"), file_name, options, + self.uri, + options.get("format", "pdf"), + file_name, + options, ) - _logger.info("Printing job '{}' for document {}".format(res, file_name)) + _logger.info(f"Printing job '{res}' for document {file_name}") except Exception as e: - _logger.error( - "Could not submit job to print node. This is what we get:\n%s" % e - ) + _logger.error("Could not submit job to print node. This is what we get:\n%s" % e) return True def enable(self): @@ -112,9 +111,7 @@ def enable(self): def disable(self): print_node_printers = self.filtered("print_node_printer") - print_node_printers.write( - {"status": "unavailable", "status_message": "disabled by user"} - ) + print_node_printers.write({"status": "unavailable", "status_message": "disabled by user"}) return super(PrintingPrinter, self - print_node_printers).disable() # API interaction @@ -122,21 +119,21 @@ def disable(self): @api.model def ReadFile(self, pathname): """Read contents of a file and return content. - Args: - pathname: string, (path)name of file. - Returns: - string: contents of file. + Args: + pathname: string, (path)name of file. + Returns: + string: contents of file. """ try: f = open(pathname, "rb") try: s = f.read() - except IOError as error: + except OSError as error: _logger.info("Error reading %s\n%s", pathname, error) finally: f.close() return s - except IOError as error: + except OSError as error: _logger.error("Error opening %s\n%s", pathname, error) return None @@ -164,7 +161,7 @@ def _submit_job(self, printerid, jobtype, jobsrc, options): # Make the title unique for each job, since the printer by default will # name the print job file the same as the title. datehour = time.strftime("%b%d%H%M", time.localtime()) - title = "{}{}".format(datehour, jobsrc) + title = f"{datehour}{jobsrc}" data = { "printerId": printerid, @@ -177,18 +174,14 @@ def _submit_job(self, printerid, jobtype, jobsrc, options): @api.model def _get_response(self, service, data=None): - api_key = ( - self.env["ir.config_parameter"] - .sudo() - .get_param("base_report_to_print_node.api_key") - ) + api_key = self.env["ir.config_parameter"].sudo().get_param("base_report_to_print_node.api_key") if not api_key: dummy, action_id = self.env["ir.model.data"].get_object_reference( "base_setup", "action_general_configuration" ) msg = _("You haven't configured your 'Print Node Api Key'.") raise RedirectWarning(msg, action_id, _("Go to the configuration panel")) - request_url = "{}/{}".format(PRINTNODE_URL, service) + request_url = f"{PRINTNODE_URL}/{service}" headers = { "authorization": "Basic " + base64.b64encode(api_key.encode("UTF-8")).decode("UTF-8"), } @@ -199,7 +192,5 @@ def _get_response(self, service, data=None): req = urllib.request.Request(request_url, data_json, headers) response = urllib.request.urlopen(req, timeout=TIMEOUT).read() except HTTPError: - raise UserError( - _("Could not connect to print node. Check your configuration") - ) + raise UserError(_("Could not connect to print node. Check your configuration")) return json.loads(response.decode("utf-8")) diff --git a/base_report_to_print_node/wizards/res_config_settings.py b/base_report_to_print_node/wizards/res_config_settings.py index 8ce3ba77..5ecf50d6 100644 --- a/base_report_to_print_node/wizards/res_config_settings.py +++ b/base_report_to_print_node/wizards/res_config_settings.py @@ -3,11 +3,9 @@ # directory ############################################################################## from odoo import fields, models -from odoo.exceptions import UserError class ResConfigSettings(models.TransientModel): - _inherit = "res.config.settings" print_node_api_key = fields.Char( diff --git a/base_ux/__manifest__.py b/base_ux/__manifest__.py index ec098966..7fed0379 100644 --- a/base_ux/__manifest__.py +++ b/base_ux/__manifest__.py @@ -18,30 +18,27 @@ # ############################################################################## { - 'name': 'Base UX', - 'version': "18.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Base UX", + "version": "18.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "base", + "mail", # depends on mail for tracking on fields ], - 'depends': [ - 'base', - 'mail', # depends on mail for tracking on fields + "data": [ + "views/ir_actions_act_window_view.xml", + "views/mail_template_view.xml", + "views/res_company_view.xml", ], - 'data': [ - 'views/ir_actions_act_window_view.xml', - 'views/mail_template_view.xml', - 'views/res_company_view.xml', - ], - 'demo': [ - ], - 'test': [ - ], - 'installable': True, - 'auto_install': False, - 'application': False, + "demo": [], + "test": [], + "installable": True, + "auto_install": False, + "application": False, } diff --git a/base_ux/models/ir_actions_act_window.py b/base_ux/models/ir_actions_act_window.py index fba60cd7..fb0b7ee1 100644 --- a/base_ux/models/ir_actions_act_window.py +++ b/base_ux/models/ir_actions_act_window.py @@ -1,24 +1,23 @@ -from odoo import models, api +from odoo import api, models class IrActionsActWindow(models.Model): - _inherit = 'ir.actions.act_window' + _inherit = "ir.actions.act_window" def create_action(self): - """ Create a contextual action for each act window. """ - model = self.env['ir.model'] - for rec in self.filtered('res_model'): - res_model = model.search([('model', '=', rec.res_model)]) - rec.write({'binding_model_id': res_model.id, - 'binding_type': 'action'}) + """Create a contextual action for each act window.""" + model = self.env["ir.model"] + for rec in self.filtered("res_model"): + res_model = model.search([("model", "=", rec.res_model)]) + rec.write({"binding_model_id": res_model.id, "binding_type": "action"}) return True def unlink_action(self): - """ Remove the contextual actions created for the act window. """ - self.check_access_rights('write', raise_exception=True) - self.filtered('binding_model_id').write({'binding_model_id': False}) + """Remove the contextual actions created for the act window.""" + self.check_access_rights("write", raise_exception=True) + self.filtered("binding_model_id").write({"binding_model_id": False}) return True - @api.onchange('res_model') + @api.onchange("res_model") def update_binding_model_id(self): self.binding_model_id = False diff --git a/base_ux/models/ir_actions_server.py b/base_ux/models/ir_actions_server.py index c48dbf26..cc258119 100644 --- a/base_ux/models/ir_actions_server.py +++ b/base_ux/models/ir_actions_server.py @@ -1,19 +1,21 @@ -from odoo import models, api +from odoo import api, models from odoo.tools import html2plaintext from odoo.tools.safe_eval import wrap_module -class IrActionsServer(models.Model): - _inherit = 'ir.actions.server' +class IrActionsServer(models.Model): + _inherit = "ir.actions.server" - re = wrap_module(__import__('re'), []) + re = wrap_module(__import__("re"), []) @api.model def _get_eval_context(self, action=None): - """ Enable re python library to regex search and html2plaintext function from odoo tools """ + """Enable re python library to regex search and html2plaintext function from odoo tools""" eval_context = super()._get_eval_context(action=action) - eval_context.update({ - 're': self.re, - 'html2plaintext': html2plaintext, - }) + eval_context.update( + { + "re": self.re, + "html2plaintext": html2plaintext, + } + ) return eval_context diff --git a/base_ux/models/mail_activity.py b/base_ux/models/mail_activity.py index 33236f11..2ae4cb4b 100644 --- a/base_ux/models/mail_activity.py +++ b/base_ux/models/mail_activity.py @@ -2,20 +2,21 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import api, fields, models +from odoo import api, models + class MailActivity(models.Model): - _inherit = 'mail.activity' + _inherit = "mail.activity" - @api.onchange('activity_type_id') + @api.onchange("activity_type_id") def _onchange_activity_type_id(self): - """ overrides original method: keep the activity description when + """overrides original method: keep the activity description when changing the activity type, regardless of the activity type's description, - and change the activity user only if the activity type has a default user """ + and change the activity user only if the activity type has a default user""" note = self.note user = self.user_id super()._onchange_activity_type_id() if user and user != self.user_id and not self.activity_type_id.default_user_id: self.user_id = user - if note != '


    ' and note != False and note != self.note: + if note != "


    " and note != False and note != self.note: self.note = note diff --git a/base_ux/models/mail_template.py b/base_ux/models/mail_template.py index 89ca538b..e2914e16 100644 --- a/base_ux/models/mail_template.py +++ b/base_ux/models/mail_template.py @@ -2,11 +2,11 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import models, fields +from odoo import fields, models class MailTemplate(models.Model): - _inherit = 'mail.template' + _inherit = "mail.template" active = fields.Boolean( default=True, diff --git a/base_ux/models/res_company.py b/base_ux/models/res_company.py index ad3a4438..a9d3c4a3 100644 --- a/base_ux/models/res_company.py +++ b/base_ux/models/res_company.py @@ -2,11 +2,11 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import models, fields +from odoo import fields, models class ResCompany(models.Model): - _inherit = 'res.company' + _inherit = "res.company" active = fields.Boolean( default=True, diff --git a/base_ux/models/res_country_state.py b/base_ux/models/res_country_state.py index b9f5e2e7..c4d82fe0 100644 --- a/base_ux/models/res_country_state.py +++ b/base_ux/models/res_country_state.py @@ -6,7 +6,6 @@ class ResCountryState(models.Model): + _inherit = "res.country.state" - _inherit = 'res.country.state' - - _order = 'country_id,name' + _order = "country_id,name" diff --git a/base_ux/models/res_partner.py b/base_ux/models/res_partner.py index d2189ced..20e847b7 100644 --- a/base_ux/models/res_partner.py +++ b/base_ux/models/res_partner.py @@ -2,10 +2,10 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import models, fields +from odoo import fields, models class ResPartner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" active = fields.Boolean(tracking=True) diff --git a/mail_activity_automation/__manifest__.py b/mail_activity_automation/__manifest__.py index d5b6ad75..f224ce54 100644 --- a/mail_activity_automation/__manifest__.py +++ b/mail_activity_automation/__manifest__.py @@ -1,23 +1,21 @@ - { - 'name': 'Mail Activity Automation', - 'version': "18.0.1.0.0", - 'category': 'Communications', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Mail Activity Automation", + "version": "18.0.1.0.0", + "category": "Communications", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "mail", ], - 'depends': [ - 'mail', + "data": [ + "views/mail_activity_type_views.xml", + "data/ir_cron_data.xml", ], - 'data': [ - 'views/mail_activity_type_views.xml', - 'data/ir_cron_data.xml', - ], - 'installable': True, - 'auto_install': False, - 'application': False, + "installable": True, + "auto_install": False, + "application": False, } diff --git a/mail_activity_automation/models/mail_activity.py b/mail_activity_automation/models/mail_activity.py index 06203f68..dd95284a 100644 --- a/mail_activity_automation/models/mail_activity.py +++ b/mail_activity_automation/models/mail_activity.py @@ -1,20 +1,22 @@ -from odoo import models import datetime +from odoo import models + class MailActivity(models.Model): _inherit = "mail.activity" def _cron_run_activities(self): - activities = self.search([('activity_type_id.run_automatically', '=', True), ('date_deadline', '<=', datetime.date.today())]) + activities = self.search( + [("activity_type_id.run_automatically", "=", True), ("date_deadline", "<=", datetime.date.today())] + ) for activity in activities: activity.with_context(from_bot=True).action_done_schedule_next() def _action_done(self, feedback=False, attachment_ids=None): - if self._context.get('from_bot') and self.activity_type_id.mail_template_ids: + if self._context.get("from_bot") and self.activity_type_id.mail_template_ids: for mail_template in self.activity_type_id.mail_template_ids: self.env[self.res_model].browse(self.res_id).message_post_with_source( - mail_template, - subtype_xmlid='mail.mt_comment' + mail_template, subtype_xmlid="mail.mt_comment" ) return super()._action_done(feedback=feedback, attachment_ids=attachment_ids) diff --git a/mail_activity_automation/models/mail_activity_type.py b/mail_activity_automation/models/mail_activity_type.py index 3ea2da7e..f47ad10d 100644 --- a/mail_activity_automation/models/mail_activity_type.py +++ b/mail_activity_automation/models/mail_activity_type.py @@ -1,11 +1,9 @@ -from odoo import models, fields, api +from odoo import fields, models class MailActivityType(models.Model): _inherit = "mail.activity.type" - run_automatically = fields.Boolean(help="Si marca esta opción, llegada la fecha de vencimiento, se enviará la plantilla seleccionada y se marcará la actividad como realizado.") - - - - + run_automatically = fields.Boolean( + help="Si marca esta opción, llegada la fecha de vencimiento, se enviará la plantilla seleccionada y se marcará la actividad como realizado." + ) diff --git a/mail_activity_board_ux/__manifest__.py b/mail_activity_board_ux/__manifest__.py index 4c7123cb..88b1fe2d 100644 --- a/mail_activity_board_ux/__manifest__.py +++ b/mail_activity_board_ux/__manifest__.py @@ -18,32 +18,29 @@ # ############################################################################## { - 'name': 'Mail Activity Board UX', - 'version': "17.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'depends': [ - 'mail_activity_board', + "name": "Mail Activity Board UX", + "version": "17.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "depends": [ + "mail_activity_board", ], - 'external_dependencies': { - }, - 'data': [ - 'views/mail_activity_views.xml', + "external_dependencies": {}, + "data": [ + "views/mail_activity_views.xml", ], "assets": { "web.assets_backend": [ - ('remove', 'mail_activity_board/static/src/components/chatter/chatter.xml'), + ("remove", "mail_activity_board/static/src/components/chatter/chatter.xml"), ], }, - 'demo': [ - ], - 'test': [ - ], - 'installable': False, - 'auto_install': False, - 'application': False, + "demo": [], + "test": [], + "installable": False, + "auto_install": False, + "application": False, } diff --git a/mail_activity_board_ux/models/mail_activity.py b/mail_activity_board_ux/models/mail_activity.py index c35b7f65..5a721fc4 100644 --- a/mail_activity_board_ux/models/mail_activity.py +++ b/mail_activity_board_ux/models/mail_activity.py @@ -7,11 +7,11 @@ class MailActivity(models.Model): def open_activity_dashboard_form(self): return { - 'type': 'ir.actions.act_window', - 'res_model': self._name, - 'view_type': 'form', - 'view_mode': 'form', - 'target': 'current', - 'res_id': self.id, - 'context': dict(self._context), + "type": "ir.actions.act_window", + "res_model": self._name, + "view_type": "form", + "view_mode": "form", + "target": "current", + "res_id": self.id, + "context": dict(self._context), } diff --git a/mail_internal/__init__.py b/mail_internal/__init__.py index 41eb4adc..5cb1c491 100644 --- a/mail_internal/__init__.py +++ b/mail_internal/__init__.py @@ -1 +1 @@ -from . import wizards \ No newline at end of file +from . import wizards diff --git a/mail_internal/__manifest__.py b/mail_internal/__manifest__.py index ba07d08a..5babe0bb 100644 --- a/mail_internal/__manifest__.py +++ b/mail_internal/__manifest__.py @@ -1,23 +1,23 @@ { - 'name': 'Mail Internal', - 'version': '13.0.1.0.0', - 'category': 'Communications', - 'sequence': 2, - 'summary': 'Internal Messaging', - 'author': 'ADHOC SA', - 'website': 'http://www.adhoc.com/ar', - 'license': 'AGPL-3', - 'depends': [ - 'mail', + "name": "Mail Internal", + "version": "13.0.1.0.0", + "category": "Communications", + "sequence": 2, + "summary": "Internal Messaging", + "author": "ADHOC SA", + "website": "http://www.adhoc.com/ar", + "license": "AGPL-3", + "depends": [ + "mail", ], - 'data': [ - 'views/assets.xml', - 'data/mail_message_subtype_data.xml', - 'wizards/mail_compose_message_views.xml', + "data": [ + "views/assets.xml", + "data/mail_message_subtype_data.xml", + "wizards/mail_compose_message_views.xml", ], - 'qweb': [ - 'static/src/xml/mail_internal.xml', + "qweb": [ + "static/src/xml/mail_internal.xml", ], - 'installable': False, - 'application': False, + "installable": False, + "application": False, } diff --git a/mail_internal/wizards/__init__.py b/mail_internal/wizards/__init__.py index 2db3d5fe..b528d997 100644 --- a/mail_internal/wizards/__init__.py +++ b/mail_internal/wizards/__init__.py @@ -1 +1 @@ -from . import mail_compose_message \ No newline at end of file +from . import mail_compose_message diff --git a/mail_internal/wizards/mail_compose_message.py b/mail_internal/wizards/mail_compose_message.py index 0dd117f5..b6cfdf47 100644 --- a/mail_internal/wizards/mail_compose_message.py +++ b/mail_internal/wizards/mail_compose_message.py @@ -2,18 +2,19 @@ class MailComposeMessage(models.TransientModel): - - _inherit = 'mail.compose.message' + _inherit = "mail.compose.message" is_internal = fields.Boolean( - 'Send Internal Message', - help='Whether the message is only for employees', + "Send Internal Message", + help="Whether the message is only for employees", ) def send_mail(self, auto_commit=False): internal = self.env.ref("mail_internal.mt_internal_message").id - self.filtered(lambda x: x.is_internal).write({ - 'subtype_id': internal, - 'is_log': False, - }) + self.filtered(lambda x: x.is_internal).write( + { + "subtype_id": internal, + "is_log": False, + } + ) return super().send_mail(auto_commit=auto_commit) diff --git a/maintenance_ux/__manifest__.py b/maintenance_ux/__manifest__.py index 8e8b98b1..3dccf3cd 100644 --- a/maintenance_ux/__manifest__.py +++ b/maintenance_ux/__manifest__.py @@ -19,29 +19,28 @@ ############################################################################## { - 'name': 'Maintenance UX', - 'version': "18.0.1.0.0", - 'category': 'Projects & Services', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Maintenance UX", + "version": "18.0.1.0.0", + "category": "Projects & Services", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "maintenance", + "rating", ], - 'depends': [ - 'maintenance', - 'rating', + "data": [ + "data/mail_template_data.xml", + "data/maintenance_data.xml", + "views/maintenance_views.xml", ], - 'data': [ - 'data/mail_template_data.xml', - 'data/maintenance_data.xml', - 'views/maintenance_views.xml', + "demo": [ + "demo/maintenance_demo.xml", ], - 'demo':[ - 'demo/maintenance_demo.xml', - ], - 'installable': True, - 'auto_install': False, - 'application': False, + "installable": True, + "auto_install": False, + "application": False, } diff --git a/maintenance_ux/models/maintenance_request.py b/maintenance_ux/models/maintenance_request.py index 093b8c5f..05fb7d3c 100644 --- a/maintenance_ux/models/maintenance_request.py +++ b/maintenance_ux/models/maintenance_request.py @@ -7,15 +7,15 @@ class MaintenanceRequest(models.Model): - _name = 'maintenance.request' - _inherit = ['maintenance.request', 'rating.mixin'] + _name = "maintenance.request" + _inherit = ["maintenance.request", "rating.mixin"] def action_send_rating(self): - rating_template = self.env.ref('maintenance_ux.mail_template_maintenance_request_rating') + rating_template = self.env.ref("maintenance_ux.mail_template_maintenance_request_rating") for order in self: order.rating_send_request(rating_template, force_send=True) def _rating_get_partner(self): if self.create_uid.partner_id: return self.create_uid.partner_id - return self.env['res.partner'] + return self.env["res.partner"] diff --git a/portal_backend/__manifest__.py b/portal_backend/__manifest__.py index e84dc744..6b02540c 100644 --- a/portal_backend/__manifest__.py +++ b/portal_backend/__manifest__.py @@ -18,26 +18,26 @@ # ############################################################################## { - 'name': 'Portal Backend', - 'version': "18.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'depends': [ - 'portal', + "name": "Portal Backend", + "version": "18.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "depends": [ + "portal", ], - 'data': [ - 'security/res_groups.xml', - 'security/ir.model.access.csv', - 'views/portal_templates.xml', + "data": [ + "security/res_groups.xml", + "security/ir.model.access.csv", + "views/portal_templates.xml", ], - 'demo': [ - 'demo/res_users_demo.xml', + "demo": [ + "demo/res_users_demo.xml", ], - 'installable': True, - 'auto_install': False, - 'application': False, + "installable": True, + "auto_install": False, + "application": False, } diff --git a/portal_backend/controllers/discuss.py b/portal_backend/controllers/discuss.py index f5473ed0..6a81e930 100644 --- a/portal_backend/controllers/discuss.py +++ b/portal_backend/controllers/discuss.py @@ -1,13 +1,12 @@ -from odoo import http, _ +from odoo import _, http +from odoo.addons.mail.controllers.attachment import AttachmentController from odoo.exceptions import UserError from odoo.http import request -from odoo.addons.mail.controllers.attachment import AttachmentController class PortalBackendAttachmentController(AttachmentController): - - @http.route('/mail/attachment/delete', methods=['POST'], type='json', auth='public') + @http.route("/mail/attachment/delete", methods=["POST"], type="json", auth="public") def mail_attachment_delete(self, attachment_id, access_token=None, **kwargs): - if request.env.user.has_group('portal_backend.group_portal_backend'): + if request.env.user.has_group("portal_backend.group_portal_backend"): raise UserError(_("You are not allowed to remove attachments")) return super().mail_attachment_delete(attachment_id, access_token=access_token, **kwargs) diff --git a/portal_backend/controllers/patch_web_controller_utils.py b/portal_backend/controllers/patch_web_controller_utils.py index c0c099fb..1827274c 100644 --- a/portal_backend/controllers/patch_web_controller_utils.py +++ b/portal_backend/controllers/patch_web_controller_utils.py @@ -1,13 +1,14 @@ -from odoo.http import request -from odoo.addons.web.controllers import utils import sys +from odoo.addons.web.controllers import utils +from odoo.http import request + # Monkey patch to bypass is internal check for portal users def new_is_user_internal(uid): - return request.env['res.users'].with_context(portal_bypass=True).browse(uid)._is_internal() + return request.env["res.users"].with_context(portal_bypass=True).browse(uid)._is_internal() utils.is_user_internal = new_is_user_internal -sys.modules['odoo.addons.web.controllers.home'].is_user_internal = new_is_user_internal -sys.modules['odoo.addons.portal.controllers.web'].is_user_internal = new_is_user_internal +sys.modules["odoo.addons.web.controllers.home"].is_user_internal = new_is_user_internal +sys.modules["odoo.addons.portal.controllers.web"].is_user_internal = new_is_user_internal diff --git a/portal_backend/models/ir_attachment.py b/portal_backend/models/ir_attachment.py index b3fa790c..d2dad8eb 100644 --- a/portal_backend/models/ir_attachment.py +++ b/portal_backend/models/ir_attachment.py @@ -2,14 +2,12 @@ class IrAttachment(models.Model): - _inherit = 'ir.attachment' + _inherit = "ir.attachment" @api.model def check(self, mode, values=None): - - """ Portal users are not allow to access to attachments - """ - if self.env.user.has_group('portal_backend.group_portal_backend'): + """Portal users are not allow to access to attachments""" + if self.env.user.has_group("portal_backend.group_portal_backend"): super(IrAttachment, self.with_context(portal_bypass=True)).check(mode, values) else: super(IrAttachment, self).check(mode, values) diff --git a/portal_backend/models/ir_http.py b/portal_backend/models/ir_http.py index 4039a6bc..a4f4c7a7 100644 --- a/portal_backend/models/ir_http.py +++ b/portal_backend/models/ir_http.py @@ -1,41 +1,48 @@ import hashlib import json + from odoo import models from odoo.http import request from odoo.tools import ustr class Http(models.AbstractModel): - _inherit = 'ir.http' + _inherit = "ir.http" def session_info(self): user = request.env.user session_info = super().session_info() - if self.env.user.has_group('portal_backend.group_portal_backend'): + if self.env.user.has_group("portal_backend.group_portal_backend"): # the following is only useful in the context of a webclient bootstrapping # but is still included in some other calls (e.g. '/web/session/authenticate') # to avoid access errors and unnecessary information, it is only included for users # with access to the backend ('internal'-type users) - menus = request.env['ir.ui.menu'].load_menus(request.session.debug) + menus = request.env["ir.ui.menu"].load_menus(request.session.debug) ordered_menus = {str(k): v for k, v in menus.items()} menu_json_utf8 = json.dumps(ordered_menus, default=ustr, sort_keys=True).encode() - session_info['cache_hashes'].update({ - "load_menus": hashlib.sha512(menu_json_utf8).hexdigest()[:64], # sha512/256 - }) - session_info.update({ - # current_company should be default_company - "user_companies": { - 'current_company': user.company_id.id, - 'allowed_companies': { - comp.id: { - 'id': comp.id, - 'name': comp.name, - 'sequence': comp.sequence, - } for comp in user.company_ids + session_info["cache_hashes"].update( + { + "load_menus": hashlib.sha512(menu_json_utf8).hexdigest()[:64], # sha512/256 + } + ) + session_info.update( + { + # current_company should be default_company + "user_companies": { + "current_company": user.company_id.id, + "allowed_companies": { + comp.id: { + "id": comp.id, + "name": comp.name, + "sequence": comp.sequence, + } + for comp in user.company_ids + }, }, - }, - "show_effect": True, - "display_switch_company_menu": user.has_group('base.group_multi_company') and len(user.company_ids) > 1, - }) + "show_effect": True, + "display_switch_company_menu": user.has_group("base.group_multi_company") + and len(user.company_ids) > 1, + } + ) return session_info diff --git a/portal_backend/models/ir_ui_menu.py b/portal_backend/models/ir_ui_menu.py index 5ca182e7..ea6a769b 100644 --- a/portal_backend/models/ir_ui_menu.py +++ b/portal_backend/models/ir_ui_menu.py @@ -1,17 +1,17 @@ -from odoo import models, Command, tools +from odoo import Command, models, tools + class IrUiMenu(models.Model): - _inherit = 'ir.ui.menu' + _inherit = "ir.ui.menu" - @tools.ormcache_context('self._uid', 'debug', keys=('lang',)) + @tools.ormcache_context("self._uid", "debug", keys=("lang",)) def load_menus(self, debug): - """ Assert all parent menus has internal group. - """ + """Assert all parent menus has internal group.""" # NOTE: # It is important to do it here to capture the case when portal_backend is already installed and the user # installs another module with a parent menu without internal group. - parent_menus_wo_group = self.sudo().search([('parent_id', '=', False), ('groups_id', '=', False)]) - parent_menus_wo_group.with_context(from_config=True).write({ - 'groups_id': [Command.link(self.env.ref('base.group_user').id)] - }) + parent_menus_wo_group = self.sudo().search([("parent_id", "=", False), ("groups_id", "=", False)]) + parent_menus_wo_group.with_context(from_config=True).write( + {"groups_id": [Command.link(self.env.ref("base.group_user").id)]} + ) return super().load_menus(debug=debug) diff --git a/portal_backend/models/mail_activity_mixin.py b/portal_backend/models/mail_activity_mixin.py index 489cd285..b85403d7 100644 --- a/portal_backend/models/mail_activity_mixin.py +++ b/portal_backend/models/mail_activity_mixin.py @@ -1,8 +1,8 @@ -from odoo import models, fields +from odoo import fields, models class MailActivityMixin(models.AbstractModel): - _inherit = 'mail.activity.mixin' + _inherit = "mail.activity.mixin" activity_ids = fields.One2many( groups="base.group_user, portal_backend.group_portal_backend", diff --git a/portal_backend/models/mail_thread.py b/portal_backend/models/mail_thread.py index 8329792e..dd46a9da 100644 --- a/portal_backend/models/mail_thread.py +++ b/portal_backend/models/mail_thread.py @@ -1,17 +1,14 @@ -from odoo import models, fields +from odoo import fields, models class MailThread(models.AbstractModel): - _inherit = 'mail.thread' + _inherit = "mail.thread" - message_attachment_count = fields.Integer( - groups="base.group_user, portal_backend.group_portal_backend") - message_follower_ids = fields.One2many( - groups="base.group_user, portal_backend.group_portal_backend") + message_attachment_count = fields.Integer(groups="base.group_user, portal_backend.group_portal_backend") + message_follower_ids = fields.One2many(groups="base.group_user, portal_backend.group_portal_backend") def _get_mail_thread_data(self, request_list): - """ This avoids to get an error when an internal user is follower of a record that a portal_backend has access - """ - if 'followers' in request_list and self.env.user.has_group('portal_backend.group_portal_backend'): - request_list.remove('followers') + """This avoids to get an error when an internal user is follower of a record that a portal_backend has access""" + if "followers" in request_list and self.env.user.has_group("portal_backend.group_portal_backend"): + request_list.remove("followers") return super()._get_mail_thread_data(request_list) diff --git a/portal_backend/models/res_users.py b/portal_backend/models/res_users.py index 403deb7c..bd791e41 100644 --- a/portal_backend/models/res_users.py +++ b/portal_backend/models/res_users.py @@ -2,56 +2,57 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import models, api -from odoo.addons.base.models.res_users import name_selection_groups -from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG from lxml import etree from lxml.builder import E +from odoo import api, models +from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG +from odoo.addons.base.models.res_users import name_selection_groups class ResUsers(models.Model): - - _inherit = 'res.users' + _inherit = "res.users" @api.model def systray_get_activities(self): - """ We did this to avoid errors when use portal user when the module "Note" is not a depends of this module. + """We did this to avoid errors when use portal user when the module "Note" is not a depends of this module. Only apply this change if the user is portal. """ - if self.env.user.has_group('portal_backend.group_portal_backend') and self.env['ir.module.module'].sudo().search( - [('name', '=', 'note')]).state == 'installed': + if ( + self.env.user.has_group("portal_backend.group_portal_backend") + and self.env["ir.module.module"].sudo().search([("name", "=", "note")]).state == "installed" + ): self = self.sudo() return super().systray_get_activities() def _is_internal(self): self.ensure_one() - if self.sudo().has_group('portal_backend.group_portal_backend') and self.env.context.get('portal_bypass'): + if self.sudo().has_group("portal_backend.group_portal_backend") and self.env.context.get("portal_bypass"): return True return super()._is_internal() class GroupsView(models.Model): - _inherit = 'res.groups' + _inherit = "res.groups" @api.model def _update_user_groups_view(self): super()._update_user_groups_view() - if self._context.get('install_filename') or self._context.get(MODULE_UNINSTALL_FLAG): + if self._context.get("install_filename") or self._context.get(MODULE_UNINSTALL_FLAG): return - view = self.env.ref('base.user_groups_view', raise_if_not_found=False) + view = self.env.ref("base.user_groups_view", raise_if_not_found=False) arch = etree.fromstring(view.arch) # Get the user type field name - category_user_type = self.env.ref('base.module_category_user_type') - gs = self.get_application_groups([('category_id', '=', category_user_type.id)]) + category_user_type = self.env.ref("base.module_category_user_type") + gs = self.get_application_groups([("category_id", "=", category_user_type.id)]) user_type_field_name = name_selection_groups(gs.ids) # Get the portal backend field name - group_portal_backend = self.env.ref('portal_backend.group_portal_backend') - category_portal_backend = self.env.ref('portal_backend.category_portal_advanced') + group_portal_backend = self.env.ref("portal_backend.group_portal_backend") + category_portal_backend = self.env.ref("portal_backend.category_portal_advanced") - groups_to_move =[] + groups_to_move = [] # Remove from internal user view the portal backend groups. There are two cases: # Case 1: kind == selection (group string="Advanced portal") @@ -70,11 +71,13 @@ def _update_user_groups_view(self): groups_to_move += self._get_groups_between_separator(separator[0]) # Create new group for portal backend views - new_arch_pb_parent_group = E.group(*groups_to_move, invisible=f'{user_type_field_name} != {group_portal_backend.id}') + new_arch_pb_parent_group = E.group( + *groups_to_move, invisible=f"{user_type_field_name} != {group_portal_backend.id}" + ) # Set attributes pb_field_attributes = f"{user_type_field_name} != {group_portal_backend.id}" - for field in new_arch_pb_parent_group.iter('field'): + for field in new_arch_pb_parent_group.iter("field"): field.set("readonly", pb_field_attributes) # Add the new group to the arch view @@ -83,16 +86,12 @@ def _update_user_groups_view(self): # Write the arch on the original view xml_content = etree.tostring(arch) if xml_content != view.arch: - view.with_context( - install_filename=None, - lang=None - ).write({'arch': xml_content}) + view.with_context(install_filename=None, lang=None).write({"arch": xml_content}) def _get_groups_between_separator(self, element): - """ Get all the groups after a determined separator. - """ + """Get all the groups after a determined separator.""" groups = [] - while(True): + while True: next_element = element.getnext() if next_element.tag == "group": groups.append(next_element) @@ -108,19 +107,19 @@ def _get_groups_between_separator(self, element): def get_groups_by_application(self): res = super().get_groups_by_application() for index, (category, kind, groups, *rest) in enumerate(res): - if category == self.env.ref('base.module_category_user_type'): - group_portal_backend = self.env.ref('portal_backend.group_portal_backend') + if category == self.env.ref("base.module_category_user_type"): + group_portal_backend = self.env.ref("portal_backend.group_portal_backend") if group_portal_backend.id not in groups.ids: - updated_groups = self.env['res.groups'].browse(groups.ids + [group_portal_backend.id]) + updated_groups = self.env["res.groups"].browse(groups.ids + [group_portal_backend.id]) res[index] = (category, kind, updated_groups, *rest) break return res def get_application_groups(self, domain): res = super().get_application_groups(domain) - category_user_type = self.env.ref('base.module_category_user_type') - if res.mapped('category_id') == category_user_type: - group_portal_backend = self.env.ref('portal_backend.group_portal_backend') + category_user_type = self.env.ref("base.module_category_user_type") + if res.mapped("category_id") == category_user_type: + group_portal_backend = self.env.ref("portal_backend.group_portal_backend") if group_portal_backend.id not in res.ids: res += group_portal_backend return res diff --git a/portal_holidays/__manifest__.py b/portal_holidays/__manifest__.py index f9518248..1da9857a 100644 --- a/portal_holidays/__manifest__.py +++ b/portal_holidays/__manifest__.py @@ -18,33 +18,28 @@ # ############################################################################## { - 'name': 'Portal Holidays', - 'version': "18.0.1.2.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Portal Holidays", + "version": "18.0.1.2.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": ["portal_backend", "hr_holidays", "hr_holidays_attendance"], + "data": [ + "security/res_groups.xml", + "security/ir_rule.xml", + "security/ir.model.access.csv", + "views/base_menus.xml", + "views/hr_employee_views.xml", ], - 'depends': [ - 'portal_backend', - 'hr_holidays', - 'hr_holidays_attendance' + "demo": [ + "demo/hr_demo.xml", + "demo/res_users_demo.xml", ], - 'data': [ - 'security/res_groups.xml', - 'security/ir_rule.xml', - 'security/ir.model.access.csv', - 'views/base_menus.xml', - 'views/hr_employee_views.xml', - ], - 'demo': [ - 'demo/hr_demo.xml', - 'demo/res_users_demo.xml', - ], - 'installable': True, - 'auto_install': False, - 'application': False, + "installable": True, + "auto_install": False, + "application": False, } diff --git a/portal_holidays/models/hr_leave_allocation.py b/portal_holidays/models/hr_leave_allocation.py index 459623f3..f7618f53 100644 --- a/portal_holidays/models/hr_leave_allocation.py +++ b/portal_holidays/models/hr_leave_allocation.py @@ -1,10 +1,11 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models, fields +from odoo import fields, models class HolidaysAllocation(models.Model): - _inherit = 'hr.leave.allocation' + _inherit = "hr.leave.allocation" - employee_overtime = fields.Float(related='employee_id.total_overtime', groups='base.group_user,portal_holidays.group_portal_backend_holiday') + employee_overtime = fields.Float( + related="employee_id.total_overtime", groups="base.group_user,portal_holidays.group_portal_backend_holiday" + ) diff --git a/portal_timesheet/__manifest__.py b/portal_timesheet/__manifest__.py index a62268ee..d3da5b6c 100644 --- a/portal_timesheet/__manifest__.py +++ b/portal_timesheet/__manifest__.py @@ -18,35 +18,34 @@ # ############################################################################## { - 'name': 'Portal Timesheet', - 'version': "18.0.1.1.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Portal Timesheet", + "version": "18.0.1.1.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "portal_backend", + "hr_timesheet", + "timesheet_grid", + "calendar", # added to avoid creating bridge module portal_timesheet_calendar ], - 'depends': [ - 'portal_backend', - 'hr_timesheet', - 'timesheet_grid', - 'calendar', # added to avoid creating bridge module portal_timesheet_calendar + "data": [ + "security/res_groups.xml", + "security/ir_rule.xml", + "security/ir.model.access.csv", + "views/base_menus.xml", + "views/hr_employee_views.xml", ], - 'data': [ - 'security/res_groups.xml', - 'security/ir_rule.xml', - 'security/ir.model.access.csv', - 'views/base_menus.xml', - 'views/hr_employee_views.xml', - ], - 'demo': [ + "demo": [ # 'demo/hr_demo.xml', - 'demo/project_demo.xml', - 'demo/res_users_demo.xml', + "demo/project_demo.xml", + "demo/res_users_demo.xml", ], - 'installable': True, - 'auto_install': False, - 'application': False, + "installable": True, + "auto_install": False, + "application": False, } diff --git a/portal_timesheet/models/__init__.py b/portal_timesheet/models/__init__.py index ea42aa66..611a5af1 100644 --- a/portal_timesheet/models/__init__.py +++ b/portal_timesheet/models/__init__.py @@ -2,4 +2,3 @@ from . import project from . import res_users from . import account_analytic_line - diff --git a/portal_timesheet/models/account_analytic_line.py b/portal_timesheet/models/account_analytic_line.py index d9d20c05..b010f9c9 100644 --- a/portal_timesheet/models/account_analytic_line.py +++ b/portal_timesheet/models/account_analytic_line.py @@ -1,13 +1,13 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api,models +from odoo import api, models -class AccountAnalyticLine(models.Model): - _inherit = 'account.analytic.line' +class AccountAnalyticLine(models.Model): + _inherit = "account.analytic.line" @api.model def _get_favorite_project_id(self, employee_id=False): # Esto lo bypasseamos porque desde v18 trae predeterminadamente un proyecto interno que el usuario no tiene acceso - if self.env.user.has_group('portal_timesheet.group_portal_backend_timesheet'): + if self.env.user.has_group("portal_timesheet.group_portal_backend_timesheet"): self = self.sudo() return super()._get_favorite_project_id(employee_id=employee_id) diff --git a/portal_timesheet/models/ir_http.py b/portal_timesheet/models/ir_http.py index fcc4cdbc..6349b416 100644 --- a/portal_timesheet/models/ir_http.py +++ b/portal_timesheet/models/ir_http.py @@ -1,11 +1,11 @@ -from odoo import api, models +from odoo import models class Http(models.AbstractModel): - _inherit = 'ir.http' + _inherit = "ir.http" def session_info(self): - if self.env.user.has_group('portal_timesheet.group_portal_backend_timesheet'): + if self.env.user.has_group("portal_timesheet.group_portal_backend_timesheet"): return super(Http, self.with_context(portal_bypass=True)).session_info() else: return super(Http, self).session_info() diff --git a/portal_timesheet/models/project.py b/portal_timesheet/models/project.py index 3abdd8aa..1b05e42b 100644 --- a/portal_timesheet/models/project.py +++ b/portal_timesheet/models/project.py @@ -1,15 +1,17 @@ -from odoo import models, fields +from odoo import fields, models class Project(models.Model): _inherit = "project.project" total_timesheet_time = fields.Integer( - groups='hr_timesheet.group_hr_timesheet_user, portal_timesheet.group_portal_backend_timesheet') + groups="hr_timesheet.group_hr_timesheet_user, portal_timesheet.group_portal_backend_timesheet" + ) + class Task(models.Model): _inherit = "project.task" - def _ensure_fields_are_accessible(self, fields, operation='read', check_group_user=True): - if not self.env.user.has_group('portal_timesheet.group_portal_backend_timesheet'): + def _ensure_fields_are_accessible(self, fields, operation="read", check_group_user=True): + if not self.env.user.has_group("portal_timesheet.group_portal_backend_timesheet"): super()._ensure_fields_are_accessible(fields, operation, check_group_user) diff --git a/portal_timesheet/models/res_users.py b/portal_timesheet/models/res_users.py index 9e2a5887..90e49b56 100644 --- a/portal_timesheet/models/res_users.py +++ b/portal_timesheet/models/res_users.py @@ -1,13 +1,11 @@ -from odoo import models, _ -from odoo.exceptions import UserError +from odoo import models -class User(models.Model): - _inherit = ['res.users'] +class User(models.Model): + _inherit = ["res.users"] def get_last_validated_timesheet_date(self): - if not self.env.user.has_group('portal_timesheet.group_portal_backend_timesheet'): + if not self.env.user.has_group("portal_timesheet.group_portal_backend_timesheet"): return super().get_last_validated_timesheet_date() else: return self.sudo().employee_id.last_validated_timesheet_date - diff --git a/portal_timesheet/security/ir_rule.xml b/portal_timesheet/security/ir_rule.xml index a2e3578d..ca79e617 100644 --- a/portal_timesheet/security/ir_rule.xml +++ b/portal_timesheet/security/ir_rule.xml @@ -22,5 +22,5 @@ - + diff --git a/portal_timesheet_attendance/__manifest__.py b/portal_timesheet_attendance/__manifest__.py index eaca6a0c..6ebfef06 100644 --- a/portal_timesheet_attendance/__manifest__.py +++ b/portal_timesheet_attendance/__manifest__.py @@ -18,25 +18,23 @@ # ############################################################################## { - 'name': 'Portal Timesheet Attendance', - 'version': "18.0.1.0.0", - 'category': 'Base', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Portal Timesheet Attendance", + "version": "18.0.1.0.0", + "category": "Base", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "portal_timesheet", + "hr_timesheet_attendance", ], - 'depends': [ - 'portal_timesheet', - 'hr_timesheet_attendance', + "data": [ + "security/ir.model.access.csv", ], - 'data': [ - 'security/ir.model.access.csv', - ], - 'demo': [ - ], - 'installable': True, - 'auto_install': True, + "demo": [], + "installable": True, + "auto_install": True, } diff --git a/report_copies/__manifest__.py b/report_copies/__manifest__.py index 5cc04273..4a39e26b 100644 --- a/report_copies/__manifest__.py +++ b/report_copies/__manifest__.py @@ -19,24 +19,23 @@ ############################################################################## { - 'name': 'Report Copies', - 'version': "15.0.1.0.0", - 'category': 'Web & Reports', - 'sequence': 14, - 'summary': '', - 'author': 'ADHOC SA', - 'website': 'www.adhoc.com.ar', - 'license': 'AGPL-3', - 'images': [ + "name": "Report Copies", + "version": "15.0.1.0.0", + "category": "Web & Reports", + "sequence": 14, + "summary": "", + "author": "ADHOC SA", + "website": "www.adhoc.com.ar", + "license": "AGPL-3", + "images": [], + "depends": [ + "web", ], - 'depends': [ - 'web', + "data": [ + "views/report_templates.xml", + "views/ir_actions_views.xml", ], - 'data': [ - 'views/report_templates.xml', - 'views/ir_actions_views.xml', - ], - 'installable': False, - 'auto_install': False, - 'application': False, + "installable": False, + "auto_install": False, + "application": False, } diff --git a/report_copies/models/ir_actions_report.py b/report_copies/models/ir_actions_report.py index dd68e40f..757b7e15 100644 --- a/report_copies/models/ir_actions_report.py +++ b/report_copies/models/ir_actions_report.py @@ -3,12 +3,12 @@ # directory ############################################################################## -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class IrActionsReport(models.Model): - _inherit = 'ir.actions.report' + _inherit = "ir.actions.report" ncopies = fields.Integer(string="Number of print copies", default=1) @@ -16,14 +16,16 @@ class IrActionsReport(models.Model): def _get_rendering_context(self, docids, data): res = super()._get_rendering_context(docids, data) ncopies = self.ncopies - if self._context.get('force_email', False): + if self._context.get("force_email", False): ncopies = 1 - res.update({ - 'ncopies': ncopies, - }) + res.update( + { + "ncopies": ncopies, + } + ) return res - @api.constrains('ncopies') + @api.constrains("ncopies") def _check_ncopies(self): if self.filtered(lambda x: x.ncopies < 1): raise ValidationError(_("The number of copies must be strict positive and different than zero.")) diff --git a/requirements.txt b/requirements.txt index 4f5d7add..6d3a9d8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ transifex-python - diff --git a/transifex_push/__init__.py b/transifex_push/__init__.py index 881f918b..cde7136c 100644 --- a/transifex_push/__init__.py +++ b/transifex_push/__init__.py @@ -1,4 +1,3 @@ - # from . import models from . import wizard from odoo import api, SUPERUSER_ID @@ -10,8 +9,8 @@ def post_init(env): - tx_data = ast.literal_eval(os.getenv('tx_data', '[]')) + tx_data = ast.literal_eval(os.getenv("tx_data", "[]")) for api_key, organization_slug, project_slug, modules_names in tx_data: - _logger.info('Pushing transifex translations for project %s-%s', organization_slug, project_slug) - modules = env['ir.module.module'].search([('name', 'in', modules_names), ('state','=', 'installed')]) - env['base.language.export']._transifex_push(modules, api_key, organization_slug, project_slug) + _logger.info("Pushing transifex translations for project %s-%s", organization_slug, project_slug) + modules = env["ir.module.module"].search([("name", "in", modules_names), ("state", "=", "installed")]) + env["base.language.export"]._transifex_push(modules, api_key, organization_slug, project_slug) diff --git a/transifex_push/__manifest__.py b/transifex_push/__manifest__.py index ac1d217f..0db3e3aa 100644 --- a/transifex_push/__manifest__.py +++ b/transifex_push/__manifest__.py @@ -1,18 +1,18 @@ { - 'name': "Transifex Push", - 'summary': "Helper module to push translations to Transifex", - 'author': "ADHOC SA", - 'website': "http://runbot.odoo.com", - 'category': 'Website', - 'version': "18.0.1.0.0", - 'depends': [ - 'base', - 'web', + "name": "Transifex Push", + "summary": "Helper module to push translations to Transifex", + "author": "ADHOC SA", + "website": "http://runbot.odoo.com", + "category": "Website", + "version": "18.0.1.0.0", + "depends": [ + "base", + "web", ], - 'license': 'AGPL-3', - 'data': [ - 'wizard/base_export_language_views.xml', + "license": "AGPL-3", + "data": [ + "wizard/base_export_language_views.xml", ], - 'post_init_hook': 'post_init', - 'installable': True, + "post_init_hook": "post_init", + "installable": True, } diff --git a/transifex_push/wizard/__init__.py b/transifex_push/wizard/__init__.py index e0fe9148..a8fa8684 100644 --- a/transifex_push/wizard/__init__.py +++ b/transifex_push/wizard/__init__.py @@ -1,2 +1 @@ - from . import base_export_language diff --git a/transifex_push/wizard/base_export_language.py b/transifex_push/wizard/base_export_language.py index f22be091..a7780756 100644 --- a/transifex_push/wizard/base_export_language.py +++ b/transifex_push/wizard/base_export_language.py @@ -1,27 +1,28 @@ -from odoo import models, fields -from transifex.api import transifex_api -from odoo.exceptions import UserError -from odoo.tools.translate import trans_export import contextlib import io import logging +from odoo import fields, models +from odoo.exceptions import UserError +from odoo.tools.translate import trans_export +from transifex.api import transifex_api + _logger = logging.getLogger(__name__) class BaseLanguageExport(models.TransientModel): _inherit = "base.language.export" - api_key = fields.Char(default='1/7dbfd1118bec5ef2dfac3528d8c5cea3dbd42164') - organization_slug = fields.Char(default='adhoc') - project_slug = fields.Char(default='odoo-18-0') + api_key = fields.Char(default="1/7dbfd1118bec5ef2dfac3528d8c5cea3dbd42164") + organization_slug = fields.Char(default="adhoc") + project_slug = fields.Char(default="odoo-18-0") def action_transifex_push(self): self.ensure_one() self._transifex_push(self.modules, self.api_key, self.organization_slug, self.project_slug) def _transifex_push(self, modules, api_key, organization_slug, project_slug): - """ Metodo que revisa las builds y se fija los commits con cambios de la build, si lo mismos tienen configurado transifex + """Metodo que revisa las builds y se fija los commits con cambios de la build, si lo mismos tienen configurado transifex entonces itera sobre modulos e idiomas para sincornizar traducciones. IMPORTANTE: los idiomas que se deseen deben configurarse manualmente en transifex A la hora de generar los .po tenemos 3 opciones: @@ -29,32 +30,34 @@ def _transifex_push(self, modules, api_key, organization_slug, project_slug): * Usar click odoo https://pypi.org/project/click-odoo-contrib/#click-odoo-makepot-stable * Algo parecido a lo que hacía la oca https://github.com/ingadhoc/maintainer-quality-tools/blob/master/travis/travis_transifex.py#L152 """ + def _get_language_content(lang_code, module): with contextlib.closing(io.BytesIO()) as buf: - trans_export(lang_code, [module.name], buf, 'po', self._cr) + trans_export(lang_code, [module.name], buf, "po", self._cr) content = buf.getvalue().decode("utf-8") return content - _logger.info('Pushing translations to transifex') + _logger.info("Pushing translations to transifex") if not api_key or not organization_slug or not project_slug: raise UserError( - 'Se deben configurar los siguientes parametros de transfiex: api_key, organization_slug, project_slug') + "Se deben configurar los siguientes parametros de transfiex: api_key, organization_slug, project_slug" + ) - installed_langs = {x.iso_code: x.code for x in self.env['res.lang'].with_context(active_test=True).search([])} + installed_langs = {x.iso_code: x.code for x in self.env["res.lang"].with_context(active_test=True).search([])} transifex_api.setup(auth=api_key) tx_organization = transifex_api.Organization.get(slug=organization_slug) - tx_project = tx_organization.fetch('projects').get(slug=project_slug) + tx_project = tx_organization.fetch("projects").get(slug=project_slug) - tx_project_languages = {x.code: x.id for x in tx_project.fetch('languages').all()} - po_format = transifex_api.i18n_formats.get(organization=tx_organization, name='PO') + tx_project_languages = {x.code: x.id for x in tx_project.fetch("languages").all()} + po_format = transifex_api.i18n_formats.get(organization=tx_organization, name="PO") for module in modules: module_name = module.name try: # obtenemos el resource de esta manera ya que filter o get con slug o name no hacen busqueda exacta y si coincide # la primer parte nos devuelve varios resultados - resource = transifex_api.resources.get('%s:r:%s' % (tx_project.id, module_name)) + resource = transifex_api.resources.get("%s:r:%s" % (tx_project.id, module_name)) except: attributes = { "accept_translations": True, @@ -67,19 +70,20 @@ def _get_language_content(lang_code, module): } _logger.info("Creating missing resource %s on transifex project %s", module_name, tx_project.name) resource = transifex_api.Resource.create(attributes=attributes, relationships=relationships) - + # subimos .pot (terminos en ingles) content = _get_language_content(False, module) res = transifex_api.resource_strings_async_uploads.upload(resource=resource, content=content) - _logger.info('Result: %s', res) + _logger.info("Result: %s", res) # subimos traducciones existentes for tx_language in tx_project_languages: if tx_language not in installed_langs.keys(): - _logger.warning('Language %s not installed on database, skiping sync to transfiex', tx_language) + _logger.warning("Language %s not installed on database, skiping sync to transfiex", tx_language) continue content = _get_language_content(installed_langs[tx_language], module) res = transifex_api.resource_translations_async_uploads.upload( - resource=resource, content=content, language=tx_project_languages[tx_language]) - _logger.info('Result: %s', res) + resource=resource, content=content, language=tx_project_languages[tx_language] + ) + _logger.info("Result: %s", res)