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 | ||||
|         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 len(self.cart.vouchers.all()) >= 1: | ||||
|  | @ -90,7 +97,7 @@ class CartController(object): | |||
|         if product_max is not None: | ||||
|             reservations.append(product_max) | ||||
| 
 | ||||
|         self.cart.time_last_updated = timezone.now() | ||||
|         self.cart.time_last_updated = time | ||||
|         self.cart.reservation_duration = max(reservations) | ||||
| 
 | ||||
|     def end_batch(self): | ||||
|  | @ -117,6 +124,32 @@ class CartController(object): | |||
|         self.cart.revision += 1 | ||||
|         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 | ||||
|     def set_quantities(self, product_quantities): | ||||
|         ''' 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.shortcuts import render | ||||
| 
 | ||||
| from registrasion.controllers.cart import CartController | ||||
| from registrasion.controllers.item import ItemController | ||||
| from registrasion.models import commerce | ||||
| from registrasion.models import people | ||||
|  | @ -404,19 +405,32 @@ def attendee(request, form, user_id=None): | |||
|     reports = [] | ||||
| 
 | ||||
|     profile_data = [] | ||||
|     try: | ||||
|         profile = people.AttendeeProfileBase.objects.get_subclass( | ||||
|             attendee=attendee | ||||
|         ) | ||||
|         fields = profile._meta.get_fields() | ||||
|     except people.AttendeeProfileBase.DoesNotExist: | ||||
|         fields = [] | ||||
| 
 | ||||
|     exclude = set(["attendeeprofilebase_ptr", "id"]) | ||||
|     for field in profile._meta.get_fields(): | ||||
|     for field in fields: | ||||
|         if field.name in exclude: | ||||
|             # Not actually important | ||||
|             continue | ||||
|         if not hasattr(field, "verbose_name"): | ||||
|             continue  # Not a publicly visible field | ||||
|         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)) | ||||
| 
 | ||||
|     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)) | ||||
| 
 | ||||
|     links = [] | ||||
|  | @ -424,6 +438,11 @@ def attendee(request, form, user_id=None): | |||
|         reverse(views.amend_registration, args=[user_id]), | ||||
|         "Amend current cart", | ||||
|     )) | ||||
|     links.append(( | ||||
|         reverse(views.extend_reservation, args=[user_id]), | ||||
|         "Extend reservation", | ||||
|     )) | ||||
| 
 | ||||
|     reports.append(Links("Actions for " + name, links)) | ||||
| 
 | ||||
|     # Paid and pending  products | ||||
|  |  | |||
|  | @ -423,3 +423,130 @@ class BasicCartTests(RegistrationCartTestCase): | |||
|         self.assertEqual(0, count_1) | ||||
|         self.assertEqual(0, count_2) | ||||
|         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, | ||||
|     credit_note, | ||||
|     edit_profile, | ||||
|     extend_reservation, | ||||
|     guided_registration, | ||||
|     invoice, | ||||
|     invoice_access, | ||||
|  | @ -24,6 +25,7 @@ public = [ | |||
|     url(r"^checkout$", checkout, name="checkout"), | ||||
|     url(r"^checkout/([0-9]+)$", checkout, name="checkout"), | ||||
|     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]+)/([A-Z0-9]+)$", invoice, name="invoice"), | ||||
|     url(r"^invoice/([0-9]+)/manual_payment$", | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| import datetime | ||||
| import sys | ||||
| import util | ||||
| 
 | ||||
|  | @ -903,3 +904,15 @@ def amend_registration(request, user_id): | |||
|     } | ||||
| 
 | ||||
|     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…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer