mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP] Check compute qty and price day reservation&services
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- pms.users -->
|
||||
<record id="base.user_admin" model="res.users">
|
||||
<record id="base.user_root" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('pms.group_pms_manager'))]" />
|
||||
</record>
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]" />
|
||||
<record id="base.user_admin" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('pms.group_pms_manager'))]" />
|
||||
</record>
|
||||
<!-- Basic pms -->
|
||||
<record id="main_pms_room_type_restriction" model="pms.room.type.restriction">
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- users -->
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('pms.group_pms_user'))]" />
|
||||
</record>
|
||||
<!-- pms.floor -->
|
||||
<record id="pms_floor_0" model="pms.floor">
|
||||
<field name="name">Ground Floor</field>
|
||||
@@ -377,8 +381,8 @@
|
||||
eval="[(5, 0), (0, 0, {
|
||||
'pricelist_id': 1,
|
||||
'room_type_id': ref('pms_room_type_1'),
|
||||
'checkin': DateTime.today().strftime('%Y-%m-%d'),
|
||||
'checkout': (DateTime.today() + timedelta(days=2)).strftime('%Y-%m-%d'),
|
||||
'checkin': (DateTime.today() + timedelta(days=5)).strftime('%Y-%m-%d'),
|
||||
'checkout': (DateTime.today() + timedelta(days=7)).strftime('%Y-%m-%d'),
|
||||
'adults': 1,
|
||||
'state': 'confirm',
|
||||
'reservation_type': 'out',
|
||||
@@ -400,7 +404,7 @@
|
||||
<!-- pms.room.type -->
|
||||
<record id="demo_pms_room_type_0" model="pms.room.type">
|
||||
<field name="pms_property_id" ref="pms.demo_pms_property" />
|
||||
<field name="name">Economic</field>
|
||||
<field name="name">Prop. Demo Economic</field>
|
||||
<field name="code_type">ECO</field>
|
||||
<field name="list_price">21.00</field>
|
||||
<field name="class_id" ref="pms_room_type_class_0" />
|
||||
@@ -408,7 +412,7 @@
|
||||
</record>
|
||||
<record id="demo_pms_room_type_1" model="pms.room.type">
|
||||
<field name="pms_property_id" ref="pms.demo_pms_property" />
|
||||
<field name="name">Single</field>
|
||||
<field name="name">Prop. Demo Single</field>
|
||||
<field name="code_type">SNG</field>
|
||||
<field name="list_price">20.00</field>
|
||||
<field name="class_id" ref="pms_room_type_class_0" />
|
||||
|
||||
@@ -23,6 +23,9 @@ class PmsReservation(models.Model):
|
||||
_order = "last_updated_res desc, name"
|
||||
|
||||
# Default Methods ang Gets
|
||||
def _default_pricelist_id(self):
|
||||
return self.env.user.pms_property_id.default_pricelist_id.id
|
||||
|
||||
def _get_default_checkin(self):
|
||||
folio = False
|
||||
if "folio_id" in self._context:
|
||||
@@ -91,11 +94,7 @@ class PmsReservation(models.Model):
|
||||
|
||||
# Fields declaration
|
||||
name = fields.Text(
|
||||
"Reservation Description",
|
||||
required=True,
|
||||
compute="_compute_name",
|
||||
store=True,
|
||||
readonly=False,
|
||||
"Reservation Description", compute="_compute_name", store=True, readonly=False,
|
||||
)
|
||||
room_id = fields.Many2one(
|
||||
"pms.room",
|
||||
@@ -119,7 +118,6 @@ class PmsReservation(models.Model):
|
||||
room_type_id = fields.Many2one(
|
||||
"pms.room.type",
|
||||
string="Room Type",
|
||||
required=True,
|
||||
track_visibility="onchange",
|
||||
compute="_compute_room_type_id",
|
||||
store=True,
|
||||
@@ -137,7 +135,6 @@ class PmsReservation(models.Model):
|
||||
partner_invoice_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Invoice Address",
|
||||
required=True,
|
||||
help="Invoice address for current sales order.",
|
||||
compute="_compute_partner_invoice_id",
|
||||
store=True,
|
||||
@@ -162,11 +159,17 @@ class PmsReservation(models.Model):
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
service_ids = fields.One2many("pms.service", "reservation_id")
|
||||
service_ids = fields.One2many(
|
||||
"pms.service",
|
||||
"reservation_id",
|
||||
compute="_compute_service_ids",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
pricelist_id = fields.Many2one(
|
||||
"product.pricelist",
|
||||
string="Pricelist",
|
||||
required=True,
|
||||
default=_default_pricelist_id,
|
||||
ondelete="restrict",
|
||||
compute="_compute_pricelist_id",
|
||||
store=True,
|
||||
@@ -181,7 +184,6 @@ class PmsReservation(models.Model):
|
||||
related="pricelist_id.currency_id",
|
||||
string="Currency",
|
||||
readonly=True,
|
||||
required=True,
|
||||
)
|
||||
tax_ids = fields.Many2many(
|
||||
"account.tax",
|
||||
@@ -245,8 +247,8 @@ class PmsReservation(models.Model):
|
||||
out_service_description = fields.Text("Cause of out of service")
|
||||
checkin = fields.Date("Check In", required=True, default=_get_default_checkin)
|
||||
checkout = fields.Date("Check Out", required=True, default=_get_default_checkout)
|
||||
real_checkin = fields.Date("From", required=True, track_visibility="onchange")
|
||||
real_checkout = fields.Date("To", required=True, track_visibility="onchange")
|
||||
real_checkin = fields.Date("From", compute="_compute_real_checkin", store=True,)
|
||||
real_checkout = fields.Date("To", compute="_compute_real_checkout", store=True,)
|
||||
arrival_hour = fields.Char(
|
||||
"Arrival Hour",
|
||||
default=_get_default_arrival_hour,
|
||||
@@ -306,7 +308,10 @@ class PmsReservation(models.Model):
|
||||
string="Sales Channel",
|
||||
default="door",
|
||||
)
|
||||
last_updated_res = fields.Datetime("Last Updated")
|
||||
# TODO: Review functionality of last_update_res
|
||||
last_updated_res = fields.Datetime(
|
||||
"Last Updated", compute="_compute_last_updated_res", store=True, readonly=False,
|
||||
)
|
||||
folio_pending_amount = fields.Monetary(related="folio_id.pending_amount")
|
||||
shared_folio = fields.Boolean(compute="_computed_shared")
|
||||
# Used to notify is the reservation folio has other reservations/services
|
||||
@@ -320,8 +325,10 @@ class PmsReservation(models.Model):
|
||||
string="Internal Folio Notes", related="folio_id.internal_comment"
|
||||
)
|
||||
preconfirm = fields.Boolean("Auto confirm to Save", default=True)
|
||||
to_send = fields.Boolean("To Send", default=True)
|
||||
call_center = fields.Boolean(default="set_call_center_user")
|
||||
# TODO: to_send in this module?¿
|
||||
to_send = fields.Boolean(
|
||||
"To Send", default=True, compute="_compute_to_send", store=True, readonly=False,
|
||||
)
|
||||
has_confirmed_reservations_to_send = fields.Boolean(
|
||||
related="folio_id.has_confirmed_reservations_to_send", readonly=True
|
||||
)
|
||||
@@ -400,7 +407,7 @@ class PmsReservation(models.Model):
|
||||
)
|
||||
|
||||
# Compute and Search methods
|
||||
@api.depends("checkin", "checkin", "room_type_id")
|
||||
@api.depends("checkin", "checkout", "room_type_id")
|
||||
def _compute_name(self):
|
||||
for reservation in self:
|
||||
if (
|
||||
@@ -417,6 +424,8 @@ class PmsReservation(models.Model):
|
||||
+ " - "
|
||||
+ checkout_str
|
||||
)
|
||||
else:
|
||||
reservation.name = "/"
|
||||
|
||||
@api.depends("adults", "room_type_id")
|
||||
def _compute_room_id(self):
|
||||
@@ -428,6 +437,7 @@ class PmsReservation(models.Model):
|
||||
for reservation in reservations_no_room:
|
||||
if reservation.room_type_id:
|
||||
reservation.room_id = reservation._autoassign()
|
||||
# TODO: check_split reservation
|
||||
if not reservation.room_id:
|
||||
raise UserError(
|
||||
_("%s: No rooms available") % (self.room_type_id.name)
|
||||
@@ -495,7 +505,7 @@ class PmsReservation(models.Model):
|
||||
cmds = []
|
||||
days_diff = (reservation.checkout - reservation.checkin).days
|
||||
for i in range(0, days_diff):
|
||||
idate = fields.Date.from_string(reservation.checkin) + timedelta(days=i)
|
||||
idate = reservation.checkin + timedelta(days=i)
|
||||
old_line = reservation.reservation_line_ids.filtered(
|
||||
lambda r: r.date == idate
|
||||
)
|
||||
@@ -504,12 +514,34 @@ class PmsReservation(models.Model):
|
||||
reservation.reservation_line_ids -= reservation.reservation_line_ids.filtered_domain(
|
||||
[
|
||||
"|",
|
||||
("date", ">", reservation.checkout),
|
||||
("date", ">=", reservation.checkout),
|
||||
("date", "<", reservation.checkin),
|
||||
]
|
||||
)
|
||||
reservation.reservation_line_ids = cmds
|
||||
|
||||
@api.depends("board_service_room_id")
|
||||
def _compute_service_ids(self):
|
||||
for reservation in self:
|
||||
board_services = []
|
||||
old_board_lines = reservation.service_ids.filtered_domain(
|
||||
[("is_board_service", "=", True),]
|
||||
)
|
||||
if reservation.board_service_room_id:
|
||||
board = self.env["pms.board.service.room.type"].browse(
|
||||
reservation.board_service_room_id.id
|
||||
)
|
||||
for line in board.board_service_line_ids:
|
||||
res = {
|
||||
"product_id": line.product_id.id,
|
||||
"is_board_service": True,
|
||||
"folio_id": reservation.folio_id.id,
|
||||
"reservation_id": reservation.id,
|
||||
}
|
||||
board_services.append((0, False, res))
|
||||
reservation.service_ids -= old_board_lines
|
||||
reservation.service_ids = board_services
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_pricelist_id(self):
|
||||
for reservation in self:
|
||||
@@ -532,6 +564,77 @@ class PmsReservation(models.Model):
|
||||
else:
|
||||
reservation.adults = reservation.room_id.capacity
|
||||
|
||||
@api.depends("checkin")
|
||||
def _compute_real_checkin(self):
|
||||
for reservation in self:
|
||||
reservation.real_checkin = reservation.checkin
|
||||
if reservation.splitted:
|
||||
master_reservation = reservation.parent_reservation or reservation
|
||||
reservation.real_checkin = master_reservation.checkin
|
||||
splitted_reservations = self.env["pms.reservation"].search(
|
||||
[
|
||||
("splitted", "=", True),
|
||||
("folio_id", "=", self.folio_id.id),
|
||||
"|",
|
||||
("parent_reservation", "=", master_reservation.id),
|
||||
("id", "=", master_reservation.id),
|
||||
]
|
||||
)
|
||||
for split in splitted_reservations:
|
||||
if reservation.real_checkin > split.checkin:
|
||||
reservation.real_checkin = split.checkin
|
||||
|
||||
@api.depends("checkout")
|
||||
def _compute_real_checkout(self):
|
||||
for reservation in self:
|
||||
reservation.real_checkout = reservation.checkout
|
||||
if reservation.splitted:
|
||||
master_reservation = reservation.parent_reservation or reservation
|
||||
reservation.real_checkout = master_reservation.checkout
|
||||
splitted_reservations = self.env["pms.reservation"].search(
|
||||
[
|
||||
("splitted", "=", True),
|
||||
("folio_id", "=", self.folio_id.id),
|
||||
"|",
|
||||
("parent_reservation", "=", master_reservation.id),
|
||||
("id", "=", master_reservation.id),
|
||||
]
|
||||
)
|
||||
for split in splitted_reservations:
|
||||
if reservation.real_checkout < split.checkout:
|
||||
reservation.real_checkout = split.checkout
|
||||
|
||||
@api.depends("splitted", "checkout")
|
||||
def _compute_real_checkin(self):
|
||||
for reservation in self:
|
||||
if reservation.splitted:
|
||||
master_reservation = reservation.parent_reservation or reservation
|
||||
first_checkin = master_reservation.checkin
|
||||
splitted_reservations = self.env["pms.reservation"].search(
|
||||
[
|
||||
("splitted", "=", True),
|
||||
("folio_id", "=", self.folio_id.id),
|
||||
"|",
|
||||
("parent_reservation", "=", master_reservation.id),
|
||||
("id", "=", master_reservation.id),
|
||||
]
|
||||
)
|
||||
for split in splitted_reservations:
|
||||
if first_checkin > split.checkin:
|
||||
reservation.real_checkin = split.checkin
|
||||
|
||||
@api.depends("checkin", "checkout", "state")
|
||||
def _compute_to_send(self):
|
||||
for reservation in self:
|
||||
reservation.to_send = True
|
||||
|
||||
@api.depends(
|
||||
"checkin", "checkout", "discount", "state", "room_type_id", "to_assign"
|
||||
)
|
||||
def _compute_last_updated_res(self):
|
||||
for reservation in self:
|
||||
reservation.last_updated_res = fields.Datetime.now()
|
||||
|
||||
@api.depends("state", "qty_to_invoice", "qty_invoiced")
|
||||
def _compute_invoice_status(self):
|
||||
"""
|
||||
@@ -729,47 +832,6 @@ class PmsReservation(models.Model):
|
||||
|
||||
# self._compute_tax_ids() TODO: refact
|
||||
|
||||
@api.onchange("checkin", "checkout")
|
||||
def onchange_update_service_per_day(self):
|
||||
_logger.info("----------ONCHANGE4-----------")
|
||||
services = self.service_ids.filtered(lambda r: r.per_day is True)
|
||||
for service in services:
|
||||
service.onchange_product_id()
|
||||
|
||||
@api.onchange("board_service_room_id")
|
||||
def onchange_board_service(self):
|
||||
_logger.info("----------ONCHANGE1-----------")
|
||||
if self.board_service_room_id:
|
||||
board_services = [(5, 0, 0)]
|
||||
for line in self.board_service_room_id.board_service_line_ids:
|
||||
product = line.product_id
|
||||
if product.per_day:
|
||||
res = {
|
||||
"product_id": product.id,
|
||||
"is_board_service": True,
|
||||
"folio_id": self.folio_id.id,
|
||||
"reservation_id": self.id,
|
||||
}
|
||||
line = self.env["pms.service"].new(res)
|
||||
res.update(self.env["pms.service"]._prepare_add_missing_fields(res))
|
||||
res.update(
|
||||
self.env["pms.service"].prepare_service_ids(
|
||||
dfrom=self.checkin,
|
||||
days=self.nights,
|
||||
per_person=product.per_person,
|
||||
persons=self.adults,
|
||||
old_line_days=False,
|
||||
consumed_on=product.consumed_on,
|
||||
)
|
||||
)
|
||||
board_services.append((0, False, res))
|
||||
other_services = self.service_ids.filtered(lambda r: not r.is_board_service)
|
||||
self.update({"service_ids": board_services})
|
||||
self.service_ids |= other_services
|
||||
for service in self.service_ids.filtered(lambda r: r.is_board_service):
|
||||
service._compute_tax_ids()
|
||||
service.price_unit = service._compute_price_unit()
|
||||
|
||||
# Action methods
|
||||
|
||||
def open_invoices_reservation(self):
|
||||
@@ -864,10 +926,15 @@ class PmsReservation(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals.update(self._prepare_add_missing_fields(vals))
|
||||
if "folio_id" in vals and "channel_type" not in vals:
|
||||
folio = self.env["pms.folio"].browse(vals["folio_id"])
|
||||
vals.update({"channel_type": folio.channel_type})
|
||||
channel_type = (
|
||||
vals["channel_type"] if "channel_type" in vals else folio.channel_type
|
||||
)
|
||||
partner_id = (
|
||||
vals["partner_id"] if "partner_id" in vals else folio.partner_id.id
|
||||
)
|
||||
vals.update({"channel_type": channel_type, "partner_id": partner_id})
|
||||
elif "partner_id" in vals:
|
||||
folio_vals = {
|
||||
"partner_id": int(vals.get("partner_id")),
|
||||
@@ -883,98 +950,11 @@ class PmsReservation(models.Model):
|
||||
"channel_type": vals.get("channel_type"),
|
||||
}
|
||||
)
|
||||
if vals.get("service_ids"):
|
||||
for service in vals["service_ids"]:
|
||||
if service[2]:
|
||||
service[2]["folio_id"] = folio.id
|
||||
vals.update(
|
||||
{"last_updated_res": fields.Datetime.now(),}
|
||||
)
|
||||
if (
|
||||
"checkin" in vals
|
||||
and "checkout" in vals
|
||||
and "real_checkin" not in vals
|
||||
and "real_checkout" not in vals
|
||||
):
|
||||
vals["real_checkin"] = vals["checkin"]
|
||||
vals["real_checkout"] = vals["checkout"]
|
||||
record = super(PmsReservation, self).create(vals)
|
||||
if record.preconfirm:
|
||||
record.confirm()
|
||||
return record
|
||||
|
||||
def write(self, vals):
|
||||
if self.notify_update(vals):
|
||||
vals.update({"last_updated_res": fields.Datetime.now()})
|
||||
for record in self:
|
||||
checkin = vals["checkin"] if "checkin" in vals else record.checkin
|
||||
checkout = vals["checkout"] if "checkout" in vals else record.checkout
|
||||
if not record.splitted and not vals.get("splitted", False):
|
||||
if "checkin" in vals:
|
||||
vals["real_checkin"] = vals["checkin"]
|
||||
if "checkout" in vals:
|
||||
vals["real_checkout"] = vals["checkout"]
|
||||
|
||||
real_checkin = (
|
||||
vals["real_checkin"] if "real_checkin" in vals else record.real_checkin
|
||||
)
|
||||
real_checkout = (
|
||||
vals["real_checkout"]
|
||||
if "real_checkout" in vals
|
||||
else record.real_checkout
|
||||
)
|
||||
|
||||
days_diff = (
|
||||
fields.Date.from_string(checkout) - fields.Date.from_string(checkin)
|
||||
).days
|
||||
if self.compute_board_services(vals):
|
||||
record.service_ids.filtered(
|
||||
lambda r: r.is_board_service is True
|
||||
).unlink()
|
||||
board_services = []
|
||||
board = self.env["pms.board.service.room.type"].browse(
|
||||
vals["board_service_room_id"]
|
||||
)
|
||||
for line in board.board_service_line_ids:
|
||||
res = {
|
||||
"product_id": line.product_id.id,
|
||||
"is_board_service": True,
|
||||
"folio_id": vals.get("folio_id"),
|
||||
"reservation_id": self.id,
|
||||
}
|
||||
res.update(self.env["pms.service"]._prepare_add_missing_fields(res))
|
||||
board_services.append((0, False, res))
|
||||
# REVIEW: Why I need add manually the old IDs if
|
||||
# board service is (0,0,(-)) ¿?¿?¿
|
||||
record.update(
|
||||
{"service_ids": [(6, 0, record.service_ids.ids)] + board_services}
|
||||
)
|
||||
if record.compute_qty_service_day(vals):
|
||||
service_days_diff = (
|
||||
fields.Date.from_string(real_checkout)
|
||||
- fields.Date.from_string(real_checkin)
|
||||
).days
|
||||
for service in record.service_ids:
|
||||
if service.product_id.per_day:
|
||||
service.update(
|
||||
service.prepare_service_ids(
|
||||
dfrom=real_checkin,
|
||||
days=service_days_diff,
|
||||
per_person=service.product_id.per_person,
|
||||
persons=service.reservation_id.adults,
|
||||
old_line_days=service.service_line_ids,
|
||||
consumed_on=service.product_id.consumed_on,
|
||||
)
|
||||
)
|
||||
if (
|
||||
("checkin" in vals and record.checkin != vals["checkin"])
|
||||
or ("checkout" in vals and record.checkout != vals["checkout"])
|
||||
or ("state" in vals and record.state != vals["state"])
|
||||
):
|
||||
record.update({"to_send": True})
|
||||
record = super(PmsReservation, self).write(vals)
|
||||
return record
|
||||
|
||||
# Business methods
|
||||
|
||||
def _computed_shared(self):
|
||||
@@ -988,59 +968,6 @@ class PmsReservation(models.Model):
|
||||
)
|
||||
)
|
||||
|
||||
def compute_board_services(self, vals):
|
||||
"""
|
||||
We must compute service_ids when we have a board_service_id without
|
||||
service_ids associated to reservation
|
||||
"""
|
||||
if "board_service_room_id" in vals:
|
||||
if "service_ids" in vals:
|
||||
for service in vals["service_ids"]:
|
||||
if (
|
||||
"is_board_service" in service[2]
|
||||
and service[2]["is_board_service"] is True
|
||||
):
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
def compute_qty_service_day(self, vals):
|
||||
"""
|
||||
Compute if it is necesary calc price in write/create
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not vals:
|
||||
vals = {}
|
||||
if "service_ids" in vals:
|
||||
return False
|
||||
if (
|
||||
("checkin" in vals and self.checkin != vals["checkin"])
|
||||
or ("checkout" in vals and self.checkout != vals["checkout"])
|
||||
or ("adults" in vals and self.checkout != vals["adults"])
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def _prepare_add_missing_fields(self, values):
|
||||
""" Deduce missing required fields from the onchange """
|
||||
res = {}
|
||||
onchange_fields = ["tax_ids", "currency_id", "service_ids"]
|
||||
if values.get("room_type_id"):
|
||||
if not values.get("reservation_type"):
|
||||
values["reservation_type"] = "normal"
|
||||
line = self.new(values)
|
||||
for field in onchange_fields:
|
||||
if field == "service_ids":
|
||||
if self.compute_board_services(values):
|
||||
line.onchange_board_service()
|
||||
res[field] = line._fields[field].convert_to_write(
|
||||
line[field], line
|
||||
)
|
||||
if field not in values:
|
||||
res[field] = line._fields[field].convert_to_write(line[field], line)
|
||||
return res
|
||||
|
||||
def _autoassign(self):
|
||||
self.ensure_one()
|
||||
room_chosen = False
|
||||
@@ -1069,18 +996,6 @@ class PmsReservation(models.Model):
|
||||
res.message_post(subject=_("No Checkins!"), subtype="mt_comment", body=msg)
|
||||
return True
|
||||
|
||||
def notify_update(self, vals):
|
||||
if (
|
||||
"checkin" in vals
|
||||
or "checkout" in vals
|
||||
or "discount" in vals
|
||||
or "state" in vals
|
||||
or "room_type_id" in vals
|
||||
or "to_assign" in vals
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
def overbooking_button(self):
|
||||
self.ensure_one()
|
||||
self.overbooking = not self.overbooking
|
||||
@@ -1360,7 +1275,6 @@ class PmsReservation(models.Model):
|
||||
)
|
||||
)
|
||||
reservation_lines[0].append((2, rline.id, False))
|
||||
|
||||
parent_res = record.parent_reservation or record
|
||||
vals.update(
|
||||
{
|
||||
@@ -1435,7 +1349,7 @@ class PmsReservation(models.Model):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"This reservation can't be unified: They \
|
||||
all need to be in the same room"
|
||||
all need to be in the same nº room and room type"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1518,7 +1432,3 @@ class PmsReservation(models.Model):
|
||||
record.tax_ids = product.taxes_id.filtered(
|
||||
lambda r: not record.company_id or r.company_id == folio.company_id
|
||||
)
|
||||
|
||||
def set_call_center_user(self):
|
||||
user = self.env["res.users"].browse(self.env.uid)
|
||||
return user.has_group("pms.group_pms_call")
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PmsReservationLine(models.Model):
|
||||
@@ -64,7 +66,7 @@ class PmsReservationLine(models.Model):
|
||||
|
||||
# Compute and Search methods
|
||||
@api.depends(
|
||||
"date",
|
||||
"reservation_id",
|
||||
"reservation_id.pricelist_id",
|
||||
"reservation_id.room_type_id",
|
||||
"reservation_id.reservation_type",
|
||||
@@ -72,24 +74,43 @@ class PmsReservationLine(models.Model):
|
||||
def _compute_price(self):
|
||||
for line in self:
|
||||
reservation = line.reservation_id
|
||||
room_type_id = reservation.room_type_id.id
|
||||
product = self.env["pms.room.type"].browse(room_type_id).product_id
|
||||
partner = self.env["res.partner"].browse(reservation.partner_id.id)
|
||||
product = product.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=line.date,
|
||||
pricelist=reservation.pricelist_id.id,
|
||||
uom=product.uom_id.id,
|
||||
)
|
||||
line.price = self.env["account.tax"]._fix_tax_included_price_company(
|
||||
line._get_display_price(product),
|
||||
product.taxes_id,
|
||||
line.reservation_id.tax_ids,
|
||||
line.reservation_id.company_id,
|
||||
)
|
||||
# TODO: Out of service 0 amount
|
||||
if not reservation.room_type_id or not reservation.pricelist_id:
|
||||
line.price = 0
|
||||
elif line._recompute_price():
|
||||
room_type_id = reservation.room_type_id.id
|
||||
product = self.env["pms.room.type"].browse(room_type_id).product_id
|
||||
partner = self.env["res.partner"].browse(reservation.partner_id.id)
|
||||
product = product.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=line.date,
|
||||
pricelist=reservation.pricelist_id.id,
|
||||
uom=product.uom_id.id,
|
||||
)
|
||||
line.price = self.env["account.tax"]._fix_tax_included_price_company(
|
||||
line._get_display_price(product),
|
||||
product.taxes_id,
|
||||
line.reservation_id.tax_ids,
|
||||
line.reservation_id.company_id,
|
||||
)
|
||||
_logger.info(line.price)
|
||||
# TODO: Out of service 0 amount
|
||||
else:
|
||||
line.price = line._origin.price
|
||||
|
||||
def _recompute_price(self):
|
||||
#REVIEW: Conditional to avoid overriding already calculated prices,
|
||||
# I'm not sure it's the best way
|
||||
self.ensure_one()
|
||||
origin = self._origin.reservation_id
|
||||
new = self.reservation_id
|
||||
price_fields = ["pricelist_id", "room_type_id", "reservation_type"]
|
||||
if any(origin[field] != new[field] for field in price_fields) or \
|
||||
self._origin.price == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# TODO: Refact method and allowed cancelled single days
|
||||
@api.depends("reservation_id.cancelled_reason")
|
||||
@@ -201,3 +222,4 @@ class PmsReservationLine(models.Model):
|
||||
)
|
||||
# negative discounts (= surcharge) are included in the display price
|
||||
return max(base_price, final_price)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class PmsRoomType(models.Model):
|
||||
@@ -99,7 +100,7 @@ class PmsRoomType(models.Model):
|
||||
Check the max availability for an specific
|
||||
type of room in a range of dates
|
||||
"""
|
||||
reservations = self.env["pms.reservation"].get_reservations(dfrom, dto)
|
||||
reservations = self.env["pms.reservation"].get_reservations(dfrom, dto - timedelta(1))
|
||||
reservations_rooms = reservations.mapped("room_id.id")
|
||||
free_rooms = self.env["pms.room"].search(
|
||||
[("id", "not in", reservations_rooms), ("id", "not in", notthis)]
|
||||
|
||||
@@ -42,7 +42,9 @@ class PmsService(models.Model):
|
||||
return False
|
||||
|
||||
# Fields declaration
|
||||
name = fields.Char("Service description", required=True)
|
||||
name = fields.Char(
|
||||
"Service description", compute="_compute_name", store=True, readonly=False,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
"product.product", "Service", ondelete="restrict", required=True
|
||||
)
|
||||
@@ -52,7 +54,13 @@ class PmsService(models.Model):
|
||||
reservation_id = fields.Many2one(
|
||||
"pms.reservation", "Room", default=_default_reservation_id
|
||||
)
|
||||
service_line_ids = fields.One2many("pms.service.line", "service_id")
|
||||
service_line_ids = fields.One2many(
|
||||
"pms.service.line",
|
||||
"service_id",
|
||||
compute="_compute_service_line_ids",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
related="folio_id.company_id", string="Company", store=True, readonly=True
|
||||
)
|
||||
@@ -62,6 +70,9 @@ class PmsService(models.Model):
|
||||
tax_ids = fields.Many2many(
|
||||
"account.tax",
|
||||
string="Taxes",
|
||||
compute="_compute_tax_ids",
|
||||
store=True,
|
||||
readonly=False,
|
||||
domain=["|", ("active", "=", False), ("active", "=", True)],
|
||||
)
|
||||
move_line_ids = fields.Many2many(
|
||||
@@ -79,8 +90,12 @@ class PmsService(models.Model):
|
||||
sequence = fields.Integer(string="Sequence", default=10)
|
||||
state = fields.Selection(related="folio_id.state")
|
||||
per_day = fields.Boolean(related="product_id.per_day", related_sudo=True)
|
||||
product_qty = fields.Integer("Quantity", default=1)
|
||||
days_qty = fields.Integer(compute="_compute_days_qty", store=True)
|
||||
product_qty = fields.Integer(
|
||||
"Quantity",
|
||||
compute="_compute_product_qty",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
is_board_service = fields.Boolean()
|
||||
to_print = fields.Boolean("Print", help="Print in Folio Report")
|
||||
# Non-stored related field to allow portal user to
|
||||
@@ -111,7 +126,11 @@ class PmsService(models.Model):
|
||||
string="Sales Channel",
|
||||
)
|
||||
price_unit = fields.Float(
|
||||
"Unit Price", required=True, digits=("Product Price"), default=0.0
|
||||
"Unit Price",
|
||||
digits=("Product Price"),
|
||||
compute="_compute_price_unit",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
|
||||
qty_to_invoice = fields.Float(
|
||||
@@ -142,6 +161,206 @@ class PmsService(models.Model):
|
||||
)
|
||||
|
||||
# Compute and Search methods
|
||||
@api.depends("product_id")
|
||||
def _compute_name(self):
|
||||
self.name = False
|
||||
for service in self.filtered("product_id"):
|
||||
product = service.product_id.with_context(
|
||||
lang=service.folio_id.partner_id.lang,
|
||||
partner=service.folio_id.partner_id.id,
|
||||
)
|
||||
title = False
|
||||
message = False
|
||||
warning = {}
|
||||
if product.sale_line_warn != "no-message":
|
||||
title = _("Warning for %s") % product.name
|
||||
message = product.sale_line_warn_msg
|
||||
warning["title"] = title
|
||||
warning["message"] = message
|
||||
result = {"warning": warning}
|
||||
if product.sale_line_warn == "block":
|
||||
self.product_id = False
|
||||
return result
|
||||
name = product.name_get()[0][1]
|
||||
if product.description_sale:
|
||||
name += "\n" + product.description_sale
|
||||
service.name = name
|
||||
|
||||
@api.depends("reservation_id.checkin", "reservation_id.checkout", "product_id")
|
||||
def _compute_service_line_ids(self):
|
||||
for service in self.filtered("product_id"):
|
||||
day_qty = 1
|
||||
if service.reservation_id and service.product_id:
|
||||
reservation = service.reservation_id
|
||||
product = service.product_id
|
||||
consumed_on = product.consumed_on
|
||||
if product.per_day:
|
||||
lines = []
|
||||
day_qty = service._service_day_qty()
|
||||
days_diff = (reservation.checkout - reservation.checkin).days
|
||||
for i in range(0, days_diff):
|
||||
if consumed_on == "after":
|
||||
i += 1
|
||||
idate = reservation.checkin + timedelta(days=i)
|
||||
old_line = service._search_old_lines(idate)
|
||||
if idate in [line.date for line in service.service_line_ids]:
|
||||
#REVIEW: If the date is already cached (otherwise double the date)
|
||||
pass
|
||||
elif not old_line:
|
||||
lines.append(
|
||||
(0, False, {
|
||||
"date": idate,
|
||||
"day_qty": day_qty,
|
||||
})
|
||||
)
|
||||
else:
|
||||
lines.append((4, old_line.id))
|
||||
move_day = 0
|
||||
if consumed_on == "after":
|
||||
move_day = 1
|
||||
service.service_line_ids -= service.service_line_ids.filtered_domain(
|
||||
[
|
||||
"|",
|
||||
("date", "<", reservation.checkin + timedelta(move_day)),
|
||||
("date", ">=", reservation.checkout + timedelta(move_day)),
|
||||
]
|
||||
)
|
||||
_logger.info(service)
|
||||
_logger.info(lines)
|
||||
service.service_line_ids = lines
|
||||
else:
|
||||
# TODO: Review (business logic refact) no per_day logic service
|
||||
if not service.service_line_ids:
|
||||
service.service_line_ids = [(
|
||||
0,
|
||||
False,
|
||||
{
|
||||
"date": fields.Date.today(),
|
||||
"day_qty": day_qty,
|
||||
},
|
||||
)]
|
||||
else:
|
||||
# TODO: Service without reservation(room) but with folio¿?
|
||||
# example: tourist tour in group
|
||||
if not service.service_line_ids:
|
||||
service.service_line_ids = [(
|
||||
0,
|
||||
False,
|
||||
{
|
||||
"date": fields.Date.today(),
|
||||
"day_qty": day_qty,
|
||||
},
|
||||
)]
|
||||
|
||||
def _search_old_lines(self, date):
|
||||
self.ensure_one()
|
||||
old_lines = self.env['pms.service.line']
|
||||
if isinstance(self._origin.id, int):
|
||||
old_line = self._origin.service_line_ids.filtered(
|
||||
lambda r: r.date == date
|
||||
)
|
||||
return old_line
|
||||
return False
|
||||
|
||||
|
||||
@api.depends("product_id")
|
||||
def _compute_tax_ids(self):
|
||||
for service in self:
|
||||
service.tax_ids = service.product_id.taxes_id.filtered(
|
||||
lambda r: not service.company_id or r.company_id == service.company_id
|
||||
)
|
||||
|
||||
@api.depends("service_line_ids", "service_line_ids.day_qty")
|
||||
def _compute_product_qty(self):
|
||||
self.product_qty = 0
|
||||
for service in self.filtered("service_line_ids"):
|
||||
qty = sum(service.service_line_ids.mapped("day_qty"))
|
||||
service.product_qty = qty
|
||||
|
||||
@api.depends("product_id", "service_line_ids", "reservation_id.pricelist_id")
|
||||
def _compute_price_unit(self):
|
||||
for service in self:
|
||||
folio = service.folio_id
|
||||
reservation = service.reservation_id
|
||||
origin = reservation if reservation else folio
|
||||
if origin:
|
||||
if service._recompute_price():
|
||||
partner = origin.partner_id
|
||||
pricelist = origin.pricelist_id
|
||||
if reservation and service.is_board_service:
|
||||
board_room_type = reservation.board_service_room_id
|
||||
if board_room_type.price_type == "fixed":
|
||||
service.price_unit = (
|
||||
self.env["pms.board.service.room.type.line"]
|
||||
.search(
|
||||
[
|
||||
(
|
||||
"pms_board_service_room_type_id",
|
||||
"=",
|
||||
board_room_type.id,
|
||||
),
|
||||
("product_id", "=", service.product_id.id),
|
||||
]
|
||||
)
|
||||
.amount
|
||||
)
|
||||
else:
|
||||
service.price_unit = (
|
||||
reservation.price_total
|
||||
* self.env["pms.board.service.room.type.line"]
|
||||
.search(
|
||||
[
|
||||
(
|
||||
"pms_board_service_room_type_id",
|
||||
"=",
|
||||
board_room_type.id,
|
||||
),
|
||||
("product_id", "=", service.product_id.id),
|
||||
]
|
||||
)
|
||||
.amount
|
||||
) / 100
|
||||
else:
|
||||
product = service.product_id.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=service.product_qty,
|
||||
date=folio.date_order if folio else fields.Date.today(),
|
||||
pricelist=pricelist.id,
|
||||
uom=service.product_id.uom_id.id,
|
||||
fiscal_position=False,
|
||||
)
|
||||
service.price_unit = self.env[
|
||||
"account.tax"
|
||||
]._fix_tax_included_price_company(
|
||||
service._get_display_price(product),
|
||||
product.taxes_id,
|
||||
service.tax_ids,
|
||||
origin.company_id,
|
||||
)
|
||||
else:
|
||||
service.price_unit = service._origin.price_unit
|
||||
else:
|
||||
service.price_unit = 0
|
||||
|
||||
def _recompute_price(self):
|
||||
#REVIEW: Conditional to avoid overriding already calculated prices,
|
||||
# I'm not sure it's the best way
|
||||
self.ensure_one()
|
||||
#folio/reservation origin service
|
||||
folio_origin = self._origin.folio_id
|
||||
reservation_origin = self._origin.reservation_id
|
||||
origin = reservation_origin if reservation_origin else folio_origin
|
||||
#folio/reservation new service
|
||||
folio_new = self.folio_id
|
||||
reservation_new = self.reservation_id
|
||||
new = reservation_new if reservation_new else folio_new
|
||||
price_fields = ["pricelist_id", "reservation_type"]
|
||||
if any(origin[field] != new[field] for field in price_fields) or \
|
||||
self._origin.price_unit == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
@api.depends("qty_invoiced", "product_qty", "folio_id.state")
|
||||
def _get_to_invoice_qty(self):
|
||||
"""
|
||||
@@ -204,7 +423,8 @@ class PmsService(models.Model):
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
for line in self:
|
||||
if line.folio_id.state in ("draft"):
|
||||
state = line.folio_id.state or "draft"
|
||||
if state in ("draft"):
|
||||
line.invoice_status = "no"
|
||||
elif not float_is_zero(line.qty_to_invoice, precision_digits=precision):
|
||||
line.invoice_status = "to invoice"
|
||||
@@ -220,24 +440,16 @@ class PmsService(models.Model):
|
||||
|
||||
@api.depends("product_qty", "discount", "price_unit", "tax_ids")
|
||||
def _compute_amount_service(self):
|
||||
"""
|
||||
Compute the amounts of the service line.
|
||||
"""
|
||||
for record in self:
|
||||
folio = record.folio_id or self.env["pms.folio"].browse(
|
||||
self.env.context.get("default_folio_id")
|
||||
)
|
||||
reservation = record.reservation_id or self.env.context.get(
|
||||
"reservation_id"
|
||||
)
|
||||
for service in self:
|
||||
folio = service.folio_id
|
||||
reservation = service.reservation_id
|
||||
currency = folio.currency_id if folio else reservation.currency_id
|
||||
product = record.product_id
|
||||
price = record.price_unit * (1 - (record.discount or 0.0) * 0.01)
|
||||
taxes = record.tax_ids.compute_all(
|
||||
price, currency, record.product_qty, product=product
|
||||
product = service.product_id
|
||||
price = service.price_unit * (1 - (service.discount or 0.0) * 0.01)
|
||||
taxes = service.tax_ids.compute_all(
|
||||
price, currency, service.product_qty, product=product
|
||||
)
|
||||
|
||||
record.update(
|
||||
service.update(
|
||||
{
|
||||
"price_tax": sum(
|
||||
t.get("amount", 0.0) for t in taxes.get("taxes", [])
|
||||
@@ -247,92 +459,7 @@ class PmsService(models.Model):
|
||||
}
|
||||
)
|
||||
|
||||
@api.depends("service_line_ids.day_qty")
|
||||
def _compute_days_qty(self):
|
||||
for record in self:
|
||||
if record.per_day:
|
||||
qty = sum(record.service_line_ids.mapped("day_qty"))
|
||||
vals = {"days_qty": qty, "product_qty": qty}
|
||||
else:
|
||||
vals = {"days_qty": 0}
|
||||
record.update(vals)
|
||||
|
||||
# Constraints and onchanges
|
||||
@api.onchange("product_id")
|
||||
def onchange_product_id(self):
|
||||
"""
|
||||
Compute the default quantity according to the
|
||||
configuration of the selected product, in per_day
|
||||
product configuration, the qty is autocalculated and
|
||||
readonly based on service_ids qty
|
||||
"""
|
||||
if not self.product_id:
|
||||
return
|
||||
vals = {}
|
||||
vals["product_qty"] = 1.0
|
||||
for record in self:
|
||||
if record.per_day and record.reservation_id:
|
||||
product = record.product_id
|
||||
if self.env.context.get("default_reservation_id"):
|
||||
reservation = self.env["pms.reservation"].browse(
|
||||
self.env.context.get("default_reservation_id")
|
||||
)
|
||||
else:
|
||||
reservation = record.reservation_id
|
||||
if reservation.splitted:
|
||||
checkin = reservation.real_checkin
|
||||
checkout = reservation.real_checkout
|
||||
else:
|
||||
checkin = reservation.checkin
|
||||
checkout = reservation.checkout
|
||||
checkin_dt = fields.Date.from_string(checkin)
|
||||
checkout_dt = fields.Date.from_string(checkout)
|
||||
nights = abs((checkout_dt - checkin_dt).days)
|
||||
vals.update(
|
||||
record.prepare_service_ids(
|
||||
dfrom=checkin,
|
||||
days=nights,
|
||||
per_person=product.per_person,
|
||||
persons=reservation.adults,
|
||||
old_line_days=record.service_line_ids,
|
||||
consumed_on=product.consumed_on,
|
||||
)
|
||||
)
|
||||
if record.product_id.daily_limit > 0:
|
||||
for day in record.service_line_ids:
|
||||
day.no_free_resources()
|
||||
"""
|
||||
Description and warnings
|
||||
"""
|
||||
product = self.product_id.with_context(
|
||||
lang=self.folio_id.partner_id.lang, partner=self.folio_id.partner_id.id
|
||||
)
|
||||
title = False
|
||||
message = False
|
||||
warning = {}
|
||||
if product.sale_line_warn != "no-message":
|
||||
title = _("Warning for %s") % product.name
|
||||
message = product.sale_line_warn_msg
|
||||
warning["title"] = title
|
||||
warning["message"] = message
|
||||
result = {"warning": warning}
|
||||
if product.sale_line_warn == "block":
|
||||
self.product_id = False
|
||||
return result
|
||||
|
||||
name = product.name_get()[0][1]
|
||||
if product.description_sale:
|
||||
name += "\n" + product.description_sale
|
||||
vals["name"] = name
|
||||
"""
|
||||
Compute tax and price unit
|
||||
"""
|
||||
self._compute_tax_ids()
|
||||
vals["price_unit"] = self._compute_price_unit()
|
||||
record.update(vals)
|
||||
|
||||
# Action methods
|
||||
|
||||
def open_service_ids(self):
|
||||
action = self.env.ref("pms.action_pms_services_form").read()[0]
|
||||
action["views"] = [(self.env.ref("pms.pms_service_view_form").id, "form")]
|
||||
@@ -355,119 +482,9 @@ class PmsService(models.Model):
|
||||
name="", args=args, operator="ilike", limit=limit
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals.update(self._prepare_add_missing_fields(vals))
|
||||
if self.compute_lines_out_vals(vals):
|
||||
reservation = self.env["pms.reservation"].browse(vals["reservation_id"])
|
||||
product = self.env["product.product"].browse(vals["product_id"])
|
||||
if reservation.splitted:
|
||||
checkin = reservation.real_checkin
|
||||
checkout = reservation.real_checkout
|
||||
else:
|
||||
checkin = reservation.checkin
|
||||
checkout = reservation.checkout
|
||||
checkin_dt = fields.Date.from_string(checkin)
|
||||
checkout_dt = fields.Date.from_string(checkout)
|
||||
nights = abs((checkout_dt - checkin_dt).days)
|
||||
vals.update(
|
||||
self.prepare_service_ids(
|
||||
dfrom=checkin,
|
||||
days=nights,
|
||||
per_person=product.per_person,
|
||||
persons=reservation.adults,
|
||||
old_day_lines=False,
|
||||
consumed_on=product.consumed_on,
|
||||
)
|
||||
)
|
||||
record = super(PmsService, self).create(vals)
|
||||
return record
|
||||
|
||||
def write(self, vals):
|
||||
# If you write product, We must check if its necesary create or delete
|
||||
# service lines
|
||||
if vals.get("product_id"):
|
||||
product = self.env["product.product"].browse(vals.get("product_id"))
|
||||
if not product.per_day:
|
||||
vals.update({"service_line_ids": [(5, 0, 0)]})
|
||||
else:
|
||||
for record in self:
|
||||
reservations = self.env["pms.reservation"]
|
||||
reservation = (
|
||||
reservations.browse(vals["reservation_id"])
|
||||
if "reservation_id" in vals
|
||||
else record.reservation_id
|
||||
)
|
||||
if reservation.splitted:
|
||||
checkin = reservation.real_checkin
|
||||
checkout = reservation.real_checkout
|
||||
else:
|
||||
checkin = reservation.checkin
|
||||
checkout = reservation.checkout
|
||||
checkin_dt = fields.Date.from_string(checkin)
|
||||
checkout_dt = fields.Date.from_string(checkout)
|
||||
nights = abs((checkout_dt - checkin_dt).days)
|
||||
record.update(
|
||||
record.prepare_service_ids(
|
||||
dfrom=checkin,
|
||||
days=nights,
|
||||
per_person=product.per_person,
|
||||
persons=reservation.adults,
|
||||
old_line_days=self.service_line_ids,
|
||||
consumed_on=product.consumed_on,
|
||||
)
|
||||
)
|
||||
res = super(PmsService, self).write(vals)
|
||||
return res
|
||||
|
||||
# Business methods
|
||||
@api.model
|
||||
def _prepare_add_missing_fields(self, values):
|
||||
""" Deduce missing required fields from the onchange """
|
||||
res = {}
|
||||
onchange_fields = ["price_unit", "tax_ids", "name"]
|
||||
if values.get("product_id"):
|
||||
line = self.new(values)
|
||||
if any(f not in values for f in onchange_fields):
|
||||
line.onchange_product_id()
|
||||
for field in onchange_fields:
|
||||
if field not in values:
|
||||
res[field] = line._fields[field].convert_to_write(line[field], line)
|
||||
return res
|
||||
|
||||
def compute_lines_out_vals(self, vals):
|
||||
"""
|
||||
Compute if It is necesary service days in write/create
|
||||
"""
|
||||
if not vals:
|
||||
vals = {}
|
||||
if "product_id" in vals:
|
||||
product = (
|
||||
self.env["product.product"].browse(vals["product_id"])
|
||||
if "product_id" in vals
|
||||
else self.product_id
|
||||
)
|
||||
if product.per_day and "service_line_ids" not in vals:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _compute_tax_ids(self):
|
||||
for record in self:
|
||||
# If company_id is set, always filter taxes by the company
|
||||
folio = record.folio_id or self.env["pms.folio"].browse(
|
||||
self.env.context.get("default_folio_id")
|
||||
)
|
||||
reservation = record.reservation_id or self.env.context.get(
|
||||
"reservation_id"
|
||||
)
|
||||
origin = folio if folio else reservation
|
||||
record.tax_ids = record.product_id.taxes_id.filtered(
|
||||
lambda r: not record.company_id or r.company_id == origin.company_id
|
||||
)
|
||||
|
||||
def _get_display_price(self, product):
|
||||
folio = self.folio_id or self.env.context.get("default_folio_id")
|
||||
reservation = self.reservation_id or self.env.context.get("reservation_id")
|
||||
folio = self.folio_id
|
||||
reservation = self.reservation_id
|
||||
origin = folio if folio else reservation
|
||||
if origin.pricelist_id.discount_policy == "with_discount":
|
||||
return product.with_context(pricelist=origin.pricelist_id.id).price
|
||||
@@ -501,90 +518,13 @@ class PmsService(models.Model):
|
||||
# negative discounts (= surcharge) are included in the display price
|
||||
return max(base_price, final_price)
|
||||
|
||||
def _compute_price_unit(self):
|
||||
# Businness Methods
|
||||
def _service_day_qty(self):
|
||||
self.ensure_one()
|
||||
folio = self.folio_id or self.env.context.get("default_folio_id")
|
||||
reservation = self.reservation_id or self.env.context.get("reservation_id")
|
||||
origin = reservation if reservation else folio
|
||||
if origin:
|
||||
partner = origin.partner_id
|
||||
pricelist = origin.pricelist_id
|
||||
if reservation and self.is_board_service:
|
||||
board_room_type = reservation.board_service_room_id
|
||||
if board_room_type.price_type == "fixed":
|
||||
return (
|
||||
self.env["pms.board.service.room.type.line"]
|
||||
.search(
|
||||
[
|
||||
(
|
||||
"pms_board_service_room_type_id",
|
||||
"=",
|
||||
board_room_type.id,
|
||||
),
|
||||
("product_id", "=", self.product_id.id),
|
||||
]
|
||||
)
|
||||
.amount
|
||||
)
|
||||
else:
|
||||
return (
|
||||
reservation.price_total
|
||||
* self.env["pms.board.service.room.type.line"]
|
||||
.search(
|
||||
[
|
||||
(
|
||||
"pms_board_service_room_type_id",
|
||||
"=",
|
||||
board_room_type.id,
|
||||
),
|
||||
("product_id", "=", self.product_id.id),
|
||||
]
|
||||
)
|
||||
.amount
|
||||
) / 100
|
||||
else:
|
||||
product = self.product_id.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=self.product_qty,
|
||||
date=folio.date_order if folio else fields.Date.today(),
|
||||
pricelist=pricelist.id,
|
||||
uom=self.product_id.uom_id.id,
|
||||
fiscal_position=False,
|
||||
)
|
||||
return self.env["account.tax"]._fix_tax_included_price_company(
|
||||
self._get_display_price(product),
|
||||
product.taxes_id,
|
||||
self.tax_ids,
|
||||
origin.company_id,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def prepare_service_ids(self, **kwargs):
|
||||
"""
|
||||
Prepare line and respect the old manual changes on lines
|
||||
"""
|
||||
cmds = [(5, 0, 0)]
|
||||
old_line_days = kwargs.get("old_line_days")
|
||||
consumed_on = (
|
||||
kwargs.get("consumed_on") if kwargs.get("consumed_on") else "before"
|
||||
)
|
||||
total_qty = 0
|
||||
day_qty = 1
|
||||
# WARNING: Change adults in reservation NOT update qty service!!
|
||||
if kwargs.get("per_person"):
|
||||
day_qty = kwargs.get("persons")
|
||||
for i in range(0, kwargs.get("days")):
|
||||
if consumed_on == "after":
|
||||
i += 1
|
||||
idate = (
|
||||
fields.Date.from_string(kwargs.get("dfrom")) + timedelta(days=i)
|
||||
).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
if not old_line_days or idate not in old_line_days.mapped("date"):
|
||||
cmds.append((0, False, {"date": idate, "day_qty": day_qty}))
|
||||
total_qty = total_qty + day_qty
|
||||
else:
|
||||
old_line = old_line_days.filtered(lambda r: r.date == idate)
|
||||
cmds.append((4, old_line.id))
|
||||
total_qty = total_qty + old_line.day_qty
|
||||
return {"service_line_ids": cmds, "product_qty": total_qty}
|
||||
qty = self.product_qty if len(self.service_line_ids) == 1 else 0
|
||||
if not self.reservation_id:
|
||||
return qty
|
||||
# TODO: Pass per_person to service line from product default_per_person
|
||||
if self.product_id.per_person:
|
||||
qty = self.reservation_id.adults
|
||||
return qty
|
||||
|
||||
@@ -260,8 +260,7 @@
|
||||
name="partner_id"
|
||||
default_focus="1"
|
||||
placeholder="Lastname, Firstname"
|
||||
attrs="{'readonly':[('folio_id','!=',False)],
|
||||
'invisible':[('reservation_type','in',('out'))]}"
|
||||
attrs="{'invisible':[('reservation_type','in',('out'))]}"
|
||||
required="1"
|
||||
/>
|
||||
<field
|
||||
@@ -529,7 +528,7 @@
|
||||
<button
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa fa-1x fa-bed"
|
||||
icon="fa-1x fa-bed"
|
||||
name="open_service_ids"
|
||||
attrs="{'invisible':[('is_board_service','=', False)]}"
|
||||
/>
|
||||
@@ -558,11 +557,10 @@
|
||||
<button
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa fa-2x fa-bars"
|
||||
icon="fa-2x fa-bars"
|
||||
name="open_service_ids"
|
||||
attrs="{'invisible': [('per_day','=',False)]}"
|
||||
/>
|
||||
<field name="days_qty" invisible="1" />
|
||||
<field name="price_unit" />
|
||||
<field name="discount" />
|
||||
<field name="tax_ids" widget="many2many_tags" />
|
||||
@@ -592,6 +590,7 @@
|
||||
/>
|
||||
<field name="reservation_line_ids" nolabel="1">
|
||||
<tree create="false" delete="false" editable="bottom">
|
||||
<field name="id" />
|
||||
<field name="date" readonly="1" force_save="1" />
|
||||
<field name="price" />
|
||||
<field name="discount" />
|
||||
@@ -768,24 +767,24 @@
|
||||
options="{'no_open': True}"
|
||||
/>
|
||||
<span
|
||||
class="fa fa-user"
|
||||
class="fa-user"
|
||||
style="margin-left:20px;"
|
||||
attrs="{'invisible': [('reservation_type','not in',('normal'))]}"
|
||||
/>
|
||||
<span
|
||||
class="fa fa-black-tie"
|
||||
class="fa-black-tie"
|
||||
style="margin-left:20px; color: #C67;"
|
||||
attrs="{'invisible': [('reservation_type','not in',('staff'))]}"
|
||||
/>
|
||||
<h3>
|
||||
From <span class="fa fa-sign-in" style="margin: 5px;" />
|
||||
From <span class="fa-sign-in" style="margin: 5px;" />
|
||||
<field
|
||||
name="checkin"
|
||||
style="margin-right: 10px;"
|
||||
readonly="1"
|
||||
/>
|
||||
to
|
||||
<span class="fa fa-sign-out" style="margin-right: 5px;" />
|
||||
<span class="fa-sign-out" style="margin-right: 5px;" />
|
||||
<field name="checkout" readonly="1" />
|
||||
</h3>
|
||||
</h2>
|
||||
@@ -910,7 +909,7 @@
|
||||
<button
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa fa-2x fa-suitcase"
|
||||
icon="fa-2x fa-suitcase"
|
||||
name="open_reservation_form"
|
||||
help="Open Reservation Room Detail"
|
||||
/>
|
||||
@@ -1008,11 +1007,6 @@
|
||||
domain="[('to_assign','=',True)]"
|
||||
/>
|
||||
<separator />
|
||||
<filter
|
||||
string="Call Center"
|
||||
name="call_center"
|
||||
domain="[('channel_type', '=', 'call')]"
|
||||
/>
|
||||
<filter
|
||||
string="Web"
|
||||
name="web"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
force_save="1"
|
||||
/>
|
||||
</group>
|
||||
<field name="days_qty" invisible="1" />
|
||||
<field name="price_unit" invisible="1" />
|
||||
<field name="discount" invisible="1" />
|
||||
<field name="tax_ids" widget="many2many_tags" invisible="1" />
|
||||
@@ -89,7 +88,6 @@
|
||||
name="open_service_ids"
|
||||
attrs="{'invisible': [('per_day','=',False)]}"
|
||||
/>
|
||||
<field name="days_qty" invisible="1" />
|
||||
<field name="price_unit" />
|
||||
<field name="discount" />
|
||||
<field name="tax_ids" widget="many2many_tags" />
|
||||
|
||||
@@ -89,7 +89,6 @@ class FolioWizard(models.TransientModel):
|
||||
room_type_wizard_ids = fields.One2many(
|
||||
"pms.room.type.wizard", "folio_wizard_id", string="Room Types"
|
||||
)
|
||||
call_center = fields.Boolean(default=_get_default_center_user)
|
||||
|
||||
def assign_rooms(self):
|
||||
self.assign = True
|
||||
@@ -270,7 +269,8 @@ class FolioWizard(models.TransientModel):
|
||||
"board_service_room_id": line.board_service_room_id.id,
|
||||
"to_assign": line.to_assign,
|
||||
"service_ids": services_room,
|
||||
"pricelist_id": self.pricelist_id.id, # REVIEW: Create folio with reservations dont respect the pricelist_id on folio dict
|
||||
# REVIEW: Create folio with reservations dont respect the pricelist_id on folio dict
|
||||
"pricelist_id": self.pricelist_id.id,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -16,13 +16,7 @@
|
||||
<field name="company_id" invisible="1" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="call_center" invisible="1" />
|
||||
<field
|
||||
name="channel_type"
|
||||
required="1"
|
||||
force_save="1"
|
||||
attrs="{'readonly':[('call_center','=',True)]}"
|
||||
/>
|
||||
<field name="channel_type" required="1" force_save="1" />
|
||||
<field name="pricelist_id" />
|
||||
<field name="internal_comment" />
|
||||
<field name="credit_card_details" />
|
||||
|
||||
Reference in New Issue
Block a user