diff --git a/tapir/coop/services/membership_resignation_service.py b/tapir/coop/services/membership_resignation_service.py index 7007fd713..f577cab80 100644 --- a/tapir/coop/services/membership_resignation_service.py +++ b/tapir/coop/services/membership_resignation_service.py @@ -3,6 +3,7 @@ from dateutil.relativedelta import relativedelta from django.contrib.auth.models import User from django.db import transaction +from django.db.models import Q from tapir.accounts.models import TapirUser from tapir.coop.models import MembershipResignation, ShareOwnership, MembershipPause @@ -21,6 +22,10 @@ def update_shifts_and_shares_and_pay_out_day( resignation: MembershipResignation, actor: TapirUser | User ): shares = ShareOwnership.objects.filter(share_owner=resignation.share_owner) + end_date_null_or_after_cancellation_filter = Q(end_date__isnull=True) | Q( + end_date__gte=resignation.cancellation_date + ) + shares = shares.filter(end_date_null_or_after_cancellation_filter) match resignation.resignation_type: case MembershipResignation.ResignationType.BUY_BACK: @@ -29,6 +34,10 @@ def update_shifts_and_shares_and_pay_out_day( ) resignation.pay_out_day = new_end_date resignation.save() + end_date_null_or_after_pay_out_day_filter = Q( + end_date__isnull=True + ) | Q(end_date__gte=resignation.pay_out_day) + shares = shares.filter(end_date_null_or_after_pay_out_day_filter) shares.update(end_date=new_end_date) return case MembershipResignation.ResignationType.GIFT_TO_COOP: diff --git a/tapir/coop/tests/membership_resignation/test_service.py b/tapir/coop/tests/membership_resignation/test_service.py index 533b19840..e973867ae 100644 --- a/tapir/coop/tests/membership_resignation/test_service.py +++ b/tapir/coop/tests/membership_resignation/test_service.py @@ -38,6 +38,40 @@ def setUp(self) -> None: self.given_feature_flag_value(feature_flag_membership_resignation, True) mock_timezone_now(self, self.NOW) + def test_updateShiftsAndSharesAndPayOutDay_default_sharesWithEndDateBeforeCancellationAreNotAffected( + self, + ): + actor = self.login_as_member_office_user() + share_owner: ShareOwner = ShareOwnerFactory.create(nb_shares=2) + shares = share_owner.share_ownerships.all() + share_that_end_in_the_past = shares[0] + share_that_end_in_the_past.end_date = self.TODAY - datetime.timedelta(days=1) + share_that_end_in_the_past.save() + share_that_end_in_the_future = shares[1] + share_that_end_in_the_future.end_date = self.TODAY + datetime.timedelta(days=1) + share_that_end_in_the_future.save() + + resignation = MembershipResignationFactory.create( + share_owner=share_owner, + resignation_type=MembershipResignation.ResignationType.GIFT_TO_COOP, + cancellation_date=self.TODAY, + ) + + MembershipResignationService.update_shifts_and_shares_and_pay_out_day( + resignation=resignation, actor=actor + ) + + share_that_end_in_the_past.refresh_from_db() + self.assertEqual( + self.TODAY - datetime.timedelta(days=1), + share_that_end_in_the_past.end_date, + ) + share_that_end_in_the_future.refresh_from_db() + self.assertEqual( + self.TODAY, + share_that_end_in_the_future.end_date, + ) + def test_updateShiftsAndSharesAndPayOutDay_resignationTypeBuyBack_sharesEndDateAndPayOutDaySetToThreeYearsAfterResignation( self, ): @@ -62,6 +96,41 @@ def test_updateShiftsAndSharesAndPayOutDay_resignationTypeBuyBack_sharesEndDateA share.end_date, ) + def test_updateShiftsAndSharesAndPayOutDay_resignationTypeBuyBack_sharesThatEndBeforePayOutDayNotAffected( + self, + ): + actor = self.login_as_member_office_user() + share_owner: ShareOwner = ShareOwnerFactory.create(nb_shares=2) + share_that_end_between_now_and_pay_out_day = ( + share_owner.share_ownerships.first() + ) + share_that_end_between_now_and_pay_out_day.end_date = ( + self.TODAY + datetime.timedelta(weeks=10) + ) + share_that_end_between_now_and_pay_out_day.save() + resignation = MembershipResignationFactory.create( + share_owner=share_owner, + resignation_type=MembershipResignation.ResignationType.BUY_BACK, + cancellation_date=self.TODAY, + ) + + MembershipResignationService.update_shifts_and_shares_and_pay_out_day( + resignation=resignation, actor=actor + ) + + resignation.refresh_from_db() + expected_pay_out_day = datetime.date(year=2027, month=12, day=31) + self.assertEqual( + 1, + share_owner.share_ownerships.filter( + end_date=self.TODAY + datetime.timedelta(weeks=10) + ).count(), + ) + self.assertEqual( + 1, + share_owner.share_ownerships.filter(end_date=expected_pay_out_day).count(), + ) + def test_updateShiftsAndSharesAndPayOutDay_resignationTypeGiftToCoop_sharesEndDateAndPayOutDaySetToResignationDate( self, ):