Projet

Général

Profil

0001-virtual-agendas-balance-fill-rate-40056.patch

Emmanuel Cazenave, 24 février 2020 15:15

Télécharger (8,4 ko)

Voir les différences:

Subject: [PATCH] virtual agendas: balance fill rate (#40056)

 chrono/api/views.py | 57 ++++++++++++++++++++++++++-----
 tests/test_api.py   | 81 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 8 deletions(-)
chrono/api/views.py
561 561

  
562 562
            # get all free slots and separate them by desk
563 563
            all_slots = get_all_slots(agenda, agenda.get_meetingtype(id_=meeting_type_id))
564
            all_slots = [slot for slot in all_slots if not slot.full]
564
            all_free_slots = [slot for slot in all_slots if not slot.full]
565 565
            datetimes_by_desk = defaultdict(set)
566
            for slot in all_slots:
566
            for slot in all_free_slots:
567 567
                datetimes_by_desk[slot.desk.id].add(slot.start_datetime)
568 568

  
569
            # TODO: fill policy for virtual agendas
570
            # search first desk where all requested slots are free
571
            for available_desk_id in sorted(datetimes_by_desk.keys()):
572
                if datetimes.issubset(datetimes_by_desk[available_desk_id]):
573
                    available_desk = Desk.objects.get(id=available_desk_id)
574
                    break
569
            available_desk = None
570

  
571
            if agenda.kind == 'virtual':
572
                # Compute fill_rate by agenda/date
573
                fill_rates = defaultdict(dict)
574
                for slot in all_slots:
575
                    ref_date = slot.start_datetime.date()
576
                    if ref_date not in fill_rates[slot.desk.agenda]:
577
                        date_dict = fill_rates[slot.desk.agenda][ref_date] = {'free': 0, 'full': 0}
578
                    else:
579
                        date_dict = fill_rates[slot.desk.agenda][ref_date]
580
                    if slot.full:
581
                        date_dict['full'] += 1
582
                    else:
583
                        date_dict['free'] += 1
584
                for dd in fill_rates.values():
585
                    for date_dict in dd.values():
586
                        date_dict['fill_rate'] = date_dict['full'] / (date_dict['full'] + date_dict['free'])
587

  
588
                # select the agenda a desk on the agenda with min fill_rate on the given date
589
                for available_desk_id in sorted(datetimes_by_desk.keys()):
590
                    if datetimes.issubset(datetimes_by_desk[available_desk_id]):
591
                        desk = Desk.objects.get(id=available_desk_id)
592
                        if available_desk is None:
593
                            available_desk = desk
594
                            available_desk_rate = 0
595
                            for dt in datetimes:
596
                                available_desk_rate += fill_rates[available_desk.agenda][dt.date()][
597
                                    'fill_rate'
598
                                ]
599
                        else:
600
                            for dt in datetimes:
601
                                desk_rate = 0
602
                                for dt in datetimes:
603
                                    desk_rate += fill_rates[desk.agenda][dt.date()]['fill_rate']
604
                            if desk_rate < available_desk_rate:
605
                                available_desk = desk
606
                                available_desk_rate = desk_rate
607

  
575 608
            else:
609
                # meeting agenda
610
                # search first desk where all requested slots are free
611
                for available_desk_id in sorted(datetimes_by_desk.keys()):
612
                    if datetimes.issubset(datetimes_by_desk[available_desk_id]):
613
                        available_desk = Desk.objects.get(id=available_desk_id)
614
                        break
615

  
616
            if available_desk is None:
576 617
                return Response(
577 618
                    {
578 619
                        'err': 1,
tests/test_api.py
2589 2589
    assert resp_booking.json['err'] == 1
2590 2590
    assert resp_booking.json['err_class'] == 'no more desk available'
2591 2591
    assert resp_booking.json['err_desc'] == 'no more desk available'
2592

  
2593

  
2594
def test_virtual_agendas_meetings_booking_default_policy(app, mock_now, user):
2595
    foo_agenda = Agenda.objects.create(
2596
        label='Foo Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=5
2597
    )
2598
    MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
2599
    foo_desk_1 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 1')
2600
    foo_desk_2 = Desk.objects.create(agenda=foo_agenda, label='Foo desk 2')
2601
    TimePeriod.objects.create(
2602
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk_1,
2603
    )
2604
    TimePeriod.objects.create(
2605
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=foo_desk_2,
2606
    )
2607

  
2608
    bar_agenda = Agenda.objects.create(
2609
        label='Bar Meeting', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=5
2610
    )
2611
    MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
2612
    bar_desk_1 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 1')
2613
    bar_desk_2 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 2')
2614
    bar_desk_3 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 3')
2615
    bar_desk_4 = Desk.objects.create(agenda=bar_agenda, label='Bar desk 3')
2616
    TimePeriod.objects.create(
2617
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_1,
2618
    )
2619
    TimePeriod.objects.create(
2620
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_2,
2621
    )
2622
    TimePeriod.objects.create(
2623
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_3,
2624
    )
2625
    TimePeriod.objects.create(
2626
        weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=bar_desk_4,
2627
    )
2628

  
2629
    virt_agenda = Agenda.objects.create(
2630
        label='Virtual Agenda', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=5
2631
    )
2632
    VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=foo_agenda)
2633
    VirtualMember.objects.create(virtual_agenda=virt_agenda, real_agenda=bar_agenda)
2634
    virt_meeting_type = virt_agenda.iter_meetingtypes()[0]
2635
    # We are saturday and we can book for next monday and tuesday, 4 slots available each day
2636
    api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, virt_meeting_type.slug)
2637
    resp = app.get(api_url)
2638
    # We are saturday and we can book for next monday, 4 slots available each day
2639
    assert len(resp.json['data']) == 4
2640

  
2641
    # there are 6 desks so we can make 6 bookings on the same slot
2642
    fillslot_url = resp.json['data'][0]['api']['fillslot_url']
2643
    app.authorization = ('Basic', ('john.doe', 'password'))
2644
    for i in range(1, 7):
2645
        foo_num_bookings = Booking.objects.filter(event__desk__agenda=foo_agenda).count()
2646
        bar_num_bookings = Booking.objects.filter(event__desk__agenda=bar_agenda).count()
2647
        foo_fill_rate = foo_num_bookings / 2
2648
        bar_fill_rate = bar_num_bookings / 4
2649
        next_agenda = None
2650
        if i != 1:
2651
            if foo_fill_rate < bar_fill_rate:
2652
                next_agenda = foo_agenda
2653
            elif foo_fill_rate > bar_fill_rate:
2654
                next_agenda = bar_agenda
2655
            elif foo_fill_rate == bar_fill_rate:
2656
                next_agenda = None
2657

  
2658
        resp_booking = app.post(fillslot_url)
2659
        assert Booking.objects.count() == i
2660
        booking = Booking.objects.get(pk=resp_booking.json['booking_id'])
2661
        assert (
2662
            resp_booking.json['datetime']
2663
            == localtime(booking.event.start_datetime).strftime('%Y-%m-%d %H:%M:%S')
2664
            == resp.json['data'][0]['datetime']
2665
        )
2666
        if next_agenda:
2667
            assert booking.event.agenda == next_agenda
2668

  
2669
    foo_num_bookings = Booking.objects.filter(event__desk__agenda=foo_agenda).count()
2670
    bar_num_bookings = Booking.objects.filter(event__desk__agenda=bar_agenda).count()
2671
    assert foo_num_bookings == 2
2672
    assert bar_num_bookings == 4
2592
-