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.

143 lines
6.2 KiB

  1. # -*- coding: utf-8 -*-
  2. from datetime import datetime as dtdatetime, time as dttime
  3. from odoo import models, fields, api
  4. from pytz import timezone, utc
  5. def float2time(fhours, seconds=False):
  6. hrs = int(fhours)
  7. fmin = (fhours - hrs) * 60
  8. min = int(fmin)
  9. sec = 0
  10. if seconds:
  11. fsec = (fmin - min) * 60
  12. sec = int(fsec)
  13. return dttime(hrs, min, sec)
  14. class RestaurantBooking(models.Model):
  15. _name = 'restaurant.booking'
  16. _description = "Restaurant booking"
  17. _order = 'date, time_start, count desc'
  18. @api.model
  19. def default_get(self, fields_list):
  20. defaults = super().default_get(fields_list)
  21. start = self.env.context.get('default_datetime_start', False)
  22. table_id = self.env.context.get('default_table_id', False)
  23. if start:
  24. defaults['date'] = start[:10]
  25. dtstart = fields.Datetime.context_timestamp(self, fields.Datetime.to_datetime(start))
  26. tstart = dtstart.hour
  27. if tstart:
  28. defaults['time_start'] = tstart
  29. if table_id:
  30. defaults['table_ids'] = [(6, 0, [table_id])]
  31. return defaults
  32. name = fields.Char(string="Name", required=True)
  33. date = fields.Date(string="Date", required=True)
  34. time_start = fields.Float(string="Start", required=True, group_operator=False)
  35. time_stop = fields.Float(string="Stop", compute="_get_time_stop", store=True, inverse="_set_time_stop",
  36. required=True, group_operator=False)
  37. duration = fields.Float(string="Duration", required=True, group_operator=False)
  38. datetime_start = fields.Datetime(string="Date start", compute="_get_datetimes", store=True)
  39. datetime_stop = fields.Datetime(string="Date stop", compute="_get_datetimes", store=True)
  40. count = fields.Integer(string="People count", required=True)
  41. available_table_ids = fields.Many2many(comodel_name='restaurant.table', string="Available tables",
  42. column1="booking_id", column2="table_id", relation="booking_available_table_rel",
  43. compute="_get_available_tables")
  44. table_ids = fields.Many2many(comodel_name='restaurant.table', string="Tables", required=True,
  45. column1="booking_id", column2="table_id", relation="booking_table_rel",
  46. domain="[('id', 'in', available_table_ids)]")
  47. table_capacity = fields.Integer(string="Capacity", compute="_get_table_capacity")
  48. table_capacity_ok = fields.Boolean(string="Capacity OK", compute="_check_table_capacity")
  49. table_booking_ids = fields.One2many(comodel_name="restaurant.table_booking", inverse_name="booking_id",
  50. string="Tables bookings", readonly=True)
  51. @api.depends('time_start', 'duration')
  52. def _get_time_stop(self):
  53. for booking in self:
  54. if booking.time_start and booking.duration:
  55. booking.time_stop = booking.time_start + booking.duration
  56. else:
  57. booking.time_stop = 0.0
  58. @api.onchange('time_stop')
  59. def _set_time_stop(self):
  60. for booking in self:
  61. stop = booking.time_stop
  62. if stop:
  63. booking.duration = stop - booking.time_start
  64. @api.depends('date', 'time_start', 'time_stop')
  65. def _get_datetimes(self):
  66. user_tz = timezone(self.env.user.tz)
  67. for booking in self:
  68. date = booking.date
  69. if date and booking.time_start:
  70. dt_start = user_tz.localize(dtdatetime.combine(date, float2time(booking.time_start)))
  71. booking.datetime_start = dt_start.astimezone(utc).replace(tzinfo=None)
  72. else:
  73. booking.datetime_start = False
  74. if date and booking.time_stop:
  75. dt_stop = user_tz.localize(dtdatetime.combine(date, float2time(booking.time_stop)))
  76. booking.datetime_stop = dt_stop.astimezone(utc).replace(tzinfo=None)
  77. else:
  78. booking.datetime_stop = False
  79. @api.depends('table_ids')
  80. def _get_table_capacity(self):
  81. for booking in self:
  82. booking.table_capacity = sum(booking.table_ids.mapped('seats'))
  83. @api.depends('table_capacity', 'count')
  84. def _check_table_capacity(self):
  85. for booking in self:
  86. booking.table_capacity_ok = bool(booking.table_capacity >= booking.count)
  87. @api.depends('datetime_start', 'datetime_stop', 'table_ids')
  88. def _get_available_tables(self):
  89. Table = self.env['restaurant.table']
  90. TableBooking = self.env['restaurant.table_booking']
  91. for booking in self:
  92. if booking.datetime_start and booking.datetime_stop:
  93. tbookings = TableBooking.search([
  94. '|', '&', ('datetime_start', '<', booking.datetime_stop),
  95. ('datetime_start', '>=', booking.datetime_start),
  96. '&', ('datetime_stop', '>', booking.datetime_start),
  97. ('datetime_stop', '<=', booking.datetime_stop)
  98. ])
  99. booking.available_table_ids = Table.search([
  100. ('bookable', '=', True),
  101. ('id', 'not in', tbookings.mapped('table_id').ids),
  102. ]) - booking.table_ids
  103. else:
  104. booking.available_table_ids = [(5, 0, 0)]
  105. @api.model_create_multi
  106. def create(self, vals_list):
  107. for vals in vals_list:
  108. vals.update({
  109. 'table_booking_ids': [(0, 0, {'table_id': table_id}) for table_id in vals['table_ids'][0][2]]
  110. })
  111. res = super().create(vals_list)
  112. return res
  113. def write(self, vals):
  114. res = super().write(vals)
  115. TableBooking = self.env['restaurant.table_booking']
  116. to_unlink = TableBooking
  117. for booking in self:
  118. tables = booking.table_ids
  119. table_bookings = booking.table_booking_ids
  120. delete = table_bookings.filtered(lambda rtb: rtb.table_id not in tables)
  121. to_unlink |= delete
  122. to_create = tables - (table_bookings - delete).mapped('table_id')
  123. if to_create:
  124. TableBooking.create([{
  125. 'booking_id': booking.id,
  126. 'table_id': table.id,
  127. } for table in to_create])
  128. if to_unlink:
  129. to_unlink.unlink()
  130. return res