mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
@@ -36,6 +36,7 @@
|
|||||||
"data/pms_confirmed_reservation_email_template.xml",
|
"data/pms_confirmed_reservation_email_template.xml",
|
||||||
"data/pms_modified_reservation_email_template.xml",
|
"data/pms_modified_reservation_email_template.xml",
|
||||||
"data/pms_cancelled_reservation_email_template.xml",
|
"data/pms_cancelled_reservation_email_template.xml",
|
||||||
|
"data/pms_precheckin_invitation_email_template.xml",
|
||||||
"data/pms_data.xml",
|
"data/pms_data.xml",
|
||||||
"data/traveller_report_paperformat.xml",
|
"data/traveller_report_paperformat.xml",
|
||||||
"report/pms_folio.xml",
|
"report/pms_folio.xml",
|
||||||
@@ -81,8 +82,10 @@
|
|||||||
"views/reservation_portal_templates.xml",
|
"views/reservation_portal_templates.xml",
|
||||||
"views/res_company_views.xml",
|
"views/res_company_views.xml",
|
||||||
"views/traveller_report_template.xml",
|
"views/traveller_report_template.xml",
|
||||||
|
"views/assets.xml",
|
||||||
"wizards/wizard_split_join_swap_reservation.xml",
|
"wizards/wizard_split_join_swap_reservation.xml",
|
||||||
"views/pms_automated_mails_views.xml",
|
"views/pms_automated_mails_views.xml",
|
||||||
|
"views/precheckin_portal_templates.xml",
|
||||||
"wizards/wizard_massive_changes.xml",
|
"wizards/wizard_massive_changes.xml",
|
||||||
"wizards/wizard_advanced_filters.xml",
|
"wizards/wizard_advanced_filters.xml",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from odoo import _, http
|
import re
|
||||||
|
|
||||||
|
from odoo import _, fields, http, tools
|
||||||
from odoo.exceptions import AccessError, MissingError
|
from odoo.exceptions import AccessError, MissingError
|
||||||
from odoo.http import request
|
from odoo.http import request
|
||||||
|
|
||||||
@@ -109,6 +111,35 @@ class PortalFolio(CustomerPortal):
|
|||||||
values = self._folio_get_page_view_values(folio_sudo, access_token, **kw)
|
values = self._folio_get_page_view_values(folio_sudo, access_token, **kw)
|
||||||
return request.render("pms.folio_portal_template", values)
|
return request.render("pms.folio_portal_template", values)
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/folios/<int:folio_id>/precheckin"], type="http", auth="user", website=True
|
||||||
|
)
|
||||||
|
def portal_my_folio_precheckin(
|
||||||
|
self, folio_id, access_token=None, report_type=None, download=False, **kw
|
||||||
|
):
|
||||||
|
values = self._prepare_portal_layout_values()
|
||||||
|
try:
|
||||||
|
folio_sudo = self._document_check_access(
|
||||||
|
"pms.folio",
|
||||||
|
folio_id,
|
||||||
|
access_token=access_token,
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my")
|
||||||
|
values.update(self._folio_get_page_view_values(folio_sudo, access_token, **kw))
|
||||||
|
values.update({"no_breadcrumbs": True, "error": {}})
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_folio_precheckin", values)
|
||||||
|
|
||||||
|
|
||||||
class PortalReservation(CustomerPortal):
|
class PortalReservation(CustomerPortal):
|
||||||
def _prepare_home_portal_values(self, counters):
|
def _prepare_home_portal_values(self, counters):
|
||||||
@@ -144,9 +175,7 @@ class PortalReservation(CustomerPortal):
|
|||||||
auth="user",
|
auth="user",
|
||||||
website=True,
|
website=True,
|
||||||
)
|
)
|
||||||
def portal_my_reservations(
|
def portal_my_reservations(self, page=1, date_begin=None, date_end=None):
|
||||||
self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw
|
|
||||||
):
|
|
||||||
partner = request.env.user.partner_id
|
partner = request.env.user.partner_id
|
||||||
values = self._prepare_portal_layout_values()
|
values = self._prepare_portal_layout_values()
|
||||||
Reservation = request.env["pms.reservation"]
|
Reservation = request.env["pms.reservation"]
|
||||||
@@ -208,9 +237,403 @@ class PortalReservation(CustomerPortal):
|
|||||||
)
|
)
|
||||||
except (AccessError, MissingError):
|
except (AccessError, MissingError):
|
||||||
return request.redirect("/my")
|
return request.redirect("/my")
|
||||||
# for attachment in reservation_sudo.attachment_ids:
|
|
||||||
# attachment.generate_access_token()
|
|
||||||
values = self._reservation_get_page_view_values(
|
values = self._reservation_get_page_view_values(
|
||||||
reservation_sudo, access_token, **kw
|
reservation_sudo, access_token, **kw
|
||||||
)
|
)
|
||||||
return request.render("pms.portal_my_reservation_detail", values)
|
return request.render("pms.portal_my_reservation_detail", values)
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/reservations/<int:reservation_id>/precheckin"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_reservation_precheckin(self, reservation_id, access_token=None, **kw):
|
||||||
|
try:
|
||||||
|
reservation_sudo = self._document_check_access(
|
||||||
|
"pms.reservation",
|
||||||
|
reservation_id,
|
||||||
|
access_token=access_token,
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my")
|
||||||
|
values = self._reservation_get_page_view_values(
|
||||||
|
reservation_sudo, access_token, **kw
|
||||||
|
)
|
||||||
|
values.update({"no_breadcrumbs": True, "error": {}})
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_reservation_precheckin", values)
|
||||||
|
|
||||||
|
|
||||||
|
class PortalPrecheckin(CustomerPortal):
|
||||||
|
def _precheckin_get_page_view_values(self, checkin_partner, access_token, **kwargs):
|
||||||
|
values = {"checkin_partner": checkin_partner, "token": access_token}
|
||||||
|
return self._get_page_view_values(
|
||||||
|
checkin_partner,
|
||||||
|
access_token,
|
||||||
|
values,
|
||||||
|
"my_precheckins_history",
|
||||||
|
False,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/precheckin/<int:checkin_partner_id>"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
)
|
||||||
|
def portal_my_precheckin_detail(self, checkin_partner_id, access_token=None, **kw):
|
||||||
|
try:
|
||||||
|
checkin_sudo = self._document_check_access(
|
||||||
|
"pms.checkin.partner",
|
||||||
|
checkin_partner_id,
|
||||||
|
access_token=access_token,
|
||||||
|
)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my")
|
||||||
|
values = self._precheckin_get_page_view_values(checkin_sudo, access_token, **kw)
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
"no_breadcrumbs": True,
|
||||||
|
"error": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_precheckin_detail", values)
|
||||||
|
|
||||||
|
@http.route(["/my/precheckin"], type="http", auth="user", website=True, csrf=False)
|
||||||
|
def portal_precheckin_submit(self, **kw):
|
||||||
|
values = dict()
|
||||||
|
checkin_partner = request.env["pms.checkin.partner"].browse(int(kw.get("id")))
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"checkin_partner": checkin_partner,
|
||||||
|
"error": {},
|
||||||
|
"error_message": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
if kw:
|
||||||
|
error, error_message = self.form_validate(kw, None)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"no_breadcrumbs": True,
|
||||||
|
"error": error,
|
||||||
|
"error_message": error_message,
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if error:
|
||||||
|
return request.render("pms.portal_my_precheckin_detail", values)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
values = kw
|
||||||
|
if values.get("document_type"):
|
||||||
|
doc_type = (
|
||||||
|
request.env["res.partner.id_category"]
|
||||||
|
.sudo()
|
||||||
|
.search([("name", "=", values.get("document_type"))])
|
||||||
|
)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"document_type": doc_type.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
request.env["pms.checkin.partner"].sudo()._save_data_from_portal(
|
||||||
|
values
|
||||||
|
)
|
||||||
|
doc_type_ids = (
|
||||||
|
request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"success": True,
|
||||||
|
"checkin_partner": checkin_partner,
|
||||||
|
"no_breadcrumbs": True,
|
||||||
|
"error": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_precheckin_detail", values)
|
||||||
|
except (AccessError, MissingError):
|
||||||
|
return request.redirect("/my")
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/precheckin/folio_reservation"],
|
||||||
|
type="http",
|
||||||
|
auth="user",
|
||||||
|
website=True,
|
||||||
|
csrf=False,
|
||||||
|
)
|
||||||
|
def portal_precheckin_folio_submit(self, **kw):
|
||||||
|
errors = {}
|
||||||
|
e_messages = {}
|
||||||
|
counter = 1
|
||||||
|
has_error = False
|
||||||
|
checkin_partners = False
|
||||||
|
if kw.get("folio_id"):
|
||||||
|
folio = request.env["pms.folio"].browse(int(kw.get("folio_id")))
|
||||||
|
checkin_partners = folio.checkin_partner_ids
|
||||||
|
elif kw.get("reservation_id"):
|
||||||
|
reservation = request.env["pms.reservation"].browse(
|
||||||
|
int(kw.get("reservation_id"))
|
||||||
|
)
|
||||||
|
checkin_partners = reservation.checkin_partner_ids
|
||||||
|
for checkin in checkin_partners:
|
||||||
|
values = {
|
||||||
|
"id": kw.get("id-" + str(counter)),
|
||||||
|
"firstname": kw.get("firstname-" + str(counter)),
|
||||||
|
"lastname": kw.get("lastname-" + str(counter)),
|
||||||
|
"lastname2": kw.get("lastname2-" + str(counter)),
|
||||||
|
"gender": kw.get("gender-" + str(counter)),
|
||||||
|
"birthdate_date": kw.get("birthdate_date-" + str(counter))
|
||||||
|
if kw.get("birthdate_date-" + str(counter))
|
||||||
|
else False,
|
||||||
|
"document_type": kw.get("document_type-" + str(counter)),
|
||||||
|
"document_number": kw.get("document_number-" + str(counter)),
|
||||||
|
"document_expedition_date": kw.get(
|
||||||
|
"document_expedition_date-" + str(counter)
|
||||||
|
)
|
||||||
|
if kw.get("document_expedition_date-" + str(counter))
|
||||||
|
else False,
|
||||||
|
"mobile": kw.get("mobile-" + str(counter)),
|
||||||
|
"email": kw.get("email-" + str(counter)),
|
||||||
|
"nationality_id": kw.get("nationality_id-" + str(counter)),
|
||||||
|
"state": kw.get("state-" + str(counter)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if values.get("document_type"):
|
||||||
|
doc_type_code = values.get("document_type")
|
||||||
|
doc_type = (
|
||||||
|
request.env["res.partner.id_category"]
|
||||||
|
.sudo()
|
||||||
|
.search([("name", "=", doc_type_code)])
|
||||||
|
)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"document_type": doc_type.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
error, error_message = self.form_validate(kw, counter)
|
||||||
|
errors.update(error)
|
||||||
|
e_messages.update(error_message)
|
||||||
|
if error_message:
|
||||||
|
has_error = True
|
||||||
|
else:
|
||||||
|
checkin.sudo()._save_data_from_portal(values)
|
||||||
|
counter = counter + 1
|
||||||
|
values = {"no_breadcrumbs": True}
|
||||||
|
doc_type_ids = request.env["res.partner.id_category"].sudo().search([])
|
||||||
|
country_ids = request.env["res.country"].search([])
|
||||||
|
state_ids = request.env["res.country.state"].search([])
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"doc_type_ids": doc_type_ids,
|
||||||
|
"country_ids": country_ids,
|
||||||
|
"state_ids": state_ids,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if has_error:
|
||||||
|
filtered_dict_error = {k: v for k, v in errors.items() if v}
|
||||||
|
filtered_dict_error_messages = {k: v for k, v in e_messages.items() if v}
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"error": filtered_dict_error,
|
||||||
|
"error_message": filtered_dict_error_messages,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
values.update({"success": True, "error": {}})
|
||||||
|
if kw.get("folio_id"):
|
||||||
|
folio = request.env["pms.folio"].browse(int(kw.get("folio_id")))
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"folio": folio,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_folio_precheckin", values)
|
||||||
|
elif kw.get("reservation_id"):
|
||||||
|
reservation = request.env["pms.reservation"].browse(
|
||||||
|
int(kw.get("reservation_id"))
|
||||||
|
)
|
||||||
|
values.update(
|
||||||
|
{
|
||||||
|
"reservation": reservation,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return request.render("pms.portal_my_reservation_precheckin", values)
|
||||||
|
|
||||||
|
def form_validate(self, data, counter):
|
||||||
|
error, error_message = self.form_document_validate(data, counter)
|
||||||
|
keys = data.keys()
|
||||||
|
mobile = "mobile" if "mobile" in keys else "mobile-" + str(counter)
|
||||||
|
if data[mobile]:
|
||||||
|
if not re.match(
|
||||||
|
r"^(\d{3}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?\d{2}[\-\s]?|"
|
||||||
|
r"\d{3}[\-\s]?\d{3}[\-\s]?\d{3})$",
|
||||||
|
data[mobile],
|
||||||
|
):
|
||||||
|
error[mobile] = "error"
|
||||||
|
error_message[mobile] = "Invalid phone"
|
||||||
|
birthdate_date = (
|
||||||
|
"birthdate_date"
|
||||||
|
if "birthdate_date" in keys
|
||||||
|
else "birthdate_date-" + str(counter)
|
||||||
|
)
|
||||||
|
if data[birthdate_date] and data[birthdate_date] > str(fields.Datetime.today()):
|
||||||
|
error[birthdate_date] = "error"
|
||||||
|
error_message[birthdate_date] = "Birthdate must be less than today"
|
||||||
|
email = "email" if "email" in keys else "email-" + str(counter)
|
||||||
|
if data[email] and not tools.single_email_re.match(data[email]):
|
||||||
|
error[email] = "error"
|
||||||
|
error_message[email] = "Email format is wrong"
|
||||||
|
firstname = "firstname" if "firstname" in keys else "firstname-" + str(counter)
|
||||||
|
lastname = "lastname" if "lastname" in keys else "lastname-" + str(counter)
|
||||||
|
lastname2 = "lastname2" if "lastname2" in keys else "lastname2-" + str(counter)
|
||||||
|
if not data[firstname] and not data[lastname] and not data[lastname2]:
|
||||||
|
error[firstname] = "error"
|
||||||
|
error_message[firstname] = "Firstname or any lastname are not included"
|
||||||
|
return error, error_message
|
||||||
|
|
||||||
|
def form_document_validate(self, data, counter):
|
||||||
|
error = dict()
|
||||||
|
error_message = {}
|
||||||
|
keys = data.keys()
|
||||||
|
document_number = (
|
||||||
|
"document_number"
|
||||||
|
if "document_number" in keys
|
||||||
|
else "document_number-" + str(counter)
|
||||||
|
)
|
||||||
|
document_type = (
|
||||||
|
"document_type"
|
||||||
|
if "document_type" in keys
|
||||||
|
else "document_type-" + str(counter)
|
||||||
|
)
|
||||||
|
document_expedition_date = (
|
||||||
|
"document_expedition_date"
|
||||||
|
if "document_expedition_date" in keys
|
||||||
|
else "document_expedition_date-" + str(counter)
|
||||||
|
)
|
||||||
|
if data[document_expedition_date] and not data[document_number]:
|
||||||
|
error[document_expedition_date] = "error"
|
||||||
|
error_message[
|
||||||
|
document_expedition_date
|
||||||
|
] = "Document Number not entered and Document Type is not selected"
|
||||||
|
if data[document_number]:
|
||||||
|
if not data[document_type]:
|
||||||
|
error[document_type] = "error"
|
||||||
|
error_message[document_type] = "Document Type is not selected"
|
||||||
|
if data[document_type] == "D":
|
||||||
|
if len(data[document_number]) == 9 or len(data[document_number]) == 10:
|
||||||
|
if not re.match(r"^\d{8}[ -]?[a-zA-Z]$", data[document_number]):
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[document_number] = "The DNI format is wrong"
|
||||||
|
letters = {
|
||||||
|
0: "T",
|
||||||
|
1: "R",
|
||||||
|
2: "W",
|
||||||
|
3: "A",
|
||||||
|
4: "G",
|
||||||
|
5: "M",
|
||||||
|
6: "Y",
|
||||||
|
7: "F",
|
||||||
|
8: "P",
|
||||||
|
9: "D",
|
||||||
|
10: "X",
|
||||||
|
11: "B",
|
||||||
|
12: "N",
|
||||||
|
13: "J",
|
||||||
|
14: "Z",
|
||||||
|
15: "S",
|
||||||
|
16: "Q",
|
||||||
|
17: "V",
|
||||||
|
18: "H",
|
||||||
|
19: "L",
|
||||||
|
20: "C",
|
||||||
|
21: "K",
|
||||||
|
22: "E",
|
||||||
|
}
|
||||||
|
dni_number = data[document_number][0:8]
|
||||||
|
dni_letter = data[document_number][
|
||||||
|
len(data[document_number]) - 1 : len(data[document_number])
|
||||||
|
]
|
||||||
|
if letters.get(int(dni_number) % 23) != dni_letter.upper():
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[document_number] = "DNI format is invalid"
|
||||||
|
else:
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[document_number] = "DNI is invalid"
|
||||||
|
if data[document_type] == "C" and not re.match(
|
||||||
|
r"^\d{8}[ -]?[a-zA-Z]$", data[document_number]
|
||||||
|
):
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[document_number] = "The Driving License format is wrong"
|
||||||
|
if data[document_type] == "N" and not re.match(
|
||||||
|
r"^[X|Y]{1}[ -]?\d{7,8}[ -]?[a-zA-Z]$", data[document_number]
|
||||||
|
):
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[
|
||||||
|
document_number
|
||||||
|
] = "The Spanish Residence Permit format is wrong"
|
||||||
|
if data[document_type] == "X" and not re.match(
|
||||||
|
r"^[X|Y]{1}[ -]?\d{7,8}[ -]?[a-zA-Z]$", data[document_number]
|
||||||
|
):
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[
|
||||||
|
document_number
|
||||||
|
] = "The European Residence Permit format is wrong"
|
||||||
|
elif data[document_type]:
|
||||||
|
error[document_number] = "error"
|
||||||
|
error_message[document_number] = "Document Number not entered"
|
||||||
|
return error, error_message
|
||||||
|
|
||||||
|
@http.route(
|
||||||
|
["/my/precheckin/send_invitation"],
|
||||||
|
auth="user",
|
||||||
|
type="json",
|
||||||
|
website=True,
|
||||||
|
csrf=False,
|
||||||
|
)
|
||||||
|
def portal_precheckin_folio_send_invitation(self, **kw):
|
||||||
|
if kw.get("folio_id"):
|
||||||
|
folio = request.env["pms.folio"].browse(int(kw.get("folio_id")))
|
||||||
|
kw.update({"folio": folio})
|
||||||
|
checkin_partner = request.env["pms.checkin.partner"].browse(
|
||||||
|
int(kw["checkin_partner_id"])
|
||||||
|
)
|
||||||
|
firstname = kw["firstname"]
|
||||||
|
email = kw["email"]
|
||||||
|
checkin_partner.write({"firstname": firstname, "email": email})
|
||||||
|
checkin_partner.send_portal_invitation_email(firstname, email)
|
||||||
|
# request.portal_my_folio_precheckin(kw)
|
||||||
|
|||||||
57
pms/data/pms_precheckin_invitation_email_template.xml
Normal file
57
pms/data/pms_precheckin_invitation_email_template.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record id="precheckin_invitation_email" model="mail.template">
|
||||||
|
<field name="name">Precheckin Invitation</field>
|
||||||
|
<field name="model_id" ref="pms.model_pms_checkin_partner" />
|
||||||
|
<field
|
||||||
|
name="subject"
|
||||||
|
>Hi ${object.firstname}, do your check-in now in ${object.pms_property_id.name}</field>
|
||||||
|
<field
|
||||||
|
name="email_from"
|
||||||
|
>${object.pms_property_id.partner_id.email | safe}</field>
|
||||||
|
<field
|
||||||
|
name="email_to"
|
||||||
|
>${(object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') | safe}</field>
|
||||||
|
<field name="body_html" type="html">
|
||||||
|
<div>
|
||||||
|
Do your check-in now and save time.
|
||||||
|
<br />
|
||||||
|
Access our<strong
|
||||||
|
> quick registration system</strong>. In a few steps you will be able to register your data in an agile, simple and secure way,<strong
|
||||||
|
> avoiding queues at reception</strong>.
|
||||||
|
If you register your data in our system, <strong
|
||||||
|
> your passage through reception will be much faster</strong>, being able to enjoy the comfort of your room right away.
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding: 20px 0 0px 0; ">
|
||||||
|
<table border="0" cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<a
|
||||||
|
href="/my/precheckin/${object.id}?access_token=${object.access_token}"
|
||||||
|
target="_blank"
|
||||||
|
style="text-decoration: none; color: #FFFFFF; font-size: 2em; padding: 10px 20px 10px 20px;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="padding: 0.5em; background-color: #45C2B1; border-color: #45C2B1; border-width: 2px;border-style:solid; border-bottom-style: solid;border-left-style: solid;border-right-style: solid;border-top-style: solid;-webkit-border-radius: 10; -moz-border-radius: 10; border-radius: 10px;font-size: 12px;"
|
||||||
|
>Check-in
|
||||||
|
</div>
|
||||||
|
<center><img
|
||||||
|
src="https://www.aldahotels.es/firma/email/llegada/check-in.png"
|
||||||
|
alt="Hacer check-in"
|
||||||
|
width="80px"
|
||||||
|
height="80px"
|
||||||
|
href="${object.url}"
|
||||||
|
/></center></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -3,15 +3,20 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from odoo import _, api, fields, models
|
from odoo import _, api, fields, models
|
||||||
from odoo.exceptions import UserError, ValidationError
|
from odoo.exceptions import UserError, ValidationError
|
||||||
|
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||||
from odoo.tools.safe_eval import safe_eval
|
from odoo.tools.safe_eval import safe_eval
|
||||||
|
|
||||||
|
|
||||||
class PmsCheckinPartner(models.Model):
|
class PmsCheckinPartner(models.Model):
|
||||||
_name = "pms.checkin.partner"
|
_name = "pms.checkin.partner"
|
||||||
_description = "Partner Checkins"
|
_description = "Partner Checkins"
|
||||||
|
_inherit = ["portal.mixin"]
|
||||||
_rec_name = "identifier"
|
_rec_name = "identifier"
|
||||||
_check_pms_properties_auto = True
|
_check_pms_properties_auto = True
|
||||||
|
|
||||||
@@ -459,6 +464,13 @@ class PmsCheckinPartner(models.Model):
|
|||||||
else:
|
else:
|
||||||
record.partner_incongruences = False
|
record.partner_incongruences = False
|
||||||
|
|
||||||
|
def _compute_access_url(self):
|
||||||
|
super(PmsCheckinPartner, self)._compute_access_url()
|
||||||
|
for checkin in self:
|
||||||
|
checkin.access_url = "/my/precheckin/%s" % (checkin.id)
|
||||||
|
|
||||||
|
# Constraints and onchanges
|
||||||
|
|
||||||
@api.constrains("departure", "arrival")
|
@api.constrains("departure", "arrival")
|
||||||
def _check_departure(self):
|
def _check_departure(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
@@ -648,6 +660,30 @@ class PmsCheckinPartner(models.Model):
|
|||||||
checkin_vals[key] = value
|
checkin_vals[key] = value
|
||||||
checkin.write(checkin_vals)
|
checkin.write(checkin_vals)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
self, doc_type, doc_date, birthdate
|
||||||
|
):
|
||||||
|
today = fields.datetime.today()
|
||||||
|
datetime_doc_date = datetime.strptime(doc_date, DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
if datetime_doc_date < today:
|
||||||
|
return datetime_doc_date
|
||||||
|
datetime_birthdate = datetime.strptime(birthdate, DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
age = today.year - datetime_birthdate.year
|
||||||
|
document_type = self.env["res.partner.id_category"].search(
|
||||||
|
[("id", "=", doc_type)]
|
||||||
|
)
|
||||||
|
document_expedition_date = False
|
||||||
|
if document_type.code == "D" or document_type.code == "P":
|
||||||
|
if age < 30:
|
||||||
|
document_expedition_date = datetime_doc_date - relativedelta(years=5)
|
||||||
|
else:
|
||||||
|
document_expedition_date = datetime_doc_date - relativedelta(years=10)
|
||||||
|
if document_type.code == "C":
|
||||||
|
if age < 70:
|
||||||
|
document_expedition_date = datetime_doc_date - relativedelta(years=10)
|
||||||
|
return document_expedition_date
|
||||||
|
|
||||||
def action_on_board(self):
|
def action_on_board(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.reservation_id.checkin > fields.Date.today():
|
if record.reservation_id.checkin > fields.Date.today():
|
||||||
@@ -703,3 +739,57 @@ class PmsCheckinPartner(models.Model):
|
|||||||
"type": "ir.actions.act_window",
|
"type": "ir.actions.act_window",
|
||||||
"context": ctx,
|
"context": ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _save_data_from_portal(self, values):
|
||||||
|
checkin_partner = self.env["pms.checkin.partner"].browse(int(values.get("id")))
|
||||||
|
if values.get("nationality_id"):
|
||||||
|
nationality_id = self.env["res.country"].search(
|
||||||
|
[("id", "=", values.get("nationality_id"))]
|
||||||
|
)
|
||||||
|
values.update({"nationality_id": nationality_id.id})
|
||||||
|
else:
|
||||||
|
values.update({"nationality_id": False})
|
||||||
|
if not values.get("document_type"):
|
||||||
|
values.update({"document_type": False})
|
||||||
|
if values.get("state"):
|
||||||
|
state_id = self.env["res.country.state"].search(
|
||||||
|
[("id", "=", values.get("state"))]
|
||||||
|
)
|
||||||
|
values.update({"state_id": state_id})
|
||||||
|
values.pop("state")
|
||||||
|
if values.get("document_expedition_date"):
|
||||||
|
doc_type = values.get("document_type")
|
||||||
|
doc_date = values.get("document_expedition_date")
|
||||||
|
birthdate = values.get("birthdate_date")
|
||||||
|
document_expedition_date = (
|
||||||
|
self.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type, doc_date, birthdate
|
||||||
|
)
|
||||||
|
)
|
||||||
|
values.update({"document_expedition_date": document_expedition_date})
|
||||||
|
checkin_partner.sudo().write(values)
|
||||||
|
|
||||||
|
def send_portal_invitation_email(self, invitation_firstname=None, email=None):
|
||||||
|
template = self.sudo().env.ref(
|
||||||
|
"pms.precheckin_invitation_email", raise_if_not_found=False
|
||||||
|
)
|
||||||
|
subject = template._render_field(
|
||||||
|
"subject", [6, 0, self.id], compute_lang=True, post_process=True
|
||||||
|
)[self.id]
|
||||||
|
body = template._render_field(
|
||||||
|
"body_html", [6, 0, self.id], compute_lang=True, post_process=True
|
||||||
|
)[self.id]
|
||||||
|
invitation_mail = (
|
||||||
|
self.env["mail.mail"]
|
||||||
|
.sudo()
|
||||||
|
.create(
|
||||||
|
{
|
||||||
|
"subject": subject,
|
||||||
|
"body_html": body,
|
||||||
|
"email_from": self.pms_property_id.partner_id.email,
|
||||||
|
"email_to": email,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
invitation_mail.send()
|
||||||
|
|||||||
@@ -770,6 +770,8 @@ class PmsFolio(models.Model):
|
|||||||
# else:
|
# else:
|
||||||
# raise UserError(_("Some reservations have different currency"))
|
# raise UserError(_("Some reservations have different currency"))
|
||||||
|
|
||||||
|
# is_checkin = fields.Boolean()
|
||||||
|
|
||||||
def _compute_access_url(self):
|
def _compute_access_url(self):
|
||||||
super(PmsFolio, self)._compute_access_url()
|
super(PmsFolio, self)._compute_access_url()
|
||||||
for folio in self:
|
for folio in self:
|
||||||
|
|||||||
@@ -1135,6 +1135,11 @@ class PmsReservation(models.Model):
|
|||||||
# date checking
|
# date checking
|
||||||
record.check_in_out_dates()
|
record.check_in_out_dates()
|
||||||
|
|
||||||
|
def _compute_precheckin_url(self):
|
||||||
|
super(PmsReservation, self)._compute_access_url()
|
||||||
|
for reservation in self:
|
||||||
|
reservation.access_url = "/my/reservations/precheckin/%s" % (reservation.id)
|
||||||
|
|
||||||
@api.depends("pms_property_id", "folio_id")
|
@api.depends("pms_property_id", "folio_id")
|
||||||
def _compute_arrival_hour(self):
|
def _compute_arrival_hour(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
|
|||||||
@@ -62,3 +62,5 @@ user_access_pms_folio_portal,user_access_pms_folio_portal,model_pms_folio,base.g
|
|||||||
user_access_pms_reservation_portal,user_access_pms_reservation_portal,model_pms_reservation,base.group_portal,1,0,0,0
|
user_access_pms_reservation_portal,user_access_pms_reservation_portal,model_pms_reservation,base.group_portal,1,0,0,0
|
||||||
user_access_pms_automated_mails,user_access_pms_automated_mails,model_pms_automated_mails,pms.group_pms_user,1,1,1,1
|
user_access_pms_automated_mails,user_access_pms_automated_mails,model_pms_automated_mails,pms.group_pms_user,1,1,1,1
|
||||||
access_pms_several_partners_wizard,access_pms_several_partners_wizard,model_pms_several_partners_wizard,base.group_user,1,1,1,1
|
access_pms_several_partners_wizard,access_pms_several_partners_wizard,model_pms_several_partners_wizard,base.group_user,1,1,1,1
|
||||||
|
user_access_res_partner_portal,user_access_res_partner_portal,model_res_partner,base.group_portal,1,1,1,1
|
||||||
|
user_access_pms_precheckin_portal,user_access_pms_precheckin_portal,model_pms_checkin_partner,base.group_portal,1,1,1,1
|
||||||
|
|||||||
|
@@ -237,5 +237,26 @@
|
|||||||
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
<field name="perm_read" eval="True" />
|
<field name="perm_read" eval="True" />
|
||||||
</record>
|
</record>
|
||||||
|
<record id="pms_precheckin_rule_portal" model="ir.rule">
|
||||||
|
<field name="name">Portal Personal Pre-checkin</field>
|
||||||
|
<field name="model_id" ref="model_pms_checkin_partner" />
|
||||||
|
<field name="domain_force">[]</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
</record>
|
||||||
|
<record id="res_partner_rule_portal" model="ir.rule">
|
||||||
|
<field name="name">Res Partner Rule</field>
|
||||||
|
<field name="model_id" ref="model_res_partner" />
|
||||||
|
<field name="domain_force">[]</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
</record>
|
||||||
|
<record id="res_checkin_partner_rule_portal" model="ir.rule">
|
||||||
|
<field name="name">Portal Checkin Partner Rule</field>
|
||||||
|
<field name="model_id" ref="model_pms_checkin_partner" />
|
||||||
|
<field name="domain_force">[]</field>
|
||||||
|
<field name="groups" eval="[(4, ref('base.group_portal'))]" />
|
||||||
|
<field name="perm_read" eval="True" />
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
41
pms/static/src/js/send_invitation_data.js
Normal file
41
pms/static/src/js/send_invitation_data.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
odoo.define("pms.SendInvitationData", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
require("web.dom_ready");
|
||||||
|
var publicWidget = require("web.public.widget");
|
||||||
|
|
||||||
|
publicWidget.registry.SendInvitationData = publicWidget.Widget.extend({
|
||||||
|
selector: ".o_send_invitation_js",
|
||||||
|
events: {
|
||||||
|
click: "_onReminderToggleClick",
|
||||||
|
},
|
||||||
|
|
||||||
|
_onReminderToggleClick: function (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
var checkinPartnerId = $(ev.currentTarget)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.find("input[name=checkin_partner_id]")
|
||||||
|
.val();
|
||||||
|
var firstname = $(ev.currentTarget)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.find("input[name=invitation_firstname]")
|
||||||
|
.val();
|
||||||
|
var email = $(ev.currentTarget)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.find("input[name=invitation_email]")
|
||||||
|
.val();
|
||||||
|
this._rpc({
|
||||||
|
route: "/my/precheckin/send_invitation",
|
||||||
|
params: {
|
||||||
|
checkin_partner_id: checkinPartnerId,
|
||||||
|
firstname: firstname,
|
||||||
|
email: email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return publicWidget.registry.SendInvitationData;
|
||||||
|
});
|
||||||
@@ -1189,3 +1189,289 @@ class TestPmsCheckinPartner(TestPms):
|
|||||||
msg="A partner can be added to the checkin partner",
|
msg="A partner can be added to the checkin partner",
|
||||||
):
|
):
|
||||||
several_partners_wizard.add_partner()
|
several_partners_wizard.add_partner()
|
||||||
|
|
||||||
|
def test_calculate_dni_expedition_date_from_validity_date_age_lt_30(self):
|
||||||
|
"""
|
||||||
|
Check that the calculate_doc_type_expedition_date_from_validity_date()
|
||||||
|
method calculates correctly the expedition_date of an id category DNI
|
||||||
|
when the age is less than 30.
|
||||||
|
-------------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id DNI, birthdate calculated so that the age
|
||||||
|
is = 20 years old and document_date = today + 1 year. The expected
|
||||||
|
expedition date has to be doc_date - 5 years
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "D")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() + datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
|
||||||
|
# age=20 years old
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=7305)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
|
||||||
|
# expected_expedition_date = doc_date - 5 years
|
||||||
|
expected_exp_date = doc_date - datetime.timedelta(days=1826.25)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
expected_exp_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_calculate_dni_expedition_date_from_validity_date_age_gt_30(self):
|
||||||
|
"""
|
||||||
|
Check that the calculate_doc_type_expedition_date_from_validity_date()
|
||||||
|
method calculates correctly the expedition_date of an id category DNI
|
||||||
|
when the age is greater than 30.
|
||||||
|
-------------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id DNI, birthdate calculated so that the age
|
||||||
|
is = 40 years old and document_date = today + 1 year. The expected
|
||||||
|
expedition date has to be doc_date - 10 years
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "D")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() + datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
|
||||||
|
# age=40 years old
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=14610)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
|
||||||
|
# expected_expedition_date = doc_date - 10 years
|
||||||
|
expected_exp_date = doc_date - datetime.timedelta(days=3652.5)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
expected_exp_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_calculate_passport_expedition_date_from_validity_date_age_lt_30(self):
|
||||||
|
"""
|
||||||
|
Check that the calculate_doc_type_expedition_date_from_validity_date()
|
||||||
|
method calculates correctly the expedition_date of an id category Passport
|
||||||
|
when the age is less than 30.
|
||||||
|
-------------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id Passport, birthdate calculated so that the age
|
||||||
|
is = 20 years old and document_date = today + 1 year. The expected
|
||||||
|
expedition date has to be doc_date - 5 years
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "P")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() + datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
|
||||||
|
# age=20 years old
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=7305)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
|
||||||
|
# expected_expedition_date = doc_date - 5 years
|
||||||
|
expected_exp_date = doc_date - datetime.timedelta(days=1826.25)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
expected_exp_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_calculate_passport_expedition_date_from_validity_date_age_gt_30(self):
|
||||||
|
"""
|
||||||
|
Check that the calculate_doc_type_expedition_date_from_validity_date()
|
||||||
|
method calculates correctly the expedition_date of an id category Passport
|
||||||
|
when the age is greater than 30.
|
||||||
|
-------------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id Passport, birthdate calculated so that the age
|
||||||
|
is = 40 years old and document_date = today + 1 year. The expected
|
||||||
|
expedition date has to be doc_date - 10 years
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "P")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() + datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
|
||||||
|
# age=40 years old
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=14610)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
|
||||||
|
# expected_expedition_date = doc_date - 10 years
|
||||||
|
expected_exp_date = doc_date - datetime.timedelta(days=3652.5)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
expected_exp_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_calculate_drive_license_expedition_date_from_validity_date_age_lt_70(self):
|
||||||
|
"""
|
||||||
|
Check that the calculate_doc_type_expedition_date_from_validity_date()
|
||||||
|
method calculates correctly the expedition_date of an id category Driving
|
||||||
|
License when the age is lesser than 70.
|
||||||
|
-------------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id DNI, birthdate calculated so that the age
|
||||||
|
is = 40 years old and document_date = today + 1 year. The expected
|
||||||
|
expedition date has to be doc_date - 10 years
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "C")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() + datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
|
||||||
|
# age=40 years old
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=14610)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
|
||||||
|
# expected_expedition_date = doc_date - 10 years
|
||||||
|
expected_exp_date = doc_date - datetime.timedelta(days=3652.5)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
expected_exp_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_calculate_expedition_date(self):
|
||||||
|
"""
|
||||||
|
Check that if the value of the doc_date is less than today,
|
||||||
|
the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
returns the value of the doc_date as expedition_date.
|
||||||
|
-----------
|
||||||
|
We launch the method calculate_doc_type_expedition_date_from_validity_date
|
||||||
|
with the parameters doc_type_id DNI, birthdate calculated so that the age
|
||||||
|
is = 20 years old and document_date = today - 1 year. The expected
|
||||||
|
expedition date has to be the value of doc_date.
|
||||||
|
"""
|
||||||
|
doc_type_id = (
|
||||||
|
self.env["res.partner.id_category"].search([("code", "=", "D")]).id
|
||||||
|
)
|
||||||
|
doc_date = fields.date.today() - datetime.timedelta(days=366)
|
||||||
|
doc_date_str = str(doc_date)
|
||||||
|
birthdate = fields.date.today() - datetime.timedelta(days=7305)
|
||||||
|
birthdate_str = str(birthdate)
|
||||||
|
expedition_date = (
|
||||||
|
self.checkin1.calculate_doc_type_expedition_date_from_validity_date(
|
||||||
|
doc_type_id, doc_date_str, birthdate_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
date_expedition_date = datetime.date(
|
||||||
|
year=expedition_date.year,
|
||||||
|
month=expedition_date.month,
|
||||||
|
day=expedition_date.day,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
date_expedition_date,
|
||||||
|
doc_date,
|
||||||
|
"Expedition date doesn't correspond with expected expedition date",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_save_checkin_from_portal(self):
|
||||||
|
"""
|
||||||
|
Check by subtesting that a checkin partner is saved correctly
|
||||||
|
with the _save_data_from_portal() method.
|
||||||
|
---------
|
||||||
|
A reservation is created with an adult, and it will create a checkin partner.
|
||||||
|
A dictionary is created with the values to be saved and with the key 'id'
|
||||||
|
equal to the id of the checkin_partner created when the reservation was
|
||||||
|
created. We launch the _save_data_from_portal() method, passing the created
|
||||||
|
dictionary as a parameter. Then it is verified that the value of each key
|
||||||
|
in the dictionary corresponds to the fields of the saved checkin_partner.
|
||||||
|
"""
|
||||||
|
self.reservation = self.env["pms.reservation"].create(
|
||||||
|
{
|
||||||
|
"checkin": datetime.date.today() + datetime.timedelta(days=10),
|
||||||
|
"checkout": datetime.date.today() + datetime.timedelta(days=13),
|
||||||
|
"room_type_id": self.room_type1.id,
|
||||||
|
"partner_id": self.host1.id,
|
||||||
|
"adults": 1,
|
||||||
|
"pms_property_id": self.pms_property1.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
checkin_partner_id = self.reservation.checkin_partner_ids[0]
|
||||||
|
checkin_partner_vals = {
|
||||||
|
"id": checkin_partner_id.id,
|
||||||
|
"firstname": "Serafín",
|
||||||
|
"lastname": "Rivas",
|
||||||
|
"lastname2": "Gonzalez",
|
||||||
|
"document_type": self.id_category,
|
||||||
|
"document_number": "18038946T",
|
||||||
|
"document_expedition_date": "2015-10-07",
|
||||||
|
"birthdate_date": "1983-10-05",
|
||||||
|
"mobile": "60595595",
|
||||||
|
"email": "serafin@example.com",
|
||||||
|
"gender": "male",
|
||||||
|
"nationality_id": "1",
|
||||||
|
"state": "1",
|
||||||
|
}
|
||||||
|
checkin_partner_id._save_data_from_portal(checkin_partner_vals)
|
||||||
|
nationality_id = self.env["res.country"].browse(
|
||||||
|
checkin_partner_vals["nationality_id"]
|
||||||
|
)
|
||||||
|
checkin_partner_vals.update(
|
||||||
|
{
|
||||||
|
"birthdate_date": datetime.date(1983, 10, 5),
|
||||||
|
"document_expedition_date": datetime.date(2015, 10, 7),
|
||||||
|
"nationality_id": nationality_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
for key in checkin_partner_vals:
|
||||||
|
with self.subTest(k=key):
|
||||||
|
self.assertEqual(
|
||||||
|
self.reservation.checkin_partner_ids[0][key],
|
||||||
|
checkin_partner_vals[key],
|
||||||
|
"The value of " + key + " is not correctly established",
|
||||||
|
)
|
||||||
|
|||||||
13
pms/views/assets.xml
Normal file
13
pms/views/assets.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<template id="assets_frontend" inherit_id="portal.assets_frontend">
|
||||||
|
<xpath expr="//script[last()]" position="after">
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/pms/static/src/js/send_invitation_data.js"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -63,6 +63,10 @@
|
|||||||
>
|
>
|
||||||
<t t-esc="folio.name" />
|
<t t-esc="folio.name" />
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
t-att-href="folio.get_portal_url(suffix='/precheckin')"
|
||||||
|
t-att-title="Precheckin"
|
||||||
|
>Precheckin</a>
|
||||||
</td>
|
</td>
|
||||||
<td><span t-field="folio.date_order" /></td>
|
<td><span t-field="folio.date_order" /></td>
|
||||||
<td class="text-right"><span
|
<td class="text-right"><span
|
||||||
@@ -167,11 +171,6 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!--
|
|
||||||
Sales Order content : intro, informations, order lines, remarks, descriptions ....
|
|
||||||
This template should contains all the printable element of the SO. This is the
|
|
||||||
template rendered in PDF with the report engine.
|
|
||||||
-->
|
|
||||||
<template id="folio_portal_content" name="Folio Portal Content">
|
<template id="folio_portal_content" name="Folio Portal Content">
|
||||||
<t t-set="address">
|
<t t-set="address">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -360,7 +360,7 @@
|
|||||||
string="General Info"
|
string="General Info"
|
||||||
name="contact_details"
|
name="contact_details"
|
||||||
>
|
>
|
||||||
<field name="partner_id" />
|
<field name="partner_id" invisible="1" />
|
||||||
<field
|
<field
|
||||||
name="document_type"
|
name="document_type"
|
||||||
attrs="{'invisible':[('reservation_type','in',('out'))]}"
|
attrs="{'invisible':[('reservation_type','in',('out'))]}"
|
||||||
|
|||||||
1391
pms/views/precheckin_portal_templates.xml
Normal file
1391
pms/views/precheckin_portal_templates.xml
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user