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 @@
+
+
+
+
+
+
+
+
+
+
+
+
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 %}
-
-
-
-
@@ -183,6 +179,7 @@
"sSearchPlaceholder": "Search...",
"sLengthMenu": "Results : _MENU_",
},
+ "order": [[ 0, "desc" ]],
"stripeClasses": [],
"lengthMenu": [5, 10, 20, 50],
"pageLength": 10
diff --git a/templates/manage_communications/feedback_list.html b/templates/manage_communications/feedback_list.html
index a9f76d5..5681a58 100644
--- a/templates/manage_communications/feedback_list.html
+++ b/templates/manage_communications/feedback_list.html
@@ -2,10 +2,7 @@
{% load static %}
{% block stylesheet %}
-
{% include "cdn_through_html/datatable_cdn_css.html" %}
- {% include "cdn_through_html/animate_cdn_css.html" %}
- {% include "cdn_through_html/modal_cdn_css.html" %}
{% endblock %}
@@ -13,142 +10,65 @@
-
-
+
+
Manage Feedback
-
-
+
+
-
-
-
-
-
-{% endblock content %}
-
-{% block javascript %}
-
-
-
- {% include "cdn_through_html/datatable_cdn_css.html" %}
-
-
-{% endblock %}
\ No newline at end of file
+
+ {% endblock content %}
+
+ {% block javascript %}
+
+ {% include "cdn_through_html/datatable_cdn_js.html" %}
+
+
+ {% endblock %}
\ No newline at end of file
diff --git a/templates/manage_communications/ticket_list.html b/templates/manage_communications/ticket_list.html
index a39ed9d..d84cf47 100644
--- a/templates/manage_communications/ticket_list.html
+++ b/templates/manage_communications/ticket_list.html
@@ -178,6 +178,7 @@
"sSearchPlaceholder": "Search...",
"sLengthMenu": "Results : _MENU_",
},
+ "order": [[ 0, "desc" ]],
"stripeClasses": [],
"lengthMenu": [5, 10, 20, 50],
"pageLength": 10