diff --git a/booking/models/membership_models.py b/booking/models/membership_models.py index af2e5a10..02845246 100644 --- a/booking/models/membership_models.py +++ b/booking/models/membership_models.py @@ -264,6 +264,47 @@ def calculate_membership_end_date(cls, end_date=None): return return get_first_of_next_month_from_timestamp(end_date.timestamp()) + def _reallocate_booking(self, booking, other_active_memberships): + # no-show or cancelled bookings are just set to no membership and unpaid + if booking.no_show or booking.status == "CANCELLED": + booking.membership = None + booking.paid = False + booking.payment_confirmed = False + booking.save() + return booking + # assign to first valid membership + for membership in other_active_memberships: + if membership.valid_for_event(booking.event): + booking.membership = membership + booking.paid = True + booking.payment_confirmed = True + booking.save() + ActivityLog.objects.create( + log=f"Reallocated booking {booking.id} (user {self.user.username}) to membership {membership}" + ) + return booking + # assign to first valid block + active_block = booking.get_next_active_block() + if active_block is not None: + booking.membership = None + booking.block = active_block + booking.paid = True + booking.payment_confirmed = True + booking.save() + ActivityLog.objects.create( + log=f"Reallocated booking {booking.id} (user {self.user.username}) to block {active_block.id}" + ) + return booking + # no valid membership or block, set to None + booking.membership = None + booking.paid = False + booking.payment_confirmed = False + booking.save() + ActivityLog.objects.create( + log=f"Booking {booking.id} (user {self.user.username}) for cancelled membership set to unpaid" + ) + return booking + def reallocate_bookings(self): """ 1) Check user's membership for bookings that shouldn't be there and reallocate if possible @@ -282,4 +323,15 @@ def reallocate_bookings(self): # temporory logging ActivityLog.objects.create( log=f"Reallocate bookings called {self.subscription_id}" - ) \ No newline at end of file + ) + if self.end_date: + # check for open bookings for events after the end date + bookings_after_end_date = self.bookings.filter(event__date__gt=self.end_date) + other_active_memberships = self.user.memberships.filter(subscription_status="active") + for booking in bookings_after_end_date: + booking = self._reallocate_booking(booking, other_active_memberships) + + elif self.subscription_status == "active": + # check for unpaid bookings that this membership is eligible for and assign the membership to it + # email user a notification? + ... \ No newline at end of file diff --git a/booking/tests/test_membership_models.py b/booking/tests/test_membership_models.py index 9fce4565..903b0255 100644 --- a/booking/tests/test_membership_models.py +++ b/booking/tests/test_membership_models.py @@ -816,10 +816,12 @@ def test_reallocate_bookings_after_cancel_with_other_membership_inactive(seller) # New membership starts next month, not yet active next_user_membership = baker.make( UserMembership, + user=user_membership.user, membership=user_membership.membership, start_date=datetime(2020, 4, 1, tzinfo=dt_tz.utc), subscription_status="inactive", ) + assert not next_user_membership.valid_for_event(booking_next.event) user_membership.reallocate_bookings() @@ -848,16 +850,18 @@ def test_reallocate_bookings_after_cancel_with_other_membership_active(seller): # New membership starts next month, not yet active next_user_membership = baker.make( UserMembership, + user=user_membership.user, membership=user_membership.membership, start_date=datetime(2020, 4, 1, tzinfo=dt_tz.utc), subscription_status="active", ) + assert next_user_membership.valid_for_event(booking_next.event) user_membership.reallocate_bookings() for bk in booking_set: bk.refresh_from_db() - + # next months booking has been removed assert set(user_membership.bookings.all()) == {booking, booking_end_of_month} # allocated to next membership @@ -866,7 +870,6 @@ def test_reallocate_bookings_after_cancel_with_other_membership_active(seller): assert booking_next.paid -@pytest.mark.xfail @pytest.mark.freeze_time("2020-03-21") @patch("booking.models.membership_models.StripeConnector", MockConnector) def test_reallocate_bookings_after_cancel_with_active_block(seller): @@ -881,17 +884,18 @@ def test_reallocate_bookings_after_cancel_with_active_block(seller): ) assert block.active_block() - assert booking_next.has_available_block + assert booking_next.get_next_active_block() == block # change status to cancelled user_membership.subscription_status == "canceled" + user_membership.end_date = datetime(2020, 4, 1, tzinfo=dt_tz.utc) user_membership.save() user_membership.reallocate_bookings() for bk in booking_set: bk.refresh_from_db() - + # next months booking has been removed assert set(user_membership.bookings.all()) == {booking, booking_end_of_month} # allocated to next membership