def add_shift_slot(request): business = get_curr_business(request) slot_names_generator = ((name, name) for name in get_business_slot_names(business)) if request.method == 'POST': slot_form = ShiftSlotForm(request.POST, business=business, names=slot_names_generator) if slot_form.is_valid(): data = slot_form.cleaned_data constraint_creator = SlotConstraintCreator(data) slot_creator = SlotCreator(business, data, constraint_creator) try: slot_creator.create() messages.success(request, 'slot form was ok') return HttpResponseRedirect('/') except ObjectDoesNotExist as e: logger.error('object does not exist: %s', e) return HttpResponseBadRequest('object does not exist: %s' % str(e)) else: day = request.POST.get('day') slot_holiday = get_holiday(get_curr_year(), day, get_next_week_num()) return render(request, 'manager/new_shift.html', { 'form': slot_form, 'week_range': get_next_week_string(), 'holiday': slot_holiday }, status=400) else: day = request.GET.get('day', '') start_hour = request.GET.get('startTime', '') slot_holiday = get_holiday(get_curr_year(), day, get_next_week_num()) form = ShiftSlotForm(initial={ 'day': day, 'start_hour': start_hour.replace('-', ':') }, business=business, names=slot_names_generator) return render( request, 'manager/new_shift.html', { 'form': form, 'week_range': get_next_week_string(), 'holiday': slot_holiday, 'logo_conf': get_logo_conf() })
def _create_new_slot(self): slot_constraint_json = self.constraint_creator.create() slot_holiday = get_holiday(get_curr_year(), self.slot_data['day'], get_next_week_num()) new_slot = ShiftSlot(business=self.business, day=self.slot_data['day'], start_hour=self.slot_data['start_hour'], end_hour=self.slot_data['end_hour'], week=get_next_week_num(), holiday=slot_holiday) if self.slot_data.get('save_as') != '': self._create_slot_with_name(new_slot, slot_constraint_json) else: self._create_new_slot_without_name(new_slot, slot_constraint_json)
def create_slots_for_next_week(business, waiter='1', bartender='1', cook='1', num=1): slots = [] for i in range(num): s = ShiftSlot.objects.create(business=business, year=get_curr_year(), week=get_next_week_num(), day=str(i + 1), start_hour=get_time_from_str('16:00'), end_hour=get_time_from_str('17:00')) s.constraints = json.dumps({ 'waiter': { 'num': waiter }, 'bartender': { 'num': bartender }, 'cook': { 'num': cook } }) s.save() slots.append(s) return slots
def generate_shifts(request): def execute_shift_generation(business): business.set_shift_generation_pending() business.save() if settings.CELERY: tasks.generate_next_week_shifts.delay( business.business_name, settings.SHIFT_GENERATION_ALGORITHM_LEVEL) else: tasks.generate_next_week_shifts( business.business_name, settings.SHIFT_GENERATION_ALGORITHM_LEVEL) if request.method == 'POST': next_week_slots = ShiftSlot.objects.filter( week=get_next_week_num(), business=get_curr_business(request)) if not len(next_week_slots): messages.error(request, 'No slots next week !') return HttpResponseBadRequest('No slots next week !') else: execute_shift_generation(get_curr_business(request)) create_manager_msg( recipients=get_curr_business(request).get_employees(), subject='New Shifts', text='Your manager has generated shifts for next week', wait_for_mail_results=False) messages.success(request, 'Shifts generation requested successfully') return HttpResponse('Request triggered') return wrong_method(request)
def get_next_week_slots_calendar(request): shifts_json = [] slot_id_to_constraints_dict = {} next_week_slots = ShiftSlot.objects.filter( week=get_next_week_num(), business=get_curr_business(request)).select_related('shift') for slot in next_week_slots: text_color, title = slot.get_color_and_title() jsoned_shift = json.dumps({ 'id': str(slot.id), 'title': title, 'start': slot.start_time_str(), 'end': slot.end_time_str(), 'backgroundColor': '#205067' if not slot.was_shift_generated() else 'blue', 'textColor': text_color }) shifts_json.append(jsoned_shift) slot_id_to_constraints_dict[slot.id] = slot.constraints shifts_json.append(json.dumps(slot_id_to_constraints_dict)) logger.debug('jsoned shifts are %s', shifts_json) return JsonResponse(shifts_json, safe=False)
def validate_slot_not_overlaping(clean_data): next_week_slots = ShiftSlot.objects.filter(week=get_next_week_num(), day=clean_data['day']) \ .order_by('start_hour') if not next_week_slots: return ordered_start_time = next_week_slots.order_by('start_hour') ordered_end_time = next_week_slots.order_by('end_hour') if list(ordered_start_time) != list(ordered_end_time): raise forms.ValidationError('weird error: slot not ok even before your slot :( check them') sorted_start_times = [slot.start_hour for slot in ordered_start_time] sorted_end_times = [slot.end_hour for slot in ordered_end_time] if clean_data['start_hour'] in sorted_start_times or clean_data['end_hour'] in sorted_end_times: raise forms.ValidationError('slot overlap') sorted_start_times.append(clean_data['start_hour']) sorted_start_times.sort() sorted_end_times.append(clean_data['end_hour']) sorted_end_times.sort() curr_start_index = sorted_start_times.index(clean_data['start_hour']) curr_end_index = sorted_end_times.index(clean_data['end_hour']) if curr_start_index != curr_end_index: raise forms.ValidationError('slot overlap') curr_index = curr_start_index if (curr_index != 0 and sorted_start_times[curr_index] < sorted_end_times[curr_index - 1]) \ or (curr_index != len(sorted_start_times) - 1 and sorted_end_times[curr_index] > sorted_start_times[curr_index + 1]): raise forms.ValidationError('slot overlap')
def test_should_be_next_week(self): slot = ShiftSlot.objects.create(business=self.test_business, year=get_curr_year(), week=get_next_week_num(), day='1', start_hour='12:30:00', end_hour='13:00:00') self.assertTrue(slot.is_next_week())
def add_mandatory_slots(self): mandatory_slots = ShiftSlot.objects.filter( is_mandatory=True, business=self.employee.business, week=get_next_week_num()) logger.debug('mandatory slots are %s', mandatory_slots) mandatory_slots = list(mandatory_slots) self.requested_slots.add(*mandatory_slots)
def _create_saved_slot(self): saved_slot = SavedSlot.objects.get(name=self.slot_data['name']) logger.info('Going to create slot from existing saved slot: %s', saved_slot) ShiftSlot.objects.create(business=self.business, day=self.slot_data['day'], week=get_next_week_num(), start_hour=self.slot_data['start_hour'], end_hour=self.slot_data['end_hour'], saved_slot=saved_slot)
def test_overlap_slots_should_fail(self): ShiftSlot.objects.create( business=Business.objects.get(business_name='dummy'), week=get_next_week_num(), day='3', start_hour='12:00:00', end_hour='13:00:00') form = ShiftSlotForm( self.dummy_slot, business=Business.objects.get(business_name='dummy')) self.assertFalse(form.is_valid())
def setUpTestData(cls): create_new_manager({'username': '******', 'password': '******'}) cls.emp = create_new_employee({ 'username': '******', 'password': '******' }) cls.next_week_num = get_next_week_num() cls.slot = ShiftSlot.objects.create( business=Business.objects.get(business_name='dummy'), week=cls.next_week_num, day='3', start_hour='12:00:00', end_hour='13:00:00')
def test_attributes_should_be_copied_from_saved_slot(self): saved_slot = SavedSlot.objects.create(name='test_saved_slot', constraints='{}') slot = ShiftSlot.objects.create(business=self.test_business, year=get_curr_year(), week=get_next_week_num(), day='1', start_hour='12:30:00', end_hour='13:00:00', saved_slot=saved_slot) self.assertEqual(slot.name, saved_slot.name) self.assertEqual(slot.constraints, saved_slot.constraints) self.assertEqual(slot.is_mandatory, saved_slot.is_mandatory)
def add_preferred_slots(self): next_week_non_mandatory_slots = ShiftSlot.objects.filter(week=get_next_week_num(), business=self.employee.business)\ .exclude(is_mandatory=True) relevant_slots = [ slot for slot in next_week_non_mandatory_slots if slot.get_time_frame_code() in self.employee.get_preferred_time_frame_codes() ] logger.info( 'Going to add slots to automatic slots request of emp %s: %s', self.employee, relevant_slots) for slot in relevant_slots: self.requested_slots.add(slot)
def submit_slots_request(request): next_week_no = get_next_week_num() curr_business = get_curr_business(request) curr_profile = get_curr_profile(request) start_week, end_week = get_current_week_range() existing_request = ShiftRequest.objects.filter( employee=curr_profile, submission_time__range=[start_week, end_week]).last() if request.method == 'GET': form = SelectSlotsForm(instance=existing_request, business=curr_business, week=next_week_no) existing_slots = existing_request.requested_slots.all( ) if existing_request else [] request_enabled = curr_business.slot_request_enabled return render( request, 'employee/slot_list.html', { 'form': form, 'existing_slots': existing_slots, 'request_enabled': request_enabled }) else: form = SelectSlotsForm(request.POST, business=curr_business, week=next_week_no, instance=existing_request) if form.is_valid(): shifts_request = save_shifts_request(form, curr_profile) logger.info('slots chosen are: %s', str(shifts_request.requested_slots.all())) messages.success(request, 'request saved') else: logger.error('couldn\'t save slots request: %s', str(form.errors.as_text())) messages.error(request, message='couldn\'t save slots request: %s' % str(form.errors.as_text())) return HttpResponseRedirect('/')
def generate_next_week_shifts(business_name, level): business = Business.objects.get(pk=business_name) next_week = get_next_week_num() slots = ShiftSlot.objects.filter(business=business, week=next_week) shift_generator = ShiftGeneratorFactory.create(level, slots) try: shift_generator.generate() business.set_shift_generation_success() business.save() logger.info('Generated shifts for business %s week num %d', business.business_name, next_week) except Exception as e: business.set_shift_generation_failure() business.save() logger.info( 'FAILED - generated shifts for business %s week num %d: %s', business.business_name, next_week, str(e)) raise e
def is_next_week(self): return self.week == get_next_week_num()