# -*- 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) 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) @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', 'table_ids') 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: tbookings = TableBooking.search([ '|', '&', ('datetime_start', '<', booking.datetime_stop), ('datetime_start', '>=', booking.datetime_start), '&', ('datetime_stop', '>', booking.datetime_start), ('datetime_stop', '<=', booking.datetime_stop) ]) booking.available_table_ids = Table.search([ ('bookable', '=', True), ('id', 'not in', tbookings.mapped('table_id').ids), ]) - booking.table_ids else: booking.available_table_ids = [(5, 0, 0)] @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