Refactory 06

This commit is contained in:
Oscar 2021-10-09 12:00:26 -05:00
parent 27151e1bb4
commit c25314760c
9 changed files with 780 additions and 811 deletions

View File

@ -5,7 +5,7 @@ from . import location
from . import configuration
from . import room
from . import booking
from . import operation
from . import folio
from . import housekeeping
from . import company
from . import city
@ -31,18 +31,17 @@ def register():
product.PriceList,
city.MigrationCity,
booking.Booking,
booking.Folio,
booking.BookingDailyStart,
configuration.ConfigurationProduct,
housekeeping.Housekeeping,
housekeeping.HousekeepingCleaningType,
company.Company,
operation.FolioCharge,
# operation.Operation,
# operation.OperationMaintenance,
# operation.OperationGuest,
# operation.TransferOperationStart,
# operation.TransferChargeStart,
folio.Folio,
folio.FolioCharge,
# folio.folioMaintenance,
# folio.folioGuest,
# folio.TransferfolioStart,
# folio.TransferChargeStart,
party.Party,
channel.ChannelTax,
booking.Guest,
@ -50,11 +49,11 @@ def register():
booking.BookingVoucher,
booking.RoomsOccupancyStart,
booking.BookingForecastStart,
# operation.OpenMigrationStart,
# operation.CheckOutOperationFailed,
# operation.ChangeRoomStart,
# operation.OperationVoucher,
# operation.StatisticsByMonthStart,
# folio.OpenMigrationStart,
# folio.CheckOutfolioFailed,
# folio.ChangeRoomStart,
# folio.folioVoucher,
# folio.StatisticsByMonthStart,
sale.InvoiceIncomeDailyStart,
service.Service,
service.ServiceLine,
@ -72,10 +71,10 @@ def register():
booking.BookingForecastReport,
booking.RoomsOccupancyReport,
booking.BookingDailyReport,
# operation.Migration,
# operation.OperationReport,
# operation.OperationByConsumerReport,
# operation.StatisticsByMonthReport,
# folio.Migration,
# folio.folioReport,
# folio.folioByConsumerReport,
# folio.StatisticsByMonthReport,
sale.InvoiceIncomeDailyReport,
sale.InvoiceSimplifiedReport,
service.ServiceReport,
@ -88,13 +87,13 @@ def register():
booking.BookingForecast,
booking.RoomsOccupancy,
booking.BookingDaily,
# operation.OpenMigration,
# operation.CheckOutOperation,
# operation.OperationBill,
# operation.ChangeRoom,
# operation.TransferOperation,
# operation.TransferCharge,
# operation.StatisticsByMonth,
# folio.OpenMigration,
# folio.CheckOutfolio,
# folio.folioBill,
# folio.ChangeRoom,
# folio.Transferfolio,
# folio.TransferCharge,
# folio.StatisticsByMonth,
service.CreateDailyServices,
housekeeping.HousekeepingService,
booking.GuestsList,

Binary file not shown.

View File

@ -125,10 +125,10 @@ class Booking(Workflow, ModelSQL, ModelView):
vehicle_plate = fields.Integer('Vehicle Plate', states=STATES)
travel_cause = fields.Char('Travel Cause', states=STATES)
taxes_exception = fields.Boolean('Taxes Exception', states=STATES)
total_advance = fields.Function(fields.Numeric('Total Advance'),
'get_total_advance')
pending_to_pay = fields.Function(fields.Numeric('Pending to Pay'),
'get_pending_to_pay')
total_advance = fields.Function(fields.Numeric('Total Advance',
digits=(16, 2)), 'get_total_advance')
pending_to_pay = fields.Function(fields.Numeric('Pending to Pay',
digits=(16, 2)),'get_pending_to_pay')
breakfast_included = fields.Boolean('Breakfast Included')
@classmethod
@ -137,13 +137,11 @@ class Booking(Workflow, ModelSQL, ModelView):
cls._order.insert(0, ('create_date', 'DESC'))
cls._transitions |= set((
('offer', 'confirmed'),
('confirmed', 'offer'),
('offer', 'not_confirmed'),
('offer', 'cancelled'),
('confirmed', 'offer'),
('cancelled', 'offer'),
('confirmed', 'cancelled'),
('not_confirmed', 'confirmed'),
('not_confirmed', 'cancelled'),
('confirmed', 'not_show'),
))
cls._buttons.update({
'select_rooms': {
@ -153,30 +151,16 @@ class Booking(Workflow, ModelSQL, ModelView):
'invisible': Eval('state') != 'offer',
},
'cancel': {
'invisible': Eval('state').in_(['cancel', '']) and
Eval('registration_state') == 'check_out',
'invisible': Eval('state').in_(['cancel', ''])
},
'offer': {
'invisible': Eval('state').in_(['offer', 'confirmed'])
or Eval('registration_state').in_(['check_in', 'check_out']),
},
'confirm': {
'invisible': ~Eval('state').in_(['offer', 'not_confirmed'])
'invisible': ~Eval('state').in_(['offer', 'not_show'])
},
'not_confirm': {
'invisible': Eval('state') != 'offer',
},
'check_in': {
'invisible': Eval('state') != 'confirmed' and
Eval('registration_state').in_(['check_in', 'check_out']),
},
'no_show': {
'invisible': Eval('state') != 'confirmed' and
Eval('registration_state').in_(['check_in', 'check_out']),
},
'check_out': {
'invisible': Eval('state') != 'confirmed' and
Eval('registration_state') == 'check_out',
'not_show': {
'invisible': Eval('state') != 'confirmed',
},
'pay_advance': {
'invisible':
@ -276,8 +260,8 @@ class Booking(Workflow, ModelSQL, ModelView):
@classmethod
@ModelView.button
@Workflow.transition('not_confirmed')
def not_confirm(cls, records):
@Workflow.transition('not_show')
def not_show(cls, records):
pass
@classmethod
@ -446,611 +430,6 @@ class Booking(Workflow, ModelSQL, ModelView):
self.breakfast_included = self.price_list.breakfast_included
class Folio(ModelSQL, ModelView):
'Folio'
__name__ = 'hotel.folio'
booking = fields.Many2One('hotel.booking', 'Booking', ondelete='CASCADE',
select=True)
registration_card = fields.Char('Registration Card', readonly=True,
select=True, help="Unique sequence for card guest registration.")
room = fields.Many2One('hotel.room', 'Room', select=True, states={
'required': Eval('registration_state') == 'check_in',
'readonly': Eval('registration_state') == 'check_in',
})
arrival_date = fields.Date('Arrival Date', required=True,
states=STATES_CHECKIN)
departure_date = fields.Date('Departure Date', required=True,
states=STATES_CHECKIN)
product = fields.Many2One('product.product', 'Product',
select=True, domain=[
('template.type', '=', 'service'),
('template.kind', '=', 'accommodation'),
], required=True, states=STATES_CHECKIN)
unit_price = fields.Numeric('Unit Price', digits=(16, 4),
states={
'required': Bool(Eval('product')),
'readonly': Eval('registration_state') == 'check_in',
})
uom = fields.Many2One('product.uom', 'UOM', readonly=True)
main_guest = fields.Many2One('party.party', 'Main Guest', select=True,
states={
'required': Eval('registration_state') == 'check_in',
'readonly': Eval('registration_state') == 'check_in',
}
)
contact = fields.Char('Contact', states=STATES_CHECKIN)
num_children = fields.Function(fields.Integer('No. Children'),
'get_num_children')
nights_quantity = fields.Function(fields.Integer('Nights'),
'get_nights_quantity')
host_quantity = fields.Integer('Host', states=STATES_CHECKIN)
unit_digits = fields.Function(fields.Integer('Unit Digits'), 'get_unit_digits')
notes = fields.Text('Notes')
total_amount = fields.Function(fields.Numeric('Total Amount',
digits=(16, 2)), 'get_total_amount')
total_commission = fields.Function(fields.Numeric('Channel Commission',
digits=(16, 2)), 'get_channel_commission')
guests = fields.One2Many('hotel.booking.guest', 'booking_line', 'Guests',
states={
'readonly': ~Eval('registration_state').in_(['check_in']),
})
nationality = fields.Many2One('party.nationality', 'Nationality',
states=STATES_CHECKIN)
origin_country = fields.Many2One('party.nationality', 'Origin Country',
select=True, states=STATES_CHECKIN)
target_country = fields.Many2One('party.nationality', 'Target Country',
select=True, states=STATES_CHECKIN)
registration_state = fields.Selection(REGISTRATION_STATE,
'Registration State', readonly=True)
charges = fields.One2Many('hotel.folio.charge', 'folio', 'Charges',
states={
'readonly': ~Eval('registration_state').in_(['check_in']),
})
party = fields.Many2One('party.party', 'Party to Bill', select=True,
states={
'readonly': Eval('registration_state').in_(['check_out']),
})
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line')
invoice = fields.Function(fields.Many2One('account.invoice', 'Invoice'),
'get_invoice')
invoice_state = fields.Selection(INVOICE_STATES, 'Invoice State', readonly=True)
@classmethod
def __setup__(cls):
super(Folio, cls).__setup__()
cls._check_modify_exclude = [
'nationality', 'origin_country', 'target_country',
'registration_state', 'guests'
],
cls._buttons.update({
'check_in': {
'invisible': Eval('registration_state').in_(['check_in', 'check_out']),
},
'check_out': {
'invisible': Eval('registration_state').in_(['check_out', 'pending']),
},
'bill': {
'invisible': Eval('registration_state') != 'check_out',
}
})
@classmethod
@ModelView.button
def check_in(cls, records):
config_party = Pool().get('party.configuration')(1)
validate_party = config_party.validate_party
if not validate_party:
config_party.validate_party = True
config_party.save()
booking = records[0].booking
# booking.party.pre_validate()
for rec in records:
rec.set_registration_card_number()
line = records[0]
# if line.state == 'offer':
# raise UserError(gettext('hotel.msg_missing_confirm_booking'))
if line.main_guest is None:
raise UserError(gettext('hotel.msg_missing_main_guest'))
if line.room is None:
raise UserError(gettext('hotel.msg_missing_select_room'))
booking.check_rooms()
cls.write([records[0]], {'registration_state': 'check_in'})
change_state = all(
[rl.registration_state == 'check_in' for rl in booking.lines]
)
print('change_state..', change_state)
if change_state:
booking.registration_state = 'check_in'
booking.save()
if config_party.validate_party != validate_party:
config_party.validate_party = validate_party
config_party.save()
@classmethod
@ModelView.button
def check_out(cls, records):
for record in records:
cls.write([record], {'registration_state': 'check_out'})
@classmethod
@ModelView.button
def bill(cls, records):
for rec in records:
# if rec.complementary:
# return
cls.create_invoice(rec)
def set_registration_card_number(self):
"""
Fill the number field for registration card with sequence
"""
pool = Pool()
Config = pool.get('hotel.configuration')
config = Config.get_configuration()
if self.registration_card:
return
if not config.registration_card_sequence:
raise UserError(gettext('hotel.msg_missing_sequence_registration'))
number = config.registration_card_sequence.get()
self.registration_card = number
self.save()
@classmethod
def create_invoice(cls, record):
pool = Pool()
Date = pool.get('ir.date')
InvoiceLine = pool.get('account.invoice.line')
FolioCharge = pool.get('hotel.folio.charge')
Configuration = pool.get('hotel.configuration')
configuration = Configuration.get_configuration()
# SaleVoucher = pool.get('sale.sale-account.voucher')
# date_ = Date.today()
# ctx = {}
invoice_to_create = cls.get_grouped_invoices([record])
print(invoice_to_create)
for rec in invoice_to_create.values():
# if rec.get('price_list'):
# ctx['price_list'] = rec.get('price_list')
# ctx['sale_date'] = date_
# ctx['currency'] = rec['currency']
# ctx['customer'] = rec['party'].id
invoice = cls._get_new_invoice(rec)
invoice.save()
# Here add payments to invoice
# if rec.get('vouchers'):
# for v in rec['vouchers']:
# SaleVoucher.create([{
# 'voucher': v.id,
# 'sale': sale.id
# }])
# Add and create default charges lines if exists
if rec.get('guests_qty') and rec.get('add_default_charges'):
for product in configuration.default_charges:
if rec['party']:
taxes_ids = cls.get_taxes(invoice, product, rec)
new_line = {
'invoice': invoice.id,
'type': 'line',
'unit': product.template.default_uom.id,
'quantity': rec['guests_qty'],
'unit_price': product.template.list_price,
'product': product.id,
'description': product.rec_name,
}
if taxes_ids:
new_line.update({'taxes': [('add', taxes_ids)]})
if new_line:
InvoiceLine.create([new_line])
print('XXXXX', rec)
for _line in rec['lines']:
line, = InvoiceLine.create([
cls._get_invoice_line(invoice, _line, rec)
])
if _line.get('folios'):
cls.write(_line.get('folios'), {
'invoice_line': line.id,
# 'invoice_state': 'in_process'
})
else:
FolioCharge.write([_line.get('charge')], {
'invoice_line': line.id,
'state': 'invoiced',
})
@classmethod
def _get_invoice_line(cls, invoice, line, record):
product = line['product']
new_line = {
# 'invoice_line': invoice.id,
'type': 'line',
'invoice': invoice.id,
'unit': product.template.default_uom.id,
'account': product.template.account_category.account_revenue_used.id,
'invoice_type': 'out',
'operation_center': 1,
'quantity': line['quantity'],
'unit_price': line['unit_price'],
'product': product.id,
'party': invoice.party.id,
'description': line['description'],
}
if not line['taxes_exception']:
taxes_ids = cls.get_taxes(invoice, line['product'], record)
if taxes_ids:
new_line.update({'taxes': [('add', taxes_ids)]})
return new_line
@classmethod
def get_taxes(cls, invoice, product, rec):
ctx = cls.get_context_price(invoice, product, rec)
return ctx['taxes']
@classmethod
def get_context_price(cls, invoice, product, rec):
context = {}
context['currency'] = rec['currency']
context['customer'] = rec['party'].id
context['price_list'] = rec['price_list']
context['uom'] = product.template.default_uom.id
# Set taxes before unit_price to have taxes in context of sale price
taxes = []
pattern = {}
for tax in product.customer_taxes_used:
if invoice.party and invoice.party.customer_tax_rule:
tax_ids = invoice.party.customer_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if invoice.party and invoice.party.customer_tax_rule:
tax_ids = invoice.party.customer_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
context['taxes'] = taxes
return context
@staticmethod
def default_main_guest():
party = Transaction().context.get('party')
return party
@staticmethod
def default_host_quantity():
return 1
@staticmethod
def default_accommodation():
Configuration = Pool().get('hotel.configuration')
configuration = Configuration.get_configuration()
if configuration.default_accommodation:
return configuration.default_accommodation.id
@classmethod
def validate(cls, lines):
super(Folio, cls).validate(lines)
for line in lines:
# line.check_method()
pass
def get_invoice(self, name=None):
if self.invoice_line and self.invoice_line.invoice:
self.invoice_line.invoice.id
# @fields.depends('accommodation', 'product')
# def on_change_accommodation(self):
# if not self.accommodation:
# self.product = None
@classmethod
def get_room_info(cls, fo):
description = ' \n'.join([
fo.product.rec_name,
'Huesped Principal: ' + fo.main_guest.name,
'Habitacion: ' + fo.room.name,
'Llegada: ' + str(fo.arrival_date),
'Salida: ' + str(fo.departure_date),
])
return description
@classmethod
def get_grouped_invoices(cls, folios):
res = {}
# transfered = []
# for op in folios:
# for top in op.transfered_operations:
# top.party = op.party
# transfered.append(top)
#
# if transfered:
# folios.extend(transfered)
ffols = [fol for fol in folios if not fol.invoice_line]
for fo in ffols:
if fo.party:
party = fo.party
else:
party = fo.main_guest
booking = fo.booking
agent_id = booking.party_seller.party.id if booking.party_seller else None
if party.id not in res.keys():
# Add room product to sale
res[party.id] = {
'party': party,
'currency': booking.currency.id,
'payment_term': None,
'guests_qty': len(fo.guests) + 1,
'reference': '',
'agent': agent_id,
'rooms': fo.room.name,
'company': booking.company.id,
'price_list': booking.price_list.id if booking.price_list else None,
'add_default_charges': False,
'vouchers': booking.vouchers,
'lines': [{
'folios': [fo],
'description': cls.get_room_info(fo),
'quantity': fo.nights_quantity,
'product': fo.product,
'unit_price': fo.unit_price,
'taxes_exception': booking.taxes_exception,
}]
}
else:
res[party.id]['rooms'] += ' ' + fo.room.name
res[party.id]['lines'].append({
'folios': [fo],
'description': cls.get_room_info(fo),
'quantity': fo.nights_quantity,
'product': fo.accommodation,
'unit_price': fo.unit_price,
'taxes_exception': booking.taxes_exception,
})
for charge in fo.charges:
if charge.invoice_line:
continue
invoice_party_id = charge.invoice_to.id
unit_price = booking.currency.round(charge.unit_price)
if invoice_party_id != party.id:
if invoice_party_id not in res.keys():
res[invoice_party_id] = {
'party': charge.invoice_to.id,
'currency': booking.currency.id,
'payment_term': None,
'lines': [],
}
res[invoice_party_id]['lines'].append({
'description': ' | '.join([
str(charge.date_service),
charge.order or '',
charge.description or ''
]),
'quantity': charge.quantity,
'product': charge.product,
'unit_price': unit_price,
'charge': charge,
'taxes_exception': booking.taxes_exception,
})
return res
@fields.depends('product', 'unit_price', 'uom', 'booking', 'nights_quantity')
def on_change_product(self):
Product = Pool().get('product.product')
if self.product and self.booking:
self.uom = self.product.default_uom.id
with Transaction().set_context(self.booking.get_context_price(self.product)):
self.unit_price = Product.get_sale_price([self.product],
self.nights_quantity or 0)[self.product.id]
if self.unit_price:
self.unit_price = self.booking.currency.round(self.unit_price)
else:
self.unit_price = self.product.list_price
@fields.depends('arrival_date', 'departure_date')
def on_change_arrival_date(self):
if not self.arrival_date or (
self.departure_date and self.departure_date > self.arrival_date):
return
self.departure_date = self.arrival_date + timedelta(days=1)
def check_method(self):
"""
Check the methods.
"""
Date = Pool().get('ir.date')
if self.registration_state in (['check_in', 'check_out']):
raise UserError(gettext('hotel.msg_reservation_checkin'))
if self.arrival_date < Date.today():
raise UserError(gettext('hotel.msg_invalid_arrival_date'))
if self.arrival_date >= self.departure_date:
raise UserError(gettext('hotel.msg_invalid_date'))
# Operation = Pool().get('hotel.operation')
# operations = Operation.search([
# ('room', '=', self.room.id),
# ['AND',
# ['OR', [
# ('start_date', '>=', self.arrival_date),
# ('end_date', '<=', self.arrival_date),
# ], [
# ('start_date', '>=', self.departure_date),
# ('end_date', '<=', self.departure_date),
# ]]
# ]
# ])
# if operations:
# raise AccessError(gettext('hotel.msg_occupied_room', s=self.departure_date))
# config = Pool().get('hotel.configuration')(1)
# quarantine_days = config.quarantine_rooms
# room_id = self.room.id
# if quarantine_days:
# delta = timedelta(days=int(quarantine_days))
# _date = self.arrival_date - delta
# operations = Operation.search([
# ['AND',
# ['OR', [
# ('room', '=', room_id),
# ('end_date', '=', _date)
# ],
# [
# ('room', '=', room_id),
# ('end_date', '=', self.arrival_date)
# ]]]])
# if operations:
# raise AccessError(gettext('hotel.msg_restring_room', s=self.room.name))
def get_state(self, name):
if self.booking:
return self.booking.state
def get_host_quantity(self, name):
res = 0
if self.num_adult:
res += self.num_adult
if self.num_children:
res += self.num_children
return res
@classmethod
def get_available_rooms(cls, start_date, end_date, rooms_ids=[], oper=None):
"""
Look for available rooms.
given the date interval, return a list of room ids.
a room is available if it has no operation that overlaps
with the given date interval.
the optional 'rooms' list is a list of room instance, is an
additional filter, specifying the ids of the desirable rooms.
the optional 'oper' is an operation object that has to be
filtered out of the test. it is useful for validating an already
existing operation.
"""
if start_date >= end_date:
raise UserError(gettext('hotel.msg_invalid_date_range'))
# define the domain of the operations that find a
# room to be available
dom = ['AND', ['OR',
[
('arrival_date', '>=', start_date),
('arrival_date', '<', end_date),
], [
('departure_date', '<=', end_date),
('departure_date', '>', start_date),
], [
('arrival_date', '<=', start_date),
('departure_date', '>=', end_date),
],
]]
## If oper was specified, do not compare the operations with it
if oper is not None:
dom.append(('id', '!=', oper.id))
if rooms_ids:
dom.append(('room', 'in', rooms_ids))
folios = cls.search(dom)
rooms_not_available_ids = [folio.room.id for folio in folios]
rooms_available_ids = set(rooms_ids) - set(rooms_not_available_ids)
return list(rooms_available_ids)
@fields.depends('arrival_date', 'departure_date')
def get_nights_quantity(self, name=None):
"""
Compute nights between start and end
return a integer the mean days of occupancy.
"""
nights = 0
if not self.arrival_date or not self.departure_date:
return nights
nights = (self.departure_date - self.arrival_date).days
return nights
def get_total_amount(self, name):
"""
The total amount of booking based on room flat price.
TODO: If room fee is applied should be used for total price calculation
instead of flat price. Fee is linked to channel management.
"""
res = _ZERO
if self.nights_quantity and self.unit_price:
res = self.nights_quantity * self.unit_price
return res
def get_channel_commission(self, name):
"""
Calculation of sale commission for channel based on booking total amount
"""
res = Decimal(0)
if self.total_amount and self.booking.party_seller and \
self.booking.party_seller.party.sale_commission:
res = self.total_amount * self.booking.party_seller.sale_commission / 100
return res
@classmethod
def _get_new_invoice(cls, data):
pool = Pool()
Invoice = pool.get('account.invoice')
Party = pool.get('party.party')
Agent = pool.get('commission.agent')
Journal = pool.get('account.journal')
PaymentTerm = pool.get('account.invoice.payment_term')
Date = pool.get('ir.date')
date_ = Date.today()
price_list_id = None
if data.get('price_list'):
price_list_id = data['price_list']
company_id = Transaction().context.get('company')
party = data['party']
description = data.get('rooms')
reference = data.get('reference')
agent = None
if data.get('agent'):
agent = Agent(data['agent'])
journal, = Journal.search([
('type', '=', 'revenue'),
], limit=1)
address = Party.address_get(party, type='invoice')
payment_term = data.get('payment_term', None)
if not payment_term:
payment_terms = PaymentTerm.search([])
payment_term = payment_terms[0]
return Invoice(
company=company_id,
payment_term=payment_term.id,
party=party.id,
account=party.account_receivable_used.id,
invoice_date=date_,
description=description,
state='draft',
reference=reference,
agent=agent,
journal=journal,
type='out',
invoice_type='1',
invoice_address=address.id,
)
class BookingReport(Report):
__name__ = 'hotel.booking'
@ -1707,103 +1086,3 @@ class BookingDailyReport(Report):
report_context['company'] = Company(data['company']).party.name
report_context['date'] = data['date']
return report_context
class HotelCharge(Workflow, ModelSQL, ModelView):
'Hotel Charge'
__name__ = 'hotel.charge'
booking_line = fields.Many2One('', 'Booking Line',
required=True)
service_date = fields.Date('Service Date', select=True, required=True)
product = fields.Many2One('product.product', 'Product',
domain=[('salable', '=', True)], required=True)
quantity = fields.Integer('Quantity', required=True)
invoice_to = fields.Many2One('party.party', 'Invoice To', required=True)
unit_price = fields.Numeric('Unit Price', required=True)
unit_price_w_tax = fields.Function(fields.Numeric('Unit Price'),
'get_unit_price_w_tax')
order = fields.Char('Order', select=True)
description = fields.Char('Description', select=True)
state = fields.Selection(INVOICE_STATES, 'State', readonly=True)
state_string = state.translated('state')
sale_line = fields.Many2One('sale.line', 'Sale Line', readonly=True)
amount = fields.Function(fields.Numeric('Amount',
digits=(16, 2)), 'get_amount')
taxed_amount = fields.Function(fields.Numeric('Amount with Tax',
digits=(16, 2)), 'get_taxed_amount')
@classmethod
def __setup__(cls):
super(HotelCharge, cls).__setup__()
cls._buttons.update({
'transfer': {
'invisible': True,
},
# 'bill': {
# 'invisible': Eval('invoice_state') is not None,
# },
})
@staticmethod
def default_quantity():
return 1
@staticmethod
def default_date_service():
today = Pool().get('ir.date').today()
return today
def get_amount(self, name=None):
if self.quantity and self.unit_price:
return self.quantity * self.unit_price_w_tax
return 0
def get_unit_price_w_tax(self, name=None):
Tax = Pool().get('account.tax')
res = self.unit_price or 0
if self.unit_price:
values = Tax.compute(
self.product.template.customer_taxes_used,
self.unit_price, 1)
if values:
value = values[0]
res = value['base'] + value['amount']
return res
def get_taxed_amount(self, name=None):
if self.quantity and self.unit_price:
return self.quantity * self.unit_price
# def get_sale(self, name=None):
# if self.sale_line:
# return self.sale_line.sale.id
# def compute_amount_with_tax(line):
# tax_amount = _ZERO
# amount = _ZERO
# if line.taxes:
# tax_list = Tax.compute(line.taxes, line.unit_price or _ZERO,
# line.quantity or 0.0)
#
# tax_amount = sum([t['amount'] for t in tax_list], _ZERO)
#
# if line.unit_price:
# amount = line.unit_price * Decimal(line.quantity)
# return amount + tax_amount
@classmethod
@ModelView.button
def bill(cls, records):
cls.create_sales(records)
@classmethod
@ModelView.button_action('hotel.wizard_operation_line_transfer')
def transfer(cls, records):
pass
@fields.depends('unit_price', 'product')
def on_change_product(self):
if self.product:
self.unit_price = self.product.template.list_price
self.description = self.product.description

View File

@ -10,7 +10,16 @@ from trytond.report import Report
from trytond.wizard import Wizard, StateView, StateAction, Button, StateTransition
from trytond.transaction import Transaction
from trytond.model.exceptions import AccessError
from trytond.exceptions import UserError
from trytond.i18n import gettext
from constants import REGISTRATION_STATE, COMPLEMENTARY, INVOICE_STATES
STATES_CHECKIN = {
'readonly': Eval('registration_state').in_(
['check_in', 'no_show', 'cancelled']
),
'required': Eval('registration_state') == 'check_in',
}
STATES_OP = {
'readonly': Eval('state').in_(['check_out', 'done', 'cancelled'])
@ -33,23 +42,712 @@ COLOR_MNT = {
'done': '#d45757',
}
INVOICE_STATES = [
('', ''),
('pending', 'Pending'),
('in_process', 'In Process'),
('invoiced', 'Invoiced'),
('paid', 'Paid')
]
COMPLEMENTARY = [
('', ''),
('in_house', 'In House'),
('courtesy', 'Courtesy')
]
_ZERO = Decimal('0')
class Folio(ModelSQL, ModelView):
'Folio'
__name__ = 'hotel.folio'
booking = fields.Many2One('hotel.booking', 'Booking', ondelete='CASCADE',
select=True)
registration_card = fields.Char('Registration Card', readonly=True,
select=True, help="Unique sequence for card guest registration.")
room = fields.Many2One('hotel.room', 'Room', select=True, states={
'required': Eval('registration_state') == 'check_in',
'readonly': Eval('registration_state') == 'check_in',
})
arrival_date = fields.Date('Arrival Date', required=True,
states=STATES_CHECKIN)
departure_date = fields.Date('Departure Date', required=True,
states=STATES_CHECKIN)
product = fields.Many2One('product.product', 'Product',
select=True, domain=[
('template.type', '=', 'service'),
('template.kind', '=', 'accommodation'),
], required=True, states=STATES_CHECKIN)
unit_price = fields.Numeric('Unit Price', digits=(16, 4),
states={
'required': Bool(Eval('product')),
'readonly': Eval('registration_state') == 'check_in',
})
uom = fields.Many2One('product.uom', 'UOM', readonly=True)
main_guest = fields.Many2One('party.party', 'Main Guest', select=True,
states={
'required': Eval('registration_state') == 'check_in',
'readonly': Eval('registration_state') == 'check_in',
}
)
contact = fields.Char('Contact', states=STATES_CHECKIN)
num_children = fields.Function(fields.Integer('No. Children'),
'get_num_children')
nights_quantity = fields.Function(fields.Integer('Nights'),
'get_nights_quantity')
host_quantity = fields.Integer('Host', states=STATES_CHECKIN)
unit_digits = fields.Function(fields.Integer('Unit Digits'), 'get_unit_digits')
notes = fields.Text('Notes')
total_amount = fields.Function(fields.Numeric('Total Amount',
digits=(16, 2)), 'get_total_amount')
total_commission = fields.Function(fields.Numeric('Channel Commission',
digits=(16, 2)), 'get_channel_commission')
guests = fields.One2Many('hotel.booking.guest', 'booking_line', 'Guests',
states={'readonly': ~Eval('registration_state').in_(['check_in'])})
nationality = fields.Many2One('party.nationality', 'Nationality',
states=STATES_CHECKIN)
origin_country = fields.Many2One('party.nationality', 'Origin Country',
select=True, states=STATES_CHECKIN)
target_country = fields.Many2One('party.nationality', 'Target Country',
select=True, states=STATES_CHECKIN)
registration_state = fields.Selection(REGISTRATION_STATE,
'Registration State', readonly=True)
charges = fields.One2Many('hotel.folio.charge', 'folio', 'Charges',
states={
'readonly': ~Eval('registration_state').in_(['check_in']),
})
party = fields.Many2One('party.party', 'Party to Bill', select=True,
states={
'readonly': Eval('registration_state').in_(['check_out']),
})
invoice_line = fields.Many2One('account.invoice.line', 'Invoice Line')
invoice = fields.Function(fields.Many2One('account.invoice', 'Invoice'),
'get_invoice')
invoice_state = fields.Selection(INVOICE_STATES, 'Invoice State', readonly=True)
type_complementary = fields.Selection(COMPLEMENTARY, 'Type Complementary',
states={
'invisible': ~Bool(Eval('complementary')),
'required': Bool(Eval('complementary')),
})
@classmethod
def __setup__(cls):
super(Folio, cls).__setup__()
cls._check_modify_exclude = [
'nationality', 'origin_country', 'target_country',
'registration_state', 'guests'
],
cls._buttons.update({
'check_in': {
'invisible': Eval('registration_state').in_(['check_in', 'check_out']),
},
'check_out': {
'invisible': Eval('registration_state').in_(['check_out', 'pending']),
},
'bill': {
'invisible': Eval('registration_state') != 'check_out',
}
})
@classmethod
@ModelView.button
def check_in(cls, records):
config_party = Pool().get('party.configuration')(1)
validate_party = config_party.validate_party
if not validate_party:
config_party.validate_party = True
config_party.save()
for rec in records:
# rec.booking.party.pre_validate()
if rec.booking.state == 'offer':
raise UserError(gettext('hotel.msg_missing_confirm_booking'))
if rec.main_guest is None:
raise UserError(gettext('hotel.msg_missing_main_guest'))
if rec.room is None:
raise UserError(gettext('hotel.msg_missing_select_room'))
rec.set_registration_number()
rec.booking.check_rooms()
cls.write(records, {'registration_state': 'check_in'})
# change_state = all(
# [rl.registration_state == 'check_in' for rl in booking.lines]
# )
# print('change_state..', change_state)
# if change_state:
# booking.registration_state = 'check_in'
# booking.save()
if config_party.validate_party != validate_party:
config_party.validate_party = validate_party
config_party.save()
@classmethod
@ModelView.button
def check_out(cls, records):
for record in records:
cls.write([record], {'registration_state': 'check_out'})
@classmethod
@ModelView.button
def bill(cls, records):
for rec in records:
# if rec.complementary:
# return
cls.create_invoice(rec)
def set_registration_number(self):
"""
Fill the number field for registration card with sequence
"""
pool = Pool()
Config = pool.get('hotel.configuration')
config = Config.get_configuration()
if self.registration_card:
return
if not config.registration_card_sequence:
raise UserError(gettext('hotel.msg_missing_sequence_registration'))
number = config.registration_card_sequence.get()
self.registration_card = number
self.save()
@classmethod
def create_invoice(cls, record):
pool = Pool()
Date = pool.get('ir.date')
InvoiceLine = pool.get('account.invoice.line')
FolioCharge = pool.get('hotel.folio.charge')
Configuration = pool.get('hotel.configuration')
configuration = Configuration.get_configuration()
# SaleVoucher = pool.get('sale.sale-account.voucher')
# date_ = Date.today()
# ctx = {}
invoice_to_create = cls.get_grouped_invoices([record])
print(invoice_to_create)
for rec in invoice_to_create.values():
# if rec.get('price_list'):
# ctx['price_list'] = rec.get('price_list')
# ctx['sale_date'] = date_
# ctx['currency'] = rec['currency']
# ctx['customer'] = rec['party'].id
invoice = cls._get_new_invoice(rec)
invoice.save()
# Here add payments to invoice
# if rec.get('vouchers'):
# for v in rec['vouchers']:
# SaleVoucher.create([{
# 'voucher': v.id,
# 'sale': sale.id
# }])
# Add and create default charges lines if exists
if rec.get('guests_qty') and rec.get('add_default_charges'):
for product in configuration.default_charges:
if rec['party']:
taxes_ids = cls.get_taxes(invoice, product, rec)
new_line = {
'invoice': invoice.id,
'type': 'line',
'unit': product.template.default_uom.id,
'quantity': rec['guests_qty'],
'unit_price': product.template.list_price,
'product': product.id,
'description': product.rec_name,
}
if taxes_ids:
new_line.update({'taxes': [('add', taxes_ids)]})
if new_line:
InvoiceLine.create([new_line])
print('XXXXX', rec)
for _line in rec['lines']:
line, = InvoiceLine.create([
cls._get_invoice_line(invoice, _line, rec)
])
if _line.get('folios'):
cls.write(_line.get('folios'), {
'invoice_line': line.id,
# 'invoice_state': 'in_process'
})
else:
FolioCharge.write([_line.get('charge')], {
'invoice_line': line.id,
'state': 'invoiced',
})
@classmethod
def _get_invoice_line(cls, invoice, line, record):
product = line['product']
new_line = {
'type': 'line',
'invoice': invoice.id,
'unit': product.template.default_uom.id,
'account': product.template.account_category.account_revenue_used.id,
'invoice_type': 'out',
'operation_center': 1,
'quantity': line['quantity'],
'unit_price': line['unit_price'],
'product': product.id,
'party': invoice.party.id,
'description': line['description'],
}
if not line['taxes_exception']:
taxes_ids = cls.get_taxes(invoice, line['product'], record)
if taxes_ids:
new_line.update({'taxes': [('add', taxes_ids)]})
return new_line
@classmethod
def get_taxes(cls, invoice, product, rec):
ctx = cls.get_context_price(invoice, product, rec)
return ctx['taxes']
@classmethod
def get_context_price(cls, invoice, product, rec):
context = {}
context['currency'] = rec['currency']
context['customer'] = rec['party'].id
context['price_list'] = rec['price_list']
context['uom'] = product.template.default_uom.id
# Set taxes before unit_price to have taxes in context of sale price
taxes = []
pattern = {}
for tax in product.customer_taxes_used:
if invoice.party and invoice.party.customer_tax_rule:
tax_ids = invoice.party.customer_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if invoice.party and invoice.party.customer_tax_rule:
tax_ids = invoice.party.customer_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
context['taxes'] = taxes
return context
@staticmethod
def default_main_guest():
party = Transaction().context.get('party')
return party
@staticmethod
def default_host_quantity():
return 1
@staticmethod
def default_accommodation():
Configuration = Pool().get('hotel.configuration')
configuration = Configuration.get_configuration()
if configuration.default_accommodation:
return configuration.default_accommodation.id
@classmethod
def validate(cls, lines):
super(Folio, cls).validate(lines)
for line in lines:
# line.check_method()
pass
def get_invoice(self, name=None):
if self.invoice_line and self.invoice_line.invoice:
self.invoice_line.invoice.id
# @fields.depends('accommodation', 'product')
# def on_change_accommodation(self):
# if not self.accommodation:
# self.product = None
@classmethod
def get_room_info(cls, fo):
description = ' \n'.join([
fo.product.rec_name,
'Huesped Principal: ' + fo.main_guest.name,
'Habitacion: ' + fo.room.name,
'Llegada: ' + str(fo.arrival_date),
'Salida: ' + str(fo.departure_date),
])
return description
@classmethod
def get_grouped_invoices(cls, folios):
res = {}
# transfered = []
# for op in folios:
# for top in op.transfered_operations:
# top.party = op.party
# transfered.append(top)
#
# if transfered:
# folios.extend(transfered)
ffols = [fol for fol in folios if not fol.invoice_line]
for fo in ffols:
if fo.party:
party = fo.party
else:
party = fo.main_guest
booking = fo.booking
agent_id = booking.party_seller.party.id if booking.party_seller else None
if party.id not in res.keys():
# Add room product to sale
res[party.id] = {
'party': party,
'currency': booking.currency.id,
'payment_term': None,
'guests_qty': len(fo.guests) + 1,
'reference': '',
'agent': agent_id,
'rooms': fo.room.name,
'company': booking.company.id,
'price_list': booking.price_list.id if booking.price_list else None,
'add_default_charges': False,
'vouchers': booking.vouchers,
'lines': [{
'folios': [fo],
'description': cls.get_room_info(fo),
'quantity': fo.nights_quantity,
'product': fo.product,
'unit_price': fo.unit_price,
'taxes_exception': booking.taxes_exception,
}]
}
else:
res[party.id]['rooms'] += ' ' + fo.room.name
res[party.id]['lines'].append({
'folios': [fo],
'description': cls.get_room_info(fo),
'quantity': fo.nights_quantity,
'product': fo.accommodation,
'unit_price': fo.unit_price,
'taxes_exception': booking.taxes_exception,
})
for charge in fo.charges:
if charge.invoice_line:
continue
invoice_party_id = charge.invoice_to.id
unit_price = booking.currency.round(charge.unit_price)
if invoice_party_id != party.id:
if invoice_party_id not in res.keys():
res[invoice_party_id] = {
'party': charge.invoice_to.id,
'currency': booking.currency.id,
'payment_term': None,
'lines': [],
}
res[invoice_party_id]['lines'].append({
'description': ' | '.join([
str(charge.date_service),
charge.order or '',
charge.description or ''
]),
'quantity': charge.quantity,
'product': charge.product,
'unit_price': unit_price,
'charge': charge,
'taxes_exception': booking.taxes_exception,
})
return res
@fields.depends('product', 'unit_price', 'uom', 'booking', 'nights_quantity')
def on_change_product(self):
Product = Pool().get('product.product')
if self.product and self.booking:
self.uom = self.product.default_uom.id
with Transaction().set_context(
self.booking.get_context_price(self.product)):
self.unit_price = Product.get_sale_price([self.product],
self.nights_quantity or 0)[self.product.id]
if self.unit_price:
self.unit_price = self.booking.currency.round(self.unit_price)
else:
self.unit_price = self.product.list_price
@fields.depends('arrival_date', 'departure_date')
def on_change_arrival_date(self):
if not self.arrival_date or (
self.departure_date and self.departure_date > self.arrival_date):
return
self.departure_date = self.arrival_date + timedelta(days=1)
def check_method(self):
"""
Check the methods.
"""
Date = Pool().get('ir.date')
if self.registration_state in (['check_in', 'check_out']):
raise UserError(gettext('hotel.msg_reservation_checkin'))
if self.arrival_date < Date.today():
raise UserError(gettext('hotel.msg_invalid_arrival_date'))
if self.arrival_date >= self.departure_date:
raise UserError(gettext('hotel.msg_invalid_date'))
# Operation = Pool().get('hotel.operation')
# operations = Operation.search([
# ('room', '=', self.room.id),
# ['AND',
# ['OR', [
# ('start_date', '>=', self.arrival_date),
# ('end_date', '<=', self.arrival_date),
# ], [
# ('start_date', '>=', self.departure_date),
# ('end_date', '<=', self.departure_date),
# ]]
# ]
# ])
# if operations:
# raise AccessError(gettext('hotel.msg_occupied_room', s=self.departure_date))
# config = Pool().get('hotel.configuration')(1)
# quarantine_days = config.quarantine_rooms
# room_id = self.room.id
# if quarantine_days:
# delta = timedelta(days=int(quarantine_days))
# _date = self.arrival_date - delta
# operations = Operation.search([
# ['AND',
# ['OR', [
# ('room', '=', room_id),
# ('end_date', '=', _date)
# ],
# [
# ('room', '=', room_id),
# ('end_date', '=', self.arrival_date)
# ]]]])
# if operations:
# raise AccessError(gettext('hotel.msg_restring_room', s=self.room.name))
def get_state(self, name):
if self.booking:
return self.booking.state
def get_host_quantity(self, name):
res = 0
if self.num_adult:
res += self.num_adult
if self.num_children:
res += self.num_children
return res
@classmethod
def get_available_rooms(cls, start_date, end_date, rooms_ids=[], oper=None):
"""
Look for available rooms.
given the date interval, return a list of room ids.
a room is available if it has no operation that overlaps
with the given date interval.
the optional 'rooms' list is a list of room instance, is an
additional filter, specifying the ids of the desirable rooms.
the optional 'oper' is an operation object that has to be
filtered out of the test. it is useful for validating an already
existing operation.
"""
if start_date >= end_date:
raise UserError(gettext('hotel.msg_invalid_date_range'))
# define the domain of the operations that find a
# room to be available
dom = ['AND', ['OR',
[
('arrival_date', '>=', start_date),
('arrival_date', '<', end_date),
], [
('departure_date', '<=', end_date),
('departure_date', '>', start_date),
], [
('arrival_date', '<=', start_date),
('departure_date', '>=', end_date),
],
]]
## If oper was specified, do not compare the operations with it
if oper is not None:
dom.append(('id', '!=', oper.id))
if rooms_ids:
dom.append(('room', 'in', rooms_ids))
folios = cls.search(dom)
rooms_not_available_ids = [folio.room.id for folio in folios]
rooms_available_ids = set(rooms_ids) - set(rooms_not_available_ids)
return list(rooms_available_ids)
@fields.depends('arrival_date', 'departure_date')
def get_nights_quantity(self, name=None):
"""
Compute nights between start and end
return a integer the mean days of occupancy.
"""
nights = 0
if not self.arrival_date or not self.departure_date:
return nights
nights = (self.departure_date - self.arrival_date).days
return nights
def get_total_amount(self, name):
"""
The total amount of booking based on room flat price.
TODO: If room fee is applied should be used for total price calculation
instead of flat price. Fee is linked to channel management.
"""
res = _ZERO
if self.nights_quantity and self.unit_price:
res = self.nights_quantity * self.unit_price
return res
def get_channel_commission(self, name):
"""
Calculation of sale commission for channel based on booking total amount
"""
res = Decimal(0)
if self.total_amount and self.booking.party_seller and \
self.booking.party_seller.party.sale_commission:
res = self.total_amount * self.booking.party_seller.sale_commission / 100
return res
@classmethod
def _get_new_invoice(cls, data):
pool = Pool()
Invoice = pool.get('account.invoice')
Party = pool.get('party.party')
Agent = pool.get('commission.agent')
Journal = pool.get('account.journal')
PaymentTerm = pool.get('account.invoice.payment_term')
Date = pool.get('ir.date')
date_ = Date.today()
price_list_id = None
if data.get('price_list'):
price_list_id = data['price_list']
company_id = Transaction().context.get('company')
party = data['party']
description = data.get('rooms')
reference = data.get('reference')
agent = None
if data.get('agent'):
agent = Agent(data['agent'])
journal, = Journal.search([
('type', '=', 'revenue'),
], limit=1)
address = Party.address_get(party, type='invoice')
payment_term = data.get('payment_term', None)
if not payment_term:
payment_terms = PaymentTerm.search([])
payment_term = payment_terms[0]
return Invoice(
company=company_id,
payment_term=payment_term.id,
party=party.id,
account=party.account_receivable_used.id,
invoice_date=date_,
description=description,
state='draft',
reference=reference,
agent=agent,
journal=journal,
type='out',
invoice_type='1',
invoice_address=address.id,
)
class HotelCharge(Workflow, ModelSQL, ModelView):
'Hotel Charge'
__name__ = 'hotel.charge'
folio = fields.Many2One('', 'Booking Line', required=True)
service_date = fields.Date('Service Date', select=True, required=True)
product = fields.Many2One('product.product', 'Product',
domain=[('salable', '=', True)], required=True)
quantity = fields.Integer('Quantity', required=True)
invoice_to = fields.Many2One('party.party', 'Invoice To', required=True)
unit_price = fields.Numeric('Unit Price', required=True)
unit_price_w_tax = fields.Function(fields.Numeric('Unit Price'),
'get_unit_price_w_tax')
order = fields.Char('Order', select=True)
description = fields.Char('Description', select=True)
state = fields.Selection(INVOICE_STATES, 'State', readonly=True)
state_string = state.translated('state')
sale_line = fields.Many2One('sale.line', 'Sale Line', readonly=True)
amount = fields.Function(fields.Numeric('Amount',
digits=(16, 2)), 'get_amount')
taxed_amount = fields.Function(fields.Numeric('Amount with Tax',
digits=(16, 2)), 'get_taxed_amount')
@classmethod
def __setup__(cls):
super(HotelCharge, cls).__setup__()
cls._buttons.update({
'transfer': {
'invisible': True,
},
# 'bill': {
# 'invisible': Eval('invoice_state') is not None,
# },
})
@staticmethod
def default_quantity():
return 1
@staticmethod
def default_date_service():
today = Pool().get('ir.date').today()
return today
def get_amount(self, name=None):
if self.quantity and self.unit_price:
return self.quantity * self.unit_price_w_tax
return 0
def get_unit_price_w_tax(self, name=None):
Tax = Pool().get('account.tax')
res = self.unit_price or 0
if self.unit_price:
values = Tax.compute(
self.product.template.customer_taxes_used,
self.unit_price, 1)
if values:
value = values[0]
res = value['base'] + value['amount']
return res
def get_taxed_amount(self, name=None):
if self.quantity and self.unit_price:
return self.quantity * self.unit_price
# def get_sale(self, name=None):
# if self.sale_line:
# return self.sale_line.sale.id
# def compute_amount_with_tax(line):
# tax_amount = _ZERO
# amount = _ZERO
# if line.taxes:
# tax_list = Tax.compute(line.taxes, line.unit_price or _ZERO,
# line.quantity or 0.0)
#
# tax_amount = sum([t['amount'] for t in tax_list], _ZERO)
#
# if line.unit_price:
# amount = line.unit_price * Decimal(line.quantity)
# return amount + tax_amount
@classmethod
@ModelView.button
def bill(cls, records):
cls.create_sales(records)
@classmethod
@ModelView.button_action('hotel.wizard_operation_line_transfer')
def transfer(cls, records):
pass
@fields.depends('unit_price', 'product')
def on_change_product(self):
if self.product:
self.unit_price = self.product.template.list_price
self.description = self.product.description
# class Operation(Workflow, ModelSQL, ModelView):
# 'Operation'
# __name__ = 'hotel.operation'
@ -833,12 +1531,12 @@ class OperationMaintenance(Workflow, ModelSQL, ModelView):
start_date = values.get('start_date') or rec.start_date
end_date = values.get('end_date') or rec.end_date
room = Room(values.get('room') or rec.room)
Operation().check_dates(start_date, end_date, room, rec.operation)
rec.update_operation({
'start_date': start_date,
'end_date': end_date,
'room': room.id,
})
# Operation().check_dates(start_date, end_date, room, rec.operation)
# rec.update_operation({
# 'start_date': start_date,
# 'end_date': end_date,
# 'room': room.id,
# })
super(OperationMaintenance, cls).write(records, values)
def check_method(self):

View File

@ -15,6 +15,18 @@ this repository contains the full copyright notices and license terms. -->
<field name="name">folio_charge_form</field>
</record>
<record model="ir.action.report" id="report_folio">
<field name="name">Folio Statement</field>
<field name="model">hotel.folio</field>
<field name="report_name">hotel.folio</field>
<field name="report">hotel/folio.fodt</field>
</record>
<record model="ir.action.keyword" id="report_folio_keyword">
<field name="keyword">form_print</field>
<field name="model">hotel.folio,-1</field>
<field name="action" ref="report_folio"/>
</record>
<!-- <record model="ir.ui.view" id="operation_view_tree">
<field name="model">hotel.operation</field>
<field name="type">tree</field>
@ -214,18 +226,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="act_window" ref="act_operation_tree"/>
</record>
<record model="ir.action.report" id="report_operation">
<field name="name">Statement Operation</field>
<field name="model">hotel.operation</field>
<field name="report_name">hotel.operation</field>
<field name="report">hotel/operation.fodt</field>
</record>
<record model="ir.action.keyword" id="report_operation_keyword">
<field name="keyword">form_print</field>
<field name="model">hotel.operation,-1</field>
<field name="action" ref="report_operation"/>
</record>
<record model="ir.action.wizard" id="wizard_operation_check_out">
<field name="name">Operation Check Out</field>
<field name="wiz_name">hotel.operation.check_out</field>

View File

@ -21,7 +21,7 @@ xml:
data_category.xml
location.xml
booking.xml
operation.xml
folio.xml
housekeeping.xml
company.xml
city.xml

View File

@ -2,17 +2,16 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="booking"/>
<field name="room"/>
<field name="product"/>
<field name="registration_card"/>
<field name="main_guest"/>
<field name="room"/>
<field name="nights_quantity"/>
<field name="arrival_date"/>
<field name="departure_date"/>
<field name="unit_price"/>
<field name="total_amount"/>
<field name="host_quantity"/>
<field name="registration_state"/>
<field name="invoice_state"/>
<field name="booking"/>
<field name="unit_price"/>
<field name="total_amount"/>
</tree>

View File

@ -20,12 +20,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="media"/>
<label name="party_seller"/>
<field name="party_seller" widget="selection"/>
<label name="taxes_exception"/>
<field name="taxes_exception"/>
<label name="plan"/>
<field name="plan"/>
<label name="breakfast_included"/>
<field name="breakfast_included"/>
<label name="taxes_exception"/>
<field name="taxes_exception"/>
<button name="select_rooms" string="Select Rooms"
icon="tryton-open" colspan="2"/>
<button name="send_email" string="Send Email"
@ -86,15 +86,11 @@ this repository contains the full copyright notices and license terms. -->
<group col="7" colspan="6" id="advances">
<button name="pay_advance" string="Add Advance" icon="tryton-open"
colspan="2"/>
<label name="total_advance"/>
<field name="total_advance"/>
<label name="registration_state"/>
<field name="registration_state"/>
<!-- <button name="check_in" string="Check In"
icon="tryton-forward"/>
<button name="check_out" string="Check Out"
icon="tryton-ok"/> -->
<button name="no_show" string="No Show" icon="tryton-cancel"/>
<label name="total_advance"/>
<field name="total_advance"/>
<button name="no_show" string="No Show" icon="tryton-cancel"/>
<label name="state"/>
<field name="state"/>
</group>
<group col="8" colspan="6" id="amounts">
<label name="untaxed_amount"/>
@ -106,15 +102,13 @@ this repository contains the full copyright notices and license terms. -->
<label name="pending_to_pay"/>
<field name="pending_to_pay"/>
</group>
<group col="8" colspan="6" id="buttons">
<label name="state"/>
<field name="state"/>
<group col="4" colspan="6" id="buttons">
<button name="offer" string="Offer"
icon="tryton-clear"/>
<button name="cancel" string="Cancel"
icon="tryton-cancel"/>
<button name="not_confirm" string="Not Confirm"
icon="tryton-forward"/>
<button name="not_show" string="Not Show"
icon="tryton-cancel"/>
<button name="confirm" string="Confirm"
icon="tryton-forward"/>
<!-- <label name="satisfaction"/>