From 8c158bf978ae6a15cd0c79bdfd722e1469abdf39 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Thu, 23 Jan 2025 10:09:53 +0000 Subject: [PATCH] [ADD] mail_reply_stage --- mail_reply_stage/README.rst | 89 ++++ mail_reply_stage/__init__.py | 1 + mail_reply_stage/__manifest__.py | 16 + mail_reply_stage/models/__init__.py | 2 + mail_reply_stage/models/mail_message.py | 68 +++ mail_reply_stage/models/mail_reply_config.py | 62 +++ mail_reply_stage/readme/CONFIGURE.rst | 14 + mail_reply_stage/readme/DESCRIPTION.rst | 1 + mail_reply_stage/security/ir.model.access.csv | 3 + .../static/description/index.html | 434 ++++++++++++++++++ .../views/mail_reply_config_views.xml | 38 ++ .../odoo/addons/mail_reply_stage | 1 + setup/mail_reply_stage/setup.py | 6 + 13 files changed, 735 insertions(+) create mode 100644 mail_reply_stage/README.rst create mode 100644 mail_reply_stage/__init__.py create mode 100644 mail_reply_stage/__manifest__.py create mode 100644 mail_reply_stage/models/__init__.py create mode 100644 mail_reply_stage/models/mail_message.py create mode 100644 mail_reply_stage/models/mail_reply_config.py create mode 100644 mail_reply_stage/readme/CONFIGURE.rst create mode 100644 mail_reply_stage/readme/DESCRIPTION.rst create mode 100644 mail_reply_stage/security/ir.model.access.csv create mode 100644 mail_reply_stage/static/description/index.html create mode 100644 mail_reply_stage/views/mail_reply_config_views.xml create mode 120000 setup/mail_reply_stage/odoo/addons/mail_reply_stage create mode 100644 setup/mail_reply_stage/setup.py diff --git a/mail_reply_stage/README.rst b/mail_reply_stage/README.rst new file mode 100644 index 0000000000..76e6cf7c5a --- /dev/null +++ b/mail_reply_stage/README.rst @@ -0,0 +1,89 @@ +================ +Mail Reply Stage +================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3e0a708a7c69ddc0f3b1222b5c268d8d6acc6f32c6de186e7c9a5df995a98bb3 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github + :target: https://github.com/OCA/social/tree/15.0/mail_reply_stage + :alt: OCA/social +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/social-15-0/social-15-0-mail_reply_stage + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/social&target_branch=15.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module has the feature to automatically update the stage of the record when a non-internal user sends an update to the record. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Go to **Settings > Mail Reply Configurations** and create records according to your needs. + +For each record: + +- **Model**: Choose a model (required). +- **Parent Field**: Select the field for the parent field ID (e.g., if you select the model as project.task, choose project_id as the parent field). + If a parent field is selected, the system will update the reply stage based on the parent (e.g., tasks under the project will use the reply stage of the matched configuration). + If this field is left empty, all records without a matching configuration for their project will use the configuration record that does not specify a parent field. +- **Parent Model**: The system will assign this automatically. +- **Parent Field Value**: Set up the name of the parent record (e.g., project name). +- **Parent Stage Field**: Choose the stages field from the parent model to verify that the reply stage is within the parent stages. +- **Reply Stage Field**: Choose the field for the stage that will be automatically updated when a non-internal user sends an update.(required) +- **Reply Stage**: Set the stage value that will be updated.(required) +- **No Reply Stage**: Set the stage value. If the record is in this state, updates from the user will not change the stage of the record.(required) + +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 +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Quartile + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/social `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mail_reply_stage/__init__.py b/mail_reply_stage/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/mail_reply_stage/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/mail_reply_stage/__manifest__.py b/mail_reply_stage/__manifest__.py new file mode 100644 index 0000000000..3b23f33c05 --- /dev/null +++ b/mail_reply_stage/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2025 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Mail Reply Stage", + "category": "Mail", + "version": "15.0.1.0.0", + "author": "Quartile, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/social", + "license": "AGPL-3", + "depends": ["mail"], + "data": [ + "security/ir.model.access.csv", + "views/mail_reply_config_views.xml", + ], + "installable": True, +} diff --git a/mail_reply_stage/models/__init__.py b/mail_reply_stage/models/__init__.py new file mode 100644 index 0000000000..ad64cea8ed --- /dev/null +++ b/mail_reply_stage/models/__init__.py @@ -0,0 +1,2 @@ +from . import mail_message +from . import mail_reply_config diff --git a/mail_reply_stage/models/mail_message.py b/mail_reply_stage/models/mail_message.py new file mode 100644 index 0000000000..2ec2681111 --- /dev/null +++ b/mail_reply_stage/models/mail_message.py @@ -0,0 +1,68 @@ +# Copyright 2025 Quartile Limited +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import api, models + + +class MailMessage(models.Model): + _inherit = "mail.message" + + @api.model_create_multi + def create(self, values_list): + messages = super().create(values_list) + for message in messages: + user = message.author_id.user_ids[:1] + if user and user.has_group("base.group_user"): + continue + if message.subtype_id and message.subtype_id.internal: + continue + res_model = ( + self.env["ir.model"] + .sudo() + .search([("model", "=", message.model)], limit=1) + ) + if not res_model: + continue + resource = self.env[message.model].browse(message.res_id) + config_records = self.env["mail.reply.config"].search( + [("model_id", "=", res_model.id)] + ) + matched_config = None + for config in config_records: + if config.parent_field_id: + parent_field_value = getattr( + resource, config.parent_field_id.name, None + ) + if ( + parent_field_value + and getattr(parent_field_value, "name", None) + == config.parent_field_value + ): + matched_config = config + break + else: + matched_config = config + if not matched_config: + continue + current_stage = getattr( + resource, matched_config.reply_stage_field_id.name, None + ) + if current_stage == matched_config.remain_stage: + continue + reply_stage_rec = self.env[ + matched_config.reply_stage_field_id.relation + ].search([("name", "=", matched_config.reply_stage)]) + if config.parent_stage_field_id: + allowed_stages = getattr( + parent_field_value, + config.parent_stage_field_id.name, + self.env[matched_config.parent_stage_field_id.relation], + ) + reply_stage_rec = reply_stage_rec.filtered( + lambda stage: stage in allowed_stages + ) + if reply_stage_rec: + resource.sudo().write( + {matched_config.reply_stage_field_id.name: reply_stage_rec.id} + ) + return messages diff --git a/mail_reply_stage/models/mail_reply_config.py b/mail_reply_stage/models/mail_reply_config.py new file mode 100644 index 0000000000..b8a93f15b0 --- /dev/null +++ b/mail_reply_stage/models/mail_reply_config.py @@ -0,0 +1,62 @@ +# Copyright 2025 Quartile Limited +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import api, fields, models + + +class MailReplyStage(models.Model): + _name = "mail.reply.config" + + model_id = fields.Many2one( + "ir.model", string="Model", required=True, ondelete="cascade" + ) + parent_field_id = fields.Many2one( + "ir.model.fields", + string="Parent Field", + domain="[('model_id', '=', model_id), ('ttype', '=', 'many2one')]", + ondelete="cascade", + ) + parent_model_name = fields.Char( + related="parent_field_id.relation", + string="Parent Model", + store=True, + help="Automatically stores the model name of the related parent entity.", + ) + parent_stage_field_id = fields.Many2one( + "ir.model.fields", + string="Parent Stage Field", + domain="[('model_id.model', '=', parent_model_name), ('ttype', '=', 'many2many')]", + ondelete="cascade", + help="A Many2Many field within the parent model that defines " + "valid stages for this configuration.", + ) + parent_field_value = fields.Char( + help="The specific value of the parent field that this configuration applies to. " + "For example, a project name." + ) + reply_stage_field_id = fields.Many2one( + "ir.model.fields", + domain="[('model_id', '=', model_id), ('ttype', '=', 'many2one')]", + required=True, + ondelete="cascade", + ) + reply_stage = fields.Char( + required=True, + help="This stage of record will be changed when a non-internal user " + "replies to the record.", + ) + remain_stage = fields.Char( + string="No Reply Stage", + required=True, + help="Record in this stage will not update to the mail reply stage " + "when a non-internal user replies to the record.", + ) + + @api.onchange("model_id") + def _onchange_model_id(self): + self.reply_stage_field_id = False + + @api.onchange("reply_stage_field_id") + def _onchange_reply_stage_field_id(self): + self.reply_stage = False + self.remain_stage = False diff --git a/mail_reply_stage/readme/CONFIGURE.rst b/mail_reply_stage/readme/CONFIGURE.rst new file mode 100644 index 0000000000..83b948593b --- /dev/null +++ b/mail_reply_stage/readme/CONFIGURE.rst @@ -0,0 +1,14 @@ +Go to **Settings > Mail Reply Configurations** and create records according to your needs. + +For each record: + +- **Model**: Choose a model (required). +- **Parent Field**: Select the field for the parent field ID (e.g., if you select the model as project.task, choose project_id as the parent field). + If a parent field is selected, the system will update the reply stage based on the parent (e.g., tasks under the project will use the reply stage of the matched configuration). + If this field is left empty, all records without a matching configuration for their project will use the configuration record that does not specify a parent field. +- **Parent Model**: The system will assign this automatically. +- **Parent Field Value**: Set up the name of the parent record (e.g., project name). +- **Parent Stage Field**: Choose the stages field from the parent model to verify that the reply stage is within the parent stages. +- **Reply Stage Field**: Choose the field for the stage that will be automatically updated when a non-internal user sends an update.(required) +- **Reply Stage**: Set the stage value that will be updated.(required) +- **No Reply Stage**: Set the stage value. If the record is in this state, updates from the user will not change the stage of the record.(required) diff --git a/mail_reply_stage/readme/DESCRIPTION.rst b/mail_reply_stage/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..c1d9deec02 --- /dev/null +++ b/mail_reply_stage/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module has the feature to automatically update the stage of the record when a non-internal user sends an update to the record. diff --git a/mail_reply_stage/security/ir.model.access.csv b/mail_reply_stage/security/ir.model.access.csv new file mode 100644 index 0000000000..7eb425b993 --- /dev/null +++ b/mail_reply_stage/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_mail_reply_config_all,mail.reply.config.all,model_mail_reply_config,,1,0,0,0 +access_mail_reply_config_admin,mail.reply.config.admin,model_mail_reply_config,base.group_system,1,1,1,1 diff --git a/mail_reply_stage/static/description/index.html b/mail_reply_stage/static/description/index.html new file mode 100644 index 0000000000..0e52ee5abf --- /dev/null +++ b/mail_reply_stage/static/description/index.html @@ -0,0 +1,434 @@ + + + + + +Mail Reply Stage + + + +
+

Mail Reply Stage

+ + +

Beta License: AGPL-3 OCA/social Translate me on Weblate Try me on Runboat

+

This module has the feature to automatically update the stage of the record when a non-internal user sends an update to the record.

+

Table of contents

+ +
+

Configuration

+

Go to Settings > Mail Reply Configurations and create records according to your needs.

+

For each record:

+
    +
  • Model: Choose a model (required).
  • +
  • +
    Parent Field: Select the field for the parent field ID (e.g., if you select the model as project.task, choose project_id as the parent field).
    +
    If a parent field is selected, the system will update the reply stage based on the parent (e.g., tasks under the project will use the reply stage of the matched configuration). +If this field is left empty, all records without a matching configuration for their project will use the configuration record that does not specify a parent field.
    +
    +
  • +
  • Parent Model: The system will assign this automatically.
  • +
  • Parent Field Value: Set up the name of the parent record (e.g., project name).
  • +
  • Parent Stage Field: Choose the stages field from the parent model to verify that the reply stage is within the parent stages.
  • +
  • Reply Stage Field: Choose the field for the stage that will be automatically updated when a non-internal user sends an update.(required)
  • +
  • Reply Stage: Set the stage value that will be updated.(required)
  • +
  • No Reply Stage: Set the stage value. If the record is in this state, updates from the user will not change the stage of the record.(required)
  • +
+
+
+

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 +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/social project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/mail_reply_stage/views/mail_reply_config_views.xml b/mail_reply_stage/views/mail_reply_config_views.xml new file mode 100644 index 0000000000..005b0fd4f1 --- /dev/null +++ b/mail_reply_stage/views/mail_reply_config_views.xml @@ -0,0 +1,38 @@ + + + + mail.reply.config.tree + mail.reply.config + + + + + + + + + + + + + + + Mail Reply Configurations + mail.reply.config + tree + + + + diff --git a/setup/mail_reply_stage/odoo/addons/mail_reply_stage b/setup/mail_reply_stage/odoo/addons/mail_reply_stage new file mode 120000 index 0000000000..dbc0c8b748 --- /dev/null +++ b/setup/mail_reply_stage/odoo/addons/mail_reply_stage @@ -0,0 +1 @@ +../../../../mail_reply_stage \ No newline at end of file diff --git a/setup/mail_reply_stage/setup.py b/setup/mail_reply_stage/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/mail_reply_stage/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)