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.

282 lines
14 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. # © 2019 Le Filament (<http://www.le-filament.com>)
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. from odoo import models, fields, api
  4. from dateutil.rrule import rrule, DAILY, MINUTELY
  5. from dateutil.relativedelta import relativedelta
  6. from datetime import datetime, timedelta
  7. from pytz import timezone
  8. class VracoopPointRetrait(models.Model):
  9. _name = "vracoop.point.retrait"
  10. _description = "Point de retrait"
  11. _inherit = ['website.published.multi.mixin']
  12. @api.model
  13. def default_get(self, fields):
  14. res = super(VracoopPointRetrait, self).default_get(fields)
  15. vracoop_time_ids = self.env['vracoop.time'].search([])
  16. vracoop_retrait_time_ids = []
  17. for vracoop_time_id in vracoop_time_ids:
  18. if vracoop_time_id.name == 6 or vracoop_time_id.name == 0:
  19. active_day = False
  20. else:
  21. active_day = True
  22. vals = {
  23. 'vracoop_time_id': vracoop_time_id.id,
  24. 'name': int(vracoop_time_id.name),
  25. 'first_morning_heure': vracoop_time_id.first_morning_heure,
  26. 'last_morning_heure': vracoop_time_id.last_morning_heure,
  27. 'first_noon_heure': vracoop_time_id.first_noon_heure,
  28. 'last_noon_heure': vracoop_time_id.last_noon_heure,
  29. 'preparation_time': vracoop_time_id.preparation_time,
  30. 'availability_time': vracoop_time_id.availability_time,
  31. 'active_day': active_day
  32. }
  33. vracoop_retrait_time_ids.append((0, 0, vals))
  34. res.update({'vracoop_retrait_time_ids': vracoop_retrait_time_ids})
  35. return res
  36. name = fields.Char("Nom du point relais")
  37. active = fields.Boolean(default=True)
  38. street = fields.Char()
  39. street2 = fields.Char()
  40. zip = fields.Char(change_default=True)
  41. city = fields.Char()
  42. state_id = fields.Many2one(
  43. "res.country.state",
  44. string='State',
  45. ondelete='restrict',
  46. domain="[('country_id', '=?', country_id)]")
  47. country_id = fields.Many2one(
  48. 'res.country', string='Country', ondelete='restrict')
  49. image = fields.Binary("Image", attachment=True,)
  50. image_medium = fields.Binary("Medium-sized image", attachment=True)
  51. image_small = fields.Binary("Small-sized image", attachment=True)
  52. vracoop_retrait_time_ids = fields.One2many(
  53. comodel_name='vracoop.retrait.time',
  54. inverse_name='vracoop_point_retrait_id',
  55. string="Configuration des horaires")
  56. nb_max_retrait = fields.Integer(
  57. "Nombre de retrait max par tranche horaire")
  58. nb_day_available = fields.Integer(
  59. "Nombre de jours pour commande", default=7)
  60. nb_hours_preparation = fields.Float(
  61. "Nombre d'heures de préparation", default=0.0)
  62. @api.multi
  63. def slot_calculate(self):
  64. self.ensure_one()
  65. LIST_WEEK_DAY = [
  66. ('lundi', 0, 1, 'lun.'),
  67. ('mardi', 1, 2, 'mar.'),
  68. ('mercredi', 2, 3, 'mer.'),
  69. ('jeudi', 3, 4, 'jeu.'),
  70. ('vendredi', 4, 5, 'ven.'),
  71. ('samedi', 5, 6, 'sam.'),
  72. ('dimanche', 6, 0, 'dim.'),
  73. ]
  74. for rec in self:
  75. today_datetime_utc = datetime.now(timezone('UTC'))
  76. today_datetime2 = today_datetime_utc.astimezone(timezone('Europe/Berlin'))
  77. today_datetime = datetime(
  78. today_datetime2.year,
  79. today_datetime2.month,
  80. today_datetime2.day,
  81. today_datetime2.hour,
  82. today_datetime2.minute,
  83. today_datetime2.second)
  84. # today_datetime = datetime.strptime(today_datetime2, "%Y-%m-%d %H:%M:%S")
  85. return_slot_list = []
  86. vals = []
  87. exclure_days_nb = rec.vracoop_retrait_time_ids.search_count([
  88. ('vracoop_point_retrait_id', '=', rec.id),
  89. ('active_day', '=', False)])
  90. count_day = rec.nb_day_available + exclure_days_nb
  91. # Ajout pour BUG
  92. corresponding_line = rec.vracoop_retrait_time_ids.search([
  93. ('vracoop_point_retrait_id', '=', rec.id),
  94. ('name', '=', today_datetime.strftime("%w"))])
  95. today_hour_available = today_datetime + timedelta(
  96. hours=(corresponding_line.preparation_time + rec.nb_hours_preparation))
  97. # Liste des jours où je peux récupérer la commande
  98. # en fonction nombre de jour dispo sur la fiche du point retrait
  99. first_day = datetime.today() + relativedelta(hours=corresponding_line.preparation_time + rec.nb_hours_preparation)
  100. list_week = list(rrule(
  101. DAILY,
  102. count=count_day,
  103. dtstart=first_day))
  104. for week in list_week:
  105. # On exclut les jours où la journée
  106. # du point de retrait n'est pas actif
  107. exclure_the_day = rec.vracoop_retrait_time_ids.search([
  108. ('vracoop_point_retrait_id', '=', rec.id),
  109. ('active_day', '=', False),
  110. ('name', '=', week.strftime("%w"))])
  111. if exclure_the_day:
  112. pass
  113. else:
  114. # Récupération de la ligne du jour correpsondant
  115. corresponding_line = rec.vracoop_retrait_time_ids.search([
  116. ('vracoop_point_retrait_id', '=', rec.id),
  117. ('name', '=', week.strftime("%w"))])
  118. # Récupération du nom du jour et du Short name du jour
  119. for week_day in LIST_WEEK_DAY:
  120. if week_day[2] == int(week.strftime("%w")):
  121. byweekday = week_day[1]
  122. day_short_name = week_day[3]
  123. # Calcul de l'heure à laquelle la commande est disponible
  124. time_available_week = datetime(
  125. week.year, week.month, week.day) + timedelta(
  126. hours=corresponding_line.availability_time)
  127. hour = time_available_week.strftime("%H")
  128. minute = time_available_week.strftime("%M")
  129. interval = int(hour)*60 + int(minute)
  130. first_morning_hour_week = datetime(
  131. week.year, week.month, week.day) + timedelta(
  132. hours=corresponding_line.first_morning_heure)
  133. last_morning_hour_week = datetime(
  134. week.year, week.month, week.day) + timedelta(
  135. hours=corresponding_line.last_morning_heure)
  136. first_noon_hour_week = datetime(
  137. week.year, week.month, week.day) + timedelta(
  138. hours=corresponding_line.first_noon_heure)
  139. last_noon_hour_week = datetime(
  140. week.year, week.month, week.day) + timedelta(
  141. hours=corresponding_line.last_noon_heure)
  142. # Calcul des Slots (matin et après-midi) par jour en
  143. # fonction de l'intervalle (correspondant au temps de mis
  144. # à disposition) et des dates de début et de fin de retrait
  145. list_slot_per_day_morning = list(
  146. rrule(
  147. MINUTELY,
  148. interval=interval,
  149. byweekday=byweekday,
  150. dtstart=first_morning_hour_week,
  151. until=last_morning_hour_week))
  152. list_slot_per_day_noon = list(
  153. rrule(
  154. MINUTELY, interval=interval,
  155. byweekday=byweekday,
  156. dtstart=first_noon_hour_week,
  157. until=last_noon_hour_week))
  158. slots = []
  159. nb_sale_slot = 0
  160. # Heure disponible pour un retrait
  161. # en fonction du temps de préparation
  162. # today_hour_available = today_datetime + timedelta(
  163. # hours=(corresponding_line.preparation_time + rec.nb_hours_preparation))
  164. # Boucle pour les créneaux du matin
  165. for slot_elem in list_slot_per_day_morning:
  166. # Conversion du 1er Slot en HH:MM
  167. first_slot = slot_elem.strftime("%H:%M")
  168. # Calcul du dernier slot
  169. # en fonction du temps de mis à dsiposition
  170. slot_elem_last = slot_elem + timedelta(
  171. hours=corresponding_line.availability_time)
  172. # Conversion du Dernier Slot en HH:MM
  173. last_slot = slot_elem_last.strftime("%H:%M")
  174. if slot_elem >= last_morning_hour_week:
  175. continue
  176. if slot_elem_last >= last_morning_hour_week:
  177. slot_elem_last = last_morning_hour_week
  178. last_slot = slot_elem_last.strftime("%H:%M")
  179. # Si le jour est égal à la date du jour
  180. if (slot_elem_last > last_morning_hour_week):
  181. if (today_hour_available > last_morning_hour_week):
  182. continue
  183. if (today_hour_available > slot_elem_last):
  184. continue
  185. if (today_hour_available > slot_elem):
  186. slot_elem_first = today_hour_available + timedelta(
  187. hours=1.0)
  188. first_slot = slot_elem_first.strftime("%H:00")
  189. if first_slot == last_slot:
  190. continue
  191. # Vérification si
  192. # Nombre max de retrait défini a été atteint
  193. # Pas de controle si La valeur définie est 0
  194. if rec.nb_max_retrait > 0:
  195. first_slot_hour = first_slot.split(":")
  196. first_slot_float = float(
  197. '%s.%s' % (first_slot_hour[0], first_slot_hour[1]))
  198. nb_sale_slot = self.env['sale.order'].search_count(
  199. [('vracoop_point_retrait_id', '=', rec.id),
  200. ('day_retrait', '=', week.date()),
  201. ('hour_retrait', '=', first_slot_float)])
  202. if nb_sale_slot < rec.nb_max_retrait:
  203. slots.append((first_slot, last_slot))
  204. else:
  205. slots.append((first_slot, last_slot))
  206. # Boucle pour les créneaux de l'après-midi
  207. for slot_elem in list_slot_per_day_noon:
  208. # Conversion du 1er Slot en HH:MM
  209. first_slot = slot_elem.strftime("%H:%M")
  210. # Calcul du dernier slot
  211. # en fonction du temps de mis à dsiposition
  212. slot_elem_last = slot_elem + timedelta(
  213. hours=corresponding_line.availability_time)
  214. # Conversion du Dernier Slot en HH:MM
  215. last_slot = slot_elem_last.strftime("%H:%M")
  216. if slot_elem >= last_noon_hour_week:
  217. continue
  218. if slot_elem_last >= last_noon_hour_week:
  219. slot_elem_last = last_noon_hour_week
  220. last_slot = slot_elem_last.strftime("%H:%M")
  221. # Si le jour est égal à la date du jour
  222. if (slot_elem_last > last_noon_hour_week):
  223. if (today_hour_available > last_noon_hour_week):
  224. continue
  225. if (today_hour_available > slot_elem_last):
  226. continue
  227. if (today_hour_available > slot_elem):
  228. slot_elem_first = today_hour_available + timedelta(
  229. hours=1.0)
  230. first_slot = slot_elem_first.strftime("%H:00")
  231. if first_slot == last_slot:
  232. continue
  233. # Vérification si
  234. # Nombre max de retrait défini a été atteint
  235. # Pas de controle si La valeur définie est 0
  236. if rec.nb_max_retrait > 0:
  237. first_slot_hour = first_slot.split(":")
  238. first_slot_float = float(
  239. '%s.%s' % (first_slot_hour[0], first_slot_hour[1]))
  240. nb_sale_slot = self.env['sale.order'].search_count(
  241. [('vracoop_point_retrait_id', '=', rec.id),
  242. ('day_retrait', '=', week.date()),
  243. ('hour_retrait', '=', first_slot_float)])
  244. if nb_sale_slot < rec.nb_max_retrait:
  245. slots.append((first_slot, last_slot))
  246. else:
  247. slots.append((first_slot, last_slot))
  248. return_slot_list = slots
  249. if return_slot_list:
  250. vals.append(
  251. (day_short_name,
  252. week,
  253. week.strftime("%b"), return_slot_list))
  254. return vals