Merge branch 'chrisjrn/20161006'
This commit is contained in:
commit
dec0a759ca
5 changed files with 200 additions and 6 deletions
|
@ -76,7 +76,14 @@ class CartController(object):
|
||||||
determine whether the cart has reserved the items and discounts it
|
determine whether the cart has reserved the items and discounts it
|
||||||
holds. '''
|
holds. '''
|
||||||
|
|
||||||
reservations = [datetime.timedelta()]
|
time = timezone.now()
|
||||||
|
|
||||||
|
# Calculate the residual of the _old_ reservation duration
|
||||||
|
# if it's greater than what's in the cart now, keep it.
|
||||||
|
time_elapsed_since_updated = (time - self.cart.time_last_updated)
|
||||||
|
residual = self.cart.reservation_duration - time_elapsed_since_updated
|
||||||
|
|
||||||
|
reservations = [datetime.timedelta(0), residual]
|
||||||
|
|
||||||
# If we have vouchers, we're entitled to an hour at minimum.
|
# If we have vouchers, we're entitled to an hour at minimum.
|
||||||
if len(self.cart.vouchers.all()) >= 1:
|
if len(self.cart.vouchers.all()) >= 1:
|
||||||
|
@ -90,7 +97,7 @@ class CartController(object):
|
||||||
if product_max is not None:
|
if product_max is not None:
|
||||||
reservations.append(product_max)
|
reservations.append(product_max)
|
||||||
|
|
||||||
self.cart.time_last_updated = timezone.now()
|
self.cart.time_last_updated = time
|
||||||
self.cart.reservation_duration = max(reservations)
|
self.cart.reservation_duration = max(reservations)
|
||||||
|
|
||||||
def end_batch(self):
|
def end_batch(self):
|
||||||
|
@ -117,6 +124,32 @@ class CartController(object):
|
||||||
self.cart.revision += 1
|
self.cart.revision += 1
|
||||||
self.cart.save()
|
self.cart.save()
|
||||||
|
|
||||||
|
def extend_reservation(self, timedelta):
|
||||||
|
''' Extends the reservation on this cart by the given timedelta.
|
||||||
|
This can only be done if the current state of the cart is valid (i.e
|
||||||
|
all items and discounts in the cart are still available.)
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
timedelta (timedelta): The amount of time to extend the cart by.
|
||||||
|
The resulting reservation_duration will be now() + timedelta,
|
||||||
|
unless the requested extension is *LESS* than the current
|
||||||
|
reservation deadline.
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.validate_cart()
|
||||||
|
cart = self.cart
|
||||||
|
cart.refresh_from_db()
|
||||||
|
|
||||||
|
elapsed = (timezone.now() - cart.time_last_updated)
|
||||||
|
|
||||||
|
if cart.reservation_duration - elapsed > timedelta:
|
||||||
|
return
|
||||||
|
|
||||||
|
cart.time_last_updated = timezone.now()
|
||||||
|
cart.reservation_duration = timedelta
|
||||||
|
cart.save()
|
||||||
|
|
||||||
@_modifies_cart
|
@_modifies_cart
|
||||||
def set_quantities(self, product_quantities):
|
def set_quantities(self, product_quantities):
|
||||||
''' Sets the quantities on each of the products on each of the
|
''' Sets the quantities on each of the products on each of the
|
||||||
|
|
|
@ -15,6 +15,7 @@ from django.db.models import Case, When, Value
|
||||||
from django.db.models.fields.related import RelatedField
|
from django.db.models.fields.related import RelatedField
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from registrasion.controllers.cart import CartController
|
||||||
from registrasion.controllers.item import ItemController
|
from registrasion.controllers.item import ItemController
|
||||||
from registrasion.models import commerce
|
from registrasion.models import commerce
|
||||||
from registrasion.models import people
|
from registrasion.models import people
|
||||||
|
@ -404,19 +405,32 @@ def attendee(request, form, user_id=None):
|
||||||
reports = []
|
reports = []
|
||||||
|
|
||||||
profile_data = []
|
profile_data = []
|
||||||
|
try:
|
||||||
profile = people.AttendeeProfileBase.objects.get_subclass(
|
profile = people.AttendeeProfileBase.objects.get_subclass(
|
||||||
attendee=attendee
|
attendee=attendee
|
||||||
)
|
)
|
||||||
|
fields = profile._meta.get_fields()
|
||||||
|
except people.AttendeeProfileBase.DoesNotExist:
|
||||||
|
fields = []
|
||||||
|
|
||||||
exclude = set(["attendeeprofilebase_ptr", "id"])
|
exclude = set(["attendeeprofilebase_ptr", "id"])
|
||||||
for field in profile._meta.get_fields():
|
for field in fields:
|
||||||
if field.name in exclude:
|
if field.name in exclude:
|
||||||
# Not actually important
|
# Not actually important
|
||||||
continue
|
continue
|
||||||
if not hasattr(field, "verbose_name"):
|
if not hasattr(field, "verbose_name"):
|
||||||
continue # Not a publicly visible field
|
continue # Not a publicly visible field
|
||||||
value = getattr(profile, field.name)
|
value = getattr(profile, field.name)
|
||||||
|
|
||||||
|
if isinstance(field, models.ManyToManyField):
|
||||||
|
value = ", ".join(str(i) for i in value.all())
|
||||||
|
|
||||||
profile_data.append((field.verbose_name, value))
|
profile_data.append((field.verbose_name, value))
|
||||||
|
|
||||||
|
cart = CartController.for_user(attendee.user)
|
||||||
|
reservation = cart.cart.reservation_duration + cart.cart.time_last_updated
|
||||||
|
profile_data.append(("Current cart reserved until", reservation))
|
||||||
|
|
||||||
reports.append(ListReport("Profile", ["", ""], profile_data))
|
reports.append(ListReport("Profile", ["", ""], profile_data))
|
||||||
|
|
||||||
links = []
|
links = []
|
||||||
|
@ -424,6 +438,11 @@ def attendee(request, form, user_id=None):
|
||||||
reverse(views.amend_registration, args=[user_id]),
|
reverse(views.amend_registration, args=[user_id]),
|
||||||
"Amend current cart",
|
"Amend current cart",
|
||||||
))
|
))
|
||||||
|
links.append((
|
||||||
|
reverse(views.extend_reservation, args=[user_id]),
|
||||||
|
"Extend reservation",
|
||||||
|
))
|
||||||
|
|
||||||
reports.append(Links("Actions for " + name, links))
|
reports.append(Links("Actions for " + name, links))
|
||||||
|
|
||||||
# Paid and pending products
|
# Paid and pending products
|
||||||
|
|
|
@ -423,3 +423,130 @@ class BasicCartTests(RegistrationCartTestCase):
|
||||||
self.assertEqual(0, count_1)
|
self.assertEqual(0, count_1)
|
||||||
self.assertEqual(0, count_2)
|
self.assertEqual(0, count_2)
|
||||||
self.assertEqual(1, count_3)
|
self.assertEqual(1, count_3)
|
||||||
|
|
||||||
|
def test_reservation_duration_forwards(self):
|
||||||
|
''' Reservation duration should be the maximum of the durations (small)
|
||||||
|
'''
|
||||||
|
|
||||||
|
new_res = self.RESERVATION * 2
|
||||||
|
self.PROD_2.reservation_duration = new_res
|
||||||
|
self.PROD_2.save()
|
||||||
|
|
||||||
|
cart = TestingCartController.for_user(self.USER_1)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, self.RESERVATION)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_2, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
def test_reservation_duration_backwards(self):
|
||||||
|
''' Reservation duration should be the maximum of the durations (big)
|
||||||
|
'''
|
||||||
|
|
||||||
|
new_res = self.RESERVATION * 2
|
||||||
|
self.PROD_2.reservation_duration = new_res
|
||||||
|
self.PROD_2.save()
|
||||||
|
|
||||||
|
cart = TestingCartController.for_user(self.USER_1)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_2, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
|
||||||
|
def test_reservation_duration_removals(self):
|
||||||
|
''' Reservation duration should update with removals
|
||||||
|
'''
|
||||||
|
|
||||||
|
new_res = self.RESERVATION * 2
|
||||||
|
self.PROD_2.reservation_duration = new_res
|
||||||
|
self.PROD_2.save()
|
||||||
|
|
||||||
|
self.set_time(datetime.datetime(2015, 1, 1, tzinfo=UTC))
|
||||||
|
cart = TestingCartController.for_user(self.USER_1)
|
||||||
|
|
||||||
|
one_third = new_res / 3
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_2, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
# Reservation duration should not decrease if time hasn't decreased
|
||||||
|
cart.set_quantity(self.PROD_2, 0)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
# Adding a new product should not reset the reservation duration below
|
||||||
|
# the old one
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res)
|
||||||
|
|
||||||
|
self.add_timedelta(one_third)
|
||||||
|
|
||||||
|
# The old reservation duration is still longer than PROD_1's
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, new_res - one_third)
|
||||||
|
|
||||||
|
self.add_timedelta(one_third)
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, self.RESERVATION)
|
||||||
|
|
||||||
|
def test_reservation_extension_less_than_current(self):
|
||||||
|
''' Reservation extension should have no effect if it's too small
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.set_time(datetime.datetime(2015, 1, 1, tzinfo=UTC))
|
||||||
|
cart = TestingCartController.for_user(self.USER_1)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, self.RESERVATION)
|
||||||
|
|
||||||
|
cart.extend_reservation(datetime.timedelta(minutes=30))
|
||||||
|
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, self.RESERVATION)
|
||||||
|
|
||||||
|
def test_reservation_extension(self):
|
||||||
|
''' Test various reservation extension bits.
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.set_time(datetime.datetime(2015, 1, 1, tzinfo=UTC))
|
||||||
|
cart = TestingCartController.for_user(self.USER_1)
|
||||||
|
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, self.RESERVATION)
|
||||||
|
|
||||||
|
hours = datetime.timedelta(hours=1)
|
||||||
|
cart.extend_reservation(24 * hours)
|
||||||
|
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, 24 * hours)
|
||||||
|
|
||||||
|
self.add_timedelta(1 * hours)
|
||||||
|
|
||||||
|
# PROD_1's reservation is less than what we've added to the cart
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(cart.cart.reservation_duration, 23 * hours)
|
||||||
|
|
||||||
|
# Now the extension should only have 59 minutes remaining
|
||||||
|
# so the autoextend behaviour should kick in
|
||||||
|
self.add_timedelta(datetime.timedelta(hours=22, minutes=1))
|
||||||
|
cart.add_to_cart(self.PROD_1, 1)
|
||||||
|
cart.cart.refresh_from_db()
|
||||||
|
self.assertEqual(
|
||||||
|
cart.cart.reservation_duration,
|
||||||
|
self.PROD_1.reservation_duration,
|
||||||
|
)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from .views import (
|
||||||
checkout,
|
checkout,
|
||||||
credit_note,
|
credit_note,
|
||||||
edit_profile,
|
edit_profile,
|
||||||
|
extend_reservation,
|
||||||
guided_registration,
|
guided_registration,
|
||||||
invoice,
|
invoice,
|
||||||
invoice_access,
|
invoice_access,
|
||||||
|
@ -24,6 +25,7 @@ public = [
|
||||||
url(r"^checkout$", checkout, name="checkout"),
|
url(r"^checkout$", checkout, name="checkout"),
|
||||||
url(r"^checkout/([0-9]+)$", checkout, name="checkout"),
|
url(r"^checkout/([0-9]+)$", checkout, name="checkout"),
|
||||||
url(r"^credit_note/([0-9]+)$", credit_note, name="credit_note"),
|
url(r"^credit_note/([0-9]+)$", credit_note, name="credit_note"),
|
||||||
|
url(r"^extend/([0-9]+)$", extend_reservation, name="extend_reservation"),
|
||||||
url(r"^invoice/([0-9]+)$", invoice, name="invoice"),
|
url(r"^invoice/([0-9]+)$", invoice, name="invoice"),
|
||||||
url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", invoice, name="invoice"),
|
url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", invoice, name="invoice"),
|
||||||
url(r"^invoice/([0-9]+)/manual_payment$",
|
url(r"^invoice/([0-9]+)/manual_payment$",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import datetime
|
||||||
import sys
|
import sys
|
||||||
import util
|
import util
|
||||||
|
|
||||||
|
@ -903,3 +904,15 @@ def amend_registration(request, user_id):
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "registrasion/amend_registration.html", data)
|
return render(request, "registrasion/amend_registration.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
@user_passes_test(_staff_only)
|
||||||
|
def extend_reservation(request, user_id, days=7):
|
||||||
|
''' Allows staff to extend the reservation on a given user's cart.
|
||||||
|
'''
|
||||||
|
|
||||||
|
user = User.objects.get(id=int(user_id))
|
||||||
|
cart = CartController.for_user(user)
|
||||||
|
cart.extend_reservation(datetime.timedelta(days=days))
|
||||||
|
|
||||||
|
return redirect(request.META["HTTP_REFERER"])
|
||||||
|
|
Loading…
Reference in a new issue