diff --git a/accounts/api/serializers.py b/accounts/api/serializers.py index ff0e98d..7ed4d78 100644 --- a/accounts/api/serializers.py +++ b/accounts/api/serializers.py @@ -190,20 +190,27 @@ class ProfileSerializer(serializers.ModelSerializer): return "" def get_has_active_subscription(self, obj): + subscription_status = { + "has_active_subscription": False, + "in_grace_period": False, + "grace_period_end_date": None, + } today = timezone.now().date() - try: - last_active_subscription = PrincipalSubscription.objects.filter( - principal=obj, - is_paid=True, - cancelled=False, - deleted=False, - active=True, - status=SubscriptionStatus.ACTIVE, - end_date__gte=today, - ).latest("end_date") - return True # If the query does not raise DoesNotExist, return True - except PrincipalSubscription.DoesNotExist: - return False # If no matching subscription is found, return False + active_subscriptions = PrincipalSubscription.objects.filter( + principal=obj, + is_paid=True, + cancelled=False, + deleted=False, + active=True, + status=SubscriptionStatus.ACTIVE, + end_date__gte=today, + ) + if active_subscriptions.exists(): + latest_subscription = active_subscriptions.last() + subscription_status["has_active_subscription"] = latest_subscription.is_paid and latest_subscription.status == SubscriptionStatus.ACTIVE and latest_subscription.end_date >= today + subscription_status["in_grace_period"] = not subscription_status["has_active_subscription"] and latest_subscription.grace_period_end_date >= today + subscription_status["grace_period_end_date"] = latest_subscription.grace_period_end_date if subscription_status["in_grace_period"] else None + return active_subscriptions.exists() def to_representation(self, instance): data = super().to_representation(instance) diff --git a/accounts/forms.py b/accounts/forms.py index d7343de..d4d90ee 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -113,8 +113,10 @@ class IAmPrincipalForm(forms.ModelForm): # Set is_superuser and is_staff based on principal_type if principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_ADMIN): instance.is_superuser = True + instance.is_staff = True elif principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_SUBADMIN): instance.is_staff = True + instance.is_superuser = False if commit: instance.save() return instance @@ -327,8 +329,8 @@ class IAmPrincipalResourceLinkForm(IAmPrincipalForm): model = models.IAmPrincipal fields = [ "principal_type", - # "first_name", - # "last_name", + "first_name", + "last_name", "email", # "password", # "confirm_password", diff --git a/accounts/views.py b/accounts/views.py index 96b5c7c..6f5c89d 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -17,7 +17,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse_lazy from django.views import generic from django.db import models, transaction, IntegrityError - +from django.utils import timezone from accounts import permission from goodtimes import constants from . import resource_action @@ -215,7 +215,7 @@ class PrincipalCreateOrUpdateView(LoginRequiredMixin, generic.View): if not principal.pk: # pk is None for new objects principal.created_by = request.user principal.modified_by = request.user - principal.modified_on = datetime.datetime.now() + principal.modified_on = timezone.now() # Save the object principal.save() diff --git a/goodtimes/services.py b/goodtimes/services.py index a331534..c960d50 100644 --- a/goodtimes/services.py +++ b/goodtimes/services.py @@ -295,7 +295,7 @@ class PaymentProcessingService: payment_method="", transaction_status=TransactionStatus.SUCCESS, amount=0, - coin=1, + coins=1, comment="Referral reward", # Populate other fields as necessary, such as `order_id`, `product_id`, or `reference_id` if applicable ) diff --git a/manage_communications/utils.py b/manage_communications/utils.py new file mode 100644 index 0000000..1c7f74a --- /dev/null +++ b/manage_communications/utils.py @@ -0,0 +1,16 @@ +import logging +from threading import Thread + +# Configure logging at the beginning of your application +logging.basicConfig(level=logging.INFO, filename='app.log', filemode='a', format='%(name)s - %(levelname)s - %(message)s') + +def send_email_async(email_service): + try: + email_service.send() + print("Email sent from utils successfully!") + except Exception as e: + # Log the exception + print(f"Failed to send email: {e}") + logging.error(f"Failed to send email: {e}") + # Optionally, you could use other means to notify you of the failure, + # such as sending an alert to an admin email, or using a monitoring service. \ No newline at end of file diff --git a/manage_communications/views.py b/manage_communications/views.py index bb1b4fd..6cdaeba 100644 --- a/manage_communications/views.py +++ b/manage_communications/views.py @@ -1,6 +1,11 @@ +import threading +from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from accounts import resource_action from django.views import generic + +from goodtimes.services import EmailService +from manage_communications.utils import send_email_async from .models import Feedback, ContactUs, Tickets from goodtimes import constants from django.shortcuts import get_object_or_404, redirect, render @@ -42,6 +47,33 @@ class ContactUsReplyView(LoginRequiredMixin, generic.View): instance.reply = message instance.save() messages.success(request, self.success_message) + name = instance.name + email = instance.email_address + subject = instance.subject + # Create an instance of the EmailService + email_service = EmailService( + subject=f"GoodTimes - {subject}", + to=[ + email, + ], + from_email=settings.EMAIL_HOST_USER, + ) + print("email_service: ", email_service) + email_service.load_template( + "manage_communications/contact_us_email.html", + context={ + "email": email, + "message": message, + "subject": subject, + "name": name, + }, + ) + # Send the email using threading + email_thread = threading.Thread( + target=send_email_async, args=(email_service,) + ) + email_thread.start() + print("Email sent from views successfully!") except self.model.DoesNotExist: messages.error(request, "Contact Us entry not found") except Exception as e: @@ -94,6 +126,7 @@ class TicketListView(LoginRequiredMixin, generic.ListView): context["page_name"] = self.page_name return context + class FeedbackListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_MANAGE_FEEDBACK resource = resource_action.RESOURCE_MANAGE_FEEDBACK diff --git a/manage_wallets/api/views.py b/manage_wallets/api/views.py index e505c92..87c3636 100644 --- a/manage_wallets/api/views.py +++ b/manage_wallets/api/views.py @@ -390,7 +390,7 @@ class WithdrawalRequestCreateAPI(APIView): return ApiResponse.success( data=serializer.data, status=status.HTTP_200_OK, - message=constants.SUCCESS, + message="Request Sent Successfully", ) else: return ApiResponse.error( diff --git a/templates/manage_communications/contact_us_email.html b/templates/manage_communications/contact_us_email.html new file mode 100644 index 0000000..e4cb75c --- /dev/null +++ b/templates/manage_communications/contact_us_email.html @@ -0,0 +1,86 @@ + + + + + + + + +
+
+

Your Inquiry Has Been Received

+
+
+

Hello {{ name|default:"Customer" }},

+ +

Thank you for reaching out to us. We have received your inquiry regarding:

+
{{ subject }}
+

Here is our response:

+

{{ message }}

+

We hope this response addresses your concerns. Should you have any further questions, please do not hesitate to + contact us again.

+

Warm regards,

+

The GoodTimes Team

+
+ +
+ + + \ No newline at end of file diff --git a/templates/manage_communications/contact_us_list.html b/templates/manage_communications/contact_us_list.html index 07f7c15..a3ab53d 100644 --- a/templates/manage_communications/contact_us_list.html +++ b/templates/manage_communications/contact_us_list.html @@ -149,10 +149,6 @@ {% csrf_token %}