Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ee3fc45
commit f568827
Showing
9 changed files
with
352 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
.. |company| replace:: ADHOC SA | ||
|
||
.. |company_logo| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-logo.png | ||
:alt: ADHOC SA | ||
:target: https://www.adhoc.com.ar | ||
|
||
.. |icon| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-icon.png | ||
|
||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png | ||
:target: https://www.gnu.org/licenses/agpl | ||
:alt: License: AGPL-3 | ||
|
||
============================== | ||
Dynamic Messages on form views | ||
============================== | ||
|
||
Este modulo sirve para generar mensajes dinamicos en vistas form de cualquier modelo de Odoo. | ||
Algunos ejemplos: | ||
|
||
#. Dar un determinado warning cuando un partner es de un determinado país | ||
#. Advertir cuando un ticket es de un cliente de una determinada categoría | ||
|
||
Roadmap: | ||
#. Mejorar readme | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/ingadhoc/miscellaneous/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smashing it by providing a detailed and welcomed feedback. | ||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
* |company| |icon| | ||
|
||
Contributors | ||
------------ | ||
|
||
Maintainer | ||
---------- | ||
|
||
|company_logo| | ||
|
||
This module is maintained by the |company|. | ||
|
||
To contribute to this module, please visit https://www.adhoc.com.ar. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
############################################################################## | ||
# | ||
# Copyright (C) 2019 ADHOC SA (http://www.adhoc.com.ar) | ||
# All Rights Reserved. | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
# published by the Free Software Foundation, either version 3 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
# | ||
############################################################################## | ||
{ | ||
'name': 'Dynamic Message', | ||
'version': '16.0.1.1.0', | ||
'category': 'Base', | ||
'sequence': 14, | ||
'summary': '', | ||
'author': 'ADHOC SA', | ||
'website': 'www.adhoc.com.ar', | ||
'license': 'AGPL-3', | ||
'images': [ | ||
], | ||
'depends': [ | ||
'base', | ||
], | ||
'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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import ir_model_dynamic_message | ||
from . import ir_model_dynamic_message_line |
106 changes: 106 additions & 0 deletions
106
base_dynamic_message/models/ir_model_dynamic_message.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from odoo import models, fields, api | ||
import ast | ||
import textwrap | ||
|
||
|
||
class IrModelDynamicMessage(models.Model): | ||
_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) | ||
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') | ||
|
||
@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) | ||
|
||
@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 | ||
rec.code = """ | ||
for rec in self: | ||
messages = [] | ||
%s | ||
if not messages: | ||
rec['%s'] = False | ||
else: | ||
rec['%s'] = "<ul>%%s</ul>" %% "".join(["<li>%%s</li>" %% message for message in messages]) | ||
""" % (sub_string, field_name, field_name) | ||
|
||
@api.depends('line_ids.domain') | ||
def _compute_depends(self): | ||
for rec in self: | ||
dep_fields = [] | ||
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': | ||
dep_fields.append(element[0]) | ||
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_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, | ||
} | ||
if rec.field_id: | ||
rec.field_id.sudo().write(field_vals) | ||
else: | ||
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': """ | ||
<sheet position="before"> | ||
<div class="alert alert-%s mb-0" role="alert" attrs="{'invisible': [('%s', '=', False)]}"> | ||
<field name="%s" nolabel="1" readonly="1"/> | ||
</div> | ||
</sheet> | ||
""" % (rec.alert_type, field_name, field_name), | ||
} | ||
if rec.view_id: | ||
rec.view_id.sudo().write(view_vals) | ||
else: | ||
rec.view_id = rec.view_id.sudo().create(view_vals) | ||
|
||
@api.ondelete(at_uninstall=True) | ||
def _delete_field_and_view(self): | ||
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') | ||
] |
40 changes: 40 additions & 0 deletions
40
base_dynamic_message/models/ir_model_dynamic_message_line.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from odoo import models, fields, api | ||
import re | ||
|
||
|
||
class IrModelDynamicMessageLine(models.Model): | ||
_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') | ||
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) | ||
|
||
@api.depends('message', 'domain') | ||
def _compute_code(self): | ||
for rec in self: | ||
if rec.domain: | ||
# si el doinio tiene expresiones "EXP:" recorremos las tuplas y lo dejamos sin string y limpiamos el "EXP:"" | ||
domain = rec.domain | ||
if "EXP:" in rec.domain: | ||
# construido con chatgpt | ||
# Original string | ||
# Regular expression pattern to extract the expression parts | ||
pattern = r'"EXP: (.+?)"' | ||
|
||
matches = re.finditer(pattern, domain) | ||
|
||
for match in matches: | ||
expression = match.group(1) | ||
domain = domain.replace(f'"EXP: {expression}"', expression) | ||
|
||
rec.code = """ | ||
if rec in rec.filtered_domain(%s): | ||
messages.append('%s') | ||
""" % (domain, str(rec.message).replace('<p>', '').replace('</p>', '')) | ||
else: | ||
rec.code = False | ||
# code = self.filtered_domain(self.env['account.payment.method']._get_payment_method_domain(payment_method_code)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_ir_model_dynamic_message,access_ir_model_dynamic_message,model_ir_model_dynamic_message,base.group_user,1,0,0,0 | ||
access_ir_model_dynamic_message_line,access_ir_model_dynamic_message_line,model_ir_model_dynamic_message_line,base.group_user,1,0,0,0 | ||
access_ir_model_dynamic_message_admin,access_ir_model_dynamic_message,model_ir_model_dynamic_message,group_dynamic_messages_manager,1,1,1,1 | ||
access_ir_model_dynamic_message_line_admin,access_ir_model_dynamic_message_line,model_ir_model_dynamic_message_line,group_dynamic_messages_manager,1,1,1,1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo> | ||
<!-- <record model="ir.module.category" id="dynamic_messages_manager"> | ||
<field name="name">Manage Dynamic Messages</field> | ||
</record> --> | ||
|
||
<record id="group_dynamic_messages_manager" model="res.groups"> | ||
<field name="name">Manage Dynamic Messages</field> | ||
<!-- <field name="name">Portal Holiday</field> | ||
<field name="category_id" ref="category_portal_holiday"/> --> | ||
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/> | ||
</record> | ||
</odoo> |
89 changes: 89 additions & 0 deletions
89
base_dynamic_message/views/ir_model_dynamic_message_views.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<odoo> | ||
<record id="view_ir_model_dynamic_message_tree" model="ir.ui.view"> | ||
<field name="name">ir.model.dynamic_message.tree</field> | ||
<field name="model">ir.model.dynamic_message</field> | ||
<field name="arch" type="xml"> | ||
<tree> | ||
<field name="name"/> | ||
<field name="description"/> | ||
<field name="model_id"/> | ||
</tree> | ||
</field> | ||
</record> | ||
|
||
<record id="view_ir_model_dynamic_message_form" model="ir.ui.view"> | ||
<field name="name">ir.model.dynamic_message.form</field> | ||
<field name="model">ir.model.dynamic_message</field> | ||
<field name="arch" type="xml"> | ||
<form> | ||
<header> | ||
<button string="Create / Update" type="object" name="confirm" class="oe_highlight"/> | ||
</header> | ||
<sheet> | ||
<field name="id" invisible="1"/> | ||
<field name="model_name" invisible="1"/> | ||
<group> | ||
<group> | ||
<field name="name"/> | ||
<field name="description"/> | ||
<field name="model_id" force_save="True" options="{'no_create': True, 'no_open': True}" attrs="{'readonly': ['|', ('line_ids', '!=', []), ('id', '!=', False)]}"/> | ||
</group> | ||
<group> | ||
<field name="alert_type"/> | ||
<field name="view_to_inherit_id" domain="[('arch_db', 'like', '<sheet>'), ('type', '=', 'form'), ('model', '=', model_name), ('mode', '=', 'primary')]"/> | ||
<field name="view_id" groups="base.group_no_one" readonly="True"/> | ||
<field name="field_id" groups="base.group_no_one" readonly="True"/> | ||
<field name="depends"/> | ||
</group> | ||
</group> | ||
<notebook> | ||
<page string="Lines"> | ||
<field name="line_ids"> | ||
<tree> | ||
<field name="description" optional="hide"/> | ||
<field name="domain" optional="show"/> | ||
<field name="message" optional="show"/> | ||
<field name="code" optional="show"/> | ||
<field name="model_name" invisible="True"/> | ||
</tree> | ||
<form> | ||
<p>En las expresiones, del lado derecho, se puede usar el string "EXP:[expresion]" para poner codigo dinamico. A la hora de pasar el dominio al calculo solo se | ||
dejará la expresion. Es importante que "EXP" se ponga con comillas dobles y no comillas simples tal como se muestra en los ejemplos. Las variables disponibles son: | ||
<ul> | ||
<li>rec: registro que se está evaluando</li> | ||
<li>las mismas variables disponibles en un campo calculado, por ej "datetime.datetime.now()" y "dateutil.relativedelta.relativedelta":</li> | ||
</ul> | ||
Por ej: | ||
<ul> | ||
<li>[("create_date", "=", "EXP: datetime.datetime.now() - dateutil.relativedelta.relativedelta(days=-10)")]</li> | ||
<li>[("partner_id", "in", ["EXP: rec.child_ids.ids"])]</li> | ||
</ul> | ||
</p> | ||
<group> | ||
<field name="description"/> | ||
<field name="domain" widget="domain" options="{'model': 'model_name', 'in_dialog': True}" /> | ||
<field name="message"/> | ||
<field name="code"/> | ||
<field name="model_name" invisible="True"/> | ||
</group> | ||
</form> | ||
</field> | ||
</page> | ||
<page string="Code"> | ||
<field name="code"/> | ||
</page> | ||
</notebook> | ||
</sheet> | ||
</form> | ||
</field> | ||
</record> | ||
|
||
<record id="action_ir_model_dynamic_message" model="ir.actions.act_window"> | ||
<field name="name">Dynamic Messages</field> | ||
<field name="res_model">ir.model.dynamic_message</field> | ||
<field name="target">current</field> | ||
<field name='view_mode'>tree,form</field> | ||
</record> | ||
|
||
<menuitem id="menu_ir_model_dynamic_message" groups="group_dynamic_messages_manager" sequence="100" action="action_ir_model_dynamic_message" web_icon="fa fa-info,#f1c40f,#34495e"/> | ||
</odoo> |