fsm_visit_confirmation: translate template, move away from ratings
This commit is contained in:
parent
95a95298bb
commit
81a4a904c7
6 changed files with 703 additions and 66 deletions
|
|
@ -3,10 +3,9 @@
|
|||
import logging
|
||||
import werkzeug
|
||||
|
||||
from odoo import http
|
||||
from odoo import http, _
|
||||
from odoo.http import request
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools.misc import get_lang
|
||||
from odoo.addons.base.models.ir_qweb import keep_query
|
||||
from odoo.addons.portal.controllers.portal import CustomerPortal
|
||||
from odoo.exceptions import AccessError, MissingError
|
||||
|
||||
|
|
@ -20,65 +19,101 @@ class CustomerPortalExtended(CustomerPortal):
|
|||
def portal_my_task(self, task_id, access_token=None, **kw):
|
||||
"""Override to allow access with token for public users."""
|
||||
try:
|
||||
task_sudo = self._document_check_access(
|
||||
"project.task", task_id, access_token
|
||||
task = request.env["project.task"].browse(task_id)
|
||||
task.check_access_rights("read")
|
||||
task.check_access_rights("write")
|
||||
task.check_access_rule("read")
|
||||
task.check_access_rule("write")
|
||||
except AccessError:
|
||||
task = None
|
||||
values = self._get_portal_values(task, access_token=access_token, **kw)
|
||||
if not task:
|
||||
task = values.get("task", False)
|
||||
if not task:
|
||||
return self._render_error_page(
|
||||
_("Task not found or invalid token"), task=None
|
||||
)
|
||||
except (AccessError, MissingError):
|
||||
return request.redirect("/my")
|
||||
|
||||
# Pass the task to the original method
|
||||
return super(CustomerPortalExtended, self).portal_my_task(
|
||||
result = super(CustomerPortalExtended, self).portal_my_task(
|
||||
task_id, access_token=access_token, **kw
|
||||
)
|
||||
|
||||
# If the result is a Response object (like a redirect), return it directly
|
||||
if isinstance(result, werkzeug.wrappers.Response):
|
||||
return result
|
||||
|
||||
# Otherwise, it's a rendered template, so we need to update the qcontext
|
||||
if hasattr(result, "qcontext"):
|
||||
result.qcontext.update(values)
|
||||
|
||||
return result
|
||||
|
||||
@http.route(
|
||||
"/my/fsm_confirmation/<string:token>/<string:action>",
|
||||
"/my/fsm_confirmation/<string:action>",
|
||||
type="http",
|
||||
auth="public",
|
||||
website=True,
|
||||
)
|
||||
def fsm_confirmation_action(self, token, action, **kwargs):
|
||||
def fsm_confirmation_action(self, action, **kwargs):
|
||||
"""Custom landing page for FSM visit confirmations.
|
||||
|
||||
Args:
|
||||
token: The access token for the task
|
||||
action: Either 'approve' or 'change'
|
||||
Kwargs:
|
||||
access_token: The access token for the task
|
||||
"""
|
||||
values = self._get_portal_values(**kwargs)
|
||||
task = values.get("task", False)
|
||||
if not task:
|
||||
return self._render_error_page(
|
||||
_("Task not found or invalid token"), task=None
|
||||
)
|
||||
# Store the language in kwargs for use in redirects
|
||||
lang = values.get("lang")
|
||||
|
||||
if action not in ("approve", "change"):
|
||||
raise werkzeug.exceptions.BadRequest(_("Invalid action"))
|
||||
|
||||
# Get the task using the token
|
||||
task_sudo = self._get_task_by_token(token)
|
||||
if not task_sudo:
|
||||
return self._render_error_page(_("Task not found or invalid token"))
|
||||
|
||||
# If it's an approval, update the task state directly
|
||||
if action == "approve":
|
||||
try:
|
||||
# Update task state to approved
|
||||
task_sudo.sudo().write({"state": "03_approved"})
|
||||
|
||||
task.write({"state": "03_approved"})
|
||||
|
||||
# Add a message to the chatter
|
||||
task_sudo.sudo().message_post(
|
||||
task.message_post(
|
||||
body=_("Visit approved by customer"),
|
||||
message_type="comment",
|
||||
subtype_xmlid="mail.mt_note",
|
||||
)
|
||||
|
||||
# Always redirect to the task portal page with success message
|
||||
return request.redirect(
|
||||
"/my/task/%s?visit_confirmation_status=approved&access_token=%s"
|
||||
% (task_sudo.id, token)
|
||||
redirect_url = "/my/task/%s?%s" % (
|
||||
task.id,
|
||||
keep_query(
|
||||
"access_token",
|
||||
visit_confirmation_status="approved",
|
||||
lang=lang,
|
||||
),
|
||||
)
|
||||
return request.redirect(redirect_url)
|
||||
except Exception as e:
|
||||
_logger.exception("Error approving task: %s", e)
|
||||
return self._render_error_page(str(e))
|
||||
_logger.exception(_("Error approving task: %s"), e)
|
||||
return self._render_error_page(
|
||||
_("Error approving task: %s") % str(e), task=task
|
||||
)
|
||||
|
||||
# For change requests, redirect to the task portal page with change request form
|
||||
return request.redirect(
|
||||
"/my/task/%s?visit_confirmation_status=change&token=%s&access_token=%s"
|
||||
% (task_sudo.id, token, token)
|
||||
redirect_url = "/my/task/%s?%s" % (
|
||||
task.id,
|
||||
keep_query(
|
||||
"access_token",
|
||||
visit_confirmation_status="change",
|
||||
lang=lang,
|
||||
),
|
||||
)
|
||||
return request.redirect(redirect_url)
|
||||
|
||||
@http.route(
|
||||
"/my/fsm_confirmation/submit_change",
|
||||
|
|
@ -90,60 +125,146 @@ class CustomerPortalExtended(CustomerPortal):
|
|||
)
|
||||
def fsm_confirmation_submit_change(self, **kwargs):
|
||||
"""Handle the submission of change request form."""
|
||||
token = kwargs.get("token")
|
||||
values = self._get_portal_values(**kwargs)
|
||||
|
||||
task = values.get("task", False)
|
||||
lang = values.get("lang")
|
||||
feedback = kwargs.get("feedback", "")
|
||||
|
||||
if not token or not feedback:
|
||||
return request.redirect("/my")
|
||||
|
||||
# Get the task using the token
|
||||
task_sudo = self._get_task_by_token(token)
|
||||
if not task_sudo:
|
||||
return self._render_error_page(_("Task not found or invalid token"))
|
||||
if not task:
|
||||
return self._render_error_page(
|
||||
_("Task not found or invalid token"), task=None
|
||||
)
|
||||
if not feedback:
|
||||
return self._render_error_page(
|
||||
_("No feedback provided. Please try again!"), task=task
|
||||
)
|
||||
|
||||
try:
|
||||
# Update task state to changes requested
|
||||
task_sudo.sudo().write({"state": "02_changes_requested"})
|
||||
|
||||
task.write({"state": "02_changes_requested"})
|
||||
|
||||
# Add the feedback as a message to the chatter
|
||||
task_sudo.sudo().message_post(
|
||||
task.message_post(
|
||||
body=_("Changes requested by customer: %s") % feedback,
|
||||
message_type="comment",
|
||||
subtype_xmlid="mail.mt_comment",
|
||||
)
|
||||
|
||||
# Always redirect to the task portal page with success message
|
||||
return request.redirect(
|
||||
"/my/task/%s?visit_confirmation_status=change_submitted&access_token=%s"
|
||||
% (task_sudo.id, token)
|
||||
redirect_url = "/my/task/%s?%s" % (
|
||||
task.id,
|
||||
keep_query(
|
||||
access_token=kwargs.get("access_token"),
|
||||
visit_confirmation_status="change_submitted",
|
||||
lang=lang,
|
||||
),
|
||||
)
|
||||
return request.redirect(redirect_url)
|
||||
except Exception as e:
|
||||
_logger.exception("Error submitting change request: %s", e)
|
||||
return self._render_error_page(str(e))
|
||||
_logger.exception(_("Error submitting change request: %s"), e)
|
||||
return self._render_error_page(
|
||||
_("Error submitting change request: %s") % str(e), task=task
|
||||
)
|
||||
|
||||
def _get_task_by_token(self, token):
|
||||
"""Get a task by its access token."""
|
||||
# First try to find the task directly by token
|
||||
task = request.env["project.task"].sudo().search([("access_token", "=", token)], limit=1)
|
||||
# First try to find the task directly by access token
|
||||
task = (
|
||||
request.env["project.task"]
|
||||
.sudo()
|
||||
.search([("access_token", "=", token)], limit=1)
|
||||
)
|
||||
if task:
|
||||
return task
|
||||
|
||||
|
||||
# If not found, try to find it through the rating token
|
||||
# This is for backward compatibility with existing tokens in emails
|
||||
rating = request.env["rating.rating"].sudo().search([("access_token", "=", token)], limit=1)
|
||||
rating = (
|
||||
request.env["rating.rating"]
|
||||
.sudo()
|
||||
.search([("access_token", "=", token)], limit=1)
|
||||
)
|
||||
if rating and rating.res_model == "project.task":
|
||||
task = request.env["project.task"].sudo().browse(rating.res_id)
|
||||
if task.exists():
|
||||
return task
|
||||
|
||||
|
||||
return None
|
||||
|
||||
def _render_error_page(self, error_message):
|
||||
def _render_error_page(self, error_message, task=None, **kwargs):
|
||||
"""Render an error page."""
|
||||
return request.render(
|
||||
"http_routing.http_error",
|
||||
{
|
||||
"status_code": "400",
|
||||
"status_message": error_message,
|
||||
},
|
||||
values = {
|
||||
"status_code": "400",
|
||||
"status_message": error_message,
|
||||
"lang": self._get_lang(task=task, lang=kwargs.get("lang")),
|
||||
}
|
||||
|
||||
return request.render("http_routing.http_error", values)
|
||||
|
||||
def _get_portal_values(self, task=None, **kwargs):
|
||||
"""Get common values for portal templates.
|
||||
|
||||
Args:
|
||||
task: The task record if already loaded
|
||||
**kwargs: Keyword arguments from the request
|
||||
|
||||
Returns:
|
||||
Dictionary with values for template rendering
|
||||
"""
|
||||
values = {"page_name": "task"}
|
||||
if not task:
|
||||
access_token = kwargs.get("access_token")
|
||||
if access_token:
|
||||
task = self._get_task_by_token(access_token)
|
||||
if task:
|
||||
values["task"] = task
|
||||
|
||||
# Set language and update values dictionary
|
||||
values["lang"] = self._get_lang(task=task, lang=kwargs.get("lang"))
|
||||
|
||||
# Add any additional parameters from kwargs that might be needed in templates
|
||||
for key in ["visit_confirmation_status", "error", "warning", "success"]:
|
||||
if kwargs.get(key):
|
||||
values[key] = kwargs.get(key)
|
||||
|
||||
return values
|
||||
|
||||
def _get_lang(self, task=None, lang=None):
|
||||
"""Helper method to set the language in the request environment.
|
||||
|
||||
Args:
|
||||
task: The task record (optional)
|
||||
lang: Language code (e.g., 'en_US', 'fr_FR') (optional)
|
||||
|
||||
Returns:
|
||||
The language code that was set, or None if no language was set
|
||||
"""
|
||||
# If lang is not provided, try to get it from the task
|
||||
if not lang and task:
|
||||
lang_partner = (
|
||||
task.work_order_contacts
|
||||
and task.work_order_contacts[0]
|
||||
or task.partner_id
|
||||
)
|
||||
if lang_partner and lang_partner.lang:
|
||||
lang = lang_partner.lang
|
||||
|
||||
if not lang:
|
||||
return None
|
||||
|
||||
# Get the language record
|
||||
lang_code = lang.replace("_", "-")
|
||||
lang_id = (
|
||||
request.env["res.lang"]
|
||||
.sudo()
|
||||
.search(["|", ("code", "=", lang_code), ("code", "=", lang)], limit=1)
|
||||
)
|
||||
|
||||
if lang_id:
|
||||
# Set the context language
|
||||
request.env = request.env(
|
||||
context=dict(request.env.context, lang=lang_id.code)
|
||||
)
|
||||
return lang_id.code
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
<field name="body_html" type="html">
|
||||
<div>
|
||||
<div style="margin-bottom: 16px;">
|
||||
Dear <t t-out="object.work_order_contacts and object.work_order_contacts[0].name or object.partner_id.name"/>,
|
||||
Dear <t t-out="object.work_order_contacts and object.work_order_contacts[0].name or object.partner_id.name"/>
|
||||
,
|
||||
</div>
|
||||
<div style="margin-bottom: 16px;">
|
||||
We would like to confirm the details of your upcoming service visit:
|
||||
|
|
@ -29,7 +30,8 @@
|
|||
<t t-set="partner_tz" t-value="user.tz or object.company_id.partner_id.tz or 'America/Toronto'"/>
|
||||
<span t-field="object.planned_date_begin" t-options="{'widget': 'datetime', 'timezone': partner_tz}"/>
|
||||
<div style="font-size: 12px; color: #666;">
|
||||
(Timezone: <t t-out="partner_tz"/>)
|
||||
(Timezone: <t t-out="partner_tz"/>
|
||||
)
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -42,7 +44,8 @@
|
|||
<t t-out="object.partner_id.street2"/>
|
||||
<br/>
|
||||
</t>
|
||||
<t t-out="object.partner_id.city"/>, <t t-out="object.partner_id.state_id.code"/>
|
||||
<t t-out="object.partner_id.city"/>
|
||||
, <t t-out="object.partner_id.state_id.code"/>
|
||||
<t t-out="object.partner_id.zip"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -65,12 +68,13 @@
|
|||
<tr>
|
||||
<td style="padding:10px;text-align:center;">
|
||||
<t t-set="base_url" t-value="object.get_base_url()"/>
|
||||
<a t-att-href="base_url + '/my/fsm_confirmation/' + object.access_token + '/approve'" style="background-color:#28a745;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;">
|
||||
<t t-set="lang" t-value="object.work_order_contacts and object.work_order_contacts[0].lang or object.partner_id.lang or 'en_US'"/>
|
||||
<a t-att-href="base_url + '/my/fsm_confirmation/approve?' + keep_query(lang=lang,access_token=object.access_token)" style="background-color:#28a745;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;">
|
||||
Approve Visit
|
||||
</a>
|
||||
</td>
|
||||
<td style="padding:10px;text-align:center;">
|
||||
<a t-att-href="base_url + '/my/fsm_confirmation/' + object.access_token + '/change'" style="background-color:#dc3545;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;">
|
||||
<a t-att-href="base_url + '/my/fsm_confirmation/change?' + keep_query(lang=lang,access_token=object.access_token)" style="background-color:#dc3545;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;">
|
||||
Request Changes
|
||||
</a>
|
||||
</td>
|
||||
|
|
@ -78,7 +82,8 @@
|
|||
</table>
|
||||
<div style="margin-top: 16px;">
|
||||
<p>Best regards,</p>
|
||||
<p>The <t t-out="object.company_id.name"/> service management team</p>
|
||||
<p>The <t t-out="object.company_id.name"/>
|
||||
service management team</p>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
|
|
|
|||
299
fsm_visit_confirmation/i18n/fr.po
Normal file
299
fsm_visit_confirmation/i18n/fr.po
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * fsm_visit_confirmation
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 17.0+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-27 00:31+0000\n"
|
||||
"PO-Revision-Date: 2025-02-27 00:31+0000\n"
|
||||
"Last-Translator: Marc Durepos <marc@bemade.org>\n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,body_html:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid ""
|
||||
"<div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" Dear <t t-out=\"object.work_order_contacts and object.work_order_contacts[0].name or object.partner_id.name\"></t>\n"
|
||||
",\n"
|
||||
" </div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" We would like to confirm the details of your upcoming service visit:\n"
|
||||
" </div>\n"
|
||||
" <table style=\"border-style:solid;box-sizing:border-box;border-left-color:#e7e7e7;border-bottom-color:#e7e7e7;border-right-color:#e7e7e7;border-top-color:#e7e7e7;border-left-width:1px;border-bottom-width:1px;border-right-width:1px;border-top-width:1px;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;border:1pxsolid#e7e7e7\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Task Summary</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.name\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Technician Arrival</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-set=\"partner\" t-value=\"object.work_order_contacts and object.work_order_contacts[0] or object.partner_id\"></t>\n"
|
||||
" <t t-set=\"partner_tz\" t-value=\"user.tz or object.company_id.partner_id.tz or 'America/Toronto'\"></t>\n"
|
||||
" <span t-field=\"object.planned_date_begin\" t-options=\"{'widget': 'datetime', 'timezone': partner_tz}\"></span>\n"
|
||||
" <div style=\"font-size: 12px; color: #666;\">\n"
|
||||
" (Timezone: <t t-out=\"partner_tz\"></t>\n"
|
||||
")\n"
|
||||
" </div>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Location</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.partner_id.street\"></t>\n"
|
||||
" <br>\n"
|
||||
" <t t-if=\"object.partner_id.street2\">\n"
|
||||
" <t t-out=\"object.partner_id.street2\"></t>\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" <t t-out=\"object.partner_id.city\"></t>\n"
|
||||
", <t t-out=\"object.partner_id.state_id.code\"></t>\n"
|
||||
" <t t-out=\"object.partner_id.zip\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa\">Assigned Technician(s)</td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px\">\n"
|
||||
" <t t-foreach=\"object.user_ids\" t-as=\"user\">\n"
|
||||
" <t t-out=\"user.name\"></t>\n"
|
||||
" <t t-if=\"not user_last\">\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" </t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin: 16px 0px 16px 0px;\">\n"
|
||||
" Please take a moment to confirm this visit by clicking one of the following options:\n"
|
||||
" </div>\n"
|
||||
" <table style=\"box-sizing:border-box;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <t t-set=\"base_url\" t-value=\"object.get_base_url()\"></t>\n"
|
||||
" <t t-set=\"lang\" t-value=\"object.work_order_contacts and object.work_order_contacts[0].lang or object.partner_id.lang or 'en_US'\"></t>\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/approve?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#28a745;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Approve Visit\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/change?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#dc3545;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Request Changes\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin-top: 16px;\">\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">Best regards,</p>\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">The <t t-out=\"object.company_id.name\"></t>\n"
|
||||
" service management team</p>\n"
|
||||
" </div>\n"
|
||||
" </div>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" Cher/chère<t t-out=\"object.work_order_contacts and object.work_order_contacts[0].name or object.partner_id.name\"></t>\n"
|
||||
",\n"
|
||||
" </div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" Nous aimerions confirmer les détails de votre visite de service à venir.\n"
|
||||
" </div>\n"
|
||||
" <table style=\"border-style:solid;box-sizing:border-box;border-left-color:#e7e7e7;border-bottom-color:#e7e7e7;border-right-color:#e7e7e7;border-top-color:#e7e7e7;border-left-width:1px;border-bottom-width:1px;border-right-width:1px;border-top-width:1px;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;border:1pxsolid#e7e7e7\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Visite</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.name\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Début</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-set=\"partner\" t-value=\"object.work_order_contacts and object.work_order_contacts[0] or object.partner_id\"></t>\n"
|
||||
" <t t-set=\"partner_tz\" t-value=\"user.tz or object.company_id.partner_id.tz or 'America/Toronto'\"></t>\n"
|
||||
" <span t-field=\"object.planned_date_begin\" t-options=\"{'widget': 'datetime', 'timezone': partner_tz}\"></span>\n"
|
||||
" <div style=\"font-size: 12px; color: #666;\">\n"
|
||||
" (Fuseau horaire: <t t-out=\"partner_tz\"></t>\n"
|
||||
")\n"
|
||||
" </div>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Lieu</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.partner_id.street\"></t>\n"
|
||||
" <br>\n"
|
||||
" <t t-if=\"object.partner_id.street2\">\n"
|
||||
" <t t-out=\"object.partner_id.street2\"></t>\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" <t t-out=\"object.partner_id.city\"></t>\n"
|
||||
", <t t-out=\"object.partner_id.state_id.code\"></t>\n"
|
||||
" <t t-out=\"object.partner_id.zip\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa\">Technicien(s) assigné(s)</td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px\">\n"
|
||||
" <t t-foreach=\"object.user_ids\" t-as=\"user\">\n"
|
||||
" <t t-out=\"user.name\"></t>\n"
|
||||
" <t t-if=\"not user_last\">\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" </t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin: 16px 0px 16px 0px;\">\n"
|
||||
" Veuillez prendre un moment pour confirmer cette visite en cliquant sur une des options suivantes :\n"
|
||||
" </div>\n"
|
||||
" <table style=\"box-sizing:border-box;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <t t-set=\"base_url\" t-value=\"object.get_base_url()\"></t>\n"
|
||||
" <t t-set=\"lang\" t-value=\"object.work_order_contacts and object.work_order_contacts[0].lang or object.partner_id.lang or 'en_US'\"></t>\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/approve?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#28a745;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Confirmer la visite\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/change?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#dc3545;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Demander des changements\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin-top: 16px;\">\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">Cordialement,</p>\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">L'équipe de gestion des services de <t t-out=\"object.company_id.name\"></t></p>\n"
|
||||
" </div>\n"
|
||||
" </div>\n"
|
||||
" "
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-check-circle me-2\"/>\n"
|
||||
" <strong>Success!</strong> Thank you for approving this service visit."
|
||||
msgstr ""
|
||||
"<i class=\"fa fa-check-circle me-2\"/>\n"
|
||||
" <strong>Succès!</strong> Merci d'avoir approuvé cette visite de service."
|
||||
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-exclamation-triangle me-2\"/>\n"
|
||||
" Request Changes to Service Visit"
|
||||
msgstr ""
|
||||
"<i class=\"fa fa-exclamation-triangle me-2\"/>\n"
|
||||
" Demander des changements à la visite de service"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-info-circle me-2\"/>\n"
|
||||
" <strong>Thank you!</strong> Your change request has been submitted. Our team will review it shortly."
|
||||
msgstr ""
|
||||
"<i class=\"fa fa-info-circle me-2\"/>\n"
|
||||
" <strong>Merci!</strong> Votre demande de changement a été soumise. Notre équipe examinerait cette demande rapidement."
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Changes requested by customer: %s"
|
||||
msgstr "Changements demandés par client: %s"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Error approving task: %s"
|
||||
msgstr "Erreur lors de l'approbation de la tâche: %s"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Error submitting change request: %s"
|
||||
msgstr "Erreur lors de la soumission de la demande de changement: %s"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,name:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "FSM Visit Confirmation"
|
||||
msgstr "Confirmation de visite de service"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Invalid action"
|
||||
msgstr "Action invalide"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "No feedback provided. Please try again!"
|
||||
msgstr "Aucun commentaire fourni. Veuillez réessayer!"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Please explain what changes you need..."
|
||||
msgstr "Veuillez expliquer les modifications nécessaires..."
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"Please provide details about the changes you would like to make to this "
|
||||
"service visit:"
|
||||
msgstr ""
|
||||
"Veuillez fournir des informations sur les modifications que vous souhaitez "
|
||||
"apporter à cette visite de service :"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,description:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "Send a visit confirmation email to the customer"
|
||||
msgstr "Envoyer un email de confirmation de visite au client"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,subject:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "Service Visit Confirmation: {{ object.name }}"
|
||||
msgstr "Confirmation de visite de service: {{ object.name }}"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Submit Request"
|
||||
msgstr "Soumettre la demande"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Task not found or invalid token"
|
||||
msgstr "Tâche introuvable ou jeton invalide"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Visit approved by customer"
|
||||
msgstr "Visite approuvée par le client"
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Your Comments:"
|
||||
msgstr "Vos commentaires :"
|
||||
211
fsm_visit_confirmation/i18n/fsm_visit_confirmation.pot
Normal file
211
fsm_visit_confirmation/i18n/fsm_visit_confirmation.pot
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * fsm_visit_confirmation
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 17.0+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-27 00:31+0000\n"
|
||||
"PO-Revision-Date: 2025-02-27 00:31+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: fsm_visit_confirmation
|
||||
#: model:mail.template,body_html:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid ""
|
||||
"<div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" Dear <t t-out=\"object.work_order_contacts and object.work_order_contacts[0].name or object.partner_id.name\"></t>\n"
|
||||
",\n"
|
||||
" </div>\n"
|
||||
" <div style=\"margin-bottom: 16px;\">\n"
|
||||
" We would like to confirm the details of your upcoming service visit:\n"
|
||||
" </div>\n"
|
||||
" <table style=\"border-style:solid;box-sizing:border-box;border-left-color:#e7e7e7;border-bottom-color:#e7e7e7;border-right-color:#e7e7e7;border-top-color:#e7e7e7;border-left-width:1px;border-bottom-width:1px;border-right-width:1px;border-top-width:1px;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;border:1pxsolid#e7e7e7\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Task Summary</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.name\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Technician Arrival</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-set=\"partner\" t-value=\"object.work_order_contacts and object.work_order_contacts[0] or object.partner_id\"></t>\n"
|
||||
" <t t-set=\"partner_tz\" t-value=\"user.tz or object.company_id.partner_id.tz or 'America/Toronto'\"></t>\n"
|
||||
" <span t-field=\"object.planned_date_begin\" t-options=\"{'widget': 'datetime', 'timezone': partner_tz}\"></span>\n"
|
||||
" <div style=\"font-size: 12px; color: #666;\">\n"
|
||||
" (Timezone: <t t-out=\"partner_tz\"></t>\n"
|
||||
")\n"
|
||||
" </div>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa;border-bottom:1pxsolid#e7e7e7\">Location</td>\n"
|
||||
" <td style=\"border-style:solid;box-sizing:border-box;border-bottom-color:#e7e7e7;border-left-width:0px;border-bottom-width:1px;border-right-width:0px;border-top-width:0px;padding:10px;border-bottom:1pxsolid#e7e7e7\">\n"
|
||||
" <t t-out=\"object.partner_id.street\"></t>\n"
|
||||
" <br>\n"
|
||||
" <t t-if=\"object.partner_id.street2\">\n"
|
||||
" <t t-out=\"object.partner_id.street2\"></t>\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" <t t-out=\"object.partner_id.city\"></t>\n"
|
||||
", <t t-out=\"object.partner_id.state_id.code\"></t>\n"
|
||||
" <t t-out=\"object.partner_id.zip\"></t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" <tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;background-color:#f8f9fa\">Assigned Technician(s)</td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px\">\n"
|
||||
" <t t-foreach=\"object.user_ids\" t-as=\"user\">\n"
|
||||
" <t t-out=\"user.name\"></t>\n"
|
||||
" <t t-if=\"not user_last\">\n"
|
||||
" <br>\n"
|
||||
" </t>\n"
|
||||
" </t>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin: 16px 0px 16px 0px;\">\n"
|
||||
" Please take a moment to confirm this visit by clicking one of the following options:\n"
|
||||
" </div>\n"
|
||||
" <table style=\"box-sizing:border-box;-webkit-border-vertical-spacing:0px;-webkit-border-horizontal-spacing:0px;border-collapse:collapse;caption-side:bottom;width:100%;border-spacing:0;\" width=\"100%\">\n"
|
||||
" <tbody style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\"><tr style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px\">\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <t t-set=\"base_url\" t-value=\"object.get_base_url()\"></t>\n"
|
||||
" <t t-set=\"lang\" t-value=\"object.work_order_contacts and object.work_order_contacts[0].lang or object.partner_id.lang or 'en_US'\"></t>\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/approve?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#28a745;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Approve Visit\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" <td style=\"border-style:none;box-sizing:border-box;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;border-top-width:0px;padding:10px;text-align:center\">\n"
|
||||
" <a t-att-href=\"base_url + '/my/fsm_confirmation/change?access_token=' + object.access_token + '&lang=' + lang\" style=\"box-sizing:border-box;background-color:#dc3545;padding:8px 16px;text-decoration:none;color:#fff;border-radius:5px;font-size:13px;\">\n"
|
||||
" Request Changes\n"
|
||||
" </a>\n"
|
||||
" </td>\n"
|
||||
" </tr>\n"
|
||||
" </tbody></table>\n"
|
||||
" <div style=\"margin-top: 16px;\">\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">Best regards,</p>\n"
|
||||
" <p style=\"margin:0px 0 16px 0;box-sizing:border-box;\">The <t t-out=\"object.company_id.name\"></t>\n"
|
||||
" service management team</p>\n"
|
||||
" </div>\n"
|
||||
" </div>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-check-circle me-2\"/>\n"
|
||||
" <strong>Success!</strong> Thank you for approving this service visit."
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-exclamation-triangle me-2\"/>\n"
|
||||
" Request Changes to Service Visit"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"<i class=\"fa fa-info-circle me-2\"/>\n"
|
||||
" <strong>Thank you!</strong> Your change request has been submitted. Our team will review it shortly."
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Changes requested by customer: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Error approving task: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Error submitting change request: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,name:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "FSM Visit Confirmation"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Invalid action"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "No feedback provided. Please try again!"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Please explain what changes you need..."
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid ""
|
||||
"Please provide details about the changes you would like to make to this "
|
||||
"service visit:"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,description:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "Send a visit confirmation email to the customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model:mail.template,subject:fsm_visit_confirmation.fsm_visit_confirmation_email_template
|
||||
msgid "Service Visit Confirmation: {{ object.name }}"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Submit Request"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Task not found or invalid token"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#. odoo-python
|
||||
#: code:addons/fsm_visit_confirmation/controllers/main.py:0
|
||||
#, python-format
|
||||
msgid "Visit approved by customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: fsm_visit_confirmation
|
||||
#: model_terms:ir.ui.view,arch_db:fsm_visit_confirmation.portal_my_task
|
||||
msgid "Your Comments:"
|
||||
msgstr ""
|
||||
|
|
@ -120,7 +120,7 @@ class TestFSMVisitConfirmation(HttpCase):
|
|||
"""Test the complete task approval flow"""
|
||||
# Test the FSM confirmation approve endpoint
|
||||
self.authenticate(None, None)
|
||||
url = f"/my/fsm_confirmation/{self.token}/approve"
|
||||
url = f"/my/fsm_confirmation/approve?access_token={self.token}"
|
||||
response = self.url_open(url)
|
||||
self.assertEqual(
|
||||
response.status_code, 200, "FSM confirmation approve should succeed"
|
||||
|
|
@ -146,7 +146,7 @@ class TestFSMVisitConfirmation(HttpCase):
|
|||
"""Test the complete task request changes flow"""
|
||||
# Test the FSM confirmation change endpoint
|
||||
self.authenticate(None, None)
|
||||
url = f"/my/fsm_confirmation/{self.token}/change"
|
||||
url = f"/my/fsm_confirmation/change?access_token={self.token}"
|
||||
response = self.url_open(url)
|
||||
self.assertEqual(
|
||||
response.status_code, 200, "FSM confirmation change should succeed"
|
||||
|
|
@ -157,7 +157,7 @@ class TestFSMVisitConfirmation(HttpCase):
|
|||
response = self.url_open(
|
||||
url,
|
||||
data={
|
||||
"token": self.token,
|
||||
"access_token": self.token,
|
||||
"feedback": "Need some changes",
|
||||
"csrf_token": http.Request.csrf_token(self),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
<p>Please provide details about the changes you would like to make to this service visit:</p>
|
||||
<form action="/my/fsm_confirmation/submit_change" method="post">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input type="hidden" name="token" t-att-value="request.params.get('token')"/>
|
||||
<input type="hidden" name="access_token" t-att-value="request.params.get('access_token')"/>
|
||||
<input type="hidden" name="lang" t-att-value="request.context.get('lang') or request.params.get('lang')"/>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="feedback" class="form-label">Your Comments:</label>
|
||||
|
|
|
|||
Loading…
Reference in a new issue