Fix minor
This commit is contained in:
parent
ec530288c8
commit
ac86efac4d
152
booking.py
152
booking.py
|
@ -8,38 +8,35 @@ from trytond.wizard import (
|
|||
Wizard, StateView, Button, StateTransition, StateReport
|
||||
)
|
||||
from trytond.report import Report
|
||||
from trytond.pyson import Eval, If, In, Get, Not, Or, Equal, Bool
|
||||
from trytond.pyson import Eval, If, In, Get, Bool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.i18n import gettext
|
||||
from trytond.modules.account.tax import TaxableMixin
|
||||
from .constants import (
|
||||
STATE_BOOKING, REGISTRATION_STATE, REASON, GUARANTEE, SATISFACTION,
|
||||
MEDIA, PLAN, INVOICE_METHOD, COMPLEMENTARY, PAYMENT_METHOD_CHANNEL,
|
||||
TYPE_DOCUMENT
|
||||
STATE_BOOKING, REASON, GUARANTEE, SATISFACTION, MEDIA, PLAN,
|
||||
COMPLEMENTARY, PAYMENT_METHOD_CHANNEL, TYPE_DOCUMENT
|
||||
)
|
||||
|
||||
SEPARATOR = ' | '
|
||||
_ZERO = Decimal('0.0')
|
||||
|
||||
STATES = {
|
||||
'readonly': Eval('state') != 'offer',
|
||||
}
|
||||
|
||||
NO_CHANGES = ['finished', 'cancelled', 'not_show']
|
||||
|
||||
STATES_BLOCKED = {
|
||||
'readonly': Eval('state').in_(NO_CHANGES),
|
||||
}
|
||||
|
||||
STATES_CONFIRMED = {
|
||||
'readonly': Eval('state') != 'offer',
|
||||
'required': Eval('state') == 'confirmed',
|
||||
}
|
||||
|
||||
STATES_CHECKIN = {
|
||||
'readonly': Eval('registration_state').in_(
|
||||
['check_in', 'no_show', 'cancelled']
|
||||
),
|
||||
'required': Eval('registration_state') == 'check_in',
|
||||
}
|
||||
|
||||
_ZERO = Decimal('0.0')
|
||||
|
||||
|
||||
class Booking(Workflow, ModelSQL, ModelView):
|
||||
'Booking'
|
||||
|
@ -48,44 +45,35 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
number = fields.Char('Number', readonly=True, select=True,
|
||||
help="Sequence of reservation.")
|
||||
party = fields.Many2One('party.party', 'Customer', required=False,
|
||||
select=True, help="Person or company owner of the booking.",
|
||||
states={
|
||||
# 'required': Eval('state') == 'check_in',
|
||||
'readonly': Not(In(Eval('state'), ['offer', 'confirmed'])),
|
||||
})
|
||||
contact = fields.Char('Contact', states=STATES_CHECKIN,
|
||||
select=True, states=STATES_BLOCKED,
|
||||
help="Person or company owner of the booking.")
|
||||
contact = fields.Char('Contact', states=STATES_BLOCKED,
|
||||
help='Main contact or person how request booking')
|
||||
payment_term = fields.Many2One('account.invoice.payment_term',
|
||||
'Payment Term', states=STATES_CHECKIN)
|
||||
booking_date = fields.DateTime('Booking Date', readonly=False, states=STATES)
|
||||
'Payment Term', states=STATES_BLOCKED)
|
||||
booking_date = fields.DateTime('Booking Date', readonly=True)
|
||||
guests_num = fields.Function(fields.Integer('Person Number'),
|
||||
'get_person_num')
|
||||
adult_num = fields.Function(fields.Integer('Adult Number'),
|
||||
'get_person_num')
|
||||
children_num = fields.Function(fields.Integer('Children Number'),
|
||||
'get_person_num')
|
||||
group = fields.Boolean('Group', states=STATES)
|
||||
complementary = fields.Boolean('Complementary', states=STATES)
|
||||
group = fields.Boolean('Group', states=STATES_BLOCKED)
|
||||
complementary = fields.Boolean('Complementary', states=STATES_BLOCKED)
|
||||
type_complementary = fields.Selection(COMPLEMENTARY, 'Type Complementary',
|
||||
states={
|
||||
'invisible': ~Bool(Eval('complementary')),
|
||||
'required': Bool(Eval('complementary')),
|
||||
})
|
||||
states=STATES_BLOCKED)
|
||||
channel = fields.Many2One('hotel.channel', 'Channel',
|
||||
states={
|
||||
'invisible': Eval('media') != 'ota',
|
||||
'readonly': Eval('state').in_(['confirmed', 'cancelled']),
|
||||
'readonly': Eval('state').in_(['finished', 'cancelled']),
|
||||
},
|
||||
help="Agency or channel that do reservation.")
|
||||
state = fields.Selection(STATE_BOOKING, 'State', readonly=True,
|
||||
required=True)
|
||||
registration_state = fields.Selection(REGISTRATION_STATE, 'State Registration',
|
||||
readonly=True, depends=['lines'])
|
||||
state_string = state.translated('state')
|
||||
price_list = fields.Many2One('product.price_list', 'Price List',
|
||||
states={
|
||||
'readonly': Or(Not(Equal(Eval('state'), 'offer')),
|
||||
Bool(Eval('lines'))),
|
||||
'readonly': Bool(Eval('lines')),
|
||||
}, depends=['state', 'company', 'lines'])
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
states=STATES, domain=[('id', If(In('company',
|
||||
|
@ -94,28 +82,26 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
lines = fields.One2Many('hotel.folio', 'booking', 'Folios',
|
||||
states={
|
||||
'required': Eval('state') == 'confirmed',
|
||||
'readonly': Eval('registration_state').in_(['check_in', 'check_out']),
|
||||
'readonly': Eval('state').in_(['finished', 'cancelled']),
|
||||
}, depends=['state', 'party'], context={'party': Eval('party')})
|
||||
cancellation_policy = fields.Many2One('hotel.policy.cancellation',
|
||||
'Cancellation Policy', states=STATES_CHECKIN)
|
||||
'Cancellation Policy', states=STATES_BLOCKED)
|
||||
currency = fields.Many2One('currency.currency', 'Currency',
|
||||
required=True, states={
|
||||
'readonly': (Eval('state') != 'offer') |
|
||||
(Eval('lines', [0]) & Eval('currency', 0)),
|
||||
}, depends=['state'])
|
||||
invoice_method = fields.Selection(INVOICE_METHOD, 'Invoice Method',
|
||||
required=False, states=STATES_CONFIRMED)
|
||||
satisfaction = fields.Selection(SATISFACTION, 'Satisfaction')
|
||||
media = fields.Selection(MEDIA, 'Media', states=STATES_CHECKIN,
|
||||
media = fields.Selection(MEDIA, 'Media', states=STATES_BLOCKED,
|
||||
help="Way through which the booking arrives.")
|
||||
media_string = media.translated('media')
|
||||
plan = fields.Selection(PLAN, 'Commercial Plan', states=STATES_CHECKIN,
|
||||
plan = fields.Selection(PLAN, 'Commercial Plan', states=STATES_BLOCKED,
|
||||
help="Plans offered by hotel and selected by guest for booking.")
|
||||
plan_string = plan.translated('plan')
|
||||
comments = fields.Text('Comments', states=STATES_CHECKIN)
|
||||
reason = fields.Selection(REASON, 'Tourism Segment', states=STATES_CHECKIN)
|
||||
comments = fields.Text('Comments', states=STATES_BLOCKED)
|
||||
reason = fields.Selection(REASON, 'Tourism Segment', states=STATES_BLOCKED)
|
||||
reason_string = reason.translated('segment')
|
||||
guarantee = fields.Selection(GUARANTEE, 'Guarantee', states=STATES_CHECKIN)
|
||||
guarantee = fields.Selection(GUARANTEE, 'Guarantee', states=STATES_BLOCKED)
|
||||
guarantee_string = guarantee.translated('guarantee')
|
||||
untaxed_amount = fields.Function(fields.Numeric('Untaxed Amount',
|
||||
digits=(16, 2), depends=['lines']), 'get_untaxed_amount')
|
||||
|
@ -126,27 +112,29 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
collect_amount = fields.Function(fields.Numeric('Collect Amount',
|
||||
digits=(16, 2), depends=['lines']), 'get_collect_amount')
|
||||
code = fields.Char('Code', states={'readonly': True})
|
||||
booker = fields.Many2One('party.party', 'Booker', states={'readonly': True})
|
||||
created_channel = fields.DateTime('Created Channel', states={'readonly': True})
|
||||
booker = fields.Many2One('party.party', 'Booker',
|
||||
states={'readonly': True})
|
||||
created_channel = fields.DateTime('Created Channel',
|
||||
states={'readonly': True})
|
||||
vouchers = fields.Many2Many('hotel.booking-account.voucher', 'booking',
|
||||
'voucher', 'Vouchers', states={'readonly': False})
|
||||
ota_booking_code = fields.Char('OTA Code', select=True,
|
||||
states={'invisible': Eval('media') != 'ota'}
|
||||
)
|
||||
payments = fields.One2Many('account.statement.line', 'source',
|
||||
'Payments', states=STATES_CHECKIN, readonly=True)
|
||||
vehicles_num = fields.Integer('Vehicles Number', states=STATES,
|
||||
'Payments', states=STATES_BLOCKED, readonly=True)
|
||||
vehicles_num = fields.Integer('Vehicles Number', states=STATES_BLOCKED,
|
||||
help="Number of vehicles that bring with guests.")
|
||||
travel_cause = fields.Char('Travel Cause', states=STATES)
|
||||
taxes_exception = fields.Boolean('Taxes Exception', states=STATES)
|
||||
travel_cause = fields.Char('Travel Cause', states=STATES_BLOCKED)
|
||||
taxes_exception = fields.Boolean('Taxes Exception', states=STATES_BLOCKED)
|
||||
total_advances = fields.Function(fields.Numeric('Total Advance',
|
||||
digits=(16, 2)), 'get_total_advances')
|
||||
pending_to_pay = fields.Function(fields.Numeric('Pending to Pay',
|
||||
digits=(16, 2)), 'get_pending_to_pay')
|
||||
breakfast_included = fields.Boolean('Breakfast Included')
|
||||
breakfast_included = fields.Boolean('Breakfast Included',
|
||||
states=STATES_BLOCKED)
|
||||
channel_commission = fields.Function(fields.Numeric('Channel Commission',
|
||||
digits=(16, 2), depends=['lines']), 'get_channel_commission')
|
||||
offset_move = fields.Many2One('account.move', 'Offset Move')
|
||||
commission = fields.Many2One('commission', 'Commission')
|
||||
channel_invoice = fields.Many2One('account.invoice', 'Channel Invoice',
|
||||
states={
|
||||
|
@ -162,7 +150,7 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
extra_commissions = fields.Many2Many('hotel.booking-channel.commission',
|
||||
'booking', 'commission', 'Channel Commission', domain=[
|
||||
('channel', '=', Eval('channel'))
|
||||
])
|
||||
], states=STATES_BLOCKED)
|
||||
stock_moves = fields.Function(fields.One2Many('stock.move', 'origin', 'Moves',
|
||||
readonly=True), 'get_stock_moves')
|
||||
channel_icon = fields.Function(fields.Char('Channel Icon'),
|
||||
|
@ -173,9 +161,12 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
('holder', 'Holder'),
|
||||
('holder_guest', 'Holder / Guest'),
|
||||
('guest', 'Guest'),
|
||||
], 'Responsible for Payment', states={'required': True})
|
||||
credit_card = fields.Char('Credit Card', states=STATES)
|
||||
vip = fields.Boolean('V.I.P. Customer', states=STATES)
|
||||
], 'Responsible for Payment', states={
|
||||
'required': True,
|
||||
'readonly': Eval('state').in_(NO_CHANGES),
|
||||
})
|
||||
credit_card = fields.Char('Credit Card', states=STATES_BLOCKED)
|
||||
vip = fields.Boolean('V.I.P. Customer', states=STATES_BLOCKED)
|
||||
pending_acco = fields.Function(fields.Numeric('Pending to Pay',
|
||||
digits=(16, 2)), 'get_pending_to_pay')
|
||||
pending_charges = fields.Function(fields.Numeric('Pending to Pay',
|
||||
|
@ -197,16 +188,13 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
))
|
||||
cls._buttons.update({
|
||||
'select_rooms': {
|
||||
'invisible': Eval('state').in_(
|
||||
['finished', 'cancelled', 'not_show']),
|
||||
'invisible': Eval('state').in_(NO_CHANGES),
|
||||
},
|
||||
'update_holder': {
|
||||
'invisible': Eval('state').in_(
|
||||
['finished', 'cancelled', 'not_show']),
|
||||
'invisible': Eval('state').in_(NO_CHANGES),
|
||||
},
|
||||
'cancel': {
|
||||
'invisible': Eval('state').in_(
|
||||
['cancelled', 'not_show', 'finished'])
|
||||
'invisible': Eval('state').in_(NO_CHANGES)
|
||||
},
|
||||
'offer': {
|
||||
'invisible': Eval('state').in_(['offer', 'finished'])
|
||||
|
@ -218,20 +206,17 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
'invisible': Eval('state') != 'confirmed',
|
||||
},
|
||||
'do_payment': {
|
||||
'invisible': Eval('state').in_(['offer', 'cancelled']),
|
||||
'invisible': Eval('state').in_(NO_CHANGES),
|
||||
},
|
||||
'send_email_booking': {
|
||||
'invisible': Eval('state') != 'confirmed'
|
||||
'invisible': Eval('state').in_(['finished'])
|
||||
},
|
||||
'send_email_checkin': {
|
||||
'invisible': Eval('state') != 'confirmed'
|
||||
'invisible': Eval('state').in_(['finished'])
|
||||
},
|
||||
'bill': {
|
||||
'invisible': ~Eval('state').in_(['confirmed', 'not_show']),
|
||||
},
|
||||
'bill_to_channel': {
|
||||
'invisible': ~Eval('channel'),
|
||||
},
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
|
@ -315,10 +300,6 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
def default_plan():
|
||||
return 'bed_breakfast'
|
||||
|
||||
@staticmethod
|
||||
def default_invoice_method():
|
||||
return 'by_booking'
|
||||
|
||||
@staticmethod
|
||||
def default_booking_date():
|
||||
now = datetime.now()
|
||||
|
@ -399,7 +380,7 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
|
||||
def is_person(self):
|
||||
if self.party.type_document in (
|
||||
'12', '13', '21', '22', '41', '42', '47'):
|
||||
'12', '13', '21', '22', '41', '42', '47'):
|
||||
return True
|
||||
|
||||
@fields.depends('party', 'price_list', 'lines')
|
||||
|
@ -417,8 +398,6 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
if self.channel:
|
||||
if self.channel.invoice_to == 'channel':
|
||||
self.party = self.channel.agent.party.id
|
||||
elif self.channel.invoice_to == 'customer':
|
||||
self.party = None
|
||||
if self.channel.payment_method == 'ota_collect':
|
||||
self.responsible_payment = 'holder'
|
||||
if self.channel.price_list:
|
||||
|
@ -476,8 +455,7 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
@ModelView.button
|
||||
def no_show(cls, records):
|
||||
for record in records:
|
||||
cls.write([record], {'registration_state': 'no_show'})
|
||||
record.cancel_occupancy()
|
||||
cls.write([record], {'state': 'no_show'})
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
|
@ -489,12 +467,6 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
@classmethod
|
||||
@ModelView.button_action('hotel.wizard_bill_booking')
|
||||
def bill(cls, records):
|
||||
# cls.bill_to_channel(records)
|
||||
# for rec in records:
|
||||
# cls.create_invoice(rec.lines)
|
||||
# # rec.add_payments_invoice()
|
||||
# cls.concile_charges(records)
|
||||
# cls.check_finished(records)
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
|
@ -536,20 +508,11 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
Voucher.process([voucher])
|
||||
cls.write([bk], {'vouchers': [('add', [voucher])]})
|
||||
|
||||
@classmethod
|
||||
def bill_to_channel(cls, records):
|
||||
for rec in records:
|
||||
if rec.channel_invoice or not rec.channel or \
|
||||
rec.channel.collection_mode != 'anticipated':
|
||||
continue
|
||||
cls.create_channel_invoice(rec)
|
||||
# cls.create_channel_pay(rec)
|
||||
|
||||
@classmethod
|
||||
def concile_charges(cls, records):
|
||||
'''
|
||||
We need mark charges pending to pay as paid, if the customer
|
||||
already paid all booking
|
||||
already paid all booking charges
|
||||
'''
|
||||
for booking in records:
|
||||
if booking.pending_to_pay != 0:
|
||||
|
@ -612,9 +575,7 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
if payments:
|
||||
invoice.add_payment_lines({invoice: payments})
|
||||
invoice.save()
|
||||
# to_reconcile_lines.extend(payments)
|
||||
if invoice.amount_to_pay == Decimal(0):
|
||||
# invoice.paid([invoice])
|
||||
for ml in invoice.payment_lines:
|
||||
if not ml.reconciliation:
|
||||
to_reconcile_lines.append(ml)
|
||||
|
@ -1036,8 +997,10 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
Folio.write(list(self.lines), {'registration_state': state})
|
||||
|
||||
@classmethod
|
||||
def get_context_price(cls, product, party=None, currency=None,
|
||||
_date=None, price_list=None, taxes_exception=False):
|
||||
def get_context_price(
|
||||
cls, product, party=None, currency=None,
|
||||
_date=None, price_list=None, taxes_exception=False
|
||||
):
|
||||
context = {}
|
||||
if currency:
|
||||
context['currency'] = currency.id
|
||||
|
@ -1130,7 +1093,6 @@ class Booking(Workflow, ModelSQL, ModelView):
|
|||
def get_channel_commission(self, name):
|
||||
res = [line.commission_amount
|
||||
for line in self.lines if line.commission_amount]
|
||||
# total_commission = sum(res)
|
||||
base_comm = [folio.on_change_with_room_amount() for folio in self.lines]
|
||||
for comm in self.extra_commissions:
|
||||
extras = sum(base_comm) * Decimal(comm.commission / 100)
|
||||
|
|
12
booking.xml
12
booking.xml
|
@ -59,13 +59,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="count" eval="True"/>
|
||||
<field name="act_window" ref="act_booking_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.domain" id="act_booking_form_domain_not_confirmed">
|
||||
<field name="name">Not Confirmed</field>
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="domain" eval="[('state', '=', 'not_confirmed')]" pyson="1"/>
|
||||
<field name="count" eval="True"/>
|
||||
<field name="act_window" ref="act_booking_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.domain" id="act_booking_form_domain_confirmed">
|
||||
<field name="name">Confirmed</field>
|
||||
<field name="sequence" eval="20"/>
|
||||
|
@ -74,11 +67,10 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="act_window" ref="act_booking_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.domain" id="act_booking_form_domain_no_show">
|
||||
<field name="name">No Show</field>
|
||||
<field name="name">No Show / Cancelled</field>
|
||||
<field name="sequence" eval="50"/>
|
||||
<field name="domain" eval="['OR',
|
||||
[('registration_state', '=', 'no_show')],
|
||||
[('state', '=', 'cancelled')]
|
||||
[('state', 'in', ['cancelled', 'not_show'])]
|
||||
]" pyson="1"/>
|
||||
<field name="count" eval="True"/>
|
||||
<field name="act_window" ref="act_booking_form"/>
|
||||
|
|
|
@ -70,11 +70,6 @@ PLAN = [
|
|||
('half_american', 'Half American'),
|
||||
]
|
||||
|
||||
INVOICE_METHOD = [
|
||||
('by_booking', 'By Booking'),
|
||||
('by_main_guest', 'By Main Guest'),
|
||||
]
|
||||
|
||||
COMPLEMENTARY = [
|
||||
('', ''),
|
||||
('in_house', 'In House'),
|
||||
|
|
Binary file not shown.
1
room.py
1
room.py
|
@ -90,6 +90,7 @@ class Room(Workflow, ModelSQL, ModelView):
|
|||
('inspected', 'maintenance'),
|
||||
('inspected', 'clean'),
|
||||
))
|
||||
cls._order = [('code', 'DESC')]
|
||||
cls._buttons.update({
|
||||
'clean': {
|
||||
'invisible': Eval('state').in_(['maintenance', 'clean']),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[tryton]
|
||||
version=6.0.43
|
||||
version=6.0.44
|
||||
depends:
|
||||
party
|
||||
company
|
||||
|
|
|
@ -33,9 +33,11 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<button name="select_rooms" string="Rooms" icon="tryton-board"/>
|
||||
<button name="send_email_booking" string="Send Email" icon="tryton-email"/>
|
||||
</group>
|
||||
<group col="4" id="add_info_group_taxes" colspan="2">
|
||||
<group col="6" id="add_info_group_taxes" colspan="2">
|
||||
<label name="group"/>
|
||||
<field name="group"/>
|
||||
<label name="vip"/>
|
||||
<field name="vip"/>
|
||||
<label name="taxes_exception"/>
|
||||
<field name="taxes_exception"/>
|
||||
</group>
|
||||
|
@ -77,10 +79,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="cancellation_policy" widget="selection"/>
|
||||
<label name="vehicles_num"/>
|
||||
<field name="vehicles_num"/>
|
||||
<label name="vip"/>
|
||||
<field name="vip"/>
|
||||
<label name="group"/>
|
||||
<field name="group"/>
|
||||
<newline/>
|
||||
<separator name="comments" colspan="4"/>
|
||||
<field name="comments" colspan="4"/>
|
||||
|
@ -96,8 +94,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="channel_commission"/>
|
||||
<label name="channel_invoice"/>
|
||||
<field name="channel_invoice"/>
|
||||
<label name="offset_move"/>
|
||||
<field name="offset_move"/>
|
||||
<field name="extra_commissions" colspan="4"/>
|
||||
</page>
|
||||
<page string="Notifications" id="notifications">
|
||||
|
|
|
@ -14,8 +14,6 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="location"/>
|
||||
<label name="space"/>
|
||||
<field name="space"/>
|
||||
<label name="channel_id"/>
|
||||
<field name="channel_id"/>
|
||||
<label name="main_accommodation"/>
|
||||
<field name="main_accommodation" widget="selection"/>
|
||||
<label name="max_accommodation"/>
|
||||
|
@ -24,7 +22,8 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="min_unit_price"/>
|
||||
<label name="max_unit_price"/>
|
||||
<field name="max_unit_price"/>
|
||||
<newline/>
|
||||
<label name="channel_id"/>
|
||||
<field name="channel_id"/>
|
||||
<field name="templates" colspan="2"
|
||||
view_ids="product.template_view_tree"/>
|
||||
<field name="amenities" colspan="2"
|
||||
|
|
Loading…
Reference in New Issue