# © 2019 Le Filament () # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import models, fields, api from dateutil.rrule import rrule, DAILY, MINUTELY from dateutil.relativedelta import relativedelta from datetime import datetime, timedelta from pytz import timezone class VracoopPointRetrait(models.Model): _name = "vracoop.point.retrait" _description = "Point de retrait" _inherit = ['website.published.multi.mixin'] @api.model def default_get(self, fields): res = super(VracoopPointRetrait, self).default_get(fields) vracoop_time_ids = self.env['vracoop.time'].search([]) vracoop_retrait_time_ids = [] for vracoop_time_id in vracoop_time_ids: if vracoop_time_id.name == 6 or vracoop_time_id.name == 0: active_day = False else: active_day = True vals = { 'vracoop_time_id': vracoop_time_id.id, 'name': int(vracoop_time_id.name), 'first_morning_heure': vracoop_time_id.first_morning_heure, 'last_morning_heure': vracoop_time_id.last_morning_heure, 'first_noon_heure': vracoop_time_id.first_noon_heure, 'last_noon_heure': vracoop_time_id.last_noon_heure, 'preparation_time': vracoop_time_id.preparation_time, 'availability_time': vracoop_time_id.availability_time, 'active_day': active_day } vracoop_retrait_time_ids.append((0, 0, vals)) res.update({'vracoop_retrait_time_ids': vracoop_retrait_time_ids}) return res name = fields.Char("Nom du point relais") active = fields.Boolean(default=True) street = fields.Char() street2 = fields.Char() zip = fields.Char(change_default=True) city = fields.Char() state_id = fields.Many2one( "res.country.state", string='State', ondelete='restrict', domain="[('country_id', '=?', country_id)]") country_id = fields.Many2one( 'res.country', string='Country', ondelete='restrict') image = fields.Binary("Image", attachment=True,) image_medium = fields.Binary("Medium-sized image", attachment=True) image_small = fields.Binary("Small-sized image", attachment=True) vracoop_retrait_time_ids = fields.One2many( comodel_name='vracoop.retrait.time', inverse_name='vracoop_point_retrait_id', string="Configuration des horaires") nb_max_retrait = fields.Integer( "Nombre de retrait max par tranche horaire") nb_day_available = fields.Integer( "Nombre de jours pour commande", default=7) nb_hours_preparation = fields.Float( "Nombre d'heures de préparation", default=0.0) @api.multi def slot_calculate(self): self.ensure_one() LIST_WEEK_DAY = [ ('lundi', 0, 1, 'lun.'), ('mardi', 1, 2, 'mar.'), ('mercredi', 2, 3, 'mer.'), ('jeudi', 3, 4, 'jeu.'), ('vendredi', 4, 5, 'ven.'), ('samedi', 5, 6, 'sam.'), ('dimanche', 6, 0, 'dim.'), ] for rec in self: today_datetime_utc = datetime.now(timezone('UTC')) today_datetime2 = today_datetime_utc.astimezone(timezone('Europe/Berlin')) today_datetime = datetime( today_datetime2.year, today_datetime2.month, today_datetime2.day, today_datetime2.hour, today_datetime2.minute, today_datetime2.second) # today_datetime = datetime.strptime(today_datetime2, "%Y-%m-%d %H:%M:%S") return_slot_list = [] vals = [] exclure_days_nb = rec.vracoop_retrait_time_ids.search_count([ ('vracoop_point_retrait_id', '=', rec.id), ('active_day', '=', False)]) count_day = rec.nb_day_available + exclure_days_nb # Ajout pour BUG corresponding_line = rec.vracoop_retrait_time_ids.search([ ('vracoop_point_retrait_id', '=', rec.id), ('name', '=', today_datetime.strftime("%w"))]) today_hour_available = today_datetime + timedelta( hours=(corresponding_line.preparation_time + rec.nb_hours_preparation)) # Liste des jours où je peux récupérer la commande # en fonction nombre de jour dispo sur la fiche du point retrait first_day = datetime.today() + relativedelta(hours=corresponding_line.preparation_time + rec.nb_hours_preparation) list_week = list(rrule( DAILY, count=count_day, dtstart=first_day)) for week in list_week: # On exclut les jours où la journée # du point de retrait n'est pas actif exclure_the_day = rec.vracoop_retrait_time_ids.search([ ('vracoop_point_retrait_id', '=', rec.id), ('active_day', '=', False), ('name', '=', week.strftime("%w"))]) if exclure_the_day: pass else: # Récupération de la ligne du jour correpsondant corresponding_line = rec.vracoop_retrait_time_ids.search([ ('vracoop_point_retrait_id', '=', rec.id), ('name', '=', week.strftime("%w"))]) # Récupération du nom du jour et du Short name du jour for week_day in LIST_WEEK_DAY: if week_day[2] == int(week.strftime("%w")): byweekday = week_day[1] day_short_name = week_day[3] # Calcul de l'heure à laquelle la commande est disponible time_available_week = datetime( week.year, week.month, week.day) + timedelta( hours=corresponding_line.availability_time) hour = time_available_week.strftime("%H") minute = time_available_week.strftime("%M") interval = int(hour)*60 + int(minute) first_morning_hour_week = datetime( week.year, week.month, week.day) + timedelta( hours=corresponding_line.first_morning_heure) last_morning_hour_week = datetime( week.year, week.month, week.day) + timedelta( hours=corresponding_line.last_morning_heure) first_noon_hour_week = datetime( week.year, week.month, week.day) + timedelta( hours=corresponding_line.first_noon_heure) last_noon_hour_week = datetime( week.year, week.month, week.day) + timedelta( hours=corresponding_line.last_noon_heure) # Calcul des Slots (matin et après-midi) par jour en # fonction de l'intervalle (correspondant au temps de mis # à disposition) et des dates de début et de fin de retrait list_slot_per_day_morning = list( rrule( MINUTELY, interval=interval, byweekday=byweekday, dtstart=first_morning_hour_week, until=last_morning_hour_week)) list_slot_per_day_noon = list( rrule( MINUTELY, interval=interval, byweekday=byweekday, dtstart=first_noon_hour_week, until=last_noon_hour_week)) slots = [] nb_sale_slot = 0 # Heure disponible pour un retrait # en fonction du temps de préparation # today_hour_available = today_datetime + timedelta( # hours=(corresponding_line.preparation_time + rec.nb_hours_preparation)) # Boucle pour les créneaux du matin for slot_elem in list_slot_per_day_morning: # Conversion du 1er Slot en HH:MM first_slot = slot_elem.strftime("%H:%M") # Calcul du dernier slot # en fonction du temps de mis à dsiposition slot_elem_last = slot_elem + timedelta( hours=corresponding_line.availability_time) # Conversion du Dernier Slot en HH:MM last_slot = slot_elem_last.strftime("%H:%M") if slot_elem >= last_morning_hour_week: continue if slot_elem_last >= last_morning_hour_week: slot_elem_last = last_morning_hour_week last_slot = slot_elem_last.strftime("%H:%M") # Si le jour est égal à la date du jour if (slot_elem_last > last_morning_hour_week): if (today_hour_available > last_morning_hour_week): continue if (today_hour_available > slot_elem_last): continue if (today_hour_available > slot_elem): slot_elem_first = today_hour_available + timedelta( hours=1.0) first_slot = slot_elem_first.strftime("%H:00") if first_slot == last_slot: continue # Vérification si # Nombre max de retrait défini a été atteint # Pas de controle si La valeur définie est 0 if rec.nb_max_retrait > 0: first_slot_hour = first_slot.split(":") first_slot_float = float( '%s.%s' % (first_slot_hour[0], first_slot_hour[1])) nb_sale_slot = self.env['sale.order'].search_count( [('vracoop_point_retrait_id', '=', rec.id), ('day_retrait', '=', week.date()), ('hour_retrait', '=', first_slot_float)]) if nb_sale_slot < rec.nb_max_retrait: slots.append((first_slot, last_slot)) else: slots.append((first_slot, last_slot)) # Boucle pour les créneaux de l'après-midi for slot_elem in list_slot_per_day_noon: # Conversion du 1er Slot en HH:MM first_slot = slot_elem.strftime("%H:%M") # Calcul du dernier slot # en fonction du temps de mis à dsiposition slot_elem_last = slot_elem + timedelta( hours=corresponding_line.availability_time) # Conversion du Dernier Slot en HH:MM last_slot = slot_elem_last.strftime("%H:%M") if slot_elem >= last_noon_hour_week: continue if slot_elem_last >= last_noon_hour_week: slot_elem_last = last_noon_hour_week last_slot = slot_elem_last.strftime("%H:%M") # Si le jour est égal à la date du jour if (slot_elem_last > last_noon_hour_week): if (today_hour_available > last_noon_hour_week): continue if (today_hour_available > slot_elem_last): continue if (today_hour_available > slot_elem): slot_elem_first = today_hour_available + timedelta( hours=1.0) first_slot = slot_elem_first.strftime("%H:00") if first_slot == last_slot: continue # Vérification si # Nombre max de retrait défini a été atteint # Pas de controle si La valeur définie est 0 if rec.nb_max_retrait > 0: first_slot_hour = first_slot.split(":") first_slot_float = float( '%s.%s' % (first_slot_hour[0], first_slot_hour[1])) nb_sale_slot = self.env['sale.order'].search_count( [('vracoop_point_retrait_id', '=', rec.id), ('day_retrait', '=', week.date()), ('hour_retrait', '=', first_slot_float)]) if nb_sale_slot < rec.nb_max_retrait: slots.append((first_slot, last_slot)) else: slots.append((first_slot, last_slot)) return_slot_list = slots if return_slot_list: vals.append( (day_short_name, week, week.strftime("%b"), return_slot_list)) return vals