mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[IMP]pms: Add wizard duplicate folio and improvemente in folio changes
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
"wizards/pms_booking_engine_views.xml",
|
||||
"wizards/wizard_folio_changes.xml",
|
||||
"wizards/wizard_several_partners.xml",
|
||||
"wizards/pms_booking_duplicate_views.xml",
|
||||
"views/pms_amenity_views.xml",
|
||||
"views/pms_amenity_type_views.xml",
|
||||
"views/pms_board_service_views.xml",
|
||||
|
||||
@@ -64,3 +64,5 @@ user_access_pms_automated_mails,user_access_pms_automated_mails,model_pms_automa
|
||||
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
|
||||
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
|
||||
|
||||
|
@@ -176,6 +176,15 @@
|
||||
>
|
||||
<span class="o_stat_text">New Booking Group</span>
|
||||
</button>
|
||||
<button
|
||||
type="action"
|
||||
class="oe_stat_button"
|
||||
name="%(action_booking_duplicate)d"
|
||||
icon="fa-clone"
|
||||
context="{'default_reference_folio_id': id}"
|
||||
>
|
||||
<span class="o_stat_text">Duplicate Booking</span>
|
||||
</button>
|
||||
<button
|
||||
name="preview_folio"
|
||||
type="object"
|
||||
@@ -213,16 +222,48 @@
|
||||
bg_color="bg-dark"
|
||||
attrs="{'invisible': [('reservation_type', 'not in', 'out')]}"
|
||||
/>
|
||||
<h2>
|
||||
<field name="name" />
|
||||
</h2>
|
||||
<group col="8">
|
||||
<group>
|
||||
<group>
|
||||
<h2>
|
||||
<field name="name" />
|
||||
</h2>
|
||||
</group>
|
||||
<group
|
||||
colspan="2"
|
||||
col="3"
|
||||
string="General Info"
|
||||
name="contact_details"
|
||||
class="oe_subtotal_footer oe_right oe_inline"
|
||||
name="folio_total"
|
||||
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
|
||||
>
|
||||
<field
|
||||
name="amount_untaxed"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<field
|
||||
name="amount_tax"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<div
|
||||
class="oe_subtotal_footer_separator oe_inline o_td_label"
|
||||
>
|
||||
<label for="amount_total" />
|
||||
</div>
|
||||
<field
|
||||
name="amount_total"
|
||||
nolabel="1"
|
||||
class="oe_subtotal_footer_separator"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<field
|
||||
name="commission"
|
||||
widget='monetary'
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="General Info" name="contact_details">
|
||||
<field
|
||||
name="document_type"
|
||||
attrs="{'invisible':[('reservation_type','in',('out'))]}"
|
||||
@@ -269,13 +310,8 @@
|
||||
/>
|
||||
<field name="internal_comment" />
|
||||
</group>
|
||||
<group
|
||||
colspan="2"
|
||||
col="3"
|
||||
string="Sale Details"
|
||||
name="sale_details"
|
||||
>
|
||||
<field name="pms_property_id" invisible="0" />
|
||||
<group string="Sale Details" name="sale_details">
|
||||
<field name="pms_property_id" />
|
||||
<field
|
||||
name="pricelist_id"
|
||||
attrs="{'invisible': [('reservation_type', 'not in', 'normal')]}"
|
||||
@@ -298,40 +334,6 @@
|
||||
attrs="{'readonly':[('agency_id','!=', False)], 'invisible':[('reservation_type', 'not in', 'normal')]}"
|
||||
/>
|
||||
</group>
|
||||
<group
|
||||
class="oe_subtotal_footer oe_right"
|
||||
colspan="2"
|
||||
name="folio_total"
|
||||
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
|
||||
>
|
||||
<field
|
||||
name="amount_untaxed"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<field
|
||||
name="amount_tax"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<div
|
||||
class="oe_subtotal_footer_separator oe_inline o_td_label"
|
||||
>
|
||||
<label for="amount_total" />
|
||||
</div>
|
||||
<field
|
||||
name="amount_total"
|
||||
nolabel="1"
|
||||
class="oe_subtotal_footer_separator"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
<field
|
||||
name="commission"
|
||||
widget='monetary'
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
/>
|
||||
</group>
|
||||
<div class="oe_clear" />
|
||||
|
||||
</group>
|
||||
|
||||
@@ -6,3 +6,4 @@ from . import folio_make_invoice_advance
|
||||
from . import wizard_payment_folio
|
||||
from . import wizard_folio_changes
|
||||
from . import wizard_several_partners
|
||||
from . import pms_booking_duplicate
|
||||
|
||||
535
pms/wizards/pms_booking_duplicate.py
Normal file
535
pms/wizards/pms_booking_duplicate.py
Normal file
@@ -0,0 +1,535 @@
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class BookingDuplicate(models.TransientModel):
|
||||
_name = "pms.booking.duplicate"
|
||||
_description = "Duplicate Booking"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
reference_folio_id = fields.Many2one(
|
||||
string="Folio Reference",
|
||||
help="Folio to copy data",
|
||||
comodel_name="pms.folio",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
start_date = fields.Date(
|
||||
string="From:",
|
||||
help="Date from first copy Checkin (reference min checkin folio reservation)",
|
||||
required=True,
|
||||
)
|
||||
|
||||
pricelist_id = fields.Many2one(
|
||||
string="Pricelist",
|
||||
help="Pricelist applied in folio",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="product.pricelist",
|
||||
compute="_compute_pricelist_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
related="reference_folio_id.pms_property_id",
|
||||
string="Property",
|
||||
help="Property to which the folio belongs",
|
||||
comodel_name="pms.property",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
segmentation_ids = fields.Many2many(
|
||||
string="Segmentation",
|
||||
help="Partner Tags",
|
||||
ondelete="restrict",
|
||||
comodel_name="res.partner.category",
|
||||
compute="_compute_segmentation_ids",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
partner_name = fields.Char(
|
||||
string="Partner name",
|
||||
help="In whose name is the reservation",
|
||||
compute="_compute_partner_name",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
string="Partner",
|
||||
help="Partner who made the reservation",
|
||||
comodel_name="res.partner",
|
||||
compute="_compute_partner_id",
|
||||
readonly=False,
|
||||
store=True,
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
reservation_type = fields.Selection(
|
||||
string="Type",
|
||||
help="The type of the reservation. "
|
||||
"Can be 'Normal', 'Staff' or 'Out of Service'",
|
||||
selection=[("normal", "Normal"), ("staff", "Staff"), ("out", "Out of Service")],
|
||||
compute="_compute_reservation_type",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
agency_id = fields.Many2one(
|
||||
string="Agency",
|
||||
help="Agency that made the reservation",
|
||||
comodel_name="res.partner",
|
||||
domain=[("is_agency", "=", True)],
|
||||
ondelete="restrict",
|
||||
)
|
||||
channel_type_id = fields.Many2one(
|
||||
string="Direct Sale Channel",
|
||||
help="Sales Channel through which the reservation was managed",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="pms.sale.channel",
|
||||
domain=[("channel_type", "=", "direct")],
|
||||
ondelete="restrict",
|
||||
compute="_compute_channel_type_id",
|
||||
)
|
||||
total_price_folio = fields.Float(
|
||||
string="Total Price",
|
||||
help="Total price of folio with taxes",
|
||||
compute="_compute_total_price_folio",
|
||||
)
|
||||
discount = fields.Float(
|
||||
string="Discount",
|
||||
help="Discount that be applied in total price",
|
||||
default=0,
|
||||
)
|
||||
internal_comment = fields.Text(
|
||||
string="Internal Folio Notes",
|
||||
help="Internal Folio notes for Staff",
|
||||
)
|
||||
created_folio_ids = fields.Many2many(
|
||||
string="Folios",
|
||||
help="Folios already created",
|
||||
comodel_name="pms.folio",
|
||||
)
|
||||
rooms = fields.One2many(
|
||||
string="Rooms",
|
||||
help="Rooms to create",
|
||||
readonly=False,
|
||||
store=True,
|
||||
comodel_name="pms.reservation.duplicate",
|
||||
inverse_name="booking_duplicate_id",
|
||||
compute="_compute_rooms",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
recompute_prices = fields.Boolean(
|
||||
string="Recompute Price",
|
||||
help="""Leave unchecked if you want to respect
|
||||
the price of the original reservation regardless
|
||||
of what is marked in the rate""",
|
||||
default=False,
|
||||
)
|
||||
|
||||
@api.depends("reference_folio_id")
|
||||
def _compute_pricelist_id(self):
|
||||
for record in self.filtered("reference_folio_id"):
|
||||
if not record.pricelist_id:
|
||||
record.pricelist_id = record.reference_folio_id.pricelist_id.id
|
||||
|
||||
@api.depends("reference_folio_id", "agency_id")
|
||||
def _compute_channel_type_id(self):
|
||||
for record in self.filtered("reference_folio_id"):
|
||||
if record.reference_folio_id.agency_id == record.agency_id:
|
||||
record.channel_type_id = record.reference_folio_id.channel_type_id
|
||||
elif record.agency_id:
|
||||
record.channel_type_id = record.agency_id.sale_channel_id.id
|
||||
|
||||
@api.depends("reference_folio_id")
|
||||
def _compute_segmentation_ids(self):
|
||||
for record in self:
|
||||
record.segmentation_ids = record.reference_folio_id.segmentation_ids
|
||||
|
||||
@api.depends("agency_id", "reference_folio_id")
|
||||
def _compute_partner_id(self):
|
||||
for record in self:
|
||||
if record.reference_folio_id.agency_id == record.agency_id:
|
||||
record.partner_id = record.reference_folio_id.partner_id
|
||||
elif record.agency_id and record.agency_id.invoice_to_agency:
|
||||
record.partner_id = record.agency_id.id
|
||||
elif not record.partner_id:
|
||||
record.partner_id = False
|
||||
|
||||
@api.depends("reference_folio_id")
|
||||
def _compute_reservation_type(self):
|
||||
self.reservation_type = "normal"
|
||||
for record in self:
|
||||
record.reservation_type = record.reference_folio_id.reservation_type
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_partner_name(self):
|
||||
for record in self:
|
||||
if record.reference_folio_id.partner_id == record.partner_id:
|
||||
record.partner_name = record.reference_folio_id.partner_name
|
||||
elif record.partner_id:
|
||||
record.partner_name = record.partner_id.name
|
||||
if (
|
||||
record.agency_id
|
||||
and not record.agency_id.invoice_to_agency
|
||||
and not record.partner_name
|
||||
):
|
||||
record.partner_name = _("Reservation from ") + record.agency_id.name
|
||||
elif not record.partner_name:
|
||||
record.partner_name = False
|
||||
|
||||
@api.depends("rooms.price_total")
|
||||
def _compute_total_price_folio(self):
|
||||
for record in self:
|
||||
record.total_price_folio = 0
|
||||
for line in record.rooms:
|
||||
record.total_price_folio += line.price_total
|
||||
record.total_price_folio = record.total_price_folio
|
||||
|
||||
@api.depends(
|
||||
"reference_folio_id",
|
||||
)
|
||||
def _compute_rooms(self):
|
||||
self.ensure_one()
|
||||
reference_folio = self.reference_folio_id
|
||||
|
||||
if not reference_folio:
|
||||
self.rooms = False
|
||||
return
|
||||
|
||||
cmds = [(5, 0)]
|
||||
|
||||
for reservation in reference_folio.reservation_ids.filtered(
|
||||
lambda r: r.state != "cancel"
|
||||
):
|
||||
cmds.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"reference_reservation_id": reservation.id,
|
||||
"booking_duplicate_id": self.id,
|
||||
"checkin": False,
|
||||
"checkout": False,
|
||||
"preferred_room_id": reservation.preferred_room_id,
|
||||
"room_type_id": reservation.room_type_id,
|
||||
# "arrival_hour": reservation.arrival_hour,
|
||||
# "departure_hour": reservation.departure_hour,
|
||||
# "partner_internal_comment": reservation.partner_internal_comment,
|
||||
"board_service_room_id": reservation.board_service_room_id.id,
|
||||
"adults": reservation.adults,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.rooms = cmds
|
||||
|
||||
def create_and_new(self):
|
||||
self.create_folio()
|
||||
return {
|
||||
"name": _("Duplicate Folios"),
|
||||
"res_model": "pms.booking.duplicate",
|
||||
"type": "ir.actions.act_window",
|
||||
"view_id": self.env.ref("pms.booking_duplicate").id,
|
||||
"target": "new",
|
||||
"view_mode": "form",
|
||||
"context": {
|
||||
"default_reference_folio_id": self.reference_folio_id.id,
|
||||
"default_created_folio_ids": [(6, 0, self.created_folio_ids.ids)],
|
||||
"default_start_date": self.start_date,
|
||||
},
|
||||
}
|
||||
|
||||
def create_and_close(self):
|
||||
self.create_folio()
|
||||
folio_ids = self.mapped("created_folio_ids.id")
|
||||
action = self.env.ref("pms.open_pms_folio1_form_tree_all").read()[0]
|
||||
if len(folio_ids) > 1:
|
||||
action["domain"] = [("id", "in", folio_ids)]
|
||||
elif len(folio_ids) == 1:
|
||||
form_view = [(self.env.ref("pms.pms_folio_view_form").id, "form")]
|
||||
if "views" in action:
|
||||
action["views"] = form_view + [
|
||||
(state, view) for state, view in action["views"] if view != "form"
|
||||
]
|
||||
else:
|
||||
action["views"] = form_view
|
||||
action["res_id"] = folio_ids[0]
|
||||
else:
|
||||
action = {"type": "ir.actions.act_window_close"}
|
||||
return action
|
||||
|
||||
def view_folios(self):
|
||||
folio_ids = self.mapped("created_folio_ids.id")
|
||||
action = self.env.ref("pms.open_pms_folio1_form_tree_all").read()[0]
|
||||
if len(folio_ids) > 1:
|
||||
action["domain"] = [("id", "in", folio_ids)]
|
||||
elif len(folio_ids) == 1:
|
||||
form_view = [(self.env.ref("pms.pms_folio_view_form").id, "form")]
|
||||
if "views" in action:
|
||||
action["views"] = form_view + [
|
||||
(state, view) for state, view in action["views"] if view != "form"
|
||||
]
|
||||
else:
|
||||
action["views"] = form_view
|
||||
action["res_id"] = folio_ids[0]
|
||||
else:
|
||||
action = {"type": "ir.actions.act_window_close"}
|
||||
return action
|
||||
|
||||
def create_folio(self):
|
||||
folio = self.env["pms.folio"].create(
|
||||
{
|
||||
"reservation_type": self.reservation_type,
|
||||
"pricelist_id": self.pricelist_id.id,
|
||||
"partner_id": self.partner_id.id if self.partner_id else False,
|
||||
"partner_name": self.partner_name,
|
||||
"pms_property_id": self.pms_property_id.id,
|
||||
"agency_id": self.agency_id.id,
|
||||
"channel_type_id": self.channel_type_id.id,
|
||||
"segmentation_ids": [(6, 0, self.segmentation_ids.ids)],
|
||||
"internal_comment": self.internal_comment,
|
||||
}
|
||||
)
|
||||
for res in self.rooms:
|
||||
res_vals = {
|
||||
"folio_id": folio.id,
|
||||
"checkin": res.checkin,
|
||||
"checkout": res.checkout,
|
||||
"room_type_id": res.room_type_id.id,
|
||||
"partner_id": self.partner_id.id if self.partner_id else False,
|
||||
"partner_name": self.partner_name,
|
||||
"pricelist_id": self.pricelist_id.id,
|
||||
"pms_property_id": folio.pms_property_id.id,
|
||||
"board_service_room_id": res.board_service_room_id.id,
|
||||
"adults": res.adults,
|
||||
}
|
||||
ser_vals = [(5, 0)]
|
||||
for service in res.reference_reservation_id.service_ids.filtered(
|
||||
lambda s: not s.is_board_service
|
||||
):
|
||||
ser_line_vals = [(5, 0)]
|
||||
if service.product_id.id in res.service_ids.ids:
|
||||
for ser_line in service.service_line_ids:
|
||||
ser_line_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"day_qty": ser_line.day_qty,
|
||||
"price_unit": ser_line.price_unit,
|
||||
"discount": ser_line.discount,
|
||||
"date": ser_line.date
|
||||
+ datetime.timedelta(
|
||||
days=(
|
||||
res.reference_reservation_id.checkin
|
||||
- self.start_date
|
||||
).days
|
||||
)
|
||||
if service.per_day
|
||||
else fields.Date.today(),
|
||||
},
|
||||
)
|
||||
)
|
||||
ser_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": service.product_id.id,
|
||||
"is_board_service": service.is_board_service,
|
||||
"service_line_ids": ser_line_vals,
|
||||
},
|
||||
)
|
||||
)
|
||||
res_vals["service_ids"] = ser_vals
|
||||
|
||||
if not self.recompute_prices:
|
||||
line_vals = [(5, 0)]
|
||||
for line in res.reference_reservation_id.reservation_line_ids:
|
||||
line_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"price": line.price,
|
||||
"discount": line.discount,
|
||||
"room_id": line.room_id.id,
|
||||
"date": line.date
|
||||
+ datetime.timedelta(
|
||||
days=(
|
||||
res.reference_reservation_id.checkin
|
||||
- self.start_date
|
||||
).days
|
||||
),
|
||||
},
|
||||
)
|
||||
)
|
||||
res_vals["reservation_line_ids"] = line_vals
|
||||
new_reservation = self.env["pms.reservation"].create(res_vals)
|
||||
# REVIEW: Board service overwrite prices
|
||||
for service in new_reservation.service_ids.filtered("is_board_service"):
|
||||
origin_services_board = (
|
||||
res.reference_reservation_id.service_ids.filtered(
|
||||
"is_board_service"
|
||||
)
|
||||
)
|
||||
if origin_services_board:
|
||||
service.service_line_ids.price = (
|
||||
origin_services_board.service_line_ids[0].price
|
||||
)
|
||||
self.created_folio_ids = [(4, folio.id)]
|
||||
|
||||
|
||||
class PmsReservationDuplicate(models.TransientModel):
|
||||
_name = "pms.reservation.duplicate"
|
||||
_description = "Rooms in Duplicate Folio"
|
||||
_check_pms_properties_auto = True
|
||||
|
||||
reference_reservation_id = fields.Many2one(
|
||||
string="Reservation Reference",
|
||||
help="Reservation to copy data",
|
||||
comodel_name="pms.reservation",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
adults = fields.Integer(string="Adults")
|
||||
booking_duplicate_id = fields.Many2one(
|
||||
string="Folio Wizard ID",
|
||||
comodel_name="pms.booking.duplicate",
|
||||
)
|
||||
checkin = fields.Date(
|
||||
string="From:", help="Date Reservation starts ", compute="_compute_checkin"
|
||||
)
|
||||
checkout = fields.Date(
|
||||
string="To:",
|
||||
help="Date Reservation ends",
|
||||
compute="_compute_checkout",
|
||||
)
|
||||
room_type_id = fields.Many2one(
|
||||
string="Room Type",
|
||||
help="Room Type reserved",
|
||||
comodel_name="pms.room.type",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
preferred_room_id = fields.Many2one(
|
||||
string="Room",
|
||||
help="Room reserved",
|
||||
comodel_name="pms.room",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
allowed_room_ids = fields.Many2many(
|
||||
string="Allowed Rooms",
|
||||
help="It contains all available rooms for this reservation",
|
||||
comodel_name="pms.room",
|
||||
compute="_compute_allowed_room_ids",
|
||||
)
|
||||
available = fields.Boolean(
|
||||
string="Available room",
|
||||
store="true",
|
||||
compute="_compute_available",
|
||||
)
|
||||
price_total = fields.Float(
|
||||
string="Total price",
|
||||
help="The total price in the folio",
|
||||
compute="_compute_price_total",
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
string="Property",
|
||||
help="Propertiy with access to the element;",
|
||||
related="booking_duplicate_id.pms_property_id",
|
||||
)
|
||||
board_service_room_id = fields.Many2one(
|
||||
string="Board Service",
|
||||
help="Board Service included in the room",
|
||||
comodel_name="pms.board.service.room.type",
|
||||
domain="[('pms_room_type_id','=',room_type_id)]",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
service_ids = fields.Many2many(
|
||||
string="Services",
|
||||
comodel_name="product.product",
|
||||
relation="reservation_duplicate_product_rel",
|
||||
column1="reservation_duplicate_id",
|
||||
column2="product_id",
|
||||
compute="_compute_service_ids",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends("booking_duplicate_id.start_date")
|
||||
def _compute_checkin(self):
|
||||
self.checkin = False
|
||||
start_date = self.booking_duplicate_id.start_date
|
||||
if start_date:
|
||||
checkin_ref = min(
|
||||
self.booking_duplicate_id.mapped(
|
||||
"reference_folio_id.reservation_ids.checkin"
|
||||
)
|
||||
)
|
||||
for record in self:
|
||||
if record.reference_reservation_id.checkin == checkin_ref:
|
||||
record.checkin = start_date
|
||||
else:
|
||||
dif_days = (
|
||||
record.reference_reservation_id.checkin - checkin_ref
|
||||
).nights
|
||||
record.checkin = start_date + datetime.timedelta(days=dif_days)
|
||||
|
||||
@api.depends("checkin")
|
||||
def _compute_checkout(self):
|
||||
self.checkout = False
|
||||
for record in self.filtered("checkin"):
|
||||
res_days = record.reference_reservation_id.nights
|
||||
record.checkout = record.checkin + datetime.timedelta(days=res_days)
|
||||
|
||||
@api.depends("preferred_room_id", "checkin", "checkout")
|
||||
def _compute_available(self):
|
||||
self.available = True
|
||||
for record in self:
|
||||
lines = self.env["pms.reservation.line"].search(
|
||||
[
|
||||
("date", ">=", record.checkin),
|
||||
("date", "<", record.checkout),
|
||||
("occupies_availability", "=", True),
|
||||
]
|
||||
)
|
||||
if lines:
|
||||
record.available = False
|
||||
|
||||
@api.depends(
|
||||
"checkin",
|
||||
"checkout",
|
||||
"preferred_room_id",
|
||||
"pms_property_id",
|
||||
)
|
||||
def _compute_allowed_room_ids(self):
|
||||
self.allowed_room_ids = False
|
||||
for reservation in self.filtered(lambda r: r.checkin and r.checkout):
|
||||
pms_property = reservation.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
class_id=reservation.room_type_id.class_id.id
|
||||
if reservation.room_type_id
|
||||
else False,
|
||||
real_avail=True,
|
||||
)
|
||||
allowed_room_ids = (
|
||||
pms_property.free_room_ids.ids
|
||||
- reservation.booking_duplicate_id.room_ids.mapped(
|
||||
"preferred_room_id.id"
|
||||
)
|
||||
)
|
||||
reservation.allowed_room_ids = self.env["room.id"].browse(allowed_room_ids)
|
||||
|
||||
@api.depends("room_type_id", "board_service_room_id", "checkin", "checkout")
|
||||
def _compute_price_total(self):
|
||||
self.price_total = 0
|
||||
for record in self.filtered("checkout"):
|
||||
record.price_total = record.reference_reservation_id.price_room_services_set
|
||||
|
||||
@api.depends("reference_reservation_id")
|
||||
def _compute_service_ids(self):
|
||||
for record in self:
|
||||
record.service_ids = list(
|
||||
set(record.reference_reservation_id.service_ids.mapped("product_id.id"))
|
||||
)
|
||||
181
pms/wizards/pms_booking_duplicate_views.xml
Normal file
181
pms/wizards/pms_booking_duplicate_views.xml
Normal file
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<record id="booking_duplicate" model="ir.ui.view">
|
||||
<field name="name">Duplicate Folio</field>
|
||||
<field name="model">pms.booking.duplicate</field>
|
||||
<field name="arch" type="xml">
|
||||
<form class="pt-1">
|
||||
<h2>
|
||||
<field name="reference_folio_id" required="1" readonly="1" />
|
||||
</h2>
|
||||
<div class="row">
|
||||
<div class="col-6 ">
|
||||
<group>
|
||||
<field name="pms_property_id" invisible="0" />
|
||||
<field name="reservation_type" />
|
||||
<field
|
||||
name="agency_id"
|
||||
attrs="{'invisible': [('reservation_type','!=','normal')]}"
|
||||
/>
|
||||
<field
|
||||
name="segmentation_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'invisible': [('reservation_type','!=','normal')]}"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<group>
|
||||
<field
|
||||
name="partner_id"
|
||||
string="Partner"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
attrs="{'invisible': [('reservation_type','=','out')]}"
|
||||
/>
|
||||
<field
|
||||
name="partner_name"
|
||||
string="Partner"
|
||||
required="1"
|
||||
attrs="{'invisible': [('reservation_type','=','out')]}"
|
||||
/>
|
||||
<field
|
||||
name="partner_name"
|
||||
string="Reason"
|
||||
required="1"
|
||||
attrs="{'invisible': [('reservation_type','!=','out')]}"
|
||||
/>
|
||||
<field
|
||||
default_focus="1"
|
||||
name="pricelist_id"
|
||||
string="Pricelist"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
attrs="{'required': [('reservation_type','=','normal')], 'invisible': [('reservation_type','!=','normal')]}"
|
||||
/>
|
||||
<field
|
||||
name="channel_type_id"
|
||||
attrs="{'required': [('reservation_type','=','normal')], 'invisible': [('reservation_type','!=','normal')]}"
|
||||
/>
|
||||
</group>
|
||||
<div>
|
||||
<group>
|
||||
<field
|
||||
name="internal_comment"
|
||||
placeholder="Internal comment Folio"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<group>
|
||||
<field name="start_date" />
|
||||
<field name="recompute_prices" />
|
||||
</group>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<group>
|
||||
<field name="rooms" nolabel="1">
|
||||
<tree
|
||||
editable="bottom"
|
||||
create="false"
|
||||
delete="false"
|
||||
decoration-muted="checkin == 0"
|
||||
decoration-danger="available == 0"
|
||||
>
|
||||
<field
|
||||
name="reference_reservation_id"
|
||||
invisible="1"
|
||||
/>
|
||||
<field name="booking_duplicate_id" invisible="1" />
|
||||
<field name="available" invisible="1" />
|
||||
<field name="pms_property_id" invisible="1" />
|
||||
<field name="adults" />
|
||||
<field
|
||||
name="room_type_id"
|
||||
readonly="1"
|
||||
options="{'no_open': True}"
|
||||
force_save="1"
|
||||
/>
|
||||
<field name="preferred_room_id" />
|
||||
<field name="checkin" force_save="1" />
|
||||
<field name="checkout" force_save="1" />
|
||||
<field
|
||||
name="board_service_room_id"
|
||||
attrs="{'column_invisible': [('parent.reservation_type','!=','normal')]}"
|
||||
/>
|
||||
<field
|
||||
name="service_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'column_invisible': [('parent.reservation_type','!=','normal')]}"
|
||||
readonly="1"
|
||||
/>
|
||||
<field
|
||||
name="price_total"
|
||||
readonly="1"
|
||||
force_save="1"
|
||||
attrs="{'column_invisible': [('parent.reservation_type','!=','normal')]}"
|
||||
/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row float-right border mr-2 mb-5">
|
||||
<div class="col-3 ">
|
||||
<div class="col-3 px-0">
|
||||
<group>
|
||||
<field
|
||||
name="total_price_folio"
|
||||
widget="monetary"
|
||||
attrs="{'invisible': [('reservation_type','!=','normal')]}"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<field name="created_folio_ids" readonly="1" />
|
||||
</div>
|
||||
<footer>
|
||||
<button
|
||||
name="create_and_new"
|
||||
string="Create and Continue"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
/>
|
||||
<button
|
||||
name="create_and_close"
|
||||
string="Create and Close"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<span>
|
||||
or
|
||||
</span>
|
||||
<button
|
||||
string="Cancel"
|
||||
class="btn-default border"
|
||||
special="cancel"
|
||||
/>
|
||||
<button
|
||||
name="view_folios"
|
||||
string="View Folios"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': [('created_folio_ids','=', False)]}"
|
||||
/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_booking_duplicate" model="ir.actions.act_window">
|
||||
<field name="name">Folio creation</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pms.booking.duplicate</field>
|
||||
<field name="view_id" ref="booking_duplicate" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,4 +1,6 @@
|
||||
from odoo import _, api, fields, models
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class WizardFolioChanges(models.TransientModel):
|
||||
@@ -11,6 +13,40 @@ class WizardFolioChanges(models.TransientModel):
|
||||
default=lambda self: self._default_folio_id(),
|
||||
comodel_name="pms.folio",
|
||||
)
|
||||
modification_type = fields.Selection(
|
||||
string="Modification Type",
|
||||
selection=[
|
||||
("reservations", "Reservations"),
|
||||
("dates", "Dates"),
|
||||
("services", "Services Prices"),
|
||||
],
|
||||
default="reservations",
|
||||
)
|
||||
room_type_filter_ids = fields.Many2many(
|
||||
string="Room types",
|
||||
default=lambda self: self._default_room_type_filter_ids(),
|
||||
comodel_name="pms.room.type",
|
||||
relation="folio_changes_room_type_rel",
|
||||
column1="folio_changes_id",
|
||||
column2="room_type_ids",
|
||||
domain="[('id', 'in', allowed_room_type_ids)]",
|
||||
)
|
||||
allowed_room_type_ids = fields.Many2many(
|
||||
string="Allowed Room Types",
|
||||
comodel_name="pms.room.type",
|
||||
relation="folio_changes_allowed_room_type_rel",
|
||||
column1="folio_changes_id",
|
||||
column2="allowed_room_type_ids",
|
||||
compute="_compute_allowed_room_type_ids",
|
||||
)
|
||||
change_from_date = fields.Date(
|
||||
string="Apply From",
|
||||
default=lambda self: self.default_change_from_date(),
|
||||
)
|
||||
change_to_date = fields.Date(
|
||||
string="Apply To",
|
||||
default=lambda self: self.default_change_to_date(),
|
||||
)
|
||||
reservation_ids = fields.Many2many(
|
||||
string="Reservations",
|
||||
default=lambda self: self._default_reservation_ids(),
|
||||
@@ -26,18 +62,96 @@ class WizardFolioChanges(models.TransientModel):
|
||||
relation="folio_changes_allowed_reservation_rel",
|
||||
column1="folio_changes_id",
|
||||
column2="allowed_reservation_ids",
|
||||
compute="_compute_allowed_reservations",
|
||||
compute="_compute_allowed_reservation_ids",
|
||||
)
|
||||
service_ids = fields.Many2many(
|
||||
string="Services",
|
||||
default=lambda self: self._default_service_ids(),
|
||||
comodel_name="pms.service",
|
||||
relation="folio_changes_service_rel",
|
||||
column1="folio_changes_id",
|
||||
column2="service_ids",
|
||||
domain="[('id', 'in', allowed_service_ids)]",
|
||||
)
|
||||
allowed_service_ids = fields.Many2many(
|
||||
string="Allowed Services",
|
||||
comodel_name="pms.service",
|
||||
relation="folio_changes_allowed_service_rel",
|
||||
column1="folio_changes_id",
|
||||
column2="allowed_service_ids",
|
||||
compute="_compute_allowed_service_ids",
|
||||
)
|
||||
apply_new_checkin = fields.Boolean(
|
||||
string="Apply Checkin Update",
|
||||
default=False,
|
||||
)
|
||||
new_checkin = fields.Date(
|
||||
string="New Checkin",
|
||||
default=lambda self: self.default_change_new_checkin(),
|
||||
)
|
||||
|
||||
apply_new_checkout = fields.Boolean(
|
||||
string="Apply Checkout Update",
|
||||
default=False,
|
||||
)
|
||||
new_checkout = fields.Date(
|
||||
string="New Checkout",
|
||||
default=lambda self: self.default_change_new_checkout(),
|
||||
)
|
||||
nights = fields.Integer(
|
||||
string="Nights",
|
||||
compute="_compute_nights",
|
||||
)
|
||||
dates_incongruence = fields.Boolean(
|
||||
string="Dates incrongruence",
|
||||
help="Indicates that there are reservations with different checkin and/or checkout",
|
||||
compute="_compute_dates_incongruence",
|
||||
store=True,
|
||||
)
|
||||
apply_price = fields.Boolean(
|
||||
string="Apply Price update",
|
||||
default=False,
|
||||
)
|
||||
new_price = fields.Float(
|
||||
string="New Price",
|
||||
)
|
||||
|
||||
apply_discount = fields.Boolean(
|
||||
string="Apply Discount update",
|
||||
default=False,
|
||||
)
|
||||
new_discount = fields.Float(
|
||||
string="New Discount %",
|
||||
)
|
||||
|
||||
apply_board_service = fields.Boolean(
|
||||
string="Add Board Service to reservations",
|
||||
default=False,
|
||||
)
|
||||
new_board_service_id = fields.Many2one(
|
||||
string="New Board Service",
|
||||
comodel_name="pms.board.service",
|
||||
)
|
||||
|
||||
apply_service = fields.Boolean(
|
||||
string="Add Service to reservations",
|
||||
default=False,
|
||||
)
|
||||
new_service_id = fields.Many2one(
|
||||
string="New Service",
|
||||
comodel_name="product.product",
|
||||
domain="[('sale_ok','=',True)]",
|
||||
)
|
||||
|
||||
apply_day_qty = fields.Boolean(
|
||||
string="Add Service to reservations",
|
||||
help="If not set, it will use the default product day qty",
|
||||
default=False,
|
||||
)
|
||||
day_qty = fields.Integer(
|
||||
string="Quantity per day",
|
||||
)
|
||||
|
||||
apply_on_monday = fields.Boolean(
|
||||
string="Apply Availability Rule on mondays",
|
||||
default=False,
|
||||
@@ -81,13 +195,86 @@ class WizardFolioChanges(models.TransientModel):
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return folio.reservation_ids
|
||||
|
||||
def _default_room_type_filter_ids(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return self.env["pms.room.type"].browse(
|
||||
folio.mapped("reservation_ids.room_type_id.id")
|
||||
)
|
||||
|
||||
def default_change_new_checkin(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return min(folio.reservation_ids.mapped("checkin"), default=False)
|
||||
|
||||
def default_change_new_checkout(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return max(folio.reservation_ids.mapped("checkout"), default=False)
|
||||
|
||||
def _default_service_ids(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return folio.service_ids
|
||||
|
||||
def default_change_from_date(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return min(folio.reservation_ids.mapped("checkin"), default=False)
|
||||
|
||||
def default_change_to_date(self):
|
||||
folio_id = self._context.get("active_id")
|
||||
folio = self.env["pms.folio"].browse(folio_id)
|
||||
return max(folio.reservation_ids.mapped("checkout"), default=False)
|
||||
|
||||
@api.depends("new_checkin", "new_checkout")
|
||||
def _compute_nights(self):
|
||||
for record in self:
|
||||
record.nights = (record.new_checkout - record.new_checkin).days
|
||||
|
||||
@api.depends("reservation_ids")
|
||||
def _compute_dates_incongruence(self):
|
||||
self.dates_incongruence = False
|
||||
for record in self:
|
||||
if (
|
||||
len(set(record.reservation_ids.mapped("checkin"))) > 1
|
||||
or len(set(record.reservation_ids.mapped("checkout"))) > 1
|
||||
):
|
||||
record.dates_incongruence = True
|
||||
|
||||
@api.depends("folio_id")
|
||||
def _compute_allowed_reservations(self):
|
||||
def _compute_allowed_reservation_ids(self):
|
||||
self.ensure_one()
|
||||
self.allowed_reservation_ids = self.folio_id.reservation_ids
|
||||
|
||||
@api.depends("folio_id")
|
||||
def _compute_allowed_service_ids(self):
|
||||
self.ensure_one()
|
||||
self.allowed_service_ids = self.folio_id.service_ids
|
||||
|
||||
@api.depends("folio_id")
|
||||
def _compute_allowed_room_type_ids(self):
|
||||
self.ensure_one()
|
||||
self.allowed_room_type_ids = self.env["pms.room.type"].browse(
|
||||
self.folio_id.mapped("reservation_ids.room_type_id.id")
|
||||
)
|
||||
|
||||
@api.onchange("room_type_filter_ids")
|
||||
def _onchange_room_type_filter_ids(self):
|
||||
self.service_ids = self.folio_id.service_ids.filtered(
|
||||
lambda s: s.reservation_id
|
||||
and s.reservation_id.room_type_id.id in self.room_type_filter_ids.ids
|
||||
)
|
||||
self.reservation_ids = self.folio_id.reservation_ids.filtered(
|
||||
lambda r: r.room_type_id.id in self.room_type_filter_ids.ids
|
||||
)
|
||||
|
||||
@api.onchange("reservation_ids")
|
||||
def _onchange_reservations_ids(self):
|
||||
self.new_checkin = min(self.reservation_ids.mapped("checkin"), default=False)
|
||||
self.new_checkout = max(self.reservation_ids.mapped("checkout"), default=False)
|
||||
|
||||
def button_change(self):
|
||||
vals = {}
|
||||
week_days_to_apply = (
|
||||
self.apply_on_monday,
|
||||
self.apply_on_tuesday,
|
||||
@@ -97,52 +284,117 @@ class WizardFolioChanges(models.TransientModel):
|
||||
self.apply_on_saturday,
|
||||
self.apply_on_sunday,
|
||||
)
|
||||
reservation_lines = self.reservation_ids.reservation_line_ids
|
||||
if not self.apply_on_all_week:
|
||||
reservation_lines = reservation_lines.filtered(
|
||||
lambda x: week_days_to_apply[x.date.timetuple()[6]]
|
||||
if self.modification_type == "dates":
|
||||
self._update_dates(
|
||||
reservations=self.reservation_ids,
|
||||
new_checkin=self.new_checkin,
|
||||
new_checkout=self.new_checkout,
|
||||
)
|
||||
if self.new_price or self.new_discount:
|
||||
if self.new_price:
|
||||
vals["price"] = self.new_price
|
||||
if self.new_discount:
|
||||
vals["discount"] = self.new_discount
|
||||
|
||||
reservation_lines.write(vals)
|
||||
|
||||
self.folio_id.message_post(
|
||||
body=_(
|
||||
"Prices/Discounts have been changed from folio",
|
||||
)
|
||||
)
|
||||
reservations = self.env["pms.reservation"].browse(
|
||||
reservation_lines.mapped("reservation_id.id")
|
||||
)
|
||||
for reservation in reservations:
|
||||
reservation.message_post(
|
||||
body=_(
|
||||
"Prices/Discounts have been changed from folio",
|
||||
else:
|
||||
dates = [
|
||||
self.change_from_date + timedelta(days=d)
|
||||
for d in range((self.change_to_date - self.change_from_date).days + 1)
|
||||
]
|
||||
if self.modification_type == "reservations":
|
||||
reservation_lines = self.reservation_ids.reservation_line_ids
|
||||
if not self.apply_on_all_week:
|
||||
reservation_lines = reservation_lines.filtered(
|
||||
lambda x: week_days_to_apply[x.date.timetuple()[6]]
|
||||
and x.date in dates
|
||||
)
|
||||
if self.apply_discount or self.apply_price:
|
||||
self._update_reservations(
|
||||
reservation_lines=reservation_lines,
|
||||
new_price=self.apply_price and self.new_price,
|
||||
new_discount=self.apply_discount and self.new_discount,
|
||||
)
|
||||
if self.apply_board_service and self.new_board_service_id:
|
||||
self._add_board_service(
|
||||
reservations=self.reservation_ids,
|
||||
new_board_service_id=self.new_board_service_id.id,
|
||||
)
|
||||
if self.apply_service and self.new_service_id:
|
||||
self._add_service(
|
||||
reservations=self.reservation_ids,
|
||||
new_service_id=self.new_service_id.id,
|
||||
day_qty=self.day_qty if self.apply_day_qty else -1,
|
||||
)
|
||||
elif self.modification_type == "services":
|
||||
service_lines = self.service_ids.service_line_ids
|
||||
if not self.apply_on_all_week:
|
||||
reservation_lines = service_lines.filtered(
|
||||
lambda x: week_days_to_apply[x.date.timetuple()[6]]
|
||||
and x.date in dates
|
||||
)
|
||||
self._update_services(
|
||||
service_lines=service_lines,
|
||||
new_price=self.apply_price and self.new_price,
|
||||
new_discount=self.apply_discount and self.new_discount,
|
||||
)
|
||||
if self.new_board_service_id:
|
||||
for reservation in self.reservation_ids:
|
||||
if (
|
||||
self.new_board_service_id.id
|
||||
in reservation.room_type_id.board_service_room_type_ids.ids
|
||||
):
|
||||
reservation.board_service_room_id = (
|
||||
reservation.room_type_id.board_service_room_type_ids.filtered(
|
||||
lambda x: x.pms_board_service_id.id
|
||||
== self.new_board_service_id.id
|
||||
and (
|
||||
self.folio_id.pms_property_id.id
|
||||
in x.pms_property_ids.ids
|
||||
or not x.pms_property_ids
|
||||
)
|
||||
|
||||
def _update_dates(self, reservations, new_checkin, new_checkout):
|
||||
for res in reservations:
|
||||
if new_checkin:
|
||||
res.checkin = new_checkin
|
||||
if new_checkout:
|
||||
res.checkout = new_checkout
|
||||
|
||||
def _update_reservations(
|
||||
self, reservation_lines, new_price=False, new_discount=False
|
||||
):
|
||||
line_vals = {}
|
||||
if new_price:
|
||||
line_vals["price"] = new_price
|
||||
if new_discount:
|
||||
line_vals["discount"] = new_discount
|
||||
if line_vals:
|
||||
reservation_lines.write(line_vals)
|
||||
|
||||
def _add_board_service(self, reservations, new_board_service_id):
|
||||
for reservation in reservations:
|
||||
if new_board_service_id in reservation.room_type_id.mapped(
|
||||
"board_service_room_type_ids.pms_board_service_id.id"
|
||||
):
|
||||
reservation.board_service_room_id = (
|
||||
reservation.room_type_id.board_service_room_type_ids.filtered(
|
||||
lambda x: x.pms_board_service_id.id == new_board_service_id
|
||||
and (
|
||||
reservation.folio_id.pms_property_id.id
|
||||
in x.pms_property_ids.ids
|
||||
or not x.pms_property_ids
|
||||
)
|
||||
)
|
||||
reservation.message_post(
|
||||
body=_(
|
||||
"Board service has been changed from folio",
|
||||
)
|
||||
)
|
||||
|
||||
def _add_service(self, reservations, new_service_id, day_qty):
|
||||
old_services = reservations.service_ids
|
||||
reservations.write(
|
||||
{
|
||||
"service_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": new_service_id,
|
||||
},
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
new_services = reservations.service_ids - old_services
|
||||
# Use -1 to set default qty qty per day
|
||||
if day_qty > -1:
|
||||
new_services.day_qty = day_qty
|
||||
|
||||
def _update_services(
|
||||
self, service_lines, new_price=False, new_discount=False, new_day_qty=False
|
||||
):
|
||||
line_vals = {}
|
||||
if new_price:
|
||||
line_vals["price_unit"] = new_price
|
||||
if new_discount:
|
||||
line_vals["discount"] = new_discount
|
||||
if new_day_qty:
|
||||
line_vals["day_qty"] = new_day_qty
|
||||
if line_vals:
|
||||
service_lines.write(line_vals)
|
||||
|
||||
@@ -4,105 +4,305 @@
|
||||
<field name="name">wizard.folio.changes.view.form</field>
|
||||
<field name="model">wizard.folio.changes</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Folio Changes">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<table class="table table-bordered text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>All days</th>
|
||||
<th>Sunday</th>
|
||||
<th>Monday</th>
|
||||
<th>Tuesday</th>
|
||||
<th>Wednesday</th>
|
||||
<th>Thursday</th>
|
||||
<th>Friday</th>
|
||||
<th>Saturday</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_all_week"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_sunday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_monday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_tuesday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_wednesday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_thursday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_friday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_saturday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<form string="Folio Changes" class="pt-1">
|
||||
<group>
|
||||
<field name="modification_type" />
|
||||
</group>
|
||||
<group attrs="{'invisible':[('modification_type', '=', 'dates')]}">
|
||||
<field name="change_from_date" />
|
||||
<field name="change_to_date" />
|
||||
</group>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div
|
||||
class="col-12"
|
||||
attrs="{'invisible':[('modification_type', '=', 'dates')]}"
|
||||
>
|
||||
<table class="table table-bordered text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>All days</th>
|
||||
<th>Sunday</th>
|
||||
<th>Monday</th>
|
||||
<th>Tuesday</th>
|
||||
<th>Wednesday</th>
|
||||
<th>Thursday</th>
|
||||
<th>Friday</th>
|
||||
<th>Saturday</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_all_week"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_sunday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_monday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_tuesday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_wednesday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_thursday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_friday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<field
|
||||
name="apply_on_saturday"
|
||||
widget="boolean_toggle"
|
||||
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
|
||||
/>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<group>
|
||||
<field name="folio_id" invisible="1" />
|
||||
<field name="allowed_reservation_ids" invisible="1" />
|
||||
<field name="allowed_service_ids" invisible="1" />
|
||||
<field name="allowed_room_type_ids" invisible="1" />
|
||||
<field name="room_type_filter_ids" widget="many2many_tags" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
attrs="{'invisible':[('modification_type','=','services')]}"
|
||||
widget="many2many_tags"
|
||||
/>
|
||||
<field
|
||||
name="service_ids"
|
||||
attrs="{'invisible':[('modification_type','!=','services')]}"
|
||||
widget="many2many_tags"
|
||||
/>
|
||||
</group>
|
||||
<field name="dates_incongruence" invisible="1" force_save="1" />
|
||||
<div
|
||||
class="alert alert-warning"
|
||||
role="alert"
|
||||
attrs="{'invisible': [('dates_incongruence','=',False)]}"
|
||||
>
|
||||
Selected reservations with different dates
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
attrs="{'invisible':[('modification_type', '!=', 'dates')]}"
|
||||
>
|
||||
|
||||
<div class="col-4 pr-0">
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_new_checkin"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_checkin" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_checkin"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_new_checkin','=',False)], 'required':[('apply_new_checkin','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 pr-0">
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_new_checkout"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_checkout" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_checkout"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_new_checkout','=',False)], 'required':[('apply_new_checkout','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 pr-0">
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<label for="nights" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field name="nights" nolabel="1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-5 ">
|
||||
<group>
|
||||
<field name="folio_id" invisible="1" />
|
||||
<field name="allowed_reservation_ids" invisible="1" />
|
||||
<field
|
||||
name="reservation_ids"
|
||||
widget="many2many_tags"
|
||||
nolabel="1"
|
||||
/>
|
||||
</group>
|
||||
|
||||
<div
|
||||
class="row"
|
||||
attrs="{'invisible':[('modification_type','=','dates')]}"
|
||||
>
|
||||
<div class="col-4 pr-0">
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field name="apply_price" widget="boolean_toggle" />
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_price" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_price"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_price','=',False)], 'required':[('apply_price','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<group>
|
||||
<field name="new_price" />
|
||||
<field name="new_discount" />
|
||||
<field name="new_board_service_id" />
|
||||
</group>
|
||||
<div class="col-4 pr-0">
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_discount"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_discount" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_discount"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_discount','=',False)], 'required':[('apply_discount','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-4 pr-0"
|
||||
attrs="{'invisible':[('modification_type','!=','reservations')]}"
|
||||
>
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_board_service"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_board_service_id" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_board_service_id"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_board_service','=',False)], 'required':[('apply_board_service','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 pr-0">
|
||||
<div
|
||||
class="border h-100 pt-2 px-2"
|
||||
attrs="{'invisible':[('modification_type','!=','reservations')]}"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_service"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="new_service_id" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="new_service_id"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_service','=',False)], 'required':[('apply_service','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-4 pr-0"
|
||||
attrs="{'invisible':[('modification_type','!=','services')]}"
|
||||
>
|
||||
<div class="border h-100 pt-2 px-2">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<field
|
||||
name="apply_day_qty"
|
||||
widget="boolean_toggle"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="day_qty" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<field
|
||||
name="day_qty"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('apply_day_qty','=',False)], 'required':[('apply_day_qty','=',True)]}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button
|
||||
type="object"
|
||||
|
||||
Reference in New Issue
Block a user