diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 4aade19..7e66c47 100644 Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 36d4735..e4ccd77 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index ac18520..e5fe7c7 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/forms.py b/core/forms.py index 8fec155..1740dda 100644 --- a/core/forms.py +++ b/core/forms.py @@ -158,4 +158,11 @@ class ShipperOfferForm(forms.Form): delivery_date = forms.DateField(label=_('Requested Delivery Date'), widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})) amount = forms.DecimalField(label=_('Offer Amount'), max_digits=10, decimal_places=2, widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'})) - comments = forms.CharField(label=_('Comments'), required=False, widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 2})) \ No newline at end of file + comments = forms.CharField(label=_('Comments'), required=False, widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 2})) + +class RenewSubscriptionForm(forms.Form): + subscription_plan = forms.ChoiceField( + choices=[('MONTHLY', _('Monthly Plan')), ('ANNUAL', _('Annual Plan'))], + widget=forms.Select(attrs={'class': 'form-select'}), + label=_('Subscription Plan') + ) diff --git a/core/templates/core/admin_dashboard.html b/core/templates/core/admin_dashboard.html index 2372dc3..9ed20dd 100644 --- a/core/templates/core/admin_dashboard.html +++ b/core/templates/core/admin_dashboard.html @@ -18,45 +18,63 @@ {% block content %}
-
+

{% trans "Administrator Dashboard" %}

{% trans "System overview and management" %}

- +
-
-
-
-

{{ total_users }}

-

{% trans "Total Users" %}

+
+
+
+

{{ total_users }}

+

{% trans "Total Users" %}

-
-
-
-

{{ total_trucks }}

-

{% trans "Registered Trucks" %}

+
+
+
+

{{ total_trucks }}

+

{% trans "Trucks" %}

-
-
-
-

{{ total_shipments }}

-

{% trans "Total Shipments" %}

+
+
+
+

{{ total_shipments }}

+

{% trans "Shipments" %}

-
-
-
-

{{ total_bids }}

-

{% trans "Active Bids" %}

+
+
+
+

{{ total_bids }}

+

{% trans "Bids" %}

+
+
+
+
+
+

{{ active_subscriptions }}

+

{% trans "Active Subs" %}

+
+
+
+
+
+

{{ expired_subscriptions }}

+

{% trans "Expired Subs" %}

@@ -391,4 +409,4 @@ border-bottom: none; } -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/subscription_expired.html b/core/templates/core/subscription_expired.html index 01b2bd5..4ae3541 100644 --- a/core/templates/core/subscription_expired.html +++ b/core/templates/core/subscription_expired.html @@ -8,7 +8,7 @@
- +

{% trans "Subscription Expired" %}

@@ -22,13 +22,36 @@

  • {% trans "Current Plan:" %} {{ profile.get_subscription_plan_display }}
  • -

    - {% trans "To continue using our services, please renew your subscription. You can contact our support team for renewal details." %} -

    +
    + +
    +

    {% trans "Renew Your Subscription" %}

    + +
    + {% csrf_token %} +
    + + {{ form.subscription_plan }} +
    + +
    +
    {% trans "Fee to Pay:" %}
    + 0.00 + {% trans "SAR" %} +
    + +
    + +
    +
    +
    + {% if app_settings.contact_phone or app_settings.contact_email %} -
    -
    {% trans "Contact for Renewal" %}
    +
    +
    {% trans "Need Help?" %}
    {% if app_settings.contact_phone %}

    {{ app_settings.contact_phone }}

    {% endif %} @@ -38,11 +61,8 @@
    {% endif %} -
    -{% endblock %} + + +{% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 9f88dc6..a2f06e9 100644 --- a/core/urls.py +++ b/core/urls.py @@ -23,4 +23,5 @@ urlpatterns = [ path("privacy-policy/", views.privacy_policy, name="privacy_policy"), path("terms-of-service/", views.terms_of_service, name="terms_of_service"), path("subscription-expired/", views.subscription_expired, name="subscription_expired"), -] + path("subscription-renew/", views.renew_subscription, name="renew_subscription"), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index a5102b8..0b8a4b9 100644 --- a/core/views.py +++ b/core/views.py @@ -4,7 +4,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth import login, authenticate, logout from django.utils import timezone from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection -from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm +from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm from django.contrib import messages from django.utils.translation import gettext as _ from django.db.models import Q @@ -208,6 +208,18 @@ def dashboard(request): elif profile.role == 'ADMIN' or request.user.is_superuser: pending_trucks = Truck.objects.filter(is_approved=False).order_by('-created_at') approved_trucks = Truck.objects.filter(is_approved=True).order_by('-created_at') + + # Subscription stats + today = timezone.now().date() + total_profiles = Profile.objects.exclude(role='ADMIN') + active_subscriptions = 0 + expired_subscriptions = 0 + for p in total_profiles: + if p.is_expired(): + expired_subscriptions += 1 + else: + active_subscriptions += 1 + context = { 'total_users': User.objects.count(), 'total_trucks': Truck.objects.count(), @@ -215,6 +227,8 @@ def dashboard(request): 'total_bids': Bid.objects.count(), 'pending_trucks': pending_trucks, 'approved_trucks': approved_trucks, + 'active_subscriptions': active_subscriptions, + 'expired_subscriptions': expired_subscriptions, } return render(request, 'core/admin_dashboard.html', context) else: @@ -429,10 +443,11 @@ def terms_of_service(request): context = { 'article': { 'title': _('Terms of Service'), - 'content': app_settings.terms_of_service if app_settings else _("Terms of service are coming soon.") + 'content': app_settings.terms_of_service if app_settings else _("Terms of service are soon.") } } return render(request, 'core/article_detail.html', context) + @login_required def subscription_expired(request): profile = request.user.profile @@ -440,8 +455,43 @@ def subscription_expired(request): return redirect('dashboard') app_settings = AppSetting.objects.first() + form = RenewSubscriptionForm() + + # Simplified fees dictionary for JS + fees = { + 'SHIPPER': { + 'MONTHLY': str(app_settings.shipper_monthly_fee) if app_settings else "0.00", + 'ANNUAL': str(app_settings.shipper_annual_fee) if app_settings else "0.00", + }, + 'TRUCK_OWNER': { + 'MONTHLY': str(app_settings.truck_owner_monthly_fee) if app_settings else "0.00", + 'ANNUAL': str(app_settings.truck_owner_annual_fee) if app_settings else "0.00", + } + } + return render(request, 'core/subscription_expired.html', { 'profile': profile, - 'app_settings': app_settings + 'app_settings': app_settings, + 'form': form, + 'fees_json': json.dumps(fees) }) +@login_required +def renew_subscription(request): + if request.method == 'POST': + form = RenewSubscriptionForm(request.POST) + if form.is_valid(): + profile = request.user.profile + plan = form.cleaned_data['subscription_plan'] + profile.subscription_plan = plan + profile.is_subscription_active = True + + if plan == 'MONTHLY': + profile.subscription_expiry = timezone.now().date() + timedelta(days=30) + elif plan == 'ANNUAL': + profile.subscription_expiry = timezone.now().date() + timedelta(days=365) + + profile.save() + messages.success(request, _("Subscription renewed successfully!")) + return redirect('dashboard') + return redirect('subscription_expired') \ No newline at end of file