mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[ADD] Cron no_show and no_checkout
This commit is contained in:
@@ -1,6 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Set reservation like No Show if the client does not show up -->
|
||||
<record model="ir.cron" id="noshow_reservations">
|
||||
<field name="name">Automatic No Show Reservation</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_reservation" />
|
||||
<field
|
||||
name="nextcall"
|
||||
eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 06:00:00')"
|
||||
/>
|
||||
<field name="code">model.auto_no_show()</field>
|
||||
</record>
|
||||
<!-- Set reservation like No Checout if checkout is not confirmed-->
|
||||
<record model="ir.cron" id="nocheckout_reservations">
|
||||
<field name="name">Automatic No Checkout Reservations</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="state">code</field>
|
||||
<field name="model_id" ref="model_pms_reservation" />
|
||||
<field
|
||||
name="nextcall"
|
||||
eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 12:00:00')"
|
||||
/>
|
||||
<field name="code">model.auto_no_checkout()</field>
|
||||
</record>
|
||||
<!-- Scheduler For To Inform Guest About Reservation Before 24 Hours -->
|
||||
<record model="ir.cron" id="autocheckout_reservations">
|
||||
<field name="name">Automatic Checkout on past reservations</field>
|
||||
|
||||
@@ -82,7 +82,7 @@ class PmsCheckinPartner(models.Model):
|
||||
for record in self.filtered("reservation_id"):
|
||||
record.folio_id = record.reservation_id.folio_id
|
||||
|
||||
@api.depends(lambda self: self._checkin_mandatory_fields(), "reservation_id.state")
|
||||
@api.depends(lambda self: self._checkin_mandatory_fields(depends=True))
|
||||
def _compute_state(self):
|
||||
for record in self:
|
||||
if not record.state:
|
||||
@@ -98,7 +98,11 @@ class PmsCheckinPartner(models.Model):
|
||||
else:
|
||||
record.state = "precheckin"
|
||||
|
||||
def _checkin_mandatory_fields(self):
|
||||
@api.model
|
||||
def _checkin_mandatory_fields(self, depends=False):
|
||||
# api.depends need "reservation_id.state" in de lambda function
|
||||
if depends:
|
||||
return ["reservation_id.state", "name"]
|
||||
return ["name"]
|
||||
|
||||
# Constraints and onchanges
|
||||
@@ -156,6 +160,22 @@ class PmsCheckinPartner(models.Model):
|
||||
record.update(vals)
|
||||
if record.reservation_id.state == "confirm":
|
||||
record.reservation_id.state = "onboard"
|
||||
if self._context.get("popup"):
|
||||
self.ensure_one()
|
||||
kanban_id = self.env.ref("pms.pms_checkin_partner_kanban_view").id
|
||||
return {
|
||||
"name": _("Register Checkins"),
|
||||
"views": [[kanban_id, "tree"]],
|
||||
"res_model": "pms.checkin.partner",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
"create": False,
|
||||
"edit": True,
|
||||
"popup": True,
|
||||
},
|
||||
"domain": [("reservation_id", "=", self.reservation_id.id)],
|
||||
"target": "new",
|
||||
}
|
||||
|
||||
def action_done(self):
|
||||
for record in self:
|
||||
|
||||
@@ -245,7 +245,9 @@ class PmsFolio(models.Model):
|
||||
)
|
||||
# Checkin Fields-----------------------------------------------------
|
||||
reservation_pending_arrival_ids = fields.One2many(
|
||||
string="Pending Arrival Rooms", compute="_compute_reservations_pending_arrival"
|
||||
comodel_name="pms.checkin.partner",
|
||||
string="Pending Arrival Rooms",
|
||||
compute="_compute_reservations_pending_arrival",
|
||||
)
|
||||
reservations_pending_count = fields.Integer(
|
||||
compute="_compute_reservations_pending_arrival"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, time, timedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
@@ -274,6 +274,8 @@ class PmsReservation(models.Model):
|
||||
("onboard", "On Board"),
|
||||
("done", "Out"),
|
||||
("cancelled", "Cancelled"),
|
||||
("no_show", "No Show"),
|
||||
("no_checkout", "No Checkout"),
|
||||
],
|
||||
string="Status",
|
||||
default=lambda *a: "draft",
|
||||
@@ -653,12 +655,9 @@ class PmsReservation(models.Model):
|
||||
if value not in (False, True):
|
||||
raise UserError(_("Invalid domain right operand %s", value))
|
||||
|
||||
searching_for_true = (operator == "=" and value) or (
|
||||
operator == "!=" and not value
|
||||
)
|
||||
today = fields.Date.context_today(self)
|
||||
|
||||
return [("checkin", searching_for_true, today)]
|
||||
return [("checkin", operator, today)]
|
||||
|
||||
def _compute_departure_today(self):
|
||||
for record in self:
|
||||
@@ -1224,13 +1223,60 @@ class PmsReservation(models.Model):
|
||||
|
||||
def action_checks(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref("pms.open_pms_reservation_form_tree_all").read()[0]
|
||||
action["views"] = [
|
||||
(self.env.ref("pms.pms_reservation_checkin_view_form").id, "form")
|
||||
]
|
||||
action["res_id"] = self.id
|
||||
action["target"] = "new"
|
||||
return action
|
||||
tree_id = self.env.ref("pms.pms_checkin_partner_reservation_view_tree").id
|
||||
return {
|
||||
"name": _("Register Partners"),
|
||||
"views": [[tree_id, "tree"]],
|
||||
"res_model": "pms.checkin.partner",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
"create": False,
|
||||
"edit": True,
|
||||
"popup": True,
|
||||
},
|
||||
"domain": [("reservation_id", "=", self.id), ("state", "=", "draft")],
|
||||
"target": "new",
|
||||
}
|
||||
|
||||
def action_onboard(self):
|
||||
self.ensure_one()
|
||||
kanban_id = self.env.ref("pms.pms_checkin_partner_kanban_view").id
|
||||
return {
|
||||
"name": _("Register Checkins"),
|
||||
"views": [[kanban_id, "kanban"]],
|
||||
"res_model": "pms.checkin.partner",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
"create": False,
|
||||
"edit": True,
|
||||
"popup": True,
|
||||
},
|
||||
"domain": [("reservation_id", "=", self.id), ("state", "=", "precheckin")],
|
||||
"target": "new",
|
||||
}
|
||||
|
||||
@api.model
|
||||
def auto_no_show(self):
|
||||
no_show_reservations = self.env["pms.reservation"].search(
|
||||
[
|
||||
("state", "in", ("draft", "confirm")),
|
||||
("checkin", "<", fields.Date.today()),
|
||||
]
|
||||
)
|
||||
no_show_reservations.state = "no_show"
|
||||
|
||||
@api.model
|
||||
def auto_no_checkout(self):
|
||||
reservations = self.env["pms.reservation"].search(
|
||||
[("state", "in", ("onboard",))]
|
||||
)
|
||||
for reservation in reservations:
|
||||
checkout_hour = int(reservation.departure_hour[0:2])
|
||||
checkout_minut = int(reservation.departure_hour[3:5])
|
||||
checkout_time = time(checkout_hour, checkout_minut, 00)
|
||||
checkout_datetime = datetime.combine(reservation.checkout, checkout_time)
|
||||
if checkout_datetime <= fields.Datetime.now():
|
||||
reservation.state = "no_checkout"
|
||||
|
||||
def unify(self):
|
||||
# TODO
|
||||
|
||||
@@ -338,3 +338,48 @@ class TestPmsCheckinPartner(TestHotel):
|
||||
int(2 * 100 / 3),
|
||||
"Fail the checkins data ratio on reservation",
|
||||
)
|
||||
|
||||
def test_auto_no_show(self):
|
||||
|
||||
# ARRANGE
|
||||
self.arrange_folio_reservations()
|
||||
PmsReservation = self.env["pms.reservation"]
|
||||
|
||||
# ACTION
|
||||
freezer = freeze_time("2012-01-15 10:00:00")
|
||||
freezer.start()
|
||||
PmsReservation.auto_no_show()
|
||||
|
||||
no_show_reservations = PmsReservation.search([("state", "=", "no_show")])
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
len(no_show_reservations),
|
||||
3,
|
||||
"Reservations not set like No Show",
|
||||
)
|
||||
freezer.stop()
|
||||
|
||||
def test_auto_no_checkout(self):
|
||||
|
||||
# ARRANGE
|
||||
self.arrange_single_checkin()
|
||||
PmsReservation = self.env["pms.reservation"]
|
||||
self.checkin1.action_on_board()
|
||||
|
||||
# ACTION
|
||||
freezer = freeze_time("2012-01-17 12:00:00")
|
||||
freezer.start()
|
||||
PmsReservation.auto_no_checkout()
|
||||
|
||||
no_checkout_reservations = PmsReservation.search(
|
||||
[("state", "=", "no_checkout")]
|
||||
)
|
||||
freezer.stop()
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
len(no_checkout_reservations),
|
||||
1,
|
||||
"Reservations not set like No checkout",
|
||||
)
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree
|
||||
editable="bottom"
|
||||
create="1"
|
||||
decoration-danger="state == 'draft'"
|
||||
decoration-info="state == 'done'"
|
||||
decoration-muted="state == 'cancelled'"
|
||||
@@ -61,7 +60,7 @@
|
||||
icon="fa-2x fa-check-circle"
|
||||
name="action_on_board"
|
||||
help="Get in"
|
||||
attrs="{'invisible': [('state','!=','preconfirm')]}"
|
||||
attrs="{'invisible': [('state','!=','precheckin')]}"
|
||||
/>
|
||||
<field name="identifier" />
|
||||
<field name="partner_id" required="True" />
|
||||
@@ -71,7 +70,7 @@
|
||||
<field name="departure" />
|
||||
<field name="reservation_id" invisible="1" />
|
||||
<field name="folio_id" force_save="1" invisible="1" />
|
||||
<field name="state" invisible="1" />
|
||||
<field name="state" invisible="0" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -114,7 +113,12 @@
|
||||
<field name="name">pms.checkin.partner.kanban</field>
|
||||
<field name="model">pms.checkin.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state" class="o_res_partner_kanban" sample="1">
|
||||
<kanban
|
||||
default_group_by="state"
|
||||
class="o_res_partner_kanban"
|
||||
sample="1"
|
||||
create="false"
|
||||
>
|
||||
<field name="id" />
|
||||
<field name="identifier" />
|
||||
<field name="partner_id" />
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<button
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
name="action_checks"
|
||||
name="action_onboard"
|
||||
attrs="{'invisible': [
|
||||
('state', '!=', ('onboard')),
|
||||
('arrival_today', '=', False),
|
||||
@@ -556,108 +556,6 @@
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Form view Checkin Partners from reservation -->
|
||||
<record model="ir.ui.view" id="pms_reservation_checkin_view_form">
|
||||
<field name="name">pms.reservation.checkin.form</field>
|
||||
<field name="model">pms.reservation</field>
|
||||
<field name="priority">100</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Reservation">
|
||||
<field name="reservation_type" invisible="1" />
|
||||
<field name="splitted" invisible="1" />
|
||||
<field name="state" invisible="1" />
|
||||
<field name="overbooking" invisible="1" />
|
||||
<field name="folio_id" invisible="1" />
|
||||
<field name="adults" invisible="1" />
|
||||
<field name="children" invisible="1" />
|
||||
<div
|
||||
class="alert alert-info"
|
||||
role="alert"
|
||||
style="margin-bottom:0px;"
|
||||
attrs="{'invisible': ['|',('shared_folio','=',False),('splitted', '=', True)]}"
|
||||
>
|
||||
This reservation has other reservantions and/or services in the
|
||||
folio, you can check it in the
|
||||
<bold>
|
||||
<button
|
||||
class="alert-link"
|
||||
type="object"
|
||||
name="open_folio"
|
||||
string="Folio Form"
|
||||
/>
|
||||
</bold>
|
||||
</div>
|
||||
<field name="shared_folio" invisible="1" />
|
||||
<field name="allowed_room_ids" invisible="1" />
|
||||
<sheet>
|
||||
<span
|
||||
class="label label-danger"
|
||||
attrs="{'invisible': [('state', 'not in', ('cancelled'))]}"
|
||||
>
|
||||
Cancelled Reservation!
|
||||
</span>
|
||||
<span
|
||||
class="label label-warning"
|
||||
attrs="{'invisible': [('overbooking', '=', False)]}"
|
||||
>
|
||||
OverBooking!
|
||||
</span>
|
||||
<h2>
|
||||
<field
|
||||
name="preferred_room_id"
|
||||
readonly="1"
|
||||
nolabel="1"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
style="margin-right: 30px;"
|
||||
/>
|
||||
<!-- <field
|
||||
name="partner_id"
|
||||
readonly="1"
|
||||
options="{'no_open': True}"
|
||||
/>
|
||||
<span
|
||||
class="fa-user"
|
||||
style="margin-left:20px;"
|
||||
attrs="{'invisible': [('reservation_type','not in',('normal'))]}"
|
||||
/>
|
||||
<span
|
||||
class="fa-black-tie"
|
||||
style="margin-left:20px; color: #C67;"
|
||||
attrs="{'invisible': [('reservation_type','not in',('staff'))]}"
|
||||
/> -->
|
||||
<h3>
|
||||
From
|
||||
<span class="fa-sign-in" style="margin: 5px;" />
|
||||
<field
|
||||
name="checkin"
|
||||
style="margin-right: 10px;"
|
||||
readonly="1"
|
||||
/>
|
||||
to
|
||||
<span class="fa-sign-out" style="margin-right: 5px;" />
|
||||
<field name="checkout" readonly="1" />
|
||||
</h3>
|
||||
</h2>
|
||||
<group>
|
||||
<field
|
||||
name="segmentation_ids"
|
||||
widget="many2many_tags"
|
||||
placeholder="Segmentation..."
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
</group>
|
||||
<field
|
||||
name="checkin_partner_ids"
|
||||
context="{
|
||||
'default_reservation_id': id,
|
||||
'reservation_id': id,
|
||||
'tree_view_ref':'pms.pms_checkin_partner_reservation_view_tree',
|
||||
}"
|
||||
/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="pms_reservation_view_tree">
|
||||
<field name="name">pms.reservation.tree</field>
|
||||
<field name="model">pms.reservation</field>
|
||||
@@ -799,7 +697,7 @@
|
||||
<filter
|
||||
string="To enter"
|
||||
name="to_enter"
|
||||
domain="[('state', '=', 'confirm')]"
|
||||
domain="[('arrival_today', '=', True),('state', 'in', ('draft','confirm'))]"
|
||||
/>
|
||||
<filter
|
||||
string="Overbookings"
|
||||
|
||||
Reference in New Issue
Block a user