From 221476cb528ccc2182289ecd147678138e82fc4d Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 24 Jan 2026 04:17:22 +0000 Subject: [PATCH] new update --- core/__pycache__/forms.cpython-311.pyc | Bin 15636 -> 16185 bytes core/__pycache__/urls.cpython-311.pyc | Bin 2398 -> 2505 bytes core/__pycache__/views.cpython-311.pyc | Bin 26302 -> 28602 bytes core/forms.py | 9 ++- core/templates/core/admin_dashboard.html | 64 ++++++++++------ core/templates/core/subscription_expired.html | 69 +++++++++++++++--- core/urls.py | 3 +- core/views.py | 56 +++++++++++++- 8 files changed, 161 insertions(+), 40 deletions(-) diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 4aade19ea032b403dffd5577fa82b6ef67db5aba..7e66c47dc9982a690a55e0846022855b4ed14a03 100644 GIT binary patch delta 2210 zcmZ{lTWl0n9LD$Tt-Eb^w-riDw<`-Q!9i%L(h|2NP$;dEwp_}C^|lN1B6rgfFVFU!ASK&BmQE-Z!#rrv5T=TpAg;NCtzA=l%)g?a6VlAqRm^3V7maPq@(JfX6v?2%c=2qp!F&w4?IiSK zd^;fG@8-Qi_}kgLi<7I0tSN*ejb%d|2H{v|r)&h`2#drh88MH=ZaI^qP!4kRNaeI> zGcU$wyJq>2Dw(P>)iEkOJ&fKFpbl6Fhzb$bd|>{tG+1!{K#U&4gpYtR;5`nb*tbKH z5@r}JcHsoX6RdREUUEXD=GSE&(sv5#X^tMLtk{hbjLmk#w)+qU&H?{x{6*Hf{NPOD zJmzo9bA)`&67{XQLh?ij6wV{kX!+h8R_Pu?&CpIf0Qt521FAm6i+6WM`uCI-5_}c2 z9(T%69@&cZn$nS`gY}7omeMkb#9;@kZTRu=5t_hO6YS51y=1~PR%YGaQ&3K`d#g6( zuAy54oB_T7zU1IsoV!6qbkvMRoC9)?nK*Ve)MKaCR@I_zh9-%w!!pp zDsvle-P=xVcp13DA-O5)*(x2BcPA8Wm&U$tT3ugMW-iPwoIsI~acH8#K4c4`!P@koCH1rKIO3du+@Hdi2D2tVtKoo)COhU)#o;v%tTW> zidQ2SOJ>g#Ykjk|i~h4bY8MbW(OxQ1N_%q-sm!X{rl!=9-r=1_l4?U4EuBK$h;JBO z$LESq7i~jt4zLKQ0#RKDW1}9s)rdqr5jotZ*p6O6{bolVw zr&fQ}onI8shgv2>EmNVE>0oG7&Q~m+492E{u{*I6_k8bN2giLN@2;|c_6rGy^hkBA zGrp5_v5EMWC6p_czdNm{x`>f@Ir3!l!vl!?-(H422dv=|vFq=3%Nwz1WlBr6BmeZwhOMI*!_r3`A@!Gf#%ujZ7Ok$nIo*A*24~?EPjb52t;s zw6m~(497`e0%+j~w$JH~ZR(!wmM1B7DLu@kax;Ay7J2{Ioqv*q3K5|T?B`tr&mD(i z9!LO>iAhgDA>y=zaTXv@eP#FWgydPro`Xk8=gZWyIPM1yu%oR#DdB@0=ptKb?MqMdV-TaRV^NiT)B5B| zk<%ea(_=0d>*Xoia!h(eh;+lSPJ5bX(NcwOM;I}VQJhW!uL3$pkkK^5(JK|havV+D zAau^}YkSzz^`DGji*C~;KxAdJLT65L@$Rz4&MI+Pz5lp>Aa}8u46$#!{+1*DsG1G| z!+;2fqNvS+?nB|WyzY1P+$2O{4+h#eBWr%We}T+@0?DTwGjb|g!8Yi&RuHCq5sEK>|IK@Yof=r>SN*}j zHA22(7Y5apA{@lb#Pl0?4buw}uPs~jY{l}z>x{7m$tBA<&DZvfCqKGDjk#_jniy{6 z2H^|U9b>jR<__gBR=4#V8^s;TF&^A zYa3R0jngm?4I9Tv?2XugBwnupDd0Nr5%4ibketxH@kb%Vn%#gjJz*JkNq54~VwPXS zr4B@P@GfL`{rkh0TDIXlBX_WZdWsxo>+0+axbQ(zWQ%4~aY@9EiIxiItpOh<)RJp1 aJJtyOfjblatNiGzh3^UbZ6p;J+y5_oHEX>9 diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 36d473578988d6f649b0bf48f0a6e66231828bc8..e4ccd77b867a4afefaca5d8e2c4033ed337b7d60 100644 GIT binary patch delta 212 zcmca7bW&J-IWI340}!~lmt;<2V_C#W12F`oi$=+$=m#@s8f^AsKFp+3C0tyZRGeItSx}OhpQl@tnwMIxe@h5V$0JMm zY06F(VcW%2Bs2LmTL70j&^SgQF8122%C5a9Ta2Hnfg1#iRDl`*)TuR4 delta 109 zcmX>pd{0PyIWI340}!yfmSozpF)%y^abQ3K%J{6bQC*gqD_tZ?Iz=~_K~ryY5%Xat sW>}0?1 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 -
+

{% 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