[MIG] helpdesk_portal_ticket_enriched_description_form: migrate to 18.0
This commit is contained in:
2
helpdesk_portal_ticket_enriched_description_form/.gitignore
vendored
Normal file
2
helpdesk_portal_ticket_enriched_description_form/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.*~
|
||||||
|
*pyc
|
||||||
55
helpdesk_portal_ticket_enriched_description_form/README.md
Normal file
55
helpdesk_portal_ticket_enriched_description_form/README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
================================================
|
||||||
|
helpdesk_portal_ticket_enriched_description_form
|
||||||
|
================================================
|
||||||
|
|
||||||
|
Add fields in ticket creation portal form to enrich description content.
|
||||||
|
|
||||||
|
This module extends the ``helpdesk_mgmt`` portal ticket creation form by
|
||||||
|
replacing the single description field with three structured fields:
|
||||||
|
|
||||||
|
* **Description**: Main description of the issue or request, with a placeholder
|
||||||
|
guiding the user to be precise and describe how to reproduce any bug/error.
|
||||||
|
* **Access**: Optional field for providing a link toward the error or additional
|
||||||
|
information.
|
||||||
|
* **Bug report**: Optional field to paste the complete error message (e.g., Odoo
|
||||||
|
error code).
|
||||||
|
|
||||||
|
When the ticket is submitted, these three fields are automatically concatenated
|
||||||
|
into a single formatted HTML description with labeled sections (DESCRIPTION,
|
||||||
|
ACCESS, BUG REPORT).
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Use Odoo normal module installation procedure to install
|
||||||
|
`helpdesk_portal_ticket_enriched_description_form`.
|
||||||
|
|
||||||
|
This module depends on ``helpdesk_mgmt`` which must be available.
|
||||||
|
|
||||||
|
# Known issues / Roadmap
|
||||||
|
|
||||||
|
None yet.
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `our issues website <https://git.elabore.coop/Elabore/helpdesk-tools/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
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
- Stéphan Sainléger
|
||||||
|
|
||||||
|
## Funders
|
||||||
|
|
||||||
|
The development of this module has been financially supported by:
|
||||||
|
|
||||||
|
- Elabore (https://elabore.coop)
|
||||||
|
|
||||||
|
## Maintainer
|
||||||
|
|
||||||
|
This module is maintained by Elabore.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from . import controllers
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2024 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "helpdesk_portal_ticket_enriched_description_form",
|
||||||
|
"version": "18.0.1.0.0",
|
||||||
|
"author": "Elabore",
|
||||||
|
"website": "https://elabore.coop",
|
||||||
|
"maintainer": "Stéphan Sainléger",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"category": "Tools",
|
||||||
|
"summary": "Add fieds in ticket creation portal form to enrich description content.",
|
||||||
|
# any module necessary for this one to work correctly
|
||||||
|
"depends": [
|
||||||
|
"base",
|
||||||
|
"helpdesk_mgmt",
|
||||||
|
],
|
||||||
|
"qweb": [],
|
||||||
|
"external_dependencies": {
|
||||||
|
"python": [],
|
||||||
|
},
|
||||||
|
# always loaded
|
||||||
|
"data": [
|
||||||
|
"views/helpdesk_ticket_templates.xml",
|
||||||
|
],
|
||||||
|
# only loaded in demonstration mode
|
||||||
|
"demo": [],
|
||||||
|
"js": [],
|
||||||
|
"css": [],
|
||||||
|
"installable": True,
|
||||||
|
# Install this module automatically if all dependency have been previously
|
||||||
|
# and independently installed. Used for synergetic or glue modules.
|
||||||
|
"auto_install": False,
|
||||||
|
"application": False,
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
from . import main
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Copyright 2024 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import _
|
||||||
|
from odoo.addons.helpdesk_mgmt.controllers.main import HelpdeskTicketController
|
||||||
|
|
||||||
|
|
||||||
|
def build_enriched_description(small_description=None, access=None, bug_report=None):
|
||||||
|
"""
|
||||||
|
Build a formatted HTML description from the enriched form fields.
|
||||||
|
|
||||||
|
:param small_description: Main description of the issue
|
||||||
|
:param access: Link or access information
|
||||||
|
:param bug_report: Error message or bug report details
|
||||||
|
:return: Formatted HTML string
|
||||||
|
"""
|
||||||
|
description = ""
|
||||||
|
if small_description:
|
||||||
|
description = "<b>%s</b><br/>%s" % (_("DESCRIPTION:"), small_description)
|
||||||
|
if access:
|
||||||
|
description = "%s<br/><br/><b>%s</b><br/>%s" % (
|
||||||
|
description,
|
||||||
|
_("ACCESS:"),
|
||||||
|
access,
|
||||||
|
)
|
||||||
|
if bug_report:
|
||||||
|
description = "%s<br/><br/><b>%s</b><br/>%s" % (
|
||||||
|
description,
|
||||||
|
_("BUG REPORT:"),
|
||||||
|
bug_report,
|
||||||
|
)
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
class HelpdeskTicketControllerDescription(HelpdeskTicketController):
|
||||||
|
def _prepare_submit_ticket_vals(self, **kw):
|
||||||
|
# Pop enriched fields and build description BEFORE calling super
|
||||||
|
# to avoid parent's plaintext2html(kw.get("description")) crashing on None
|
||||||
|
small_description = kw.pop("small_description", None)
|
||||||
|
access = kw.pop("access", None)
|
||||||
|
bug_report = kw.pop("bug_report", None)
|
||||||
|
description = build_enriched_description(
|
||||||
|
small_description=small_description,
|
||||||
|
access=access,
|
||||||
|
bug_report=bug_report,
|
||||||
|
)
|
||||||
|
# Set description in kw for parent, using a placeholder to avoid
|
||||||
|
# plaintext2html issues - we'll overwrite the result anyway
|
||||||
|
kw["description"] = ""
|
||||||
|
res = super()._prepare_submit_ticket_vals(**kw)
|
||||||
|
res["description"] = description
|
||||||
|
return res
|
||||||
68
helpdesk_portal_ticket_enriched_description_form/i18n/fr.po
Normal file
68
helpdesk_portal_ticket_enriched_description_form/i18n/fr.po
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 18.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-03-17 14:30+0000\n"
|
||||||
|
"PO-Revision-Date: 2026-03-17 14:30+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Language: fr\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ACCESS:"
|
||||||
|
msgstr "ACCÈS :"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Access"
|
||||||
|
msgstr "Accès"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Be precise. If there is a bug/error, please describe how to reproduce it"
|
||||||
|
msgstr "Soyez précis. Si vous avez une erreur, merci de décrire comment la reproduire."
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "BUG REPORT:"
|
||||||
|
msgstr "RAPPORT DE BUG :"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Bug report"
|
||||||
|
msgstr "Rapport de bug"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "DESCRIPTION:"
|
||||||
|
msgstr "DESCRIPTION :"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Description"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Link toward error or additional information"
|
||||||
|
msgstr "Lien vers l'erreur ou des informations complémentaires"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Paste here the complete error message (ex: error code Odoo)"
|
||||||
|
msgstr "Copier ici le message d'erreur complet (ex: code d'erreur Odoo)"
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 18.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-03-17 14:30+0000\n"
|
||||||
|
"PO-Revision-Date: 2026-03-17 14:30+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ACCESS:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Be precise. If there is a bug/error, please describe how to reproduce it"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "BUG REPORT:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Bug report"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/helpdesk_portal_ticket_enriched_description_form/controllers/main.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "DESCRIPTION:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Description"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Link toward error or additional information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: helpdesk_portal_ticket_enriched_description_form
|
||||||
|
#: model_terms:ir.ui.view,arch_db:helpdesk_portal_ticket_enriched_description_form.helpdesk_create_ticket_description
|
||||||
|
msgid "Paste here the complete error message (ex: error code Odoo)"
|
||||||
|
msgstr ""
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Copyright 2024 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import test_controller
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# Copyright 2024 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo.tests.common import TransactionCase, tagged
|
||||||
|
|
||||||
|
from ..controllers.main import build_enriched_description
|
||||||
|
|
||||||
|
|
||||||
|
@tagged("post_install", "-at_install")
|
||||||
|
class TestBuildEnrichedDescription(TransactionCase):
|
||||||
|
"""Test cases for the build_enriched_description utility function."""
|
||||||
|
|
||||||
|
def test_all_fields(self):
|
||||||
|
"""Test that all three fields are correctly concatenated."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
small_description="This is the main description",
|
||||||
|
access="https://example.com/error",
|
||||||
|
bug_report="Error 500: Internal Server Error",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn("<b>DESCRIPTION:</b>", result)
|
||||||
|
self.assertIn("This is the main description", result)
|
||||||
|
self.assertIn("<b>ACCESS:</b>", result)
|
||||||
|
self.assertIn("https://example.com/error", result)
|
||||||
|
self.assertIn("<b>BUG REPORT:</b>", result)
|
||||||
|
self.assertIn("Error 500: Internal Server Error", result)
|
||||||
|
|
||||||
|
def test_description_only(self):
|
||||||
|
"""Test with only the description field filled."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
small_description="Only description provided",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn("<b>DESCRIPTION:</b>", result)
|
||||||
|
self.assertIn("Only description provided", result)
|
||||||
|
self.assertNotIn("ACCESS:", result)
|
||||||
|
self.assertNotIn("BUG REPORT:", result)
|
||||||
|
|
||||||
|
def test_description_and_access(self):
|
||||||
|
"""Test with description and access fields filled."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
small_description="Description text",
|
||||||
|
access="https://link.com",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn("<b>DESCRIPTION:</b>", result)
|
||||||
|
self.assertIn("Description text", result)
|
||||||
|
self.assertIn("<b>ACCESS:</b>", result)
|
||||||
|
self.assertIn("https://link.com", result)
|
||||||
|
self.assertNotIn("BUG REPORT:", result)
|
||||||
|
|
||||||
|
def test_description_and_bug_report(self):
|
||||||
|
"""Test with description and bug report fields filled."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
small_description="Description text",
|
||||||
|
bug_report="Traceback error here",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn("<b>DESCRIPTION:</b>", result)
|
||||||
|
self.assertIn("Description text", result)
|
||||||
|
self.assertNotIn("ACCESS:", result)
|
||||||
|
self.assertIn("<b>BUG REPORT:</b>", result)
|
||||||
|
self.assertIn("Traceback error here", result)
|
||||||
|
|
||||||
|
def test_access_only(self):
|
||||||
|
"""Test with only the access field filled."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
access="https://link.com",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNotIn("DESCRIPTION:", result)
|
||||||
|
self.assertIn("<b>ACCESS:</b>", result)
|
||||||
|
self.assertIn("https://link.com", result)
|
||||||
|
self.assertNotIn("BUG REPORT:", result)
|
||||||
|
|
||||||
|
def test_bug_report_only(self):
|
||||||
|
"""Test with only the bug report field filled."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
bug_report="Error message",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNotIn("DESCRIPTION:", result)
|
||||||
|
self.assertNotIn("ACCESS:", result)
|
||||||
|
self.assertIn("<b>BUG REPORT:</b>", result)
|
||||||
|
self.assertIn("Error message", result)
|
||||||
|
|
||||||
|
def test_access_and_bug_report(self):
|
||||||
|
"""Test with access and bug report fields filled (no description)."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
access="https://link.com",
|
||||||
|
bug_report="Error message",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNotIn("DESCRIPTION:", result)
|
||||||
|
self.assertIn("<b>ACCESS:</b>", result)
|
||||||
|
self.assertIn("https://link.com", result)
|
||||||
|
self.assertIn("<b>BUG REPORT:</b>", result)
|
||||||
|
self.assertIn("Error message", result)
|
||||||
|
|
||||||
|
def test_empty(self):
|
||||||
|
"""Test with no fields filled."""
|
||||||
|
result = build_enriched_description()
|
||||||
|
|
||||||
|
self.assertEqual(result, "")
|
||||||
|
|
||||||
|
def test_html_structure(self):
|
||||||
|
"""Test that the HTML structure is correctly formatted with line breaks."""
|
||||||
|
result = build_enriched_description(
|
||||||
|
small_description="Desc",
|
||||||
|
access="Link",
|
||||||
|
bug_report="Error",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that sections are separated by double line breaks
|
||||||
|
self.assertIn("<br/><br/><b>ACCESS:</b>", result)
|
||||||
|
self.assertIn("<br/><br/><b>BUG REPORT:</b>", result)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="helpdesk_create_ticket_description" name="Create Ticket: Description"
|
||||||
|
inherit_id="helpdesk_mgmt.portal_create_ticket" priority="40">
|
||||||
|
<xpath expr="//textarea[@name='description']/../.." position="replace">
|
||||||
|
<div class="form-group">
|
||||||
|
<label
|
||||||
|
class="col-md-3 col-dm-4 control-label"
|
||||||
|
for="small_description"
|
||||||
|
>Description
|
||||||
|
</label>
|
||||||
|
<div class="col-md-7 col-sm-8">
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="small_description"
|
||||||
|
style="min-height: 120px"
|
||||||
|
required="True"
|
||||||
|
placeholder="Be precise. If there is a bug/error, please describe how to reproduce it"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label
|
||||||
|
class="col-md-3 col-dm-4 control-label"
|
||||||
|
for="access"
|
||||||
|
>Access
|
||||||
|
</label>
|
||||||
|
<div class="col-md-7 col-sm-8">
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
type="text"
|
||||||
|
name="access"
|
||||||
|
placeholder="Link toward error or additional information"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label
|
||||||
|
class="col-md-3 col-dm-4 control-label"
|
||||||
|
for="bug_report"
|
||||||
|
>Bug report
|
||||||
|
</label>
|
||||||
|
<div class="col-md-7 col-sm-8">
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="bug_report"
|
||||||
|
style="min-height: 120px"
|
||||||
|
placeholder="Paste here the complete error message (ex: error code Odoo)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3" />
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user