From bbe32918946feeacc25d6eae89147f5f9e14a58a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 24 Jan 2026 04:36:47 +0000 Subject: [PATCH] updates 27 --- core/__pycache__/models.cpython-311.pyc | Bin 28883 -> 31909 bytes core/__pycache__/urls.cpython-311.pyc | Bin 2505 -> 2946 bytes core/__pycache__/views.cpython-311.pyc | Bin 29468 -> 33114 bytes core/migrations/0019_transaction.py | 37 ++++++ .../0019_transaction.cpython-311.pyc | Bin 0 -> 2684 bytes core/models.py | 40 ++++++- core/templates/core/admin_dashboard.html | 39 ++++++ core/templates/core/admin_financials.html | 71 +++++++++++ core/templates/core/financial_history.html | 67 +++++++++++ core/templates/core/receipt.html | 111 ++++++++++++++++++ core/templates/core/shipper_dashboard.html | 61 +++++++++- .../templates/core/truck_owner_dashboard.html | 61 +++++++++- core/urls.py | 4 + core/views.py | 73 +++++++++++- 14 files changed, 554 insertions(+), 10 deletions(-) create mode 100644 core/migrations/0019_transaction.py create mode 100644 core/migrations/__pycache__/0019_transaction.cpython-311.pyc create mode 100644 core/templates/core/admin_financials.html create mode 100644 core/templates/core/financial_history.html create mode 100644 core/templates/core/receipt.html diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 508f24dca4914457051711d6fb9b9ee783a1c13b..a225337a5578d940122302cc59fde31778267ec0 100644 GIT binary patch delta 5010 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 delta 2406 zcmZ{le{fXQ6~}YlZeBK&4T&VWNt$00NFFAlAwVqoF$-B!$uA^{{AkN&v-`4H@?$r5 zUkrh!SeSNftByNI)2XQnGX4OoOne=ubf%rL%wSt>3x(+)k5`DO4ea5H{FBn+^?V=o@qBin{b~LRSMD8H8waX^B$xP#@^(tm$!-l< z=AAKfBqDb4SA7*_UxPsq7y<@ieELjz~DmlUB%zg-1{|HLSF)u0%ZXFii7-}(x1>l zo?lmJx0k)^*88As;>OA{YUHn19;06Vw9?R)FIB*nr8aN^0L|CS#&Jp@_hvI^1^@C5J_@GS5=uq2Nu=u&pLX4*w5 zdwyMuo0u!=OJsGm)NhnoytjV6-VUPEst;NrdRouO;3F3bIIX-4Rz_Fe}SKBSas-ixTpbM1I__|0DcFY2PP#PZ^Rst z84y#!2&(7TSir%ZoKP|ui;kI*pn5OyMM*dd>sNs#S3jKzFdLIn(uB-klS}aeqri*+nTj zo^X70)Etv-p-MpABYkAmc9&p&$^K=_2FipSPURJ_*Z-C*+V}iJGVGo$Q+5A0*!$S6 z!eoWxvR1~dbUHpzz8A2%z^k^-&;qW?7q)&vXZU<;<$t>4qt-e4h+haine(xl0lCH^V}@i#u)@eb)c+BvUhlT^%cZ`U{IBEQtNgZ{yp z-IKZowPqjgKBAFk>pNI0Xp~#8dwV7Zte7=omRAS53~`2E?5(9A@}GOx)~KgLxjNZH z=13xFnfonq4e|1z%(7fV+Og3;*HZp7u@XLKww2I&8 zv&h3e_x#l7mzz$w(v!lY!edBO6Q`P738ZL)!v72kLS_dpCWE@%)+1l=(lU79hW}DCc)1IBKhGOWy z4CKI5iIjQ;(k4owR1a1rr31_HRI*^wNqn2ly+$S8R#d=Fr3g7oXK%3^9^sevu6LJ9 z8_rAY<+k9hS-3%$sOMa-k6QTA;Dqjhiz?3TuX7v9(nx6j3|`*vqgp=Szv{nv()|dr zPFm(u9Ulp;aj*Z(US_a#;3oQzAFj&hZ3B-qeNiq^`Qk&M6%pqk)k9j$toq1gaB=un zLygD9ga%-^B&!Y3HP|BDt$83DB;M!WnB#@x(zPsI^^yDm!aM+lTdwvDZlNxFW-yC3 zZNm=T$r=hJLzX4PcKP3NCqr_IE!pT2s&m^Bu9GiDE2+o67L99^$E;4|m^#r_9c{9JOLO6lyNx8p+$65PoR^o20SNefN-{sNGcY^`abQ3e%J_V3qq-yW#0RYW`l-xWGBD{BgNYYJ z`3-?WFog^$Mj#<$ppYC~l?hNt(-bHq4;M09!?ui>fnhZeLqNJ@ltPMmFoUMW<|5`d zO!ZYlX_C^fA#F9nD3 zJekGCrKv!JL2CRo6(=XM?H4Qp1x69b`$ZrR7b#4ZWe?!e1~M6exOna6a&{*sqZ=$7 z4K5crWoMLLkvF?w8*qUo@FGj#6_!A#gvJWhD_YJMyy7pgBwS=kxWbY!Ige98QFle@ f6@AAOd>2^4FS3MRVF~|WEXB{%zzu>$nn3dbrQV9d delta 109 zcmZn?KPjxfoR^o20SH{&OEM?1F)%y^abQ3a%J}TIQQeW5D_t~7CPhD(LDOI}6U!SW sW>R3C|Ums|2HL|wZ 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 Q)J

{% trans "Quick Actions" %}

+ + +
diff --git a/core/templates/core/admin_financials.html b/core/templates/core/admin_financials.html new file mode 100644 index 0000000..f767ef9 --- /dev/null +++ b/core/templates/core/admin_financials.html @@ -0,0 +1,71 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
+
+
+

{% trans "Financial Overview" %}

+

{% trans "Manage all platform transactions, payments, and revenue." %}

+
+
+
{% trans "Total Revenue" %}
+

{{ total_revenue }}

+
+
+ +
+
+
{% trans "Recent Transactions" %}
+
+
+
+ + + + + + + + + + + + + + {% for transaction in transactions %} + + + + + + + + + + {% endfor %} + +
{% trans "User" %}{% trans "Role" %}{% trans "Receipt #" %}{% trans "Date" %}{% trans "Amount" %}{% trans "Status" %}{% trans "Action" %}
+ {{ transaction.user.username }}
+ {{ transaction.user.email }} +
+ {{ transaction.user.profile.get_role_display }} + {{ transaction.receipt_number }}{{ transaction.created_at|date:"Y-m-d" }}{{ transaction.amount }} + + {{ transaction.get_status_display }} + + + + + {% if transaction.transaction_type == 'PAYMENT' and transaction.status == 'COMPLETED' %} + + + + {% endif %} + +
+
+
+
+
+{% endblock %} diff --git a/core/templates/core/financial_history.html b/core/templates/core/financial_history.html new file mode 100644 index 0000000..ff1e3af --- /dev/null +++ b/core/templates/core/financial_history.html @@ -0,0 +1,67 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
+ + +
+
+ {% if transactions %} +
+ + + + + + + + + + + + + + {% for transaction in transactions %} + + + + + + + + + + {% endfor %} + +
{% trans "Receipt #" %}{% trans "Date" %}{% trans "Description" %}{% trans "Type" %}{% trans "Amount" %}{% trans "Status" %}{% trans "Action" %}
{{ transaction.receipt_number }}{{ transaction.created_at|date:"Y-m-d H:i" }}{{ transaction.description }} + {% if transaction.transaction_type == 'PAYMENT' %} + {% trans "Payment" %} + {% else %} + {% trans "Refund" %} + {% endif %} + {{ transaction.amount }} + + {{ transaction.get_status_display }} + + + + {% trans "Receipt" %} + +
+
+ {% else %} +
+ +

{% trans "No transactions found." %}

+
+ {% endif %} +
+
+
+{% endblock %} diff --git a/core/templates/core/receipt.html b/core/templates/core/receipt.html new file mode 100644 index 0000000..2bb48bf --- /dev/null +++ b/core/templates/core/receipt.html @@ -0,0 +1,111 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block content %} +
+
+
+
+
+
+ {% if app_settings.logo %} + {{ app_settings.app_name }} + {% else %} +

{{ app_settings.app_name|default:"MASAR CARGO" }}

+ {% endif %} +

+ {{ app_settings.contact_address|linebreaksbr }}
+ {% trans "Phone:" %} {{ app_settings.contact_phone }}
+ {% trans "Email:" %} {{ app_settings.contact_email }} +

+
+
+

{% trans "Receipt" %}

+

{% trans "Receipt #" %}: {{ transaction.receipt_number }}

+

{% trans "Date" %}: {{ transaction.created_at|date:"Y-m-d" }}

+
+
+ +
+ +
+
+
{% trans "Bill To" %}
+

{{ transaction.user.get_full_name|default:transaction.user.username }}

+

{{ transaction.user.email }}

+

{{ transaction.user.profile.full_phone_number }}

+
+
+
{% trans "Payment Method" %}
+

{{ transaction.payment_method|default:"N/A" }}

+
+
+ +
+ + + + + + + + + + + + + + + + + + + +
{% trans "Description" %}{% trans "Total" %}
{{ transaction.description }}{{ transaction.amount }}
{% trans "Total Paid" %}{{ transaction.amount }}
+
+ +
+

{% trans "Note:" %} {% trans "This is an electronically generated receipt and does not require a physical signature." %}

+
+ +
+

{% trans "Thank you for choosing MASAR CARGO!" %}

+ {% if app_settings.registration_number %} +

{% trans "CR:" %} {{ app_settings.registration_number }} | {% trans "VAT:" %} {{ app_settings.tax_number }}

+ {% endif %} +
+
+ +
+ + + {% trans "Back to History" %} + +
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/shipper_dashboard.html b/core/templates/core/shipper_dashboard.html index 4a72bcb..e0ddd95 100644 --- a/core/templates/core/shipper_dashboard.html +++ b/core/templates/core/shipper_dashboard.html @@ -17,10 +17,65 @@ {% block content %}
-
-

{% trans "Shipper Dashboard" %}

-

{% trans "Manage your shipping offers and active shipments." %}

+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+

{% trans "Shipper Dashboard" %}

+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+

{% trans "Manage your shipping offers and active shipments." %}

+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+
+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
{% trans "Add A Bid" %} diff --git a/core/templates/core/truck_owner_dashboard.html b/core/templates/core/truck_owner_dashboard.html index d7b068a..fc33194 100644 --- a/core/templates/core/truck_owner_dashboard.html +++ b/core/templates/core/truck_owner_dashboard.html @@ -18,10 +18,65 @@ {% block content %}
-
-

{% trans "Truck Owner Dashboard" %}

-

{% trans "Manage your fleet and incoming shipping offers." %}

+
+
+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+

{% trans "Truck Owner Dashboard" %}

+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+

{% trans "Manage your fleet and incoming shipping offers." %}

+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
+
+
+
+
+
+
{% trans "Financials" %}
+

{% trans "Payments" %}

+ {% trans "View History" %} +
+
+
+
{% trans "Add New Truck" %} diff --git a/core/urls.py b/core/urls.py index a2f06e9..23d8bc1 100644 --- a/core/urls.py +++ b/core/urls.py @@ -24,4 +24,8 @@ urlpatterns = [ 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"), + path("financial-history/", views.financial_history, name="financial_history"), + path("receipt//", views.transaction_receipt, name="transaction_receipt"), + path("admin/financials/", views.admin_financials, name="admin_financials"), + path("admin/refund//", views.issue_refund, name="issue_refund"), ] \ No newline at end of file diff --git a/core/views.py b/core/views.py index 8ee03a0..454b70b 100644 --- a/core/views.py +++ b/core/views.py @@ -3,7 +3,7 @@ from django.shortcuts import render, redirect, get_object_or_404 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 .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm from django.contrib import messages from django.utils.translation import gettext as _ @@ -485,6 +485,15 @@ def renew_subscription(request): if form.is_valid(): profile = request.user.profile plan = form.cleaned_data['subscription_plan'] + + # Calculate amount based on role and plan + app_settings = AppSetting.objects.first() + amount = 0 + if profile.role == 'SHIPPER': + amount = app_settings.shipper_monthly_fee if plan == 'MONTHLY' else app_settings.shipper_annual_fee + elif profile.role == 'TRUCK_OWNER': + amount = app_settings.truck_owner_monthly_fee if plan == 'MONTHLY' else app_settings.truck_owner_annual_fee + profile.subscription_plan = plan profile.is_subscription_active = True @@ -494,7 +503,17 @@ def renew_subscription(request): profile.subscription_expiry = timezone.now().date() + timedelta(days=365) profile.save() - + + # Create Transaction record + Transaction.objects.create( + user=request.user, + amount=amount, + transaction_type='PAYMENT', + status='COMPLETED', + description=f"Subscription Renewal: {plan}", + payment_method="Online Payment" + ) + # Notifications expiry_date = profile.subscription_expiry.strftime('%Y-%m-%d') msg = _("Your subscription for MASAR CARGO has been successfully renewed! Your new expiry date is %(date)s. Thank you for using our service.") % {"date": expiry_date} @@ -512,7 +531,55 @@ def renew_subscription(request): [request.user.email], fail_silently=True, ) - + messages.success(request, _("Subscription renewed successfully!")) return redirect('dashboard') return redirect('subscription_expired') + +@login_required +def financial_history(request): + transactions = Transaction.objects.filter(user=request.user) + return render(request, 'core/financial_history.html', {'transactions': transactions}) + +@login_required +def transaction_receipt(request, receipt_number): + transaction = get_object_or_404(Transaction, receipt_number=receipt_number, user=request.user) + app_settings = AppSetting.objects.first() + return render(request, 'core/receipt.html', { + 'transaction': transaction, + 'app_settings': app_settings + }) + +@login_required +def admin_financials(request): + if request.user.profile.role != 'ADMIN': + return redirect('dashboard') + transactions = Transaction.objects.all() + total_revenue = sum(t.amount for t in transactions if t.transaction_type == 'PAYMENT' and t.status == 'COMPLETED') + return render(request, 'core/admin_financials.html', { + 'transactions': transactions, + 'total_revenue': total_revenue + }) + +@login_required +def issue_refund(request, receipt_number): + if request.user.profile.role != 'ADMIN': + return redirect('dashboard') + + transaction = get_object_or_404(Transaction, receipt_number=receipt_number) + if transaction.transaction_type == 'REFUND': + messages.error(request, _("This is already a refund transaction.")) + return redirect('admin_financials') + + # Create a refund transaction + refund = Transaction.objects.create( + user=transaction.user, + amount=transaction.amount, + transaction_type='REFUND', + status='COMPLETED', + description=f"Refund for Receipt: {transaction.receipt_number}", + payment_method=transaction.payment_method + ) + + messages.success(request, _("Refund issued successfully! Receipt: %(receipt)s") % {'receipt': refund.receipt_number}) + return redirect('admin_financials')