Odoo modules related to point of sales
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
6.7 KiB

# -*- coding: utf-8 -*-
from datetime import datetime as dtdatetime, time as dttime
from odoo import models, fields, api
from pytz import timezone, utc
def float2time(fhours, seconds=False):
hrs = int(fhours)
fmin = (fhours - hrs) * 60
min = int(fmin)
sec = 0
if seconds:
fsec = (fmin - min) * 60
sec = int(fsec)
return dttime(hrs, min, sec)
class RestaurantBooking(models.Model):
_name = 'restaurant.booking'
_description = "Restaurant booking"
_order = 'date, time_start, count desc'
@api.model
def default_get(self, fields_list):
defaults = super().default_get(fields_list)
start = self.env.context.get('default_datetime_start', False)
table_id = self.env.context.get('default_table_id', False)
if start:
defaults['date'] = start[:10]
dtstart = fields.Datetime.context_timestamp(self, fields.Datetime.to_datetime(start))
tstart = dtstart.hour
if tstart:
defaults['time_start'] = tstart
if table_id:
defaults['table_ids'] = [(6, 0, [table_id])]
return defaults
name = fields.Char(string="Name", required=True)
date = fields.Date(string="Date", required=True)
time_start = fields.Float(string="Start", required=True, group_operator=False)
time_stop = fields.Float(string="Stop", compute="_get_time_stop", store=True, inverse="_set_time_stop",
required=True, group_operator=False)
duration = fields.Float(string="Duration", required=True, group_operator=False)
datetime_start = fields.Datetime(string="Date start", compute="_get_datetimes", store=True)
datetime_stop = fields.Datetime(string="Date stop", compute="_get_datetimes", store=True)
count = fields.Integer(string="People count", required=True)
can_overlap = fields.Boolean(string="Table bookings can overlap")
available_table_ids = fields.Many2many(comodel_name='restaurant.table', string="Available tables",
column1="booking_id", column2="table_id", relation="booking_available_table_rel",
compute="_get_available_tables")
table_ids = fields.Many2many(comodel_name='restaurant.table', string="Tables", required=True,
column1="booking_id", column2="table_id", relation="booking_table_rel",
domain="[('id', 'in', available_table_ids)]")
table_capacity = fields.Integer(string="Capacity", compute="_get_table_capacity")
table_capacity_ok = fields.Boolean(string="Capacity OK", compute="_check_table_capacity")
table_booking_ids = fields.One2many(comodel_name="restaurant.table_booking", inverse_name="booking_id",
string="Tables bookings", readonly=True)
_sql_constraints = [
('start_time_check', 'CHECK(time_start >= 0 AND time_start <= 24)', "The start time must be between 0 and 24."),
('stop_time_check', 'CHECK(time_stop >= 0 AND time_stop <= 24)', "The stop time must be between 0 and 24."),
('times_order_check', 'CHECK(time_start < time_stop)', "The start time must be lower than the stop time."),
]
@api.depends('time_start', 'duration')
def _get_time_stop(self):
for booking in self:
if booking.time_start and booking.duration:
booking.time_stop = booking.time_start + booking.duration
else:
booking.time_stop = 0.0
@api.onchange('time_stop')
def _set_time_stop(self):
for booking in self:
stop = booking.time_stop
if stop:
booking.duration = stop - booking.time_start
@api.depends('date', 'time_start', 'time_stop')
def _get_datetimes(self):
user_tz = timezone(self.env.user.tz)
for booking in self:
date = booking.date
if date and booking.time_start:
dt_start = user_tz.localize(dtdatetime.combine(date, float2time(booking.time_start)))
booking.datetime_start = dt_start.astimezone(utc).replace(tzinfo=None)
else:
booking.datetime_start = False
if date and booking.time_stop:
dt_stop = user_tz.localize(dtdatetime.combine(date, float2time(booking.time_stop)))
booking.datetime_stop = dt_stop.astimezone(utc).replace(tzinfo=None)
else:
booking.datetime_stop = False
@api.depends('table_ids')
def _get_table_capacity(self):
for booking in self:
booking.table_capacity = sum(booking.table_ids.mapped('seats'))
@api.depends('table_capacity', 'count')
def _check_table_capacity(self):
for booking in self:
booking.table_capacity_ok = bool(booking.table_capacity >= booking.count)
@api.depends('datetime_start', 'datetime_stop', 'can_overlap')
def _get_available_tables(self):
Table = self.env['restaurant.table']
TableBooking = self.env['restaurant.table_booking']
for booking in self:
if booking.datetime_start and booking.datetime_stop:
domain = [('bookable', '=', True)]
if not self.can_overlap:
tbookings = TableBooking.search([
'|', '&', ('datetime_start', '<', booking.datetime_stop),
('datetime_start', '>=', booking.datetime_start),
'&', ('datetime_stop', '>', booking.datetime_start),
('datetime_stop', '<=', booking.datetime_stop)
])
domain.append(('id', 'not in', tbookings.mapped('table_id').ids))
booking.available_table_ids = Table.search(domain)
else:
booking.available_table_ids = [(5, 0, 0)]
# CRUD
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals.update({
'table_booking_ids': [(0, 0, {'table_id': table_id}) for table_id in vals['table_ids'][0][2]]
})
res = super().create(vals_list)
return res
def write(self, vals):
res = super().write(vals)
TableBooking = self.env['restaurant.table_booking']
to_unlink = TableBooking
for booking in self:
tables = booking.table_ids
table_bookings = booking.table_booking_ids
delete = table_bookings.filtered(lambda rtb: rtb.table_id not in tables)
to_unlink |= delete
to_create = tables - (table_bookings - delete).mapped('table_id')
if to_create:
TableBooking.create([{
'booking_id': booking.id,
'table_id': table.id,
} for table in to_create])
if to_unlink:
to_unlink.unlink()
return res