Permalink
Browse files

Introduce Interval class

  • Loading branch information...
Benestar committed Aug 20, 2018
1 parent 10ddda3 commit f2cf3cf5c79c70ce66879c8091910abf2e183d31
@@ -34,7 +34,7 @@ def get(self, request, depot_id):
availability_data.append((
item,
self.get_chart_data(intervals),
availability.get_minimum_availability(intervals)
min(intervals).value
))

errors = request.session.pop('errors', None)
@@ -79,14 +79,14 @@ def get_chart_data(self, intervals):

data = []

for begin, end, availability in intervals:
for interval in intervals:
data.append({
"x": begin.isoformat(),
"y": availability
"x": interval.begin.isoformat(),
"y": interval.value
})
data.append({
"x": end.isoformat(),
"y": availability
"x": interval.end.isoformat(),
"y": interval.value
})

return data
@@ -1,6 +1,27 @@
from rental.models import Rental


class Interval:
"""
An interval with a beginning, an end and an associated value.
:author: Benedikt Seidl
"""

def __init__(self, begin, end, value):
self.begin = begin
self.end = end
self.value = value

def __lt__(self, other):
return self.value < other.value

def __eq__(self, other):
return (self.begin == other.begin and
self.end == other.end and
self.value == other.value)


class Availability:
"""
Helper class to determine the availability of a list of items
@@ -59,23 +80,13 @@ def get_availability_intervals(self, item):

# create intervals, initialize with full availability
for i in range(len(interval_borders) - 1):
intervals.append([interval_borders[i], interval_borders[i + 1], item.quantity])
intervals.append(Interval(interval_borders[i], interval_borders[i + 1], item.quantity))

# for each rental, modify availability during occupied intervals accordingly
for rental in relevant_rentals:
item_rental = rental.itemrental_set.get(item=item)
for interval in intervals:
if rental.start_date < interval[1] and rental.return_date > interval[0]:
interval[2] -= item_rental.quantity
if rental.start_date < interval.end and rental.return_date > interval.begin:
interval.value -= item_rental.quantity

return intervals

def get_minimum_availability(self, intervals):
"""
Get the minimum availability across all intervals
:author: Leo Tappe
"""

min_interval = min(intervals, key=lambda x: x[2])
return min_interval[2]
@@ -1,7 +1,7 @@
from verleihtool.test import ClientTestCase
from depot.models import Depot, Item, Organization
from rental.models import Rental, ItemRental
from rental.availability import Availability
from rental.availability import Availability, Interval
from datetime import datetime, timedelta


@@ -66,7 +66,7 @@ def test_no_overlap(self):
self.assertEqual([], list(availability.rentals))

intervals = availability.get_availability_intervals(self.item)
expected = [[self.start, self.end, 10]]
expected = [Interval(self.start, self.end, 10)]
self.assertEqual(intervals, expected)

def test_not_relevant(self):
@@ -78,7 +78,7 @@ def test_not_relevant(self):
self.assertEqual([rental], list(availability.rentals))

intervals = availability.get_availability_intervals(self.item)
expected = [[self.start, self.end, 10]]
expected = [Interval(self.start, self.end, 10)]
self.assertEqual(intervals, expected)

def test_completely_enclosing(self):
@@ -90,7 +90,7 @@ def test_completely_enclosing(self):
self.assertEqual([rental], list(availability.rentals))

intervals = availability.get_availability_intervals(self.item)
expected = [[self.start, self.end, 7]]
expected = [Interval(self.start, self.end, 7)]
self.assertEqual(intervals, expected)

def test_completely_enclosed(self):
@@ -103,9 +103,9 @@ def test_completely_enclosed(self):

intervals = availability.get_availability_intervals(self.item)
expected = [
[self.start, start, 10],
[start, end, 7],
[end, self.end, 10]
Interval(self.start, start, 10),
Interval(start, end, 7),
Interval(end, self.end, 10)
]
self.assertEqual(intervals, expected)

@@ -119,8 +119,8 @@ def test_left_overlap(self):

intervals = availability.get_availability_intervals(self.item)
expected = [
[self.start, end, 7],
[end, self.end, 10]
Interval(self.start, end, 7),
Interval(end, self.end, 10)
]
self.assertEqual(intervals, expected)

@@ -138,9 +138,9 @@ def test_left_and_right_no_triple_overlap(self):

intervals = availability.get_availability_intervals(self.item)
expected = [
[self.start, left_end, 7],
[left_end, right_start, 10],
[right_start, self.end, 7]
Interval(self.start, left_end, 7),
Interval(left_end, right_start, 10),
Interval(right_start, self.end, 7)
]
self.assertEqual(intervals, expected)

@@ -158,9 +158,9 @@ def test_left_and_right_triple_overlap(self):

intervals = availability.get_availability_intervals(self.item)
expected = [
[self.start, right_start, 7],
[right_start, left_end, 4],
[left_end, self.end, 7]
Interval(self.start, right_start, 7),
Interval(right_start, left_end, 4),
Interval(left_end, self.end, 7)
]
self.assertEqual(intervals, expected)

@@ -178,9 +178,9 @@ def test_enclosing_and_enclosed(self):

intervals = availability.get_availability_intervals(self.item)
expected = [
[self.start, enclosed_start, 7],
[enclosed_start, enclosed_end, 4],
[enclosed_end, self.end, 7]
Interval(self.start, enclosed_start, 7),
Interval(enclosed_start, enclosed_end, 4),
Interval(enclosed_end, self.end, 7)
]
self.assertEqual(intervals, expected)

@@ -193,7 +193,7 @@ def test_start_exactly_on_end_of_rental(self):
self.assertEqual([], list(availability.rentals))

intervals = availability.get_availability_intervals(self.item)
expected = [[self.start, self.end, 10]]
expected = [Interval(self.start, self.end, 10)]
self.assertEqual(intervals, expected)

def test_exactly_matching_rental_time_frame(self):
@@ -203,5 +203,5 @@ def test_exactly_matching_rental_time_frame(self):
self.assertEqual([rental], list(availability.rentals))

intervals = availability.get_availability_intervals(self.item)
expected = [[self.start, self.end, 7]]
expected = [Interval(self.start, self.end, 7)]
self.assertEqual(intervals, expected)
@@ -86,7 +86,7 @@ def create_items(self, rental, data):
intervals = availability.get_availability_intervals(item)

try:
available = availability.get_minimum_availability(intervals)
available = min(intervals).value
self.create_item_rental(rental, item, item_quantities[item.id], available)
except ValidationError as e:
for key, value in e:
@@ -20,7 +20,7 @@ def check_availability(self, rental):

for item_rental in rental.itemrental_set:
intervals = availability.get_availability_intervals(item_rental.item)
available = availability.get_minimum_availability(intervals)
available = min(intervals).value

if item_rental.quantity > available:
raise ValidationError({

0 comments on commit f2cf3cf

Please sign in to comment.