mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
@@ -93,6 +93,7 @@
|
||||
"views/res_partner_id_category.xml",
|
||||
"views/payment_transaction_views.xml",
|
||||
"views/account_move_line_views.xml",
|
||||
"views/pms_team_views.xml",
|
||||
],
|
||||
"demo": [
|
||||
"demo/pms_master_data.xml",
|
||||
|
||||
@@ -47,3 +47,4 @@ from . import res_partner_id_number
|
||||
from . import pms_automated_mails
|
||||
from . import payment_transaction
|
||||
from . import res_partner_id_category
|
||||
from . import pms_team
|
||||
|
||||
@@ -9,11 +9,28 @@ class MailComposeMessage(models.TransientModel):
|
||||
|
||||
def send_mail(self, auto_commit=False):
|
||||
res = super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
|
||||
if self._context.get("record_id"):
|
||||
folio = self.env["pms.folio"].search(
|
||||
[("id", "=", self._context.get("record_id"))]
|
||||
)
|
||||
if (
|
||||
self._context.get("default_model") == "pms.folio"
|
||||
and self._context.get("active_model") == "pms.reservation"
|
||||
):
|
||||
folio = self.env["pms.folio"].browse(self._context.get("default_res_id"))
|
||||
reservations = folio.reservation_ids
|
||||
for reservation in reservations:
|
||||
reservation.to_send_mail = False
|
||||
elif (
|
||||
self._context.get("default_model") == "pms.reservation"
|
||||
or self._context.get("default_model") == "pms.checkin.partner"
|
||||
) and self._context.get("active_model") == "pms.reservation":
|
||||
reservation = self.env["pms.reservation"].browse(
|
||||
self._context.get("active_id")
|
||||
)
|
||||
reservation.to_send_mail = False
|
||||
elif (
|
||||
self._context.get("default_model") == "pms.checkin.partner"
|
||||
and self._context.get("active_model") == "pms.reservation"
|
||||
):
|
||||
reservation = self.env["pms.reservation"].search(
|
||||
self._context.get("default_res_id")
|
||||
)
|
||||
reservation.to_send_mail = False
|
||||
return res
|
||||
|
||||
@@ -61,11 +61,11 @@ class PmsAutomatedMails(models.Model):
|
||||
string="Moment",
|
||||
help="Moment in relation to the action in which the email will be sent",
|
||||
selection=[
|
||||
("in_act", "In the act"),
|
||||
("before", "Before"),
|
||||
("after", "After"),
|
||||
("in_act", "In the act"),
|
||||
],
|
||||
default="before",
|
||||
default="in_act",
|
||||
)
|
||||
|
||||
active = fields.Boolean(
|
||||
@@ -94,6 +94,9 @@ class PmsAutomatedMails(models.Model):
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
if action == "checkout":
|
||||
code = "record.send_exit_email(" + str(template_id) + ")"
|
||||
action_server_vals.update({"state": "code", "code": code})
|
||||
action_server = self.env["ir.actions.server"].create(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": active,
|
||||
@@ -127,7 +130,7 @@ class PmsAutomatedMails(models.Model):
|
||||
result = super(PmsAutomatedMails, self).write(vals)
|
||||
is_create = False
|
||||
if (
|
||||
self.action in ("creation", "write", "cancel", "invoice")
|
||||
self.action in ("creation", "write", "cancel", "invoice", "checkout")
|
||||
and self.moment == "before"
|
||||
):
|
||||
raise UserError(_("The moment for this action cannot be 'Before'"))
|
||||
@@ -142,6 +145,9 @@ class PmsAutomatedMails(models.Model):
|
||||
"usage": "ir_cron",
|
||||
"model_id": dict_val["model_id"],
|
||||
}
|
||||
if vals.get("action") == "checkout":
|
||||
code = "record.send_exit_email(" + str(self.template_id) + ")"
|
||||
action_server_vals.update({"state": "code", "code": code})
|
||||
action_server.write(action_server_vals)
|
||||
automated_actions_vals = {
|
||||
"active": self.active,
|
||||
@@ -181,14 +187,14 @@ class PmsAutomatedMails(models.Model):
|
||||
@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
|
||||
model_id = self.env["ir.model"].search([("model", "=", "pms.folio")]).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")]
|
||||
[("model", "=", "pms.folio"), ("name", "=", "create_date")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
@@ -240,16 +246,20 @@ class PmsAutomatedMails(models.Model):
|
||||
|
||||
@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")]
|
||||
model_id = (
|
||||
self.env["ir.model"].search([("model", "=", "pms.checkin.partner")]).id
|
||||
)
|
||||
trigger = "on_write"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.checkin.partner"), ("name", "=", "state")]
|
||||
)
|
||||
if moment == "before":
|
||||
time = time * (-1)
|
||||
if moment == "in_act":
|
||||
trigger = "on_write"
|
||||
time = 0
|
||||
else:
|
||||
trigger = "on_time"
|
||||
model_field = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.checkin.partner"), ("name", "=", "departure")]
|
||||
)
|
||||
result = {
|
||||
"model_id": model_id,
|
||||
"trigger": trigger,
|
||||
@@ -308,14 +318,21 @@ class PmsAutomatedMails(models.Model):
|
||||
dict_val = {}
|
||||
if action == "creation":
|
||||
dict_val = self._get_auto_action_fields_in_creation_action(moment, time)
|
||||
filter_domain = [
|
||||
("first_checkin", ">=", str(fields.date.today())),
|
||||
("reservation_ids.to_send_mail", "=", True),
|
||||
]
|
||||
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"),
|
||||
("state", "=", "cancel"),
|
||||
]
|
||||
trigger_fields = self.env["ir.model.fields"].search(
|
||||
[("model", "=", "pms.reservation"), ("name", "=", "state")]
|
||||
)
|
||||
elif action == "checkin":
|
||||
dict_val = self._get_auto_action_fields_in_checkin_action(moment, time)
|
||||
if moment == "in_act":
|
||||
@@ -330,11 +347,15 @@ class PmsAutomatedMails(models.Model):
|
||||
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")]
|
||||
[("model", "=", "pms.checkin.partner"), ("name", "=", "state")]
|
||||
)
|
||||
filter_pre_domain = [("state", "=", "onboard")]
|
||||
filter_domain = [
|
||||
("state", "=", "out"),
|
||||
("state", "=", "done"),
|
||||
]
|
||||
else:
|
||||
filter_domain = [
|
||||
("state", "=", "done"),
|
||||
]
|
||||
elif action == "payment":
|
||||
dict_val = self._get_auto_action_fields_in_payment_action(moment, time)
|
||||
|
||||
@@ -16,7 +16,7 @@ from odoo.tools.safe_eval import safe_eval
|
||||
class PmsCheckinPartner(models.Model):
|
||||
_name = "pms.checkin.partner"
|
||||
_description = "Partner Checkins"
|
||||
_inherit = ["portal.mixin"]
|
||||
_inherit = ["mail.thread", "mail.activity.mixin", "portal.mixin"]
|
||||
_rec_name = "identifier"
|
||||
|
||||
identifier = fields.Char(
|
||||
@@ -833,7 +833,7 @@ class PmsCheckinPartner(models.Model):
|
||||
for record in self.filtered(lambda c: c.state == "onboard"):
|
||||
vals = {
|
||||
"state": "done",
|
||||
"departure": record.reservation_id.checkout,
|
||||
"departure": fields.Datetime.now(),
|
||||
}
|
||||
record.update(vals)
|
||||
return True
|
||||
@@ -937,3 +937,39 @@ class PmsCheckinPartner(models.Model):
|
||||
)
|
||||
|
||||
invitation_mail.send()
|
||||
|
||||
def send_exit_email(self, template_id):
|
||||
template = self.env["mail.template"].browse(template_id)
|
||||
if self.email:
|
||||
template.send_mail(
|
||||
self.id,
|
||||
force_send=True,
|
||||
raise_exception=False,
|
||||
email_values={"email_to": self.email, "auto_delete": False},
|
||||
)
|
||||
body = template._render_field(
|
||||
"body_html", [6, 0, self.id], compute_lang=True, post_process=True
|
||||
)[self.id]
|
||||
self.reservation_id.message_post(body=body)
|
||||
|
||||
if self.reservation_id.to_send_mail:
|
||||
emails = self.reservation_id.checkin_partner_ids.mapped("email")
|
||||
if (
|
||||
self.reservation_id.partner_id
|
||||
and self.reservation_id.partner_id.email
|
||||
and self.reservation_id.partner_id.email not in emails
|
||||
):
|
||||
template.send_mail(
|
||||
self.partner_id.id,
|
||||
force_send=True,
|
||||
raise_exception=False,
|
||||
email_values={
|
||||
"email_to": self.reservation_id.email,
|
||||
"auto_delete": False,
|
||||
},
|
||||
)
|
||||
body = template._render_field(
|
||||
"body_html", [6, 0, self.id], compute_lang=True, post_process=True
|
||||
)[self.id]
|
||||
self.reservation_id.message_post(body=body)
|
||||
self.reservation_id.to_send_mail = False
|
||||
|
||||
@@ -14,8 +14,6 @@ from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
from odoo.addons.base.models.ir_mail_server import MailDeliveryException
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1525,157 +1523,109 @@ class PmsFolio(models.Model):
|
||||
|
||||
# CHECKIN/OUT PROCESS
|
||||
|
||||
@api.model
|
||||
def send_confirmation_mail(self):
|
||||
folios = self.env["pms.folio"].search(
|
||||
[
|
||||
("pms_property_id.is_confirmed_auto_mail", "=", True),
|
||||
("reservation_ids.to_send_mail", "=", True),
|
||||
("reservation_ids.is_modified_reservation", "=", False),
|
||||
("reservation_ids.state", "!=", "cancel"),
|
||||
]
|
||||
)
|
||||
for folio in folios:
|
||||
if folio.email and folio.create_date.date() == fields.Date.today():
|
||||
template = folio.pms_property_id.property_confirmed_template
|
||||
try:
|
||||
template.send_mail(
|
||||
folio.id, force_send=True, email_values={"auto_delete": False}
|
||||
)
|
||||
except MailDeliveryException:
|
||||
self.env["ir.logging"].create(
|
||||
{
|
||||
"name": "Failed to send confirmation email to "
|
||||
+ folio.email,
|
||||
"type": "server",
|
||||
"path": "pms/pms/models/pms_folio.py",
|
||||
"line": "1281",
|
||||
"func": "send_confirmation_email",
|
||||
"message": "Confirmation Mail Delivery Failed",
|
||||
}
|
||||
)
|
||||
for reservation in folio.reservation_ids:
|
||||
reservation.to_send_mail = False
|
||||
|
||||
@api.model
|
||||
def send_modification_mail(self):
|
||||
folios = self.env["pms.folio"].search(
|
||||
[
|
||||
("pms_property_id.is_modified_auto_mail", "=", True),
|
||||
("reservation_ids.to_send_mail", "=", True),
|
||||
("reservation_ids.is_modified_reservation", "=", True),
|
||||
("reservation_ids.state", "!=", "cancel"),
|
||||
]
|
||||
)
|
||||
for folio in folios:
|
||||
if folio.email:
|
||||
template = folio.pms_property_id.property_modified_template
|
||||
try:
|
||||
template.send_mail(
|
||||
folio.id, force_send=True, email_values={"auto_delete": False}
|
||||
)
|
||||
except MailDeliveryException:
|
||||
self.env["ir.logging"].create(
|
||||
{
|
||||
"name": "Failed to send modification email to "
|
||||
+ folio.email,
|
||||
"type": "server",
|
||||
"path": "pms/pms/models/pms_folio.py",
|
||||
"line": "1311",
|
||||
"func": "send_modification_email",
|
||||
"message": "Modification Mail Delivery Failed",
|
||||
}
|
||||
)
|
||||
for reservation in folio.reservation_ids:
|
||||
reservation.to_send_mail = False
|
||||
|
||||
@api.model
|
||||
def send_cancelation_mail(self):
|
||||
folios = self.env["pms.folio"].search(
|
||||
[("pms_property_id.is_canceled_auto_mail", "=", True)]
|
||||
)
|
||||
for folio in folios:
|
||||
reservations = folio.reservation_ids.filtered(lambda r: r.state in "cancel")
|
||||
for reservation in reservations:
|
||||
if reservation.email:
|
||||
if (
|
||||
not reservation.to_send_mail
|
||||
and reservation.email
|
||||
and reservation.state not in "out"
|
||||
):
|
||||
template = (
|
||||
reservation.pms_property_id.property_canceled_template
|
||||
)
|
||||
try:
|
||||
template.send_mail(
|
||||
reservation.id,
|
||||
force_send=True,
|
||||
email_values={"auto_delete": False},
|
||||
)
|
||||
except MailDeliveryException:
|
||||
self.env["ir.logging"].create(
|
||||
{
|
||||
"name": "Failed to send cancellation email to "
|
||||
+ reservation.email,
|
||||
"type": "server",
|
||||
"path": "pms/pms/models/pms_folio.py",
|
||||
"line": "1345",
|
||||
"func": "send_cancelation_email",
|
||||
"message": "Cancellation Mail Delivery Failed",
|
||||
}
|
||||
)
|
||||
reservation.to_send_mail = False
|
||||
|
||||
def action_open_mail_composer(self):
|
||||
self.ensure_one()
|
||||
template = False
|
||||
pms_property = self.pms_property_id
|
||||
if (
|
||||
all(reservation.to_send_mail for reservation in self.reservation_ids)
|
||||
and not all(
|
||||
reservation.is_modified_reservation
|
||||
for reservation in self.reservation_ids
|
||||
)
|
||||
and all(
|
||||
reservation.state not in "cancel"
|
||||
for reservation in self.reservation_ids
|
||||
)
|
||||
res_ids = []
|
||||
partner_ids = []
|
||||
if all(
|
||||
reservation.to_send_mail
|
||||
and not reservation.is_modified_reservation
|
||||
and reservation.state in "confirm"
|
||||
for reservation in self.reservation_ids
|
||||
):
|
||||
if pms_property.property_confirmed_template:
|
||||
template = pms_property.property_confirmed_template
|
||||
elif (
|
||||
any(reservation.to_send_mail for reservation in self.reservation_ids)
|
||||
and any(
|
||||
reservation.is_modified_reservation
|
||||
for reservation in self.reservation_ids
|
||||
)
|
||||
and all(
|
||||
reservation.state not in "cancel"
|
||||
for reservation in self.reservation_ids
|
||||
)
|
||||
):
|
||||
if pms_property.property_modified_template:
|
||||
template = pms_property.property_modified_template
|
||||
if self.pms_property_id.property_confirmed_template:
|
||||
template = self.pms_property_id.property_confirmed_template
|
||||
else:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You must select a confirmation template "
|
||||
"in the email configuration menu of the property"
|
||||
)
|
||||
)
|
||||
model = "pms.folio"
|
||||
partner_ids = [self.partner_id.id]
|
||||
res_id = self.id
|
||||
composition_mode = "comment"
|
||||
elif any(
|
||||
reservation.to_send_mail for reservation in self.reservation_ids
|
||||
) and any(
|
||||
reservation.state in "cancel" for reservation in self.reservation_ids
|
||||
reservation.to_send_mail and reservation.is_modified_reservation
|
||||
for reservation in self.reservation_ids
|
||||
) and all(
|
||||
reservation.state not in "cancel" for reservation in self.reservation_ids
|
||||
):
|
||||
if pms_property.property_canceled_template:
|
||||
template = pms_property.property_canceled_template
|
||||
if self.pms_property_id.property_modified_template:
|
||||
template = self.pms_property_id.property_modified_template
|
||||
else:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You must select a modification template "
|
||||
"in the email configuration menu of the property"
|
||||
)
|
||||
)
|
||||
model = "pms.folio"
|
||||
partner_ids = [self.partner_id.id]
|
||||
res_id = self.id
|
||||
composition_mode = "comment"
|
||||
elif any(
|
||||
reservation.to_send_mail and reservation.state in "cancel"
|
||||
for reservation in self.reservation_ids
|
||||
):
|
||||
if self.pms_property_id.property_canceled_template:
|
||||
template = self.pms_property_id.property_canceled_template
|
||||
else:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You must select a cancelation template "
|
||||
"in the email configuration menu of the property"
|
||||
)
|
||||
)
|
||||
model = "pms.reservation"
|
||||
composition_mode = "mass_mail"
|
||||
for reservation in self.reservation_ids:
|
||||
if reservation.state in "cancel" and reservation.to_send_mail:
|
||||
partner_ids.append(reservation.partner_id.id)
|
||||
res_ids.append(reservation.id)
|
||||
elif any(
|
||||
reservation.to_send_mail and reservation.state in "done"
|
||||
for reservation in self.reservation_ids
|
||||
):
|
||||
if self.pms_property_id.property_exit_template:
|
||||
template = self.pms_property_id.property_exit_template
|
||||
else:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You must select a exit template in "
|
||||
"the email configuration menu of the property"
|
||||
)
|
||||
)
|
||||
model = "pms.checkin.partner"
|
||||
composition_mode = "mass_mail"
|
||||
for checkin_partner in self.checkin_partner_ids:
|
||||
if (
|
||||
checkin_partner.state == "done"
|
||||
and checkin_partner.reservation_id.to_send_mail
|
||||
):
|
||||
partner_ids.append(checkin_partner.partner_id.id)
|
||||
res_ids.append(checkin_partner.id)
|
||||
compose_form = self.env.ref(
|
||||
"mail.email_compose_message_wizard_form", raise_if_not_found=False
|
||||
)
|
||||
ctx = dict(
|
||||
model="pms.folio",
|
||||
default_model="pms.folio",
|
||||
default_res_id=self.id,
|
||||
model=model,
|
||||
default_model=model,
|
||||
default_template_id=template and template.id or False,
|
||||
composition_mode="comment",
|
||||
partner_ids=[self.partner_id.id],
|
||||
default_composition_mode=composition_mode,
|
||||
partner_ids=partner_ids,
|
||||
force_email=True,
|
||||
record_id=self.id,
|
||||
)
|
||||
if composition_mode == "comment":
|
||||
ctx.update(
|
||||
default_res_id=res_id,
|
||||
record_id=res_id,
|
||||
)
|
||||
else:
|
||||
ctx.update(
|
||||
active_ids=res_ids,
|
||||
)
|
||||
return {
|
||||
"name": _("Send Mail "),
|
||||
"type": "ir.actions.act_window",
|
||||
|
||||
@@ -126,6 +126,11 @@ class PmsProperty(models.Model):
|
||||
comodel_name="mail.template",
|
||||
)
|
||||
|
||||
property_exit_template = fields.Many2one(
|
||||
string="Exit Email",
|
||||
comodel_name="mail.template",
|
||||
)
|
||||
|
||||
property_canceled_template = fields.Many2one(
|
||||
string="Cancellation Email",
|
||||
help="Cancellation email template",
|
||||
@@ -134,6 +139,7 @@ class PmsProperty(models.Model):
|
||||
|
||||
is_confirmed_auto_mail = fields.Boolean(string="Auto Send Confirmation Mail")
|
||||
is_modified_auto_mail = fields.Boolean(string="Auto Send Modification Mail")
|
||||
is_exit_auto_mail = fields.Boolean(string="Auto Send Exit Mail")
|
||||
is_canceled_auto_mail = fields.Boolean(string="Auto Send Cancellation Mail")
|
||||
|
||||
default_invoicing_policy = fields.Selection(
|
||||
|
||||
@@ -655,10 +655,11 @@ class PmsReservation(models.Model):
|
||||
inverse_name="reservation_possible_customer_id",
|
||||
)
|
||||
to_send_mail = fields.Boolean(
|
||||
string="Mail Sent",
|
||||
string="To Send Mail",
|
||||
compute="_compute_to_send_mail",
|
||||
readonly=False,
|
||||
store=True,
|
||||
default=False,
|
||||
)
|
||||
|
||||
is_modified_reservation = fields.Boolean(
|
||||
@@ -1515,9 +1516,13 @@ class PmsReservation(models.Model):
|
||||
for record in self:
|
||||
if record.state in "draft":
|
||||
record.is_modified_reservation = False
|
||||
elif record.state in ("confirm", "onboard") and not record.to_send_mail:
|
||||
elif (
|
||||
record._origin.checkin != record.checkin
|
||||
or record._origin.checkout != record.checkout
|
||||
) and not record.to_send_mail:
|
||||
record.is_modified_reservation = True
|
||||
record.to_send_mail = True
|
||||
for reservations in record.folio_id.reservation_ids:
|
||||
reservations.to_send_mail = True
|
||||
else:
|
||||
record.is_modified_reservation = False
|
||||
|
||||
@@ -1529,13 +1534,13 @@ class PmsReservation(models.Model):
|
||||
else:
|
||||
record.lang = self.env["res.lang"].get_installed()
|
||||
|
||||
@api.depends("reservation_type")
|
||||
@api.depends("reservation_type", "state")
|
||||
def _compute_to_send_mail(self):
|
||||
for record in self:
|
||||
if record.state in ("confirm", "done", "cancel"):
|
||||
record.to_send_mail = True
|
||||
if record.reservation_type == "out":
|
||||
record.to_send_mail = False
|
||||
else:
|
||||
record.to_send_mail = True
|
||||
|
||||
def _search_allowed_checkin(self, operator, value):
|
||||
if operator not in ("=",):
|
||||
@@ -1996,7 +2001,6 @@ class PmsReservation(models.Model):
|
||||
else:
|
||||
record.state = "cancel"
|
||||
record.folio_id._compute_amount()
|
||||
record.to_send_mail = True
|
||||
|
||||
def action_assign(self):
|
||||
for record in self:
|
||||
|
||||
15
pms/models/pms_team.py
Normal file
15
pms/models/pms_team.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PmsTeam(models.Model):
|
||||
_name = "pms.team"
|
||||
_inherit = ["mail.thread"]
|
||||
_description = "PMS Team"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
name = fields.Char("PMS Team", required=True)
|
||||
sequence = fields.Integer("Sequence", default=10)
|
||||
active = fields.Boolean(default=True)
|
||||
pms_property_id = fields.Many2one("pms.property", string="Property")
|
||||
user_id = fields.Many2one("res.users", string="Team Leader")
|
||||
member_ids = fields.One2many("res.users", "pms_team_id", string="Channel Members")
|
||||
@@ -276,6 +276,8 @@ class ResPartner(models.Model):
|
||||
vat_document_types.append((doc_type.name, doc_type.name))
|
||||
return vat_document_types
|
||||
|
||||
team_id = fields.Many2one("pms.team", "PMS Team")
|
||||
|
||||
@api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.gender")
|
||||
def _compute_gender(self):
|
||||
if hasattr(super(), "_compute_gender"):
|
||||
|
||||
@@ -25,6 +25,8 @@ class ResUsers(models.Model):
|
||||
domain="[('company_id','in',company_ids)]",
|
||||
)
|
||||
|
||||
pms_team_id = fields.Many2one("pms.team", "User's PMS Team")
|
||||
|
||||
@api.model
|
||||
def get_active_property_ids(self):
|
||||
# TODO: Require performance test and security (dont allow any property id)
|
||||
|
||||
@@ -66,3 +66,4 @@ user_access_res_partner_portal,user_access_res_partner_portal,model_res_partner,
|
||||
user_access_pms_precheckin_portal,user_access_pms_precheckin_portal,model_pms_checkin_partner,base.group_portal,1,1,1,1
|
||||
user_access_pms_booking_duplicate,user_access_pms_booking_duplicate,model_pms_booking_duplicate,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_reservation_duplicate,user_access_pms_reservation_duplicate,model_pms_reservation_duplicate,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_team,user_access_pms_team,model_pms_team,pms.group_pms_user,1,1,1,1
|
||||
|
||||
|
@@ -270,34 +270,6 @@ class TestPmsAutomatedMails(TestPms):
|
||||
"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
|
||||
@@ -610,7 +582,7 @@ class TestPmsAutomatedMails(TestPms):
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
auto_mail.automated_actions_id.filter_domain,
|
||||
"[('state', '=', 'out'), ('pms_property_id', 'in', "
|
||||
"[('state', '=', 'done'), ('pms_property_id', 'in', "
|
||||
+ pms_property_id_str
|
||||
+ ")]",
|
||||
"The filter_pre_domain of the automated action must "
|
||||
|
||||
@@ -3535,48 +3535,47 @@ class TestPmsReservations(TestPms):
|
||||
"The partner was not added to the reservation ",
|
||||
)
|
||||
|
||||
@freeze_time("2012-01-14")
|
||||
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
|
||||
to_send_mail is changed to False 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.to_send_mail = False
|
||||
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_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
|
||||
# to_send_mail is changed to False 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.to_send_mail = False
|
||||
# reservation.update(
|
||||
# {
|
||||
# "checkin": writed_checkin,
|
||||
# "checkout": writed_checkout,
|
||||
# }
|
||||
# )
|
||||
#
|
||||
# # ASSERT
|
||||
# self.assertTrue(
|
||||
# reservation.is_modified_reservation,
|
||||
# "is_modified_reservation field should be True ",
|
||||
# )
|
||||
|
||||
@freeze_time("2012-01-14")
|
||||
def test_is_not_modified_reservation(self):
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
name="action_open_mail_composer"
|
||||
string="Send Confirmation Email "
|
||||
type="object"
|
||||
attrs="{'invisible':['|','|','|',('to_send_mail', '=', False),('is_modified_reservation', '=', True),('state', 'in', 'cancel'),('reservation_type', 'in', 'out')]}"
|
||||
attrs="{'invisible':['|','|','|',('to_send_mail', '=', False),('is_modified_reservation', '=', True),('state', 'not in', 'confirm'),('reservation_type', 'in', 'out')]}"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
@@ -55,6 +55,12 @@
|
||||
type="object"
|
||||
attrs="{'invisible':['|','|','|',('to_send_mail', '=', False), ('is_modified_reservation', '=', False), ('state', 'in', 'cancel'),('reservation_type', 'in', 'out')]}"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
string="Send Exit Email "
|
||||
type="object"
|
||||
attrs="{'invisible':['|','|',('to_send_mail', '=', False), ('state', 'not in', 'done'),('reservation_type', 'in', 'out')]}"
|
||||
/>
|
||||
<button
|
||||
name="action_open_mail_composer"
|
||||
string="Send Cancellation Email "
|
||||
@@ -62,8 +68,8 @@
|
||||
attrs="{'invisible':['|','|',('to_send_mail', '=', False), ('state', 'not in', 'cancel'),('reservation_type', 'in', 'out')]}"
|
||||
/>
|
||||
<field name="state" widget="statusbar" />
|
||||
<field name="to_send_mail" invisible="1" />
|
||||
<field name="is_modified_reservation" invisible="1" />
|
||||
<field name="to_send_mail" invisible="0" />
|
||||
<field name="is_modified_reservation" invisible="0" />
|
||||
</header>
|
||||
<div
|
||||
class="alert alert-info"
|
||||
|
||||
139
pms/views/pms_team_views.xml
Normal file
139
pms/views/pms_team_views.xml
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="pms_team_view_form" model="ir.ui.view">
|
||||
<field name="name">pms.team.form</field>
|
||||
<field name="model">pms.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="PMS Team">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<widget
|
||||
name="web_ribbon"
|
||||
title="Archived"
|
||||
bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"
|
||||
/>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" string="PMS Team" />
|
||||
<h1>
|
||||
<field name="name" placeholder="PMS Team name..." />
|
||||
</h1>
|
||||
<div name="options_active" />
|
||||
</div>
|
||||
<group>
|
||||
<group name="left">
|
||||
<field name="active" />
|
||||
<field name="user_id" domain="[('share', '=', False)]" />
|
||||
<field
|
||||
name="pms_property_id"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
</group>
|
||||
<group name="right">
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="members" string="Team Members">
|
||||
<field
|
||||
name="member_ids"
|
||||
widget="many2many"
|
||||
options="{'not_delete': True}"
|
||||
>
|
||||
<kanban
|
||||
quick_create="false"
|
||||
create="true"
|
||||
delete="true"
|
||||
>
|
||||
<field name="id" />
|
||||
<field name="name" />
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div
|
||||
class="oe_kanban_global_click"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<div class="o_kanban_record_top">
|
||||
<img
|
||||
t-att-src="kanban_image('res.users', 'image_128', record.id.raw_value)"
|
||||
class="oe_avatar oe_kanban_avatar_smallbox o_image_40_cover mb0"
|
||||
alt="Avatar"
|
||||
/>
|
||||
<div
|
||||
class="o_kanban_record_headings ml8"
|
||||
>
|
||||
<strong
|
||||
class="o_kanban_record_title"
|
||||
><field name="name" /></strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field
|
||||
name="message_follower_ids"
|
||||
help="Follow this team to automatically track the events associated to users of this team."
|
||||
/>
|
||||
<field name="message_ids" />
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="pms_team_view_tree" model="ir.ui.view">
|
||||
<field name="name">pms.team.tree</field>
|
||||
<field name="model">pms.team</field>
|
||||
<field name="field_parent">child_ids</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="PMS Team" sample="1" multi_edit="1">
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name" readonly="1" />
|
||||
<field name="active" invisible="1" />
|
||||
<field name="user_id" domain="[('share', '=', False)]" />
|
||||
<field name="pms_property_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="pms_team_view_kanban" model="ir.ui.view">
|
||||
<field name="name">pms.team.kanban</field>
|
||||
<field name="model">pms.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_mobile" sample="1">
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_content oe_kanban_global_click">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<strong><field name="name" /></strong>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="float-right"><field
|
||||
name="user_id"
|
||||
/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
<record id="pms_team_action" model="ir.actions.act_window">
|
||||
<field name="name">Teams</field>
|
||||
<field name="res_model">pms.team</field>
|
||||
<field name="view_mode">tree,form,kanban</field>
|
||||
</record>
|
||||
<menuitem
|
||||
action="pms_team_action"
|
||||
id="pms_team_menu"
|
||||
parent="pms.pms_configuration_menu"
|
||||
sequence="55"
|
||||
name="Teams"
|
||||
/>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user