Coverage for products/utils/install_membership.py: 67%
40 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-03-29 14:03 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-03-29 14:03 -0600
1import calendar
2from dateutil.relativedelta import relativedelta
3from django.db import transaction
4from django.utils import timezone
5from memberships.models import Membership, MembershipPeriod
6from memberships.serializers import MembershipPeriodSerializer
7from products.models import MembershipProduct, ProductPurchase
10def install_membership_purchase(purchase: ProductPurchase):
11 """Install all memberships in a membership purchase"""
12 owners_relation = (
13 purchase.owner_relation
14 if purchase.owner_relation
15 else [{"membership": purchase.membership.random_slug, "quantity": purchase.quantity}]
16 )
17 response_data = []
18 with transaction.atomic():
19 for item in owners_relation:
20 membership = Membership.objects.get(random_slug=item.get("membership"))
21 for i in range(item.get("quantity")):
22 data = install_single_membership_product(membership, purchase.product)
23 response_data.append(data)
24 return response_data
27def install_single_membership_product(membership: Membership, product: MembershipProduct):
28 """
29 Installation Process for membership product
30 """
31 today = timezone.datetime.today()
33 last_period = MembershipPeriod.objects.filter(membership=membership).first()
34 new_period_start = (
35 max(last_period.period_end + relativedelta(days=1), today.date()) if last_period else today.date()
36 )
38 new_period_end = _get_price_and_end_period_date(product, new_period_start)
40 period = MembershipPeriod.objects.create(
41 membership=membership,
42 product=product,
43 previous=last_period,
44 period_start=new_period_start,
45 period_end=new_period_end,
46 )
48 serializer = MembershipPeriodSerializer(period)
50 return serializer.data
53def _get_price_and_end_period_date(product, new_period_start):
54 if product.renewal_type == MembershipProduct.RenewalTypeChoices.days: 54 ↛ 60line 54 didn't jump to line 60, because the condition on line 54 was never false
55 """If renewal is by 'days' calculate period end date by adding a month/year"""
56 duration = MembershipProduct.DurationChoices.get_choice(product.duration)
57 new_period_end = new_period_start + relativedelta(**duration.days)
58 return new_period_end
60 if product.renewal_type == MembershipProduct.RenewalTypeChoices.calendar:
61 """If renewal is by 'calendar' calculate period end by taking last month/year day
62 and recalculating price by days proportion"""
64 if product.duration != MembershipProduct.DurationChoices.yearly:
65 duration = MembershipProduct.DurationChoices.get_choice(product.duration)
67 new_period_month = (new_period_start + relativedelta(months=duration.days["months"] - 1)).month
69 month_days = calendar.monthrange(new_period_start.year, new_period_month)[1]
70 new_period_end = timezone.datetime(
71 day=month_days,
72 month=new_period_month,
73 year=new_period_start.year,
74 )
76 return new_period_end.date()
78 if product.duration == MembershipProduct.DurationChoices.yearly:
79 new_period_end = timezone.datetime(day=31, month=12, year=new_period_start.year)
81 return new_period_end.date()