mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[DONE] consider SALE dates & OVERNIGHT dates on pricelist items (#38)
* [FIX] pms: fix timezones (test,compute & create) @ massive changes * [REF] pms: fiels date_start/end_overnight (pricelist_items) * [IMP] pms: SQL to consider overnight dates and priorize items (_compute_price_rule_get_items) * [REF] pms: add tests for overnight dates and unify test cases with subtests * [FIX] pms: fix apply partially pricelist items on several reservation lines * [FIX] pms: consider services to priorize pricelists * [FIX] test pricelist priority without taxs Co-authored-by: Darío Lodeiros <dario@commitsun.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from . import pms_room_type
|
||||
from . import pms_service
|
||||
from . import account_move
|
||||
from . import product_template
|
||||
from . import product_product
|
||||
from . import res_company
|
||||
from . import account_payment
|
||||
from . import pms_room_type_availability_plan
|
||||
|
||||
@@ -468,8 +468,18 @@ class PmsReservation(models.Model):
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
date_order = fields.Date(
|
||||
compute="_compute_pms_creation_date",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
# Compute and Search methods
|
||||
|
||||
def _compute_pms_creation_date(self):
|
||||
for record in self:
|
||||
record.date_order = datetime.datetime.today()
|
||||
|
||||
@api.depends("checkin", "checkout", "room_type_id")
|
||||
def _compute_name(self):
|
||||
for reservation in self:
|
||||
|
||||
@@ -275,7 +275,8 @@ class PmsReservationLine(models.Model):
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=line.date,
|
||||
date=line.reservation_id.date_order,
|
||||
date_overnight=line.date,
|
||||
pricelist=reservation.pricelist_id.id,
|
||||
uom=product.uom_id.id,
|
||||
property=reservation.pms_property_id.id,
|
||||
|
||||
@@ -65,27 +65,67 @@ class ProductPricelist(models.Model):
|
||||
def _compute_price_rule_get_items(
|
||||
self, products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
|
||||
):
|
||||
items = super(ProductPricelist, self)._compute_price_rule_get_items(
|
||||
products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
|
||||
)
|
||||
# Discard the rules with defined properties other than the context,
|
||||
# and we reorder the rules to return the most concrete property rule first
|
||||
if "property" in self._context:
|
||||
items_filtered = items.filtered(
|
||||
lambda i: not i.pms_property_ids
|
||||
or self._context["property"] in i.pms_property_ids.ids
|
||||
|
||||
if "property" in self._context and self._context["property"]:
|
||||
self.env["product.pricelist.item"].flush(
|
||||
["price", "currency_id", "company_id"]
|
||||
)
|
||||
reverse_id = items_filtered.sorted(id, reverse=True)
|
||||
return items_filtered.sorted(
|
||||
key=lambda s: (
|
||||
s.applied_on,
|
||||
True if (not s.date_end or not s.date_start) else False,
|
||||
True
|
||||
if (not s.date_end or not s.date_start)
|
||||
else (s.date_end - s.date_start).days,
|
||||
((not s.pms_property_ids, s), len(s.pms_property_ids)),
|
||||
reverse_id,
|
||||
)
|
||||
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 pms_property_product_pricelist_rel cab
|
||||
ON item.pricelist_id = cab.product_pricelist_id
|
||||
LEFT JOIN pms_property_product_pricelist_item_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_overnight IS NULL
|
||||
OR item.date_start_overnight <=%s)
|
||||
AND (item.date_end_overnight IS NULL
|
||||
OR item.date_end_overnight >=%s)
|
||||
GROUP BY item.id
|
||||
ORDER BY item.applied_on,
|
||||
/* REVIEW: priotrity date sale / date overnight */
|
||||
item.date_end - item.date_start ASC,
|
||||
item.date_end_overnight - item.date_start_overnight ASC,
|
||||
NULLIF((SELECT COUNT(1)
|
||||
FROM pms_property_product_pricelist_item_rel l
|
||||
WHERE item.id = l.product_pricelist_item_id)
|
||||
+ (SELECT COUNT(1)
|
||||
FROM pms_property_product_pricelist_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["date_overnight"],
|
||||
self._context["date_overnight"],
|
||||
),
|
||||
)
|
||||
|
||||
item_ids = [x[0] for x in self.env.cr.fetchall()]
|
||||
items = self.env["product.pricelist.item"].browse(item_ids)
|
||||
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
|
||||
|
||||
|
||||
@@ -9,3 +9,11 @@ class ProductPricelistItem(models.Model):
|
||||
pms_property_ids = fields.Many2many(
|
||||
"pms.property", string="Properties", required=False, ondelete="restrict"
|
||||
)
|
||||
date_start_overnight = fields.Date(
|
||||
string="Start Date Overnight",
|
||||
help="Start date to apply daily pricelist items",
|
||||
)
|
||||
date_end_overnight = fields.Date(
|
||||
string="End Date Overnight",
|
||||
help="End date to apply daily pricelist items",
|
||||
)
|
||||
|
||||
17
pms/models/product_product.py
Normal file
17
pms/models/product_product.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
@api.depends_context(
|
||||
"pricelist",
|
||||
"partner",
|
||||
"quantity",
|
||||
"uom",
|
||||
"date",
|
||||
"date_overnight",
|
||||
"no_variant_attributes_price_extra",
|
||||
)
|
||||
def _compute_product_price(self):
|
||||
super(ProductProduct, self)._compute_product_price()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,3 @@
|
||||
# import datetime
|
||||
# from freezegun import freeze_time
|
||||
#
|
||||
import datetime
|
||||
|
||||
from freezegun import freeze_time
|
||||
@@ -246,16 +243,13 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
# expected price
|
||||
expected_price_total = days * price_today * num_double_rooms
|
||||
|
||||
# convert dates to datetimes
|
||||
dates = self.env["pms.folio.wizard"].get_datetime_from_start_end(checkin)
|
||||
|
||||
# set pricelist item for current day
|
||||
product_tmpl_id = self.test_room_type_double.product_id.product_tmpl_id.id
|
||||
pricelist_item = self.env["product.pricelist.item"].create(
|
||||
{
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"date_start": dates[0],
|
||||
"date_end": dates[1],
|
||||
"date_start_overnight": checkin,
|
||||
"date_end_overnight": checkin,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "1_product",
|
||||
"product_tmpl_id": product_tmpl_id,
|
||||
@@ -316,16 +310,13 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
checkout = fields.date.today() + datetime.timedelta(days=1)
|
||||
days = (checkout - checkin).days
|
||||
|
||||
# convert dates to datetimes
|
||||
dates = self.env["pms.folio.wizard"].get_datetime_from_start_end(checkin)
|
||||
|
||||
# set pricelist item for current day
|
||||
product_tmpl_id = self.test_room_type_double.product_id.product_tmpl_id.id
|
||||
pricelist_item = self.env["product.pricelist.item"].create(
|
||||
{
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"date_start": dates[0],
|
||||
"date_end": dates[1],
|
||||
"date_start_overnight": checkin,
|
||||
"date_end_overnight": checkin,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "1_product",
|
||||
"product_tmpl_id": product_tmpl_id,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo import fields
|
||||
@@ -301,16 +300,11 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
|
||||
price = 20
|
||||
min_quantity = 3
|
||||
|
||||
vals = {
|
||||
"pricelist_id": self.test_pricelist,
|
||||
"date_start": datetime.datetime.combine(
|
||||
date_from,
|
||||
datetime.time.min,
|
||||
),
|
||||
"date_end": datetime.datetime.combine(
|
||||
date_to,
|
||||
datetime.time.max,
|
||||
),
|
||||
"date_start": date_from,
|
||||
"date_end": date_to,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "1_product",
|
||||
"product_tmpl_id": self.test_room_type_double.product_id.product_tmpl_id,
|
||||
@@ -330,26 +324,20 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"min_quantity": min_quantity,
|
||||
}
|
||||
).apply_massive_changes()
|
||||
vals["date_start"] = pytz.timezone("Europe/Madrid").localize(vals["date_start"])
|
||||
vals["date_end"] = pytz.timezone("Europe/Madrid").localize(vals["date_end"])
|
||||
vals["date_start_overnight"] = date_from
|
||||
vals["date_end_overnight"] = date_to
|
||||
|
||||
del vals["date_start"]
|
||||
del vals["date_end"]
|
||||
|
||||
# ASSERT
|
||||
for key in vals:
|
||||
with self.subTest(k=key):
|
||||
if key == "date_start" or key == "date_end":
|
||||
self.assertEqual(
|
||||
fields.Datetime.context_timestamp(
|
||||
self.test_pricelist.item_ids[0],
|
||||
self.test_pricelist.item_ids[0][key],
|
||||
),
|
||||
vals[key],
|
||||
"The value of " + key + " is not correctly established",
|
||||
)
|
||||
else:
|
||||
self.assertEqual(
|
||||
self.test_pricelist.item_ids[0][key],
|
||||
vals[key],
|
||||
"The value of " + key + " is not correctly established",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.test_pricelist.item_ids[0][key],
|
||||
vals[key],
|
||||
"The value of " + key + " is not correctly established",
|
||||
)
|
||||
|
||||
@freeze_time("1980-12-01")
|
||||
def test_day_of_week_pricelist_items_create(self):
|
||||
@@ -398,17 +386,12 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
|
||||
# ASSERT
|
||||
pricelist_items = self.test_pricelist.item_ids.sorted(
|
||||
key=lambda s: s.date_start
|
||||
key=lambda s: s.date_start_overnight
|
||||
)
|
||||
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
(
|
||||
fields.Datetime.context_timestamp(
|
||||
pricelist_items[index], pricelist_items[index].date_start
|
||||
)
|
||||
).timetuple()[6]
|
||||
== index
|
||||
pricelist_items[index].date_start_overnight.timetuple()[6] == index
|
||||
and test_case[index],
|
||||
"Rule not created on correct day of week",
|
||||
)
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='date_end']" position="after">
|
||||
<field name="date_start_overnight" />
|
||||
<field name="date_end_overnight" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -18,13 +18,16 @@
|
||||
expr="//field[@name='item_ids']/tree/field[@name='base']"
|
||||
position="after"
|
||||
>
|
||||
<field name="date_start_overnight" />
|
||||
<field name="date_end_overnight" />
|
||||
<field
|
||||
name="pms_property_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
|
||||
</xpath>
|
||||
|
||||
|
||||
<xpath expr="//widget[@name='web_ribbon']" position="after">
|
||||
<div class="oe_button_box " name="button_box">
|
||||
<button
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
@@ -101,13 +99,12 @@ class FolioWizard(models.TransientModel):
|
||||
)
|
||||
|
||||
num_rooms_available_by_date.append(len(rooms_available))
|
||||
datetimes = self.get_datetime_from_start_end(date_iterator)
|
||||
|
||||
pricelist_item = self.env["product.pricelist.item"].search(
|
||||
[
|
||||
("pricelist_id", "=", record.pricelist_id.id),
|
||||
("date_start", ">=", datetimes[0]),
|
||||
("date_end", "<=", datetimes[1]),
|
||||
("date_start_overnight", ">=", date_iterator),
|
||||
("date_end_overnight", "<=", date_iterator),
|
||||
("applied_on", "=", "1_product"),
|
||||
(
|
||||
"product_tmpl_id",
|
||||
@@ -164,27 +161,6 @@ class FolioWizard(models.TransientModel):
|
||||
key=lambda s: s.num_rooms_available, reverse=True
|
||||
)
|
||||
|
||||
@api.model
|
||||
def get_datetime_from_start_end(self, date):
|
||||
tz = "Europe/Madrid"
|
||||
dt_from = datetime.datetime.combine(
|
||||
date,
|
||||
datetime.time.min,
|
||||
)
|
||||
dt_to = datetime.datetime.combine(
|
||||
date,
|
||||
datetime.time.max,
|
||||
)
|
||||
dt_from = pytz.timezone(tz).localize(dt_from)
|
||||
dt_to = pytz.timezone(tz).localize(dt_to)
|
||||
|
||||
dt_from = dt_from.astimezone(pytz.utc)
|
||||
dt_to = dt_to.astimezone(pytz.utc)
|
||||
|
||||
dt_from = dt_from.replace(tzinfo=None)
|
||||
dt_to = dt_to.replace(tzinfo=None)
|
||||
return dt_from, dt_to
|
||||
|
||||
# actions
|
||||
def create_folio(self):
|
||||
for record in self:
|
||||
|
||||
@@ -54,12 +54,6 @@ class AvailabilityWizard(models.TransientModel):
|
||||
string="Total price", default=0, compute="_compute_price_total"
|
||||
)
|
||||
|
||||
splitted_availability = fields.Boolean(
|
||||
compute="_compute_splitted_availability",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.depends("num_rooms_selected", "checkin", "checkout")
|
||||
def _compute_price_total(self):
|
||||
for record in self:
|
||||
@@ -84,16 +78,13 @@ class AvailabilityWizard(models.TransientModel):
|
||||
pricelist=record.folio_wizard_id.pricelist_id.id,
|
||||
)
|
||||
num_rooms_available_by_date.append(len(rooms_available))
|
||||
datetimes = self.env["pms.folio.wizard"].get_datetime_from_start_end(
|
||||
date_iterator
|
||||
)
|
||||
|
||||
# get pricelist item
|
||||
pricelist_item = self.env["product.pricelist.item"].search(
|
||||
[
|
||||
("pricelist_id", "=", record.folio_wizard_id.pricelist_id.id),
|
||||
("date_start", ">=", datetimes[0]),
|
||||
("date_end", "<=", datetimes[1]),
|
||||
("date_start_overnight", ">=", date_iterator),
|
||||
("date_end_overnight", "<=", date_iterator),
|
||||
("applied_on", "=", "1_product"),
|
||||
(
|
||||
"product_tmpl_id",
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
@@ -10,6 +8,12 @@ class AvailabilityWizard(models.TransientModel):
|
||||
_name = "pms.massive.changes.wizard"
|
||||
_description = "Wizard for massive changes on Availability Plans & Pricelists."
|
||||
|
||||
def _default_avail_readonly(self):
|
||||
return True if self._context.get("availability_plan_id") else False
|
||||
|
||||
def _default_pricelist_readonly(self):
|
||||
return True if self._context.get("pricelist_id") else False
|
||||
|
||||
# Fields declaration
|
||||
massive_changes_on = fields.Selection(
|
||||
[("pricelist", "Pricelist"), ("availability_plan", "Availability Plan")],
|
||||
@@ -135,9 +139,10 @@ class AvailabilityWizard(models.TransientModel):
|
||||
store=False,
|
||||
readonly=True,
|
||||
)
|
||||
avail_readonly = fields.Boolean(compute="_compute_avail_readonly")
|
||||
pricelist_readonly = fields.Boolean(compute="_compute_pricelist_readonly")
|
||||
avail_readonly = fields.Boolean(default=_default_avail_readonly)
|
||||
pricelist_readonly = fields.Boolean(default=_default_pricelist_readonly)
|
||||
|
||||
@api.depends("massive_changes_on")
|
||||
def _compute_allowed_pricelist_ids(self):
|
||||
for record in self:
|
||||
record.allowed_pricelist_ids = self.env["product.pricelist"].search(
|
||||
@@ -234,10 +239,10 @@ class AvailabilityWizard(models.TransientModel):
|
||||
]
|
||||
|
||||
if record.start_date:
|
||||
domain.append(("date_start", ">=", record.start_date))
|
||||
|
||||
domain.append(("date_start_overnight", ">=", record.start_date))
|
||||
if record.end_date:
|
||||
domain.append(("date_end", "<=", record.end_date))
|
||||
domain.append(("date_end_overnight", "<=", record.end_date))
|
||||
|
||||
if record.room_type_id:
|
||||
domain.append(
|
||||
(
|
||||
@@ -265,7 +270,9 @@ class AvailabilityWizard(models.TransientModel):
|
||||
and record.end_date
|
||||
):
|
||||
record.pricelist_items_to_overwrite = items.filtered(
|
||||
lambda x: week_days_to_apply[x.date_start.timetuple()[6]]
|
||||
lambda x: week_days_to_apply[
|
||||
x.date_end_overnight.timetuple()[6]
|
||||
]
|
||||
)
|
||||
else:
|
||||
record.pricelist_items_to_overwrite = items
|
||||
@@ -290,21 +297,9 @@ class AvailabilityWizard(models.TransientModel):
|
||||
record.pricelist_items_to_overwrite
|
||||
)
|
||||
|
||||
def _compute_avail_readonly(self):
|
||||
for record in self:
|
||||
record.avail_readonly = (
|
||||
True if self._context.get("availability_plan_id") else False
|
||||
)
|
||||
|
||||
def _compute_pricelist_readonly(self):
|
||||
for record in self:
|
||||
record.pricelist_readonly = (
|
||||
True if self._context.get("pricelist_id") else False
|
||||
)
|
||||
|
||||
# actions
|
||||
def apply_massive_changes(self):
|
||||
tz = "Europe/Madrid"
|
||||
|
||||
for record in self:
|
||||
# remove old rules
|
||||
record.rules_to_overwrite.unlink()
|
||||
@@ -336,33 +331,13 @@ class AvailabilityWizard(models.TransientModel):
|
||||
else:
|
||||
rooms = [record.room_type_id]
|
||||
for room in rooms:
|
||||
# REVIEW -> maybe would be more efficient creating a list
|
||||
# and write all data in 1 operation
|
||||
if record.massive_changes_on == "pricelist":
|
||||
|
||||
dt_from = datetime.datetime.combine(
|
||||
date,
|
||||
datetime.time.min,
|
||||
)
|
||||
dt_to = datetime.datetime.combine(
|
||||
date,
|
||||
datetime.time.max,
|
||||
)
|
||||
|
||||
dt_from = pytz.timezone(tz).localize(dt_from)
|
||||
dt_to = pytz.timezone(tz).localize(dt_to)
|
||||
|
||||
dt_from = dt_from.astimezone(pytz.utc)
|
||||
dt_to = dt_to.astimezone(pytz.utc)
|
||||
|
||||
dt_from = dt_from.replace(tzinfo=None)
|
||||
dt_to = dt_to.replace(tzinfo=None)
|
||||
|
||||
self.env["product.pricelist.item"].create(
|
||||
{
|
||||
"pricelist_id": record.pricelist_id.id,
|
||||
"date_start": dt_from,
|
||||
"date_end": dt_to,
|
||||
"date_start_overnight": date,
|
||||
"date_end_overnight": date,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "1_product",
|
||||
"product_tmpl_id": room.product_id.product_tmpl_id.id,
|
||||
@@ -370,7 +345,6 @@ class AvailabilityWizard(models.TransientModel):
|
||||
"min_quantity": record.min_quantity,
|
||||
}
|
||||
)
|
||||
|
||||
else:
|
||||
self.env["pms.room.type.availability.rule"].create(
|
||||
{
|
||||
@@ -388,5 +362,23 @@ class AvailabilityWizard(models.TransientModel):
|
||||
"closed_departure": record.closed_departure,
|
||||
}
|
||||
)
|
||||
|
||||
# return {}
|
||||
if (
|
||||
record.massive_changes_on == "pricelist"
|
||||
and not record.pricelist_readonly
|
||||
):
|
||||
action = self.env.ref("product.product_pricelist_action2").read()[0]
|
||||
action["views"] = [
|
||||
(self.env.ref("pms.product_pricelist_view_form").id, "form")
|
||||
]
|
||||
action["res_id"] = record.pricelist_id.id
|
||||
return action
|
||||
if (
|
||||
record.massive_changes_on == "availability_plan"
|
||||
and not record.avail_readonly
|
||||
):
|
||||
action = self.env.ref("pms.room_type_availability_action").read()[0]
|
||||
action["views"] = [
|
||||
(self.env.ref("pms.room_type_availability_view_form").id, "form")
|
||||
]
|
||||
action["res_id"] = record.availability_plan_id.id
|
||||
return action
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
<div class="col-4">
|
||||
<group>
|
||||
<field name="price" />
|
||||
<field name="min_quantity" />
|
||||
<!-- REVIEW 'min_quantity'-->
|
||||
<!--<field name="min_quantity" />-->
|
||||
</group>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,21 +200,28 @@
|
||||
>
|
||||
<span style="text-decoration:underline;">
|
||||
<field name="num_pricelist_items_to_overwrite" />
|
||||
|
||||
</span>
|
||||
pricelist items
|
||||
<u>will be overwritten:</u>
|
||||
</b>
|
||||
|
||||
|
||||
<!-- REVIEW: a calendar view could be more understandable -->
|
||||
<field
|
||||
name="rules_to_overwrite"
|
||||
attrs="{'invisible':[('massive_changes_on','=','pricelist')]}"
|
||||
/>
|
||||
<field
|
||||
name="pricelist_items_to_overwrite"
|
||||
nolabel="1"
|
||||
attrs="{'invisible':[('massive_changes_on','=','availability_plan')]}"
|
||||
/>
|
||||
>
|
||||
<tree>
|
||||
<field name="pricelist_id" />
|
||||
<field string="Applicable on" name="name" />
|
||||
<field name="date_start_overnight" />
|
||||
<field name="date_end_overnight" />
|
||||
<field name="price" />
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
<button
|
||||
name="apply_massive_changes"
|
||||
|
||||
Reference in New Issue
Block a user