From 7ba73dff3524d99d2b150adaabb5837b74d6195a Mon Sep 17 00:00:00 2001 From: bobbyvish Date: Sun, 25 Aug 2024 19:11:49 +0530 Subject: [PATCH] refator(subscription): update functionality, list view, subscription design --- manage_events/api/filters.py | 4 +- manage_subscriptions/forms.py | 19 +++++ ...014_alter_subscription_long_description.py | 19 +++++ manage_subscriptions/models.py | 47 ++++++++++-- manage_subscriptions/urls.py | 5 ++ manage_subscriptions/views.py | 2 +- static/src/assets/css/payment/style.css | 32 +++++++- .../principal_subscriptions_list.html | 14 +--- .../subscription_details.html | 28 +++---- .../subscription_list.html | 28 +++++-- templates/stripe_html/index.html | 76 +++++++++---------- 11 files changed, 183 insertions(+), 91 deletions(-) create mode 100644 manage_subscriptions/migrations/0014_alter_subscription_long_description.py diff --git a/manage_events/api/filters.py b/manage_events/api/filters.py index e4adacb..e26a938 100644 --- a/manage_events/api/filters.py +++ b/manage_events/api/filters.py @@ -14,7 +14,7 @@ class EventFilter(filters.FilterSet): # end_date = filters.DateFilter(field_name="end_date", lookup_expr="lte") price_from = filters.NumberFilter(field_name="entry_fee", lookup_expr="gte") price_to = filters.NumberFilter(field_name="entry_fee", lookup_expr="lte") - age_group = filters.CharFilter(method="filter_age_group") + age_group = filters.CharFilter(method="filter_age_group") class Meta: model = Event @@ -32,7 +32,7 @@ class EventFilter(filters.FilterSet): def filter_category(self, queryset, name, value): category = value.split(',') return queryset.filter(category__title__in=category) - + def filter_age_group(self, queryset, name, value): age_group = value.split(',') return queryset.filter(age_group__in=age_group) diff --git a/manage_subscriptions/forms.py b/manage_subscriptions/forms.py index ececb47..d4afaee 100644 --- a/manage_subscriptions/forms.py +++ b/manage_subscriptions/forms.py @@ -11,6 +11,7 @@ class SubscriptionForm(forms.ModelForm): fields = [ "title", "short_description", + "long_description", "interval", "interval_count", "high_amount", @@ -20,6 +21,7 @@ class SubscriptionForm(forms.ModelForm): "active", "is_free", ] + exclude = [] def __init__(self, *args, **kwargs): super(SubscriptionForm, self).__init__(*args, **kwargs) @@ -29,6 +31,23 @@ class SubscriptionForm(forms.ModelForm): id__in=[event_user.id, event_manager.id] ) + if self.instance: + # If there is an instance (i.e. we're editing an existing subscription) + + # Use a dictionary comprehension to create a new dictionary of fields + # that excludes the readonly fields + self.fields = { + field_name: field + for field_name, field in self.fields.items() + if field_name not in [ + "interval", + "interval_count", + "amount", + "high_amount", + "principal_types", + ] + } + class PrincipalSubscriptionForm(forms.ModelForm): class Meta: diff --git a/manage_subscriptions/migrations/0014_alter_subscription_long_description.py b/manage_subscriptions/migrations/0014_alter_subscription_long_description.py new file mode 100644 index 0000000..51a85f9 --- /dev/null +++ b/manage_subscriptions/migrations/0014_alter_subscription_long_description.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0.2 on 2024-08-25 10:39 + +import django_quill.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('manage_subscriptions', '0013_remove_subscription_plan_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='subscription', + name='long_description', + field=django_quill.fields.QuillField(), + ), + ] diff --git a/manage_subscriptions/models.py b/manage_subscriptions/models.py index 9c929fa..70bba3b 100644 --- a/manage_subscriptions/models.py +++ b/manage_subscriptions/models.py @@ -4,6 +4,7 @@ from django.db import models from django.core.exceptions import ValidationError from accounts.models import BaseModel, IAmPrincipal, IAmPrincipalType from django.utils.translation import gettext_lazy as _ +from django_quill.fields import QuillField class Subscription(BaseModel): @@ -22,7 +23,7 @@ class Subscription(BaseModel): price_id = models.CharField(max_length=255, blank=True, null=True) product_id = models.CharField(max_length=255, blank=True, null=True) short_description = models.CharField(max_length=255, null=True, blank=True) - long_description = models.TextField(null=True, blank=True) + long_description = QuillField() image = models.ImageField(upload_to="subscription_img", null=True, blank=True) interval = models.CharField(max_length=10, choices=INTERVAL_TYPES) interval_count = models.IntegerField(default=1) @@ -56,19 +57,40 @@ class Subscription(BaseModel): def save(self, *args, **kwargs): from goodtimes.services import StripeService + if not self.delete: self.clean() - if not self.is_free: - if self.price_id: - # Stipe dont provide to update the price record except active and deactive + if self.is_free: + # If is_free is True, set amounts to 0 and remove Stripe price and product IDs + self.high_amount = 0.00 + self.amount = 0.00 + self.price_id = None + self.product_id = None + else: + if self.id and self.price_id: # Update existing subscription + # Retrieve existing price and product from Stripe price = StripeService.retrieve_price(self.price_id) if not price["success"]: raise Exception(price['message']) + # Update price active status if it differs from local active status if self.active != price["data"].active: StripeService.update_price(price_id=self.price_id, active=self.active) - else: + + # Retrieve existing product from Stripe + product = StripeService.retrive_product(self.product_id) + if not product["success"]: + raise Exception(product['message']) + + # Update product data if it has changed + if product["data"].name != self.title or product["data"].description != self.short_description: + StripeService.update_product( + product_id=self.product_id, + name=self.title, + description=self.short_description + ) + else: # Create new subscription # Create new product and price price = StripeService.create_price( product_data={ @@ -89,7 +111,7 @@ class Subscription(BaseModel): if not price["success"]: raise Exception(price['message']) - # add the id in record + # Add the IDs to the record self.price_id = price["data"].id self.product_id = price["data"].product @@ -105,8 +127,6 @@ class Subscription(BaseModel): return count[self.interval] * self.interval_count - - class SubscriptionStatus(models.TextChoices): ACTIVE = "active", _("Active") EXPIRED = "expired", _("Expired") @@ -146,6 +166,17 @@ class PrincipalSubscription(BaseModel): def __str__(self): return f"{self.subscription} - {self.principal.first_name}" + + def save(self, *args, **kwargs): + # If the subscription status is expired or inactive, set the active flag to False + if self.status in [SubscriptionStatus.EXPIRED, SubscriptionStatus.INACTIVE]: + self.active = False + + # If the active flag is False, set the status to inactive + if not self.active: + self.status = SubscriptionStatus.INACTIVE + super.save(*args, **kwargs) + def generate_order_id(email): return f"order_{str(timezone.localtime().timestamp())}{str(email)}" diff --git a/manage_subscriptions/urls.py b/manage_subscriptions/urls.py index 6e69838..21c0d15 100644 --- a/manage_subscriptions/urls.py +++ b/manage_subscriptions/urls.py @@ -12,6 +12,11 @@ urlpatterns = [ views.SubscriptionCreateOrUpdateView.as_view(), name="subscription_add", ), + path( + "subscription/edit//", + views.SubscriptionCreateOrUpdateView.as_view(), + name="subscription_edit", + ), path("subscription//", views.SubscriptionDetailView.as_view(), name="subscription_detail"), path( "subscription/delete/", diff --git a/manage_subscriptions/views.py b/manage_subscriptions/views.py index 5c582dc..1c5e00b 100644 --- a/manage_subscriptions/views.py +++ b/manage_subscriptions/views.py @@ -126,7 +126,7 @@ class SubscriptionView(LoginRequiredMixin, generic.ListView): queryset = ( super() .get_queryset() - .filter(deleted=False, active=True) + .filter(deleted=False) .prefetch_related("principal_types") ) return queryset.order_by("-created_on") diff --git a/static/src/assets/css/payment/style.css b/static/src/assets/css/payment/style.css index b58d7c4..5fb6746 100644 --- a/static/src/assets/css/payment/style.css +++ b/static/src/assets/css/payment/style.css @@ -331,6 +331,7 @@ header nav ul li a:hover:after { font-weight: 600; padding: 10px 40px; border-radius: 5px; + width: 100%; } @@ -601,8 +602,6 @@ div#accordionExample { .gold-text { color: rgb(209 170 88); - margin: 0; - padding: 12px; } .bg_color { @@ -618,9 +617,35 @@ div#accordionExample { padding: 35px; border-radius: 6px; background-color: #00000080; - text-align: center; + text-align: start; + margin-bottom: 15px; } +/* New css */ +.feat-card .para { + font-size: 18px; + } + .currency{ + font-size: 36px; + color: #fff; + margin-right:5px + } + .interval{ + font-size: 14px; + color: gray; + } + + .actual-price { + text-decoration: line-through; + color: #ccc; +} + .offer-price { + font-size: 36px; + /* font-weight: bold; */ + color: #fff; +} + + /* mediascreen */ @media (max-width: 1199px) { .big-heading br { @@ -829,6 +854,7 @@ div#accordionExample { .common-btn { /* remove default button margins */ margin: 0; + width: 100%; } .feat-card input.form-control.coupon-code-input { border-radius: 5px; diff --git a/templates/manage_subscriptions/principal_subscriptions_list.html b/templates/manage_subscriptions/principal_subscriptions_list.html index 7bbc327..2bbae88 100644 --- a/templates/manage_subscriptions/principal_subscriptions_list.html +++ b/templates/manage_subscriptions/principal_subscriptions_list.html @@ -60,18 +60,15 @@ End - Is Subscription Grace Created At - Active + style="width: 100.625px;">Active {% endcomment %} Action @@ -88,14 +85,11 @@ {{data_obj.stripe_subscription_id}} {{data_obj.start_date}} {{data_obj.end_date}} - - {{data_obj.is_stripe_subscription}} - {{data_obj.grace_period_end_date}} {{data_obj.created_on}} - + {% comment %} {{data_obj.active}} - + {% endcomment %}