diff --git a/booking/tests/test_shopping_basket_views.py b/booking/tests/test_shopping_basket_views.py index db3c5313..9fdf0e60 100644 --- a/booking/tests/test_shopping_basket_views.py +++ b/booking/tests/test_shopping_basket_views.py @@ -715,16 +715,8 @@ def test_paypal_cart_form_created_with_booking_voucher(self): resp = self.client.get(self.url + '?booking_code=foo') paypalform = resp.context['bookings_paypalform'] - booking_ids_str = ','.join( - [ - str(id) for id in Booking.objects.values_list('id', flat=True) - ] - ) # voucher only applied to first booking - self.assertEqual( - paypalform.initial['custom'], - f'obj=booking ids={booking_ids_str} usr={self.user.email} cde=foo apd={booking.id}' - ) + assert f"cde=foo apd={booking.id}" in paypalform.initial['custom'] for i, booking in enumerate(Booking.objects.all()): self.assertIn('item_name_{}'.format(i + 1), paypalform.initial) diff --git a/booking/views/shopping_basket_views.py b/booking/views/shopping_basket_views.py index 89b759bc..a9735fc0 100644 --- a/booking/views/shopping_basket_views.py +++ b/booking/views/shopping_basket_views.py @@ -143,7 +143,7 @@ def add_total_bookings_and_payment_context(request, context): if context['total_unpaid_booking_cost'] > 0: # total_unpaid_block_cost can be 0 if 100% voucher(s) applied; # paypal button replaced with an update button in template - item_ids_str = ','.join([str(item.id) for item in unpaid_bookings]) + item_ids_str = ','.join([str(item.id) for item in sorted(unpaid_bookings, key=lambda x: x.id)]) custom = context_helpers.get_paypal_custom( item_type='booking', item_ids=item_ids_str, diff --git a/studioadmin/tests/test_views/test_user_bookings_views.py b/studioadmin/tests/test_views/test_user_bookings_views.py index 0f65572e..06fab3ca 100644 --- a/studioadmin/tests/test_views/test_user_bookings_views.py +++ b/studioadmin/tests/test_views/test_user_bookings_views.py @@ -273,6 +273,7 @@ def test_booking_reopened(self): 'status': "OPEN", 'block': '', 'free_class': False, + 'send_confirmation': True, } resp = self.client.post(self.url, data=data) assert not Block.objects.exists() @@ -301,7 +302,6 @@ def test_booking_reopened_was_on_waiting_list(self): 'status': "OPEN", 'block': '', 'free_class': False, - 'send_confirmation': True } self.client.post(self.url, data=data) self.booking.refresh_from_db() @@ -361,6 +361,7 @@ def test_booking_cancelled_as_no_show(self): assert self.booking.status == "OPEN" assert self.booking.no_show assert 'Booking cancelled' in mail.outbox[0].body + assert not Block.objects.filter(block_type__identifier="transferred").exists() def test_can_update_booking_deposit_paid(self): unpaid_booking = baker.make_recipe( @@ -403,6 +404,37 @@ def test_changing_booking_status_to_cancelled_removed_block(self): assert booking.status == 'CANCELLED' assert booking.block is None assert not booking.paid + # no transfer blocks created for block-paid + assert not Block.objects.filter(block_type__identifier="transferred").exists() + + @patch("booking.models.membership_models.StripeConnector", MockConnector) + def test_changing_booking_status_to_cancelled_removed_membership(self): + user_membership = baker.make( + "booking.UserMembership", membership__name="mem", user=self.booking.user, subscription_status="active" + ) + baker.make( + "booking.MembershipItem", membership=user_membership.membership, event_type=self.booking.event.event_type, quantity=3 + ) + assert user_membership.valid_for_event(self.booking.event) + self.booking.membership = user_membership + self.booking.save() + assert self.booking.membership == user_membership + + data = { + 'id': self.booking.id, + 'paid': self.booking.paid, + 'status': "CANCELLED", + 'membership': user_membership.id + } + + resp = self.client.post(self.url, data=data) + self.booking.refresh_from_db() + assert self.booking.status == 'CANCELLED' + assert self.booking.block is None + assert self.booking.membership is None + assert not self.booking.paid + # no transfer blocks created for membership-paid + assert not Block.objects.filter(block_type__identifier="transferred").exists() def test_can_assign_booking_to_available_block(self): booking = baker.make_recipe( diff --git a/studioadmin/tests/test_views/test_user_views.py b/studioadmin/tests/test_views/test_user_views.py index bf50f508..6f543ff2 100644 --- a/studioadmin/tests/test_views/test_user_views.py +++ b/studioadmin/tests/test_views/test_user_views.py @@ -17,6 +17,7 @@ from studioadmin.utils import int_str, chaffify from studioadmin.views.users import NAME_FILTERS from studioadmin.tests.test_views.helpers import TestPermissionMixin +from stripe_payments.tests.mock_connector import MockConnector class UserListViewTests(TestPermissionMixin, TestCase): @@ -540,3 +541,18 @@ def test_attendance_list_with_dates(client): assert resp.context["user_counts"] == { user1: {event.event_type.subtype: 1} } + + +@pytest.mark.django_db +@patch("booking.models.membership_models.StripeConnector", MockConnector) +def test_user_memberships_list(client, configured_stripe_user, purchasable_membership): + user = User.objects.create_user(username="staff", password="test") + user.is_staff = True + user.save() + baker.make("booking.UserMembership", membership=purchasable_membership, user=configured_stripe_user, subscription_status="active") + url = reverse("studioadmin:user_memberships_list", args=(configured_stripe_user.id,)) + client.login(username=user.username, password="test") + resp = client.get(url) + assert resp.context["sidenav_selection"] == "users" + assert resp.status_code == 200 + assert resp.context["user"] == configured_stripe_user diff --git a/studioadmin/views/users.py b/studioadmin/views/users.py index 9bccd9fc..aadcfae3 100644 --- a/studioadmin/views/users.py +++ b/studioadmin/views/users.py @@ -499,7 +499,9 @@ def form_valid(self, form): def process_user_booking_updates(form, request): # The form clean removes block/membership if status is cancelled pre_save_booking = Booking.objects.get(id=form.instance.id) if form.instance.id else None - had_membership_or_block = pre_save_booking and (pre_save_booking.block or pre_save_booking.membership) + had_membership_or_block = pre_save_booking is not None and ( + pre_save_booking.block is not None or pre_save_booking.membership is not None + ) booking = form.save(commit=False) if form.has_changed(): if form.changed_data == ['send_confirmation']: @@ -514,7 +516,9 @@ def process_user_booking_updates(form, request): if 'status' in form.changed_data and action == 'updated': if booking.status == 'CANCELLED': + # create transfer block for paid, non-block, non-membership bookings if pre_save_booking.paid \ + and not had_membership_or_block \ and booking.event.event_type.event_type != 'EV': block_type = BlockType.get_transfer_block_type(booking.event.event_type) Block.objects.create(