Files
pms/pms/models/product_pricelist.py

206 lines
8.2 KiB
Python

# Copyright 2017 Alexandre Díaz, Pablo Quesada, Darío Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
class ProductPricelist(models.Model):
"""Before creating a 'daily' pricelist, you need to consider the following:
A pricelist marked as daily is used as a daily rate plan for room types and
therefore is related only with one property.
"""
_inherit = "product.pricelist"
_check_pms_properties_auto = True
# Fields declaration
pms_property_ids = fields.Many2many(
string="Properties",
help="Properties with access to the element;"
" if not set, all properties can access",
required=False,
comodel_name="pms.property",
relation="product_pricelist_pms_property_rel",
column1="product_pricelist_id",
column2="pms_property_id",
ondelete="restrict",
check_pms_properties=True,
)
company_id = fields.Many2one(
string="Company",
help="Company to which the pricelist belongs",
index=True,
)
cancelation_rule_id = fields.Many2one(
string="Cancelation Policy",
help="Cancelation Policy included in the room",
comodel_name="pms.cancelation.rule",
index=True,
check_pms_properties=True,
)
pricelist_type = fields.Selection(
string="Pricelist Type",
help="Pricelist types, it can be Daily Plan",
default="daily",
selection=[("daily", "Daily Plan")],
)
pms_sale_channel_ids = fields.Many2many(
string="Available Channels",
help="Sale channel for which the pricelist is included",
comodel_name="pms.sale.channel",
check_pms_properties=True,
)
availability_plan_id = fields.Many2one(
string="Availability Plan",
help="Availability Plan for which the pricelist is included",
comodel_name="pms.availability.plan",
ondelete="restrict",
index=True,
check_pms_properties=True,
)
item_ids = fields.One2many(
string="Items",
help="Items for which the pricelist is made up",
check_pms_properties=True,
)
is_pms_available = fields.Boolean(
string="Available in PMS",
help="If the pricelist is available in the PMS",
default=False,
)
def _compute_price_rule_get_items(
self, products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
):
board_service = True if self._context.get("board_service") else False
if (
"property" in self._context
and self._context["property"]
and self._context.get("consumption_date")
):
self.env.cr.execute(
"""
SELECT item.id
FROM product_pricelist_item item
LEFT JOIN product_category categ
ON item.categ_id = categ.id
LEFT JOIN product_pricelist_pms_property_rel cab
ON item.pricelist_id = cab.product_pricelist_id
LEFT JOIN product_pricelist_item_pms_property_rel lin
ON item.id = lin.product_pricelist_item_id
WHERE (lin.pms_property_id = %s OR lin.pms_property_id IS NULL)
AND (cab.pms_property_id = %s OR cab.pms_property_id IS NULL)
AND (item.product_tmpl_id IS NULL
OR item.product_tmpl_id = ANY(%s))
AND (item.product_id IS NULL OR item.product_id = ANY(%s))
AND (item.categ_id IS NULL OR item.categ_id = ANY(%s))
AND (item.pricelist_id = %s)
AND (item.date_start IS NULL OR item.date_start <=%s)
AND (item.date_end IS NULL OR item.date_end >=%s)
AND (item.date_start_consumption IS NULL
OR item.date_start_consumption <=%s)
AND (item.date_end_consumption IS NULL
OR item.date_end_consumption >=%s)
GROUP BY item.id
ORDER BY item.applied_on,
/* REVIEW: priotrity date sale / date consumption */
item.date_end - item.date_start ASC,
item.date_end_consumption - item.date_start_consumption ASC,
NULLIF((SELECT COUNT(1)
FROM product_pricelist_item_pms_property_rel l
WHERE item.id = l.product_pricelist_item_id)
+ (SELECT COUNT(1)
FROM product_pricelist_pms_property_rel c
WHERE item.pricelist_id = c.product_pricelist_id),0)
NULLS LAST,
item.id DESC;
""",
(
self._context["property"],
self._context["property"],
prod_tmpl_ids,
prod_ids,
categ_ids,
self.id,
date,
date,
self._context["consumption_date"],
self._context["consumption_date"],
),
)
item_ids = [x[0] for x in self.env.cr.fetchall()]
items = self.env["product.pricelist.item"].browse(item_ids)
if board_service:
items = items.filtered(
lambda x: x.board_service_room_type_id.id
== self._context.get("board_service")
)
else:
items = items.filtered(lambda x: not x.board_service_room_type_id.id)
else:
items = super(ProductPricelist, self)._compute_price_rule_get_items(
products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
)
return items
@api.constrains("is_pms_available", "availability_plan_id")
def _check_is_pms_available(self):
for record in self:
if record.is_pms_available and not record.availability_plan_id:
raise ValidationError(
_(
"If the pricelist is available in the PMS, "
"you must select an availability plan"
)
)
# Action methods
# Constraints and onchanges
# @api.constrains("pricelist_type", "pms_property_ids")
# def _check_pricelist_type_property_ids(self):
# for record in self:
# if record.pricelist_type == "daily" and len(record.pms_property_ids) != 1:
# raise ValidationError(
# _(
# "A daily pricelist is used as a daily Rate Plan "
# "for room types and therefore must be related with "
# "one and only one property."
# )
# )
# if record.pricelist_type == "daily" and len(record.pms_property_ids) == 1:
# pms_property_id = (
# self.env["pms.property"].search(
# [("default_pricelist_id", "=", record.id)]
# )
# or None
# )
# if pms_property_id and pms_property_id != record.pms_property_ids:
# raise ValidationError(
# _("Relationship mismatch.")
# + " "
# + _(
# "This pricelist is used as default in a "
# "different property."
# )
# )
def open_massive_changes_wizard(self):
if self.ensure_one():
return {
"view_type": "form",
"view_mode": "form",
"name": "Massive changes on Pricelist: " + self.name,
"res_model": "pms.massive.changes.wizard",
"target": "new",
"type": "ir.actions.act_window",
"context": {
"pricelist_id": self.id,
},
}