From 6c915f34486db149fd6a2d5f29c333fbf4b4f5a5 Mon Sep 17 00:00:00 2001 From: oihane Date: Thu, 1 Jul 2021 15:53:49 +0200 Subject: [PATCH 01/14] [ADD] new module crm_claim_portal (#58) --- crm_claim_portal/README.rst | 26 ++ crm_claim_portal/__init__.py | 2 + crm_claim_portal/__manifest__.py | 20 ++ crm_claim_portal/controllers/__init__.py | 1 + .../controllers/crm_claim_portal.py | 103 +++++++ crm_claim_portal/i18n/crm_claim_portal.pot | 165 +++++++++++ crm_claim_portal/i18n/es.po | 165 +++++++++++ crm_claim_portal/models/__init__.py | 1 + crm_claim_portal/models/crm_claim.py | 9 + crm_claim_portal/views/crm_claim_template.xml | 274 ++++++++++++++++++ 10 files changed, 766 insertions(+) create mode 100644 crm_claim_portal/README.rst create mode 100644 crm_claim_portal/__init__.py create mode 100644 crm_claim_portal/__manifest__.py create mode 100644 crm_claim_portal/controllers/__init__.py create mode 100644 crm_claim_portal/controllers/crm_claim_portal.py create mode 100644 crm_claim_portal/i18n/crm_claim_portal.pot create mode 100644 crm_claim_portal/i18n/es.po create mode 100644 crm_claim_portal/models/__init__.py create mode 100644 crm_claim_portal/models/crm_claim.py create mode 100644 crm_claim_portal/views/crm_claim_template.xml diff --git a/crm_claim_portal/README.rst b/crm_claim_portal/README.rst new file mode 100644 index 00000000..49c7a2dd --- /dev/null +++ b/crm_claim_portal/README.rst @@ -0,0 +1,26 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +================ +CRM Claim Portal +================ + +This module allows portal user access to their related claims. + +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 smash it by providing detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ +* Oihane Crucelaegui + +Do not contact contributors directly about support or help with technical issues. diff --git a/crm_claim_portal/__init__.py b/crm_claim_portal/__init__.py new file mode 100644 index 00000000..91c5580f --- /dev/null +++ b/crm_claim_portal/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/crm_claim_portal/__manifest__.py b/crm_claim_portal/__manifest__.py new file mode 100644 index 00000000..0101f7af --- /dev/null +++ b/crm_claim_portal/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2021 Oihane Crucelaegui - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "CRM Claim Portal", + "version": "14.0.1.0.0", + "category": "Customer Relationship Management", + "license": "AGPL-3", + "author": "AvanzOSC", + "website": "http://www.avanzosc.es", + "depends": [ + "crm_claim", + "crm_claim_usability", + "portal", + ], + "data": [ + "views/crm_claim_template.xml" + ], + "installable": True, +} diff --git a/crm_claim_portal/controllers/__init__.py b/crm_claim_portal/controllers/__init__.py new file mode 100644 index 00000000..cec4a60b --- /dev/null +++ b/crm_claim_portal/controllers/__init__.py @@ -0,0 +1 @@ +from . import crm_claim_portal diff --git a/crm_claim_portal/controllers/crm_claim_portal.py b/crm_claim_portal/controllers/crm_claim_portal.py new file mode 100644 index 00000000..507e19cd --- /dev/null +++ b/crm_claim_portal/controllers/crm_claim_portal.py @@ -0,0 +1,103 @@ + +from odoo import http, _ +from odoo.exceptions import AccessError, MissingError +from odoo.http import request +from odoo.addons.portal.controllers.portal import pager as portal_pager +from odoo.addons.portal.controllers.portal import CustomerPortal + + +class CustomerPortal(CustomerPortal): + + def _prepare_home_portal_values(self, counters): + values = super()._prepare_home_portal_values(counters) + partner = request.env.user.partner_id + + claim_obj = request.env['crm.claim'] + if 'claim_count' in counters: + values['claim_count'] = ( + claim_obj.search_count([ + ('commercial_partner_id', 'child_of', + [partner.commercial_partner_id.id]), + ]) if claim_obj.check_access_rights( + 'read', raise_exception=False) else 0) + return values + + def _claim_get_page_view_values(self, claim, access_token, **kwargs): + values = { + 'page_name': 'claim', + 'claim': claim, + } + return self._get_page_view_values( + claim, access_token, values, 'my_claims_history', False, **kwargs) + + @http.route(['/my/claims', '/my/claims/page/'], + type='http', auth="user", website=True) + def portal_my_claims( + self, page=1, date_begin=None, date_end=None, sortby=None, **kw): + values = self._prepare_portal_layout_values() + claim_obj = request.env['crm.claim'] + domain = [] + + searchbar_sortings = { + "date": { + "label": _('Newest'), + "order": "create_date desc" + }, + "name": { + "label": _("Name"), + "order": "name" + }, + } + if not sortby: + sortby = 'date' + order = searchbar_sortings[sortby]['order'] + + if date_begin and date_end: + domain += [("create_date", '>', date_begin), + ("create_date", '<=', date_end)] + + # projects count + claim_count = claim_obj.search_count(domain) + # pager + pager = portal_pager( + url="/my/claims", + url_args={ + "date_begin": date_begin, + "date_end": date_end, + "sortby": sortby + }, + total=claim_count, + page=page, + step=self._items_per_page + ) + + # content according to pager and archive selected + claims = claim_obj.search( + domain, order=order, limit=self._items_per_page, + offset=pager['offset']) + request.session["my_claims_history"] = claims.ids[:100] + + values.update({ + "date": date_begin, + "date_end": date_end, + "claims": claims, + "page_name": 'claim', + "default_url": '/my/claims', + "pager": pager, + "searchbar_sortings": searchbar_sortings, + 'sortby': sortby + }) + return request.render("crm_claim_portal.portal_my_claims", values) + + @http.route(["/my/claim/"], + type="http", auth="public", website=True) + def portal_my_claim(self, claim_id=None, access_token=None, **kw): + try: + claim_sudo = self._document_check_access( + "crm.claim", claim_id, access_token) + except (AccessError, MissingError): + return request.redirect('/my') + + values = self._claim_get_page_view_values( + claim_sudo, access_token, **kw) + return request.render("crm_claim_portal.portal_my_claim", values) diff --git a/crm_claim_portal/i18n/crm_claim_portal.pot b/crm_claim_portal/i18n/crm_claim_portal.pot new file mode 100644 index 00000000..c481bfa5 --- /dev/null +++ b/crm_claim_portal/i18n/crm_claim_portal.pot @@ -0,0 +1,165 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * crm_claim_portal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-07-01 13:48+0000\n" +"PO-Revision-Date: 2021-07-01 13:48+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: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Status:" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Assigned to" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Date:" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Deadline:" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Description" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Message and communication history" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Reported by" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_warning +msgid "Access warning" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model,name:crm_claim_portal.model_crm_claim +msgid "Claim" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_layout +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_home_sale +msgid "Claims" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Contact" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Current stage of the claim" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Current stage of this task" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,help:crm_claim_portal.field_crm_claim__access_url +msgid "Customer Portal URL" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__display_name +msgid "Display Name" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__id +msgid "ID" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim____last_update +msgid "Last Modified on" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Name" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Newest" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_url +msgid "Portal Access URL" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_ids +msgid "Rating" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_avg +msgid "Rating Average" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_feedback +msgid "Rating Last Feedback" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_image +msgid "Rating Last Image" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_value +msgid "Rating Last Value" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_count +msgid "Rating count" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,help:crm_claim_portal.field_crm_claim__rating_last_feedback +msgid "Reason of the rating" +msgstr "" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_token +msgid "Security Token" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "There are no claims." +msgstr "" diff --git a/crm_claim_portal/i18n/es.po b/crm_claim_portal/i18n/es.po new file mode 100644 index 00000000..7acded83 --- /dev/null +++ b/crm_claim_portal/i18n/es.po @@ -0,0 +1,165 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * crm_claim_portal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-07-01 13:48+0000\n" +"PO-Revision-Date: 2021-07-01 13:48+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: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Status:" +msgstr "Estado:" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Assigned to" +msgstr "Asignado a" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Date:" +msgstr "Fecha:" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Deadline:" +msgstr "Fecha tope:" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Description" +msgstr "Descripción" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Message and communication history" +msgstr "Histórico de mensajes y comunicaciones" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Reported by" +msgstr "Notificado por" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_warning +msgid "Access warning" +msgstr "Alerta de acceso" + +#. module: crm_claim_portal +#: model:ir.model,name:crm_claim_portal.model_crm_claim +msgid "Claim" +msgstr "Reclamación" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_layout +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_home_sale +msgid "Claims" +msgstr "Reclamaciones" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Contact" +msgstr "Contacto" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Current stage of the claim" +msgstr "Estado actual de la reclamación" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim +msgid "Current stage of this task" +msgstr "Etapa actual de esta tarea" + +#. module: crm_claim_portal +#: model:ir.model.fields,help:crm_claim_portal.field_crm_claim__access_url +msgid "Customer Portal URL" +msgstr "URL del portal de cliente" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__id +msgid "ID" +msgstr "Identificador" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Name" +msgstr "Nombre" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Newest" +msgstr "Más reciente" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_url +msgid "Portal Access URL" +msgstr "URL de acceso al portal" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_ids +msgid "Rating" +msgstr "Calificación" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_avg +msgid "Rating Average" +msgstr "Calificación media" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_feedback +msgid "Rating Last Feedback" +msgstr "Clasificación del último comentario" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_image +msgid "Rating Last Image" +msgstr "Clasificación de la última imagen" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_last_value +msgid "Rating Last Value" +msgstr "Calificar Último Valor" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__rating_count +msgid "Rating count" +msgstr "Cuenta de calificación" + +#. module: crm_claim_portal +#: model:ir.model.fields,help:crm_claim_portal.field_crm_claim__rating_last_feedback +msgid "Reason of the rating" +msgstr "Causa de la calificación" + +#. module: crm_claim_portal +#: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_token +msgid "Security Token" +msgstr "Token de seguridad" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "There are no claims." +msgstr "No hay reclamaciones." diff --git a/crm_claim_portal/models/__init__.py b/crm_claim_portal/models/__init__.py new file mode 100644 index 00000000..29fa1b4d --- /dev/null +++ b/crm_claim_portal/models/__init__.py @@ -0,0 +1 @@ +from . import crm_claim diff --git a/crm_claim_portal/models/crm_claim.py b/crm_claim_portal/models/crm_claim.py new file mode 100644 index 00000000..87b579b4 --- /dev/null +++ b/crm_claim_portal/models/crm_claim.py @@ -0,0 +1,9 @@ +# Copyright 2021 Oihane Crucelaegui - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class CrmClaim(models.Model): + _name = "crm.claim" + _inherit = ["crm.claim", "portal.mixin", "rating.mixin"] diff --git a/crm_claim_portal/views/crm_claim_template.xml b/crm_claim_portal/views/crm_claim_template.xml new file mode 100644 index 00000000..5b53daed --- /dev/null +++ b/crm_claim_portal/views/crm_claim_template.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From aeeef054d4f3c350f7f97b76e0d4221e26b94ec0 Mon Sep 17 00:00:00 2001 From: oihane Date: Wed, 7 Jul 2021 12:43:40 +0200 Subject: [PATCH 02/14] [IMP] crm_claim_portal: extend searchbar (#65) --- crm_claim_portal/__manifest__.py | 4 +- .../controllers/crm_claim_portal.py | 256 +++++++++++++++--- crm_claim_portal/i18n/crm_claim_portal.pot | 142 +++++++++- crm_claim_portal/i18n/es.po | 147 +++++++++- .../security/crm_claim_security.xml | 11 + crm_claim_portal/security/ir.model.access.csv | 3 + crm_claim_portal/views/crm_claim_template.xml | 187 +++---------- 7 files changed, 556 insertions(+), 194 deletions(-) create mode 100644 crm_claim_portal/security/crm_claim_security.xml create mode 100644 crm_claim_portal/security/ir.model.access.csv diff --git a/crm_claim_portal/__manifest__.py b/crm_claim_portal/__manifest__.py index 0101f7af..550c9b8e 100644 --- a/crm_claim_portal/__manifest__.py +++ b/crm_claim_portal/__manifest__.py @@ -14,7 +14,9 @@ "portal", ], "data": [ - "views/crm_claim_template.xml" + "security/ir.model.access.csv", + "security/crm_claim_security.xml", + "views/crm_claim_template.xml", ], "installable": True, } diff --git a/crm_claim_portal/controllers/crm_claim_portal.py b/crm_claim_portal/controllers/crm_claim_portal.py index 507e19cd..490e8e9a 100644 --- a/crm_claim_portal/controllers/crm_claim_portal.py +++ b/crm_claim_portal/controllers/crm_claim_portal.py @@ -1,60 +1,205 @@ -from odoo import http, _ +from collections import OrderedDict +from dateutil.relativedelta import relativedelta +from operator import itemgetter + +from odoo import fields, http, _ from odoo.exceptions import AccessError, MissingError from odoo.http import request +from odoo.tools import date_utils, groupby as groupbyelem from odoo.addons.portal.controllers.portal import pager as portal_pager from odoo.addons.portal.controllers.portal import CustomerPortal +from odoo.osv.expression import OR + class CustomerPortal(CustomerPortal): def _prepare_home_portal_values(self, counters): values = super()._prepare_home_portal_values(counters) - partner = request.env.user.partner_id - - claim_obj = request.env['crm.claim'] - if 'claim_count' in counters: - values['claim_count'] = ( - claim_obj.search_count([ - ('commercial_partner_id', 'child_of', - [partner.commercial_partner_id.id]), - ]) if claim_obj.check_access_rights( - 'read', raise_exception=False) else 0) + + if "claim_count" in counters: + values["claim_count"] = request.env["crm.claim"].search_count([]) return values def _claim_get_page_view_values(self, claim, access_token, **kwargs): values = { - 'page_name': 'claim', - 'claim': claim, + "page_name": "claim", + "claim": claim, } return self._get_page_view_values( - claim, access_token, values, 'my_claims_history', False, **kwargs) - - @http.route(['/my/claims', '/my/claims/page/'], - type='http', auth="user", website=True) - def portal_my_claims( - self, page=1, date_begin=None, date_end=None, sortby=None, **kw): - values = self._prepare_portal_layout_values() - claim_obj = request.env['crm.claim'] - domain = [] + claim, access_token, values, "my_claims_history", False, **kwargs) - searchbar_sortings = { + def _get_searchbar_sortings(self): + return { "date": { - "label": _('Newest'), + "label": _("Newest"), "order": "create_date desc" }, "name": { "label": _("Name"), - "order": "name" + "order": "name", + }, + "deadline": { + "label": _("Deadline"), + "order": "date_deadline desc", + } + } + + def _get_searchbar_filters(self): + today = fields.Date.today() + quarter_start, quarter_end = date_utils.get_quarter(today) + last_week = today + relativedelta(weeks=-1) + last_month = today + relativedelta(months=-1) + last_year = today + relativedelta(years=-1) + + return { + "all": { + "label": _("All"), + "domain": [], + }, + "today": { + "label": _("Today"), + "domain": [("create_date", "=", today)], + }, + "week": { + "label": _("This week"), + "domain": [ + ("create_date", ">=", date_utils.start_of(today, "week")), + ("create_date", "<=", date_utils.end_of(today, "week"))], + }, + "month": { + "label": _("This month"), + "domain": [ + ("create_date", ">=", date_utils.start_of(today, "month")), + ("create_date", "<=", date_utils.end_of(today, "month"))], + }, + "year": { + "label": _("This year"), + "domain": [ + ("create_date", ">=", date_utils.start_of(today, "year")), + ("create_date", "<=", date_utils.end_of(today, "year"))], + }, + "quarter": { + "label": _("This Quarter"), + "domain": [ + ("create_date", ">=", quarter_start), + ("create_date", "<=", quarter_end)], + }, + "last_week": { + "label": _("Last week"), + "domain": [ + ("create_date", ">=", + date_utils.start_of(last_week, "week")), + ("create_date", "<=", + date_utils.end_of(last_week, "week"))], + }, + "last_month": { + "label": _("Last month"), + "domain": [ + ("create_date", ">=", + date_utils.start_of(last_month, "month")), + ("create_date", "<=", + date_utils.end_of(last_month, "month"))], + }, + "last_year": { + "label": _("Last year"), + "domain": [ + ("create_date", ">=", + date_utils.start_of(last_year, "year")), + ("create_date", "<=", + date_utils.end_of(last_year, "year"))], + }, + } + + def _get_searchbar_inputs(self): + return { + "content": { + "input": "content", + "label": _( + "Search (in Content)"), + }, + "message": { + "input": "message", + "label": _("Search in Messages"), + }, + "stage": { + "input": "stage", + "label": _("Search in Stages"), + }, + "all": { + "input": "all", + "label": _("Search in All"), + }, + } + + def _get_searchbar_groupby(self): + return { + "none": { + "input": "none", + "label": _("None"), + }, + "stage": { + "input": "stage", + "label": _("Stage"), + }, + "partner": { + "input": "partner", + "label": _("Reported by"), + }, + "user": { + "input": "user", + "label": _("Assigned to"), }, } + + @http.route(["/my/claims", "/my/claims/page/"], + type="http", auth="user", website=True) + def portal_my_claims( + self, page=1, date_begin=None, date_end=None, sortby=None, + filterby=None, search=None, search_in="content", groupby=None, + **kw): + values = self._prepare_portal_layout_values() + claim_obj = request.env["crm.claim"] + + searchbar_sortings = self._get_searchbar_sortings() + searchbar_filters = self._get_searchbar_filters() + searchbar_inputs = self._get_searchbar_inputs() + searchbar_groupby = self._get_searchbar_groupby() + + # default sort by value if not sortby: - sortby = 'date' - order = searchbar_sortings[sortby]['order'] + sortby = "date" + order = searchbar_sortings[sortby]["order"] + + # default filter by value + if not filterby: + filterby = "all" + domain = searchbar_filters.get( + filterby, searchbar_filters.get("all"))["domain"] + + # default group by value + if not groupby: + groupby = "none" if date_begin and date_end: - domain += [("create_date", '>', date_begin), - ("create_date", '<=', date_end)] + domain += [("create_date", ">", date_begin), + ("create_date", "<=", date_end)] + + # search + if search and search_in: + search_domain = [] + if search_in in ('content', 'all'): + search_domain = OR( + [search_domain, ['|', ('name', 'ilike', search), + ('description', 'ilike', search)]]) + if search_in in ('message', 'all'): + search_domain = OR( + [search_domain, [('message_ids.body', 'ilike', search)]]) + if search_in in ('stage', 'all'): + search_domain = OR( + [search_domain, [('stage_id', 'ilike', search)]]) + domain += search_domain # projects count claim_count = claim_obj.search_count(domain) @@ -64,28 +209,65 @@ def portal_my_claims( url_args={ "date_begin": date_begin, "date_end": date_end, - "sortby": sortby + "sortby": sortby, + "filterby": filterby, + "groupby": groupby, + "search_in": search_in, + "search": search, }, total=claim_count, page=page, - step=self._items_per_page + step=self._items_per_page, ) # content according to pager and archive selected + if groupby == "stage": + order = "stage_id, %s" % order + # force sort on stage first to group by stage in view + elif groupby == "partner": + order = "partner_id, %s" % order + # force sort on partner first to group by partner in view + elif groupby == "user": + order = "user_id, %s" % order + # force sort on user first to group by user in view + claims = claim_obj.search( domain, order=order, limit=self._items_per_page, - offset=pager['offset']) + offset=pager["offset"]) request.session["my_claims_history"] = claims.ids[:100] + if groupby == "stage": + grouped_claims = [ + request.env["crm.claim"].concat(*g) + for k, g in groupbyelem(claims, itemgetter("stage_id"))] + elif groupby == "partner": + grouped_claims = [ + request.env["crm.claim"].concat(*g) + for k, g in groupbyelem(claims, itemgetter("partner_id"))] + elif groupby == "user": + grouped_claims = [ + request.env["crm.claim"].concat(*g) + for k, g in groupbyelem(claims, itemgetter("user_id"))] + else: + grouped_claims = [claims] + values.update({ "date": date_begin, "date_end": date_end, - "claims": claims, - "page_name": 'claim', - "default_url": '/my/claims', + "grouped_claims": grouped_claims, + "page_name": "claim", + "default_url": "/my/claims", "pager": pager, "searchbar_sortings": searchbar_sortings, - 'sortby': sortby + "searchbar_groupby": searchbar_groupby, + "searchbar_inputs": searchbar_inputs, + "search_in": search_in, + "search": search, + "sortby": sortby, + "groupby": groupby, + "searchbar_filters": OrderedDict( + sorted(searchbar_filters.items())), + "filterby": filterby, }) return request.render("crm_claim_portal.portal_my_claims", values) @@ -96,7 +278,7 @@ def portal_my_claim(self, claim_id=None, access_token=None, **kw): claim_sudo = self._document_check_access( "crm.claim", claim_id, access_token) except (AccessError, MissingError): - return request.redirect('/my') + return request.redirect("/my") values = self._claim_get_page_view_values( claim_sudo, access_token, **kw) diff --git a/crm_claim_portal/i18n/crm_claim_portal.pot b/crm_claim_portal/i18n/crm_claim_portal.pot index c481bfa5..00a9449a 100644 --- a/crm_claim_portal/i18n/crm_claim_portal.pot +++ b/crm_claim_portal/i18n/crm_claim_portal.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-01 13:48+0000\n" -"PO-Revision-Date: 2021-07-01 13:48+0000\n" +"POT-Creation-Date: 2021-07-07 10:12+0000\n" +"PO-Revision-Date: 2021-07-07 10:12+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,6 +15,21 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims assigned to:" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims in stage:" +msgstr "" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims reported by:" +msgstr "" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim msgid "Status:" @@ -55,11 +70,28 @@ msgstr "" msgid "Access warning" msgstr "" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "All" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Assigned to" +msgstr "" + #. module: crm_claim_portal #: model:ir.model,name:crm_claim_portal.model_crm_claim msgid "Claim" msgstr "" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claim Subject" +msgstr "" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_layout #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims @@ -79,7 +111,7 @@ msgstr "" #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim -msgid "Current stage of this task" +msgid "Current stage of this claim" msgstr "" #. module: crm_claim_portal @@ -87,6 +119,12 @@ msgstr "" msgid "Customer Portal URL" msgstr "" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Deadline" +msgstr "" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__display_name msgid "Display Name" @@ -105,15 +143,41 @@ msgstr "" #. module: crm_claim_portal #: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 #, python-format +msgid "Last month" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Last week" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Last year" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format msgid "Name" msgstr "" #. module: crm_claim_portal #: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 #, python-format msgid "Newest" msgstr "" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "None" +msgstr "" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_url msgid "Portal Access URL" @@ -154,12 +218,84 @@ msgstr "" msgid "Reason of the rating" msgstr "" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Ref" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Reported by" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search (in Content)" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in All" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in Messages" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in Stages" +msgstr "" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_token msgid "Security Token" msgstr "" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +#, python-format +msgid "Stage" +msgstr "" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims msgid "There are no claims." msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This Quarter" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This month" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This week" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This year" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Today" +msgstr "" diff --git a/crm_claim_portal/i18n/es.po b/crm_claim_portal/i18n/es.po index 7acded83..8ae4f23d 100644 --- a/crm_claim_portal/i18n/es.po +++ b/crm_claim_portal/i18n/es.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-01 13:48+0000\n" -"PO-Revision-Date: 2021-07-01 13:48+0000\n" +"POT-Creation-Date: 2021-07-07 10:12+0000\n" +"PO-Revision-Date: 2021-07-07 10:12+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,6 +15,24 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims assigned to:" +msgstr "" +"Reclamaciones asignadas a:" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims in stage:" +msgstr "Reclamaciones en etapa:" + +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claims reported by:" +msgstr "" +"Reclamaciones notificadas " +"por:" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim msgid "Status:" @@ -55,11 +73,28 @@ msgstr "Notificado por" msgid "Access warning" msgstr "Alerta de acceso" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "All" +msgstr "Todos" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Assigned to" +msgstr "Asignado a" + #. module: crm_claim_portal #: model:ir.model,name:crm_claim_portal.model_crm_claim msgid "Claim" msgstr "Reclamación" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Claim Subject" +msgstr "Asunto de la reclamación" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_layout #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims @@ -79,14 +114,20 @@ msgstr "Estado actual de la reclamación" #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claim -msgid "Current stage of this task" -msgstr "Etapa actual de esta tarea" +msgid "Current stage of this claim" +msgstr "Etapa actual de esta reclamación" #. module: crm_claim_portal #: model:ir.model.fields,help:crm_claim_portal.field_crm_claim__access_url msgid "Customer Portal URL" msgstr "URL del portal de cliente" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Deadline" +msgstr "Fecha tope" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__display_name msgid "Display Name" @@ -105,15 +146,41 @@ msgstr "Última modificación el" #. module: crm_claim_portal #: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 #, python-format +msgid "Last month" +msgstr "Mes anterior" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Last week" +msgstr "Semana anterior" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Last year" +msgstr "Año anterior" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format msgid "Name" msgstr "Nombre" #. module: crm_claim_portal #: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 #, python-format msgid "Newest" msgstr "Más reciente" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "None" +msgstr "Ninguno" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_url msgid "Portal Access URL" @@ -154,12 +221,84 @@ msgstr "Cuenta de calificación" msgid "Reason of the rating" msgstr "Causa de la calificación" +#. module: crm_claim_portal +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +msgid "Ref" +msgstr "" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Reported by" +msgstr "Notificado por" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search (in Content)" +msgstr "Buscar (en Contenido)" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in All" +msgstr "Buscar en todos" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in Messages" +msgstr "Buscar en mensajes" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Search in Stages" +msgstr "Buscar en etapas" + #. module: crm_claim_portal #: model:ir.model.fields,field_description:crm_claim_portal.field_crm_claim__access_token msgid "Security Token" msgstr "Token de seguridad" +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims +#, python-format +msgid "Stage" +msgstr "Etapa" + #. module: crm_claim_portal #: model_terms:ir.ui.view,arch_db:crm_claim_portal.portal_my_claims msgid "There are no claims." msgstr "No hay reclamaciones." + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This Quarter" +msgstr "Este Trimestre" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This month" +msgstr "Este mes" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This week" +msgstr "Esta semana" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "This year" +msgstr "Este año" + +#. module: crm_claim_portal +#: code:addons/crm_claim_portal/controllers/crm_claim_portal.py:0 +#, python-format +msgid "Today" +msgstr "Hoy" diff --git a/crm_claim_portal/security/crm_claim_security.xml b/crm_claim_portal/security/crm_claim_security.xml new file mode 100644 index 00000000..bc2299f6 --- /dev/null +++ b/crm_claim_portal/security/crm_claim_security.xml @@ -0,0 +1,11 @@ + + + + Claim Portal + + + [('commercial_partner_id', 'child_of', [user.partner_id.commercial_partner_id.id])] + + diff --git a/crm_claim_portal/security/ir.model.access.csv b/crm_claim_portal/security/ir.model.access.csv new file mode 100644 index 00000000..5cdf374c --- /dev/null +++ b/crm_claim_portal/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_crm_claim_portal,crm.claim.portal,crm_claim.model_crm_claim,base.group_portal,1,0,0,0 +access_crm_claim_stage_portal,crm.claim.stage.portal,crm_claim.model_crm_claim_stage,base.group_portal,1,0,0,0 diff --git a/crm_claim_portal/views/crm_claim_template.xml b/crm_claim_portal/views/crm_claim_template.xml index 5b53daed..da592d29 100644 --- a/crm_claim_portal/views/crm_claim_template.xml +++ b/crm_claim_portal/views/crm_claim_template.xml @@ -35,34 +35,54 @@ Claims - + - - - - - # - - - - - - - - - + + + + + Ref + Claim Subject + + Claims reported by: + + + Claims assigned to: + + + Claims in stage: + + Stage + + + + + + + # + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 4bbb82ce8c90430e3209025bdc15dc89dd8cdc09 Mon Sep 17 00:00:00 2001 From: oihane Date: Thu, 8 Jul 2021 14:59:57 +0200 Subject: [PATCH 03/14] [FIX] crm_claim_portal: mail links failing for portal users (#68) --- crm_claim_portal/controllers/crm_claim_portal.py | 1 + crm_claim_portal/models/crm_claim.py | 5 +++++ crm_claim_portal/views/crm_claim_template.xml | 5 ----- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crm_claim_portal/controllers/crm_claim_portal.py b/crm_claim_portal/controllers/crm_claim_portal.py index 490e8e9a..cfa04d2b 100644 --- a/crm_claim_portal/controllers/crm_claim_portal.py +++ b/crm_claim_portal/controllers/crm_claim_portal.py @@ -26,6 +26,7 @@ def _claim_get_page_view_values(self, claim, access_token, **kwargs): values = { "page_name": "claim", "claim": claim, + "user": request.env.user, } return self._get_page_view_values( claim, access_token, values, "my_claims_history", False, **kwargs) diff --git a/crm_claim_portal/models/crm_claim.py b/crm_claim_portal/models/crm_claim.py index 87b579b4..d552880d 100644 --- a/crm_claim_portal/models/crm_claim.py +++ b/crm_claim_portal/models/crm_claim.py @@ -7,3 +7,8 @@ class CrmClaim(models.Model): _name = "crm.claim" _inherit = ["crm.claim", "portal.mixin", "rating.mixin"] + + def _compute_access_url(self): + super(CrmClaim, self)._compute_access_url() + for task in self: + task.access_url = '/my/claim/%s' % task.id diff --git a/crm_claim_portal/views/crm_claim_template.xml b/crm_claim_portal/views/crm_claim_template.xml index da592d29..5324fc04 100644 --- a/crm_claim_portal/views/crm_claim_template.xml +++ b/crm_claim_portal/views/crm_claim_template.xml @@ -1,10 +1,5 @@ - - - - -