def _duration_validation(self): for option in self: if functions.float_to_time( option.duration) < '00:05' or functions.float_to_time( option.duration) > '08:00': raise ValidationError( _('The duration value must be between 0:05 and 8:00!'))
def check_slot_is_possible(self, option_id, appointment_date, appointee_id, slot_id): if not appointment_date: return False if not appointee_id: return False if not option_id: return False if not slot_id: return False option = request.env['s2u.appointment.option'].sudo().search([('id', '=', option_id)]) if not option: return False slot = request.env['s2u.appointment.slot'].sudo().search([('id', '=', slot_id)]) if not slot: return False date_start = datetime.datetime.strptime(appointment_date, '%d/%m/%Y').strftime('%Y-%m-%d') # if today, then skip slots in te past (< current time) if date_start == datetime.datetime.now().strftime('%Y-%m-%d') and self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id) < datetime.datetime.now(pytz.utc): return False event_start = self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id).strftime("%Y-%m-%d %H:%M:%S") event_stop = self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id, duration=option.duration).strftime("%Y-%m-%d %H:%M:%S") query = """ SELECT e.id FROM calendar_event e, calendar_event_res_partner_rel ep WHERE ep.res_partner_id = %s AND e.active = true AND (e.recurrency = false or e.recurrency is null) AND e.id = ep.calendar_event_id AND ((e.start >= %s AND e.start <= %s) OR (e.start <= %s AND e.stop >= %s) OR (e.stop >= %s) AND e.stop <= %s) """ request.env.cr.execute(query, (self.appointee_id_to_partner_id(appointee_id), event_start, event_stop, event_start, event_stop, event_start, event_stop)) res = request.env.cr.fetchall() if not res: if not self.recurrent_events_overlapping(appointee_id, event_start, event_stop): return True return False
def online_appointment_confirm(self, **post): error = {} error_message = [] if request.env.user._is_public(): param = request.env['ir.config_parameter'].sudo().search( [('key', '=', 's2u_online_appointment')], limit=1) if not param or param.value.lower() != 'public': return request.render( 's2u_online_appointment.only_registered_users') if not post.get('name', False): error['name'] = True error_message.append(_('Please enter your name.')) if not post.get('email', False): error['email'] = True error_message.append(_('Please enter your email address.')) elif not functions.valid_email(post.get('email', '')): error['email'] = True error_message.append(_('Please enter a valid email address.')) if not post.get('phone', False): error['phone'] = True error_message.append(_('Please enter your phone number.')) try: appointee_id = int(post.get('appointee_id', 0)) except: appointee_id = 0 if not appointee_id: error['appointee_id'] = True error_message.append(_('Please select a valid appointee.')) option = request.env['s2u.appointment.option'].sudo().search([ ('id', '=', int(post.get('appointment_option_id', 0))) ]) if not option: error['appointment_option_id'] = True error_message.append(_('Please select a valid subject.')) slot = request.env['s2u.appointment.slot'].sudo().search([ ('id', '=', int(post.get('timeslot_id', 0))) ]) if not slot: error['timeslot_id'] = True error_message.append(_('Please select a valid timeslot.')) try: date_start = datetime.datetime.strptime( post['appointment_date'], '%d/%m/%Y').strftime('%Y-%m-%d') day_slot = date_start + ' ' + functions.float_to_time(slot.slot) start_datetime = self.ld_to_utc(day_slot, appointee_id) except: error['appointment_date'] = True error_message.append(_('Please select a valid date.')) values = self.prepare_values(form_data=post) if error_message: values['error'] = error values['error_message'] = error_message return request.render('s2u_online_appointment.make_appointment', values) if not self.check_slot_is_possible(option.id, post['appointment_date'], appointee_id, slot.id): values['error'] = {'timeslot_id': True} values['error_message'] = [ _('Slot is already occupied, please choose another slot.') ] return request.render('s2u_online_appointment.make_appointment', values) appointee_partner_id = self.appointee_id_to_partner_id(appointee_id) partner = request.env.user.partner_id if request.env.user._is_public(): partner = request.env['res.partner'].sudo().search([ '|', ('phone', 'ilike', values['phone']), ('email', 'ilike', values['email']) ]) if not partner: partner = request.env['res.partner'].sudo().create({ 'name': values['name'], 'phone': values['phone'], 'email': values['email'] }) partner_ids = [appointee_partner_id, partner[0].id] appointment = { 'name': option.name, 'description': post.get('remarks', ''), 'start': start_datetime.strftime("%Y-%m-%d %H:%M:%S"), 'stop': (start_datetime + datetime.timedelta(minutes=round(option.duration * 60)) ).strftime("%Y-%m-%d %H:%M:%S"), 'duration': option.duration, 'categ_ids': [(6, 0, request.env.ref( 's2u_online_appointment_estarbien.calendar_event_type_s2u_online_appointment' ).ids)], 'partner_ids': [(6, 0, partner_ids)] } # set detaching = True, we do not want to send a mail to the attendees appointment = request.env['calendar.event'].sudo().with_context( detaching=True).create(appointment) # set all attendees on 'accepted' appointment.attendee_ids.write({'state': 'accepted'}) ##inherited automated action for telemedicine #venta = [('partner_id','in',partner_ids), ('state','in',['sale']), ('order_line.product_id.website_published','=',True)] #venta = request.env['sale.order'].sudo().search(venta, limit=1, order='create_date desc') #if venta and not request.env['sinerkia_jitsi_meet.jitsi_meet'].sudo().search([('order_id','=',venta.id)]) : # local_start_datetime = start_datetime.astimezone(timezone(request.env.user.tz or DEFAULT_TIMEZONE)) # #partners = request.env['res.partner'].sudo().search([('id', 'in', partner_ids)]) # jitsi = {'name': 'Reunión del paciente ' + partner[0].name + ' el ' + local_start_datetime.strftime('%d/%m/%Y') + ' a las ' + local_start_datetime.strftime('%H:%M:%S'), # 'date': start_datetime.strftime("%Y-%m-%d %H:%M:%S"), # 'date_delay': option.duration, # 'external_participants': [(0,0,{'name': partner[0].email})], # 'event_id': appointment.id, # 'order_id': venta.id} # jitsi = request.env['sinerkia_jitsi_meet.jitsi_meet'].sudo().create(jitsi) # patient = request.env['medical.patient'].sudo().search([('id','=',partner[0].id)]) # if not patient : # patient = request.env['medical.patient'].sudo().create({'patient_id': partner[0].id}) # doctor = request.env['medical.physician'].sudo().search([('partner_id','=',appointee_partner_id)],limit=1) # if not doctor : # doctor = request.env['medical.physician'].sudo().create({'partner_id': appointee_partner_id}) # cita = {'patient_id': patient.id, # 'doctor_id': doctor.id, # 'appointment_date': start_datetime.strftime("%Y-%m-%d %H:%M:%S"), # 'appointment_end': (start_datetime + datetime.timedelta(minutes=round(option.duration * 60))).strftime("%Y-%m-%d %H:%M:%S"), # 'duration': option.duration * 60, # 'no_invoice': True, # 'consultations_id': venta.order_line[0].product_id.id} # cita = request.env['medical.appointment'].create(cita) # registered user, we want something to show in his portal if not request.env.user._is_public(): registration = { 'partner_id': request.env.user.partner_id.id, 'appointee_id': self.appointee_id_to_partner_id(appointee_id), 'event_id': appointment.id } registration = request.env['s2u.appointment.registration'].create( registration) return request.redirect( '/online-appointment/appointment-scheduled?appointment=%d' % appointment.id)
def get_days_with_free_slots(self, option_id, appointee_id, year, month, criteria): if not option_id: return {} if not appointee_id: return {} start_datetimes = {} start_date = datetime.date(year, month, 1) for i in range(31): if start_date < datetime.date.today(): start_date += datetime.timedelta(days=1) continue if start_date.weekday() not in start_datetimes: start_datetimes[start_date.weekday()] = [] start_datetimes[start_date.weekday()].append(start_date.strftime('%Y-%m-%d')) start_date += datetime.timedelta(days=1) if start_date.month != month: break day_slots = [] option = request.env['s2u.appointment.option'].sudo().search([('id', '=', option_id)]) if not option: return {} for weekday, dates in start_datetimes.items(): slots = request.env['s2u.appointment.slot'].sudo().search([('user_id', '=', appointee_id), ('day', '=', str(weekday))]) slots = self.filter_slots(slots, criteria) for slot in slots: for d in dates: # if d == today, then skip slots in te past (< current time) if d == datetime.datetime.now().strftime('%Y-%m-%d') and self.ld_to_utc(d + ' ' + functions.float_to_time(slot.slot), appointee_id) < datetime.datetime.now(pytz.utc): continue day_slots.append({ 'timeslot': functions.float_to_time(slot.slot), 'date': d, 'start': self.ld_to_utc(d + ' ' + functions.float_to_time(slot.slot), appointee_id).strftime("%Y-%m-%d %H:%M:%S"), 'stop': self.ld_to_utc(d + ' ' + functions.float_to_time(slot.slot), appointee_id, duration=option.duration).strftime("%Y-%m-%d %H:%M:%S") }) days_with_free_slots = {} for d in day_slots: if d['date'] in days_with_free_slots: # this day is possible, there was a slot possible so skip other slot calculations for this day # We only need to inform the visitor he can click on this day (green), after that he needs to # select a valid slot. continue query = """ SELECT e.id FROM calendar_event e, calendar_event_res_partner_rel ep WHERE ep.res_partner_id = %s AND e.active = true AND (e.recurrency = false or e.recurrency is null) AND e.id = ep.calendar_event_id AND ((e.start >= %s AND e.start <= %s) OR (e.start <= %s AND e.stop >= %s) OR (e.stop >= %s) AND e.stop <= %s) """ request.env.cr.execute(query, (self.appointee_id_to_partner_id(appointee_id), d['start'], d['stop'], d['start'], d['stop'], d['start'], d['stop'])) res = request.env.cr.fetchall() if not res: if not self.recurrent_events_overlapping(appointee_id, d['start'], d['stop']): days_with_free_slots[d['date']] = True return days_with_free_slots
def slot_present(slots, slot): for s in slots: if s['timeslot'] == functions.float_to_time(slot): return True return False
def get_free_appointment_slots_for_day(self, option_id, appointment_date, appointee_id, criteria): def slot_present(slots, slot): for s in slots: if s['timeslot'] == functions.float_to_time(slot): return True return False if not appointment_date: return [] if not appointee_id: return [] option = request.env['s2u.appointment.option'].sudo().search([('id', '=', option_id)]) if not option: return [] week_day = datetime.datetime.strptime(appointment_date, '%d/%m/%Y').weekday() slots = request.env['s2u.appointment.slot'].sudo().search([('user_id', '=', appointee_id), ('day', '=', str(week_day))]) slots = self.filter_slots(slots, criteria) date_start = datetime.datetime.strptime(appointment_date, '%d/%m/%Y').strftime('%Y-%m-%d') free_slots = [] for slot in slots: # skip double slots if slot_present(free_slots, slot.slot): continue # if today, then skip slots in te past (< current time) if date_start == datetime.datetime.now().strftime('%Y-%m-%d') and self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id) < datetime.datetime.now(pytz.utc): continue event_start = self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id).strftime("%Y-%m-%d %H:%M:%S") event_stop = self.ld_to_utc(date_start + ' ' + functions.float_to_time(slot.slot), appointee_id, duration=option.duration).strftime("%Y-%m-%d %H:%M:%S") # check normal calendar events query = """ SELECT e.id FROM calendar_event e, calendar_event_res_partner_rel ep WHERE ep.res_partner_id = %s AND e.active = true AND (e.recurrency = false or e.recurrency is null) AND e.id = ep.calendar_event_id AND ((e.start >= %s AND e.start <= %s) OR (e.start <= %s AND e.stop >= %s) OR (e.stop >= %s) AND e.stop <= %s) """ request.env.cr.execute(query, (self.appointee_id_to_partner_id(appointee_id), event_start, event_stop, event_start, event_stop, event_start, event_stop)) res = request.env.cr.fetchall() if not res: if not self.recurrent_events_overlapping(appointee_id, event_start, event_stop): free_slots.append({ 'id': slot.id, 'timeslot': functions.float_to_time(slot.slot) }) return free_slots
def online_appointment_confirm(self, **post): error = {} error_message = [] if request.env.user._is_public(): param = request.env['ir.config_parameter'].sudo().search([('key', '=', 's2u_online_appointment')], limit=1) if not param or param.value.lower() != 'public': return request.render('s2u_online_appointment.only_registered_users') if not post.get('name', False): error['name'] = True error_message.append(_('Please enter your name.')) if not post.get('email', False): error['email'] = True error_message.append(_('Please enter your email address.')) elif not functions.valid_email(post.get('email', '')): error['email'] = True error_message.append(_('Please enter a valid email address.')) if not post.get('phone', False): error['phone'] = True error_message.append(_('Please enter your phonenumber.')) try: appointee_id = int(post.get('appointee_id', 0)) except: appointee_id = 0 if not appointee_id: error['appointee_id'] = True error_message.append(_('Please select a valid appointee.')) option = request.env['s2u.appointment.option'].sudo().search([('id', '=', int(post.get('appointment_option_id', 0)))]) if not option: error['appointment_option_id'] = True error_message.append(_('Please select a valid subject.')) slot = request.env['s2u.appointment.slot'].sudo().search([('id', '=', int(post.get('timeslot_id', 0)))]) if not slot: error['timeslot_id'] = True error_message.append(_('Please select a valid timeslot.')) try: date_start = datetime.datetime.strptime(post['appointment_date'], '%d/%m/%Y').strftime('%Y-%m-%d') day_slot = date_start + ' ' + functions.float_to_time(slot.slot) start_datetime = self.ld_to_utc(day_slot, appointee_id) except: error['appointment_date'] = True error_message.append(_('Please select a valid date.')) values = self.prepare_values(form_data=post) if error_message: values['error'] = error values['error_message'] = error_message return request.render('s2u_online_appointment.make_appointment', values) if not self.check_slot_is_possible(option.id, post['appointment_date'], appointee_id, slot.id): values['error'] = {'timeslot_id': True} values['error_message'] = [_('Slot is already occupied, please choose another slot.')] return request.render('s2u_online_appointment.make_appointment', values) if request.env.user._is_public(): partner = request.env['res.partner'].sudo().search(['|', ('phone', 'ilike', values['phone']), ('email', 'ilike', values['email'])]) if partner: partner_ids = [self.appointee_id_to_partner_id(appointee_id), partner[0].id] else: partner = request.env['res.partner'].sudo().create({ 'name': values['name'], 'phone': values['phone'], 'email': values['email'] }) partner_ids = [self.appointee_id_to_partner_id(appointee_id), partner[0].id] else: partner_ids = [self.appointee_id_to_partner_id(appointee_id), request.env.user.partner_id.id] # set detaching = True, we do not want to send a mail to the attendees appointment = request.env['calendar.event'].sudo().with_context(detaching=True).create({ 'name': option.name, 'description': post.get('remarks', ''), 'start': start_datetime.strftime("%Y-%m-%d %H:%M:%S"), 'stop': (start_datetime + datetime.timedelta(minutes=round(option.duration * 60))).strftime("%Y-%m-%d %H:%M:%S"), 'duration': option.duration, 'partner_ids': [(6, 0, partner_ids)] }) # set all attendees on 'accepted' appointment.attendee_ids.write({ 'state': 'accepted' }) # registered user, we want something to show in his portal if not request.env.user._is_public(): vals = { 'partner_id': request.env.user.partner_id.id, 'appointee_id': self.appointee_id_to_partner_id(appointee_id), 'event_id': appointment.id } registration = request.env['s2u.appointment.registration'].create(vals) return request.redirect('/online-appointment/appointment-scheduled?appointment=%d' % appointment.id)