+
+ ${object.partner_id.lang}
+
+
+
diff --git a/pms/models/__init__.py b/pms/models/__init__.py
index 5bcb034f5..8b246ec75 100644
--- a/pms/models/__init__.py
+++ b/pms/models/__init__.py
@@ -31,7 +31,7 @@ from . import product_pricelist_item
from . import res_partner
from . import pms_sale_channel
-# from . import mail_compose_message
+from . import mail_compose_message
from . import pms_room_type_class
from . import pms_room_closure_reason
from . import pms_service_line
@@ -46,3 +46,4 @@ from . import account_bank_statement
from . import account_journal
from . import pms_availability
from . import res_partner_id_number
+from . import pms_automated_mails
diff --git a/pms/models/mail_compose_message.py b/pms/models/mail_compose_message.py
index 62bbaad3b..e76de0ec6 100644
--- a/pms/models/mail_compose_message.py
+++ b/pms/models/mail_compose_message.py
@@ -1,24 +1,43 @@
# Copyright 2017 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import models
+from odoo import api, models
class MailComposeMessage(models.TransientModel):
_inherit = "mail.compose.message"
+ @api.model
+ def default_get(self, fields):
+ res = super(MailComposeMessage, self).default_get(fields)
+ template = self.env["mail.template"].browse(self._context.get("template_id"))
+ res.update(
+ {
+ "composition_mode": "comment",
+ "attachment_ids": False,
+ "template_id": template.id,
+ }
+ )
+ return res
+
def send_mail(self, auto_commit=False):
- if (
- self._context.get("default_model") == "pms.folio"
- and self._context.get("default_res_id")
- and self._context.get("mark_so_as_sent")
- ):
- # TODO: WorkFlow Mails
- folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
- if folio:
- cmds = [
- (1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
- ]
- if any(cmds):
- folio.reservation_ids = cmds
- return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
+ # if (
+ # self._context.get("default_model") == "pms.folio"
+ # and self._context.get("default_res_id")
+ # and self._context.get("mark_so_as_sent")
+ # ):
+ # # TODO: WorkFlow Mails
+ # folio = self.env["pms.folio"].browse([self._context["default_res_id"]])
+ # if folio:
+ # cmds = [
+ # (1, lid, {"to_send": False}) for lid in folio.reservation_ids.ids
+ # ]
+ # if any(cmds):
+ # folio.reservation_ids = cmds
+ res = super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
+ if self._context.get("record_id"):
+ reservation = self.env["pms.reservation"].search(
+ [("id", "=", self._context.get("record_id"))]
+ )
+ reservation.is_mail_send = True
+ return res
diff --git a/pms/models/pms_automated_mails.py b/pms/models/pms_automated_mails.py
new file mode 100644
index 000000000..175a8b661
--- /dev/null
+++ b/pms/models/pms_automated_mails.py
@@ -0,0 +1,367 @@
+from odoo import _, api, fields, models
+from odoo.exceptions import UserError
+
+
+class PmsAutomatedMails(models.Model):
+ _name = "pms.automated.mails"
+ _description = "Automatic Mails"
+
+ name = fields.Char(string="Name", help="Name of the automated mail.", required=True)
+
+ pms_property_ids = fields.Many2many(
+ string="Property",
+ help="Properties with access to the element;"
+ " if not set, all properties can access",
+ comodel_name="pms.property",
+ )
+
+ automated_actions_id = fields.Many2one(
+ string="Automated Actions",
+ help="automated action that is created when creating automated emails ",
+ comodel_name="base.automation",
+ )
+
+ time = fields.Integer(string="Time", help="Amount of time")
+
+ time_type = fields.Selection(
+ string="Time Range",
+ help="Type of date range",
+ selection=[
+ ("minutes", "Minutes"),
+ ("hour", "Hour"),
+ ("day", "Days"),
+ ("month", "Months"),
+ ],
+ default="day",
+ )
+ template_id = fields.Many2one(
+ string="Template",
+ help="The template that will be sent by email",
+ comodel_name="mail.template",
+ required=True,
+ )
+
+ action = fields.Selection(
+ string="Action",
+ help="The action that will cause the email to be sent ",
+ selection=[
+ ("creation", "Reservation creation"),
+ ("write", "Reservation modification"),
+ ("cancel", "Reservation cancellation"),
+ ("checkin", "Checkin"),
+ ("checkout", "Checkout"),
+ ("payment", "Payment"),
+ ("invoice", "Invoice"),
+ ],
+ default="creation",
+ required=True,
+ )
+
+ moment = fields.Selection(
+ string="Moment",
+ help="Moment in relation to the action in which the email will be sent",
+ selection=[
+ ("before", "Before"),
+ ("after", "After"),
+ ("in_act", "In the act"),
+ ],
+ default="before",
+ )
+
+ active = fields.Boolean(
+ string="Active", help="Indicates if the automated mail is active", default=True
+ )
+
+ @api.model
+ def create(self, vals):
+ name = vals.get("name")
+ action = vals.get("action")
+ time = vals.get("time")
+ date_range_type = vals.get("time_type")
+ template_id = vals.get("template_id")
+ active = vals.get("active")
+ moment = vals.get("moment")
+ properties = vals.get("pms_property_ids")
+ is_create = True
+ if action in ("creation", "write", "cancel", "invoice") and moment == "before":
+ raise UserError(_("The moment for this action cannot be 'Before'"))
+ dict_val = self._prepare_automated_actions_id(
+ action, time, moment, properties, is_create
+ )
+ action_server_vals = {
+ "name": name,
+ "state": "email",
+ "usage": "ir_cron",
+ "model_id": dict_val["model_id"],
+ }
+ action_server = self.env["ir.actions.server"].create(action_server_vals)
+ automated_actions_vals = {
+ "active": active,
+ "action_server_id": action_server.id,
+ "trigger": dict_val["trigger"],
+ "filter_domain": dict_val["filter_domain"],
+ "filter_pre_domain": dict_val["filter_pre_domain"],
+ "trg_date_range": dict_val["time"],
+ "trg_date_range_type": date_range_type,
+ "template_id": template_id,
+ }
+ model_field = dict_val["model_field"]
+ if model_field:
+ automated_actions_vals.update(
+ {
+ "trg_date_id": dict_val["model_field"].id,
+ }
+ )
+ trigger_field = dict_val["trigger_fields"]
+ if trigger_field:
+ automated_actions_vals.update(
+ {
+ "trigger_field_ids": dict_val["trigger_fields"].ids,
+ }
+ )
+ automated_action = self.env["base.automation"].create(automated_actions_vals)
+ vals.update({"automated_actions_id": automated_action.id})
+ return super(PmsAutomatedMails, self).create(vals)
+
+ def write(self, vals):
+ result = super(PmsAutomatedMails, self).write(vals)
+ is_create = False
+ if (
+ self.action in ("creation", "write", "cancel", "invoice")
+ and self.moment == "before"
+ ):
+ raise UserError(_("The moment for this action cannot be 'Before'"))
+ dict_val = self._prepare_automated_actions_id(
+ self.action, self.time, self.moment, self.pms_property_ids, is_create
+ )
+ automated_actions_id = self.automated_actions_id
+ action_server = automated_actions_id.action_server_id
+ action_server_vals = {
+ "name": self.name,
+ "state": "email",
+ "usage": "ir_cron",
+ "model_id": dict_val["model_id"],
+ }
+ action_server.write(action_server_vals)
+ automated_actions_vals = {
+ "active": self.active,
+ "action_server_id": action_server.id,
+ "trigger": dict_val["trigger"],
+ "filter_domain": dict_val["filter_domain"],
+ "filter_pre_domain": dict_val["filter_pre_domain"],
+ "trg_date_range": dict_val["time"],
+ "trg_date_range_type": self.time_type,
+ "template_id": self.template_id,
+ }
+ model_field = dict_val["model_field"]
+ if model_field:
+ automated_actions_vals.update(
+ {
+ "trg_date_id": dict_val["model_field"].id,
+ }
+ )
+ trigger_field = dict_val["trigger_fields"]
+ if trigger_field:
+ automated_actions_vals.update(
+ {
+ "trigger_field_ids": dict_val["trigger_fields"].ids,
+ }
+ )
+ automated_actions_id.write(automated_actions_vals)
+ vals.update({"automated_actions_id": automated_actions_id.id})
+ return result
+
+ def unlink(self):
+ automated_actions_id = self.automated_actions_id
+ action_server = automated_actions_id.action_server_id
+ automated_actions_id.unlink()
+ action_server.unlink()
+ return super(PmsAutomatedMails, self).unlink()
+
+ @api.model
+ def _get_auto_action_fields_in_creation_action(self, moment, time):
+ model_field = False
+ model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
+ if moment == "in_act":
+ trigger = "on_create"
+ time = 0
+ else:
+ trigger = "on_time"
+ model_field = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "create_date")]
+ )
+ result = {
+ "model_id": model_id,
+ "trigger": trigger,
+ "model_field": model_field,
+ "time": time,
+ }
+ return result
+
+ @api.model
+ def _get_auto_action_fields_in_write_or_cancel_action(self, moment, time):
+ model_field = False
+ model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
+ if moment == "in_act":
+ trigger = "on_write"
+ time = 0
+ else:
+ trigger = "on_time"
+ model_field = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "write_date")]
+ )
+ result = {
+ "model_id": model_id,
+ "trigger": trigger,
+ "model_field": model_field,
+ "time": time,
+ }
+ return result
+
+ @api.model
+ def _get_auto_action_fields_in_checkin_action(self, moment, time):
+ model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
+ trigger = "on_time"
+ model_field = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "checkin")]
+ )
+ if moment == "before":
+ time = time * (-1)
+ if moment == "in_act":
+ trigger = "on_write"
+ time = 0
+ result = {
+ "model_id": model_id,
+ "trigger": trigger,
+ "model_field": model_field,
+ "time": time,
+ }
+ return result
+
+ @api.model
+ def _get_auto_action_fields_in_checkout_action(self, moment, time):
+ model_id = self.env["ir.model"].search([("model", "=", "pms.reservation")]).id
+ trigger = "on_time"
+ model_field = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "checkout")]
+ )
+ if moment == "before":
+ time = time * (-1)
+ if moment == "in_act":
+ trigger = "on_write"
+ time = 0
+ result = {
+ "model_id": model_id,
+ "trigger": trigger,
+ "model_field": model_field,
+ "time": time,
+ }
+ return result
+
+ @api.model
+ def _get_auto_action_fields_in_payment_action(self, moment, time):
+ model_field = False
+ model_id = (
+ self.env["ir.model"]
+ .search([("model", "=", "account.payment"), ("transient", "=", False)])
+ .id
+ )
+ if moment == "in_act":
+ trigger = "on_create"
+ time = 0
+ else:
+ trigger = "on_time"
+ model_field = self.env["ir.model.fields"].search(
+ [("model", "=", "account.payment"), ("name", "=", "date")]
+ )
+ if moment == "before":
+ time = time * (-1)
+ result = {
+ "model_id": model_id,
+ "trigger": trigger,
+ "model_field": model_field,
+ "time": time,
+ }
+ return result
+
+ @api.model
+ def _get_auto_action_fields_in_invoice_action(self, moment, time):
+ trigger = False
+ model_id = self.env["ir.model"].search([("model", "=", "account.move")]).id
+ if moment == "in_act":
+ trigger = "on_create"
+ time = 0
+ result = {
+ "model_id": model_id,
+ "time": time,
+ "trigger": trigger,
+ "model_field": False,
+ }
+ return result
+
+ def _prepare_automated_actions_id(
+ self, action, time, moment, properties, is_create
+ ):
+ filter_domain = []
+ filter_pre_domain = []
+ trigger_fields = False
+ dict_val = {}
+ if action == "creation":
+ dict_val = self._get_auto_action_fields_in_creation_action(moment, time)
+ elif action == "write" or action == "cancel":
+ dict_val = self._get_auto_action_fields_in_write_or_cancel_action(
+ moment, time
+ )
+ if action == "cancel":
+ filter_domain = [
+ ("state", "=", "cancelled"),
+ ]
+ elif action == "checkin":
+ dict_val = self._get_auto_action_fields_in_checkin_action(moment, time)
+ if moment == "in_act":
+ trigger_fields = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "state")]
+ )
+ filter_pre_domain = [("state", "=", "confirm")]
+ filter_domain = [
+ ("state", "=", "onboard"),
+ ]
+ elif action == "checkout":
+ dict_val = self._get_auto_action_fields_in_checkout_action(moment, time)
+ if moment == "in_act":
+ trigger_fields = self.env["ir.model.fields"].search(
+ [("model", "=", "pms.reservation"), ("name", "=", "state")]
+ )
+ filter_pre_domain = [("state", "=", "onboard")]
+ filter_domain = [
+ ("state", "=", "out"),
+ ]
+ elif action == "payment":
+ dict_val = self._get_auto_action_fields_in_payment_action(moment, time)
+ elif action == "invoice":
+ dict_val = self._get_auto_action_fields_in_invoice_action(moment, time)
+ filter_domain = [
+ ("folio_ids", "!=", False),
+ ]
+ pms_property_ids = self._get_pms_property_ids(properties, is_create)
+ if pms_property_ids:
+ filter_domain.append(("pms_property_id", "in", pms_property_ids))
+ result = {
+ "trigger": dict_val["trigger"],
+ "model_field": dict_val["model_field"],
+ "trigger_fields": trigger_fields,
+ "filter_pre_domain": filter_pre_domain,
+ "filter_domain": filter_domain,
+ "time": dict_val["time"],
+ "model_id": dict_val["model_id"],
+ }
+ return result
+
+ def _get_pms_property_ids(self, properties, is_create):
+ pms_property_ids = []
+ if is_create:
+ pms_property_ids = properties[0][2]
+ else:
+ for pms_property in properties:
+ pms_property_ids.append(pms_property.id)
+ return pms_property_ids
diff --git a/pms/models/pms_property.py b/pms/models/pms_property.py
index 2656f4239..a524ed083 100644
--- a/pms/models/pms_property.py
+++ b/pms/models/pms_property.py
@@ -115,6 +115,39 @@ class PmsProperty(models.Model):
compute="_compute_availability",
)
+ mail_information = fields.Html(
+ string="Mail Information", help="Additional information of the mail"
+ )
+
+ privacy_policy = fields.Html(string="Privacy Policy", help="Mail privacy policy ")
+
+ property_confirmed_template = fields.Many2one(
+ string="Confirmation Template",
+ help="Confirmation email template",
+ comodel_name="mail.template",
+ default=lambda self: self.env["mail.template"]
+ .search([("name", "=", "Confirmed Reservation")])
+ .id,
+ )
+
+ property_modified_template = fields.Many2one(
+ string="Modification Template",
+ help="Modification email template",
+ comodel_name="mail.template",
+ default=lambda self: self.env["mail.template"]
+ .search([("name", "=", "Modified Reservation")])
+ .id,
+ )
+
+ property_canceled_template = fields.Many2one(
+ string="Cancellation Template",
+ help="Cancellation email template",
+ comodel_name="mail.template",
+ default=lambda self: self.env["mail.template"]
+ .search([("name", "=", "Cancelled Reservation")])
+ .id,
+ )
+
@api.depends_context(
"checkin",
"checkout",
diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py
index c2b3c2b63..3e0715b33 100644
--- a/pms/models/pms_reservation.py
+++ b/pms/models/pms_reservation.py
@@ -644,6 +644,19 @@ class PmsReservation(models.Model):
add_possible_customer = fields.Boolean(string="Add possible Customer")
+ is_mail_send = fields.Boolean(string="Mail Sent", default=False)
+
+ is_modified_reservation = fields.Boolean(
+ string="Is A Modified Reservation",
+ compute="_compute_is_modified_reservation",
+ readonly=False,
+ store=True,
+ )
+
+ lang = fields.Many2one(
+ string="Language", comodel_name="res.lang", compute="_compute_lang"
+ )
+
def _compute_date_order(self):
for record in self:
record.date_order = datetime.datetime.today()
@@ -1428,6 +1441,25 @@ class PmsReservation(models.Model):
for record in self:
self.env["pms.folio"]._apply_is_possible_existing_customer_id(record)
+ @api.depends("checkin", "checkout")
+ def _compute_is_modified_reservation(self):
+ for record in self:
+ if record.state in "draft":
+ record.is_modified_reservation = False
+ elif record.state in ("confirm", "onboard") and record.is_mail_send:
+ record.is_modified_reservation = True
+ record.is_mail_send = False
+ else:
+ record.is_modified_reservation = False
+
+ @api.depends("partner_id")
+ def _compute_lang(self):
+ for record in self:
+ if record.partner_id:
+ record.lang = record.partner_id.lang
+ else:
+ record.lang = self.env["res.lang"].get_installed()
+
def _search_allowed_checkin(self, operator, value):
if operator not in ("=",):
raise UserError(
@@ -1666,6 +1698,54 @@ class PmsReservation(models.Model):
},
}
+ def action_open_mail_composer(self):
+ self.ensure_one()
+ template = False
+ if (
+ not self.is_mail_send
+ and not self.is_modified_reservation
+ and self.state not in "cancel"
+ ):
+ template = self.env.ref(
+ "pms.confirmed_reservation_email", raise_if_not_found=False
+ )
+ elif (
+ not self.is_mail_send
+ and self.is_modified_reservation
+ and self.state not in "cancel"
+ ):
+ template = self.env.ref(
+ "pms.modified_reservation_email", raise_if_not_found=False
+ )
+ elif not self.is_mail_send and self.state in "cancel":
+ template = self.env.ref(
+ "pms.cancelled_reservation_email", raise_if_not_found=False
+ )
+ compose_form = self.env.ref(
+ "mail.email_compose_message_wizard_form", raise_if_not_found=False
+ )
+ ctx = dict(
+ model="pms.reservation",
+ default_res_model="pms.reservation",
+ default_res_id=self.id,
+ template_id=template and template.id or False,
+ composition_mode="comment",
+ partner_ids=[self.partner_id.id],
+ force_email=True,
+ record_id=self.id,
+ )
+ return {
+ "name": _("Send Confirmed Reservation Mail "),
+ "type": "ir.actions.act_window",
+ "view_type": "form",
+ "view_mode": "form",
+ "res_model": "mail.compose.message",
+ "views": [(compose_form.id, "form")],
+ "view_id": compose_form.id,
+ "target": "new",
+ "context": ctx,
+ }
+
@api.model
def name_search(self, name="", args=None, operator="ilike", limit=100):
if args is None:
@@ -1811,6 +1891,7 @@ class PmsReservation(models.Model):
else:
record.state = "cancel"
record.folio_id._compute_amount()
+ record.is_mail_send = False
def action_assign(self):
for record in self:
diff --git a/pms/security/ir.model.access.csv b/pms/security/ir.model.access.csv
index 544f75411..f536bb9a2 100644
--- a/pms/security/ir.model.access.csv
+++ b/pms/security/ir.model.access.csv
@@ -60,3 +60,4 @@ user_access_wizard_payment_folio,user_access_wizard_payment_folio,model_wizard_p
user_access_wizard_folio_changes,user_access_wizard_folio_changes,model_wizard_folio_changes,pms.group_pms_user,1,1,1,1
user_access_pms_folio_portal,user_access_pms_folio_portal,model_pms_folio,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
diff --git a/pms/tests/__init__.py b/pms/tests/__init__.py
index 4f21325fd..43e0a2cbe 100644
--- a/pms/tests/__init__.py
+++ b/pms/tests/__init__.py
@@ -38,3 +38,4 @@ from . import test_pms_wizard_split_join_swap_reservation
from . import test_product_template
from . import test_pms_multiproperty
from . import test_shared_room
+from . import test_automated_mails
diff --git a/pms/tests/test_automated_mails.py b/pms/tests/test_automated_mails.py
new file mode 100644
index 000000000..8f60d2abd
--- /dev/null
+++ b/pms/tests/test_automated_mails.py
@@ -0,0 +1,618 @@
+from odoo.exceptions import UserError
+
+from .common import TestPms
+
+
+class TestPmsAutomatedMails(TestPms):
+ def setUp(self):
+ super().setUp()
+ self.template = self.env["mail.template"].search(
+ [("name", "=", "Confirmed Reservation")]
+ )
+
+ def test_create_automated_action(self):
+ """
+ Checks that an automated_action is created correctly when an
+ automated_mail is created.
+ ---------------------
+ An automated_mail is created and then it is verified that
+ the automated_action was created.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "creation",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertTrue(
+ auto_mail.automated_actions_id, "Automated action should be created "
+ )
+
+ def test_no_action_creation_before(self):
+ """
+ Check that an automated mail cannot be created with action='creation'
+ and moment='before'.
+ -----------------------
+ An automated mail is created with action = 'creation' and moment = 'before'.
+ Then it is verified that a UserError was thrown because an automated_mail with
+ these parameters cannot be created.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "creation",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT & ASSERT
+ with self.assertRaises(
+ UserError,
+ msg="It should not be allowed to create the automated mail "
+ "with action 'creation' and moment 'before' values",
+ ):
+ self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ def test_trigger_moment_in_act_creation(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'creation' and moment = 'in_act' the trigger of the
+ automated_action created is 'on_create'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "creation",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_create",
+ "The trigger of the automated action must be 'on_create'",
+ )
+
+ def test_trigger_moment_after_in_creation_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'creation' and moment = 'after' the trigger of the
+ automated_action created is 'on_time'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "creation",
+ "moment": "after",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 1,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_time",
+ "The trigger of the automated action must be 'on_time'",
+ )
+
+ def test_trigger_moment_in_act_in_write_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'write' and moment = 'in_act' the trigger of the
+ automated_action created is 'on_write'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "write",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_write",
+ "The trigger of the automated action must be 'on_write'",
+ )
+
+ def test_trigger_moment_after_in_write_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'write' and moment = 'after' the trigger of the
+ automated_action created is 'on_time'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "write",
+ "moment": "after",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 1,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_time",
+ "The trigger of the automated action must be 'on_time'",
+ )
+
+ def test_time_moment_before_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'before' the trg_date_range
+ of the automated_action created is equal to
+ (automated_mail.time * -1)'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 60,
+ "time_type": "minutes",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ -60,
+ "The trg_date_range of the automated action must be '-60'",
+ )
+
+ def test_time_moment_in_act_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'in_act' the trg_date_range
+ of the automated_action created is equal to 0
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ 0,
+ "The trg_date_range of the automated action must be '0'",
+ )
+
+ def test_trigger_moment_before_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'before' the trigger of the
+ automated_action created is 'on_time'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 24,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_time",
+ "The trigger of the automated action must be 'on_time'",
+ )
+
+ def test_trigger_moment_in_act_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'in_act' the trigger of the
+ automated_action created is 'on_write'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_write",
+ "The trigger of the automated action must be 'on_write'",
+ )
+
+ def test_time_moment_before_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'before' the trg_date_range
+ of the automated_action created is equal to
+ (automated_mail.time * -1)'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 60,
+ "time_type": "minutes",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ -60,
+ "The trg_date_range of the automated action must be '-60'",
+ )
+
+ def test_time_moment_in_act_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'in_act' the trg_date_range
+ of the automated_action created is equal to 0.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ 0,
+ "The trg_date_range of the automated action must be '0'",
+ )
+
+ def test_trigger_moment_before_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'before' the trigger of the
+ automated_action created is 'on_time'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 24,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_time",
+ "The trigger of the automated action must be 'on_time'",
+ )
+
+ def test_trigger_moment_in_act_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'in_act' the trigger of the
+ automated_action created is 'on_write'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_write",
+ "The trigger of the automated action must be 'on_write'",
+ )
+
+ def test_trigger_moment_in_act_in_payment_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'payment' and moment = 'in_act' the trigger of the
+ automated_action created is 'on_create'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "payment",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_create",
+ "The trigger of the automated action must be 'on_create'",
+ )
+
+ def test_trigger_moment_before_in_payment_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'payment' and moment = 'before' the trigger of the
+ automated_action created is 'on_time'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "payment",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 24,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_time",
+ "The trigger of the automated action must be 'on_time'",
+ )
+
+ def test_time_moment_before_in_payment_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'payment' and moment = 'before' the trg_date_range
+ field of the automated_action is (automated_mail.time * -1).
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "payment",
+ "moment": "before",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ "time": 24,
+ "time_type": "hour",
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ -24,
+ "The trg_date_range of the automated action must be '-24'",
+ )
+
+ def test_trigger_moment_in_act_in_invoice_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'invoice' and moment = 'in_act' the trigger field
+ of the automated_action created is 'on_create'.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "invoice",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trigger,
+ "on_create",
+ "The trigger of the automated action must be 'on_create'",
+ )
+
+ def test_time_moment_in_act_in_invoice_action(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'invoice' and moment = 'in_act' the trg_date_range
+ field of the automated_action is 0.
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "invoice",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.trg_date_range,
+ 0,
+ "The trg_date_range of the automated action must be '0'",
+ )
+
+ def test_filter_pre_domain_moment_in_act_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'in_act' the filter_pre_domain
+ field of the automated_action is [('state', '=', 'confirm')].
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.filter_pre_domain,
+ "[('state', '=', 'confirm')]",
+ "The filter_pre_domain of the automated action "
+ "must be '[('state', '=', 'confirm')]'",
+ )
+
+ def test_filter_domain_moment_in_act_in_checkin(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkin' and moment = 'in_act' the filter_domain
+ field of the automated_action is
+ [('state', '=', 'onboard'), ('pms_property_id', '=', [value of property_id.id])]].
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkin",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+ pms_property_id_str = str(auto_mail.pms_property_ids.ids)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.filter_domain,
+ "[('state', '=', 'onboard'), ('pms_property_id', 'in', "
+ + pms_property_id_str
+ + ")]",
+ "The filter_domain of the automated action must be "
+ "'[('state', '=', 'onboard'), "
+ "('pms_property_id', '=', [value of property_id.id])]'",
+ )
+
+ def test_filter_pre_domain_moment_in_act_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'in_act' the filter_pre_domain
+ field of the automated_action is [('state', '=', 'onboard')].
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.filter_pre_domain,
+ "[('state', '=', 'onboard')]",
+ "The filter_pre_domain of the automated action must "
+ "be '[('state', '=', 'onboard')]'",
+ )
+
+ def test_filter_domain_moment_in_act_in_checkout(self):
+ """
+ Check that when creating an automated mail with parameters
+ action = 'checkout' and moment = 'in_act' the filter_domain
+ field of the automated_action is
+ [('state', '=', 'out'), ('pms_property_id', '=', [value of property_id.id])]].
+ """
+ # ARRANGE
+ automated_mail_vals = {
+ "name": "Auto Mail 1",
+ "template_id": self.template.id,
+ "action": "checkout",
+ "moment": "in_act",
+ "pms_property_ids": [(6, 0, [self.pms_property1.id])],
+ }
+
+ # ACT
+ auto_mail = self.env["pms.automated.mails"].create(automated_mail_vals)
+ pms_property_id_str = str(auto_mail.pms_property_ids.ids)
+
+ # ASSERT
+ self.assertEqual(
+ auto_mail.automated_actions_id.filter_domain,
+ "[('state', '=', 'out'), ('pms_property_id', 'in', "
+ + pms_property_id_str
+ + ")]",
+ "The filter_pre_domain of the automated action must "
+ "be '[('state', '=', 'out'), ('pms_property_id', '=', [value of property_id.id])]",
+ )
diff --git a/pms/tests/test_pms_reservation.py b/pms/tests/test_pms_reservation.py
index 21706c792..c7c48f119 100644
--- a/pms/tests/test_pms_reservation.py
+++ b/pms/tests/test_pms_reservation.py
@@ -3424,3 +3424,77 @@ class TestPmsReservations(TestPms):
partner.id,
"The partner was not added to the reservation ",
)
+
+ def test_is_modified_reservation(self):
+ """
+ Checked that the is_modified_reservation field is correctly set
+ to True when the checkin or checkout fields are modified in a
+ reservation.
+ ----------------------
+ A reservation is created. The checkin and checkout fields of
+ the reservation are modified. The state of the boolean
+ is_mail_send is changed to True so that the compute of
+ the is_modified_reservation field is activated correctly
+ and it is verified that the state of this field is True.
+ """
+ # ARRANGE
+ checkin = fields.date.today()
+ checkout = fields.date.today() + datetime.timedelta(days=2)
+ reservation_vals = {
+ "checkin": checkin,
+ "checkout": checkout,
+ "room_type_id": self.room_type_double.id,
+ "partner_id": self.partner1.id,
+ "pms_property_id": self.pms_property1.id,
+ }
+
+ reservation = self.env["pms.reservation"].create(reservation_vals)
+
+ # ACT
+ writed_checkin = fields.date.today() + datetime.timedelta(days=4)
+ writed_checkout = fields.date.today() + datetime.timedelta(days=6)
+ reservation.is_mail_send = True
+ reservation.update(
+ {
+ "checkin": writed_checkin,
+ "checkout": writed_checkout,
+ }
+ )
+
+ # ASSERT
+ self.assertTrue(
+ reservation.is_modified_reservation,
+ "is_modified_reservation field should be True ",
+ )
+
+ def test_is_not_modified_reservation(self):
+ """
+ Checked that the is_modified_reservation field is correctly set
+ to False when the reservation is modified but not the checkin
+ or checkout fields.
+ ----------------------
+ A reservation is created. The adults, arrival_hour and departure_hours
+ fields of the reservation are modified.The it is verified that the state
+ of this field is False.
+ """
+ # ARRANGE
+ checkin = fields.date.today()
+ checkout = fields.date.today() + datetime.timedelta(days=2)
+ reservation_vals = {
+ "checkin": checkin,
+ "checkout": checkout,
+ "room_type_id": self.room_type_double.id,
+ "partner_id": self.partner1.id,
+ "pms_property_id": self.pms_property1.id,
+ }
+
+ reservation = self.env["pms.reservation"].create(reservation_vals)
+ reservation.update(
+ {"adults": 1, "arrival_hour": "18:00", "departure_hour": "08:00"}
+ )
+
+ # ASSERT
+ self.assertFalse(
+ reservation.is_modified_reservation,
+ "is_modified_reservation field should be False ",
+ )
diff --git a/pms/views/pms_automated_mails_views.xml b/pms/views/pms_automated_mails_views.xml
new file mode 100644
index 000000000..4f49aa5d9
--- /dev/null
+++ b/pms/views/pms_automated_mails_views.xml
@@ -0,0 +1,73 @@
+
+
+
+ pms.automated_mails_view_form
+ pms.automated.mails
+
+
+
+
+
+ pms.automated.mails.tree
+ pms.automated.mails
+
+
+
+
+
+
+
+
+
+
+
+
+ Automated Mails
+ pms.automated.mails
+
+ tree,form
+
+
+
diff --git a/pms/views/pms_property_views.xml b/pms/views/pms_property_views.xml
index 4ac88fb28..f62b968f8 100644
--- a/pms/views/pms_property_views.xml
+++ b/pms/views/pms_property_views.xml
@@ -85,6 +85,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pms/views/pms_reservation_views.xml b/pms/views/pms_reservation_views.xml
index d9c3169ef..233b62735 100644
--- a/pms/views/pms_reservation_views.xml
+++ b/pms/views/pms_reservation_views.xml
@@ -43,7 +43,27 @@
states="onboard,departure_delayed"
type="object"
/>
+
+
+
+
+
There is a customer with this email or mobile, do you want to add it to the reservation?
@@ -1043,4 +1063,45 @@
form
+
+ Resend confirmation email
+ ir.actions.act_window
+ mail.compose.message
+ form
+ new
+
+ form
+
+
+
+
+ Resend modification email
+ ir.actions.act_window
+ mail.compose.message
+ form
+ new
+
+ form
+
+
+
+
+ Resend cancellation email
+ ir.actions.act_window
+ mail.compose.message
+ form
+ new
+
+ form
+
+