adding reports

This commit is contained in:
Flatlogic Bot 2026-01-25 17:15:46 +00:00
parent 3cf59feab0
commit 7e8ed2b3cb
6 changed files with 219 additions and 50 deletions

View File

@ -12,6 +12,8 @@ from django.core.mail import send_mail
from django.conf import settings
from .mail import send_html_email
import logging
import csv
from django.http import HttpResponse
class ProfileInline(admin.StackedInline):
model = Profile
@ -22,9 +24,32 @@ class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline,)
class ParcelAdmin(admin.ModelAdmin):
list_display = ('tracking_number', 'shipper', 'status', 'created_at')
list_filter = ('status', 'created_at')
search_fields = ('tracking_number', 'shipper__username', 'receiver_name')
list_display = ('tracking_number', 'shipper', 'carrier', 'price', 'status', 'payment_status', 'created_at')
list_filter = ('status', 'payment_status', 'created_at')
search_fields = ('tracking_number', 'shipper__username', 'receiver_name', 'carrier__username')
actions = ['export_as_csv']
def export_as_csv(self, request, queryset):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="parcels_report.csv"'
writer = csv.writer(response)
writer.writerow(['Tracking Number', 'Shipper', 'Carrier', 'Price (OMR)', 'Status', 'Payment Status', 'Created At', 'Updated At'])
for obj in queryset:
writer.writerow([
obj.tracking_number,
obj.shipper.username if obj.shipper else '',
obj.carrier.username if obj.carrier else '',
obj.price,
obj.get_status_display(),
obj.get_payment_status_display(),
obj.created_at,
obj.updated_at
])
return response
export_as_csv.short_description = _("Export Selected to CSV")
class PlatformProfileAdmin(admin.ModelAdmin):
fieldsets = (

View File

@ -10,7 +10,10 @@
<button class="nav-link active" id="pills-available-tab" data-bs-toggle="pill" data-bs-target="#pills-available" type="button" role="tab">{% trans "Available Shipments" %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="pills-my-tab" data-bs-toggle="pill" data-bs-target="#pills-my" type="button" role="tab">{% trans "My Deliveries" %}</button>
<button class="nav-link" id="pills-my-tab" data-bs-toggle="pill" data-bs-target="#pills-my" type="button" role="tab">{% trans "Active Deliveries" %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="pills-history-tab" data-bs-toggle="pill" data-bs-target="#pills-history" type="button" role="tab">{% trans "Transaction History" %}</button>
</li>
</ul>
@ -51,7 +54,7 @@
{% endif %}
</div>
<!-- My Deliveries -->
<!-- My Deliveries (Active) -->
<div class="tab-pane fade" id="pills-my" role="tabpanel">
{% if my_parcels %}
<div class="row g-4">
@ -87,6 +90,50 @@
<p class="text-center py-5">{% trans "You haven't accepted any shipments yet." %}</p>
{% endif %}
</div>
<!-- Transaction History -->
<div class="tab-pane fade" id="pills-history" role="tabpanel">
{% if completed_parcels %}
<div class="card shadow-sm border-0" style="border-radius: 15px;">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="ps-4">{% trans "Date" %}</th>
<th>{% trans "Tracking ID" %}</th>
<th>{% trans "From" %}</th>
<th>{% trans "To" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Status" %}</th>
</tr>
</thead>
<tbody>
{% for parcel in completed_parcels %}
<tr>
<td class="ps-4">{{ parcel.created_at|date:"Y-m-d" }}</td>
<td><span class="badge bg-light text-dark">#{{ parcel.tracking_number }}</span></td>
<td>{{ parcel.pickup_city.name|default:parcel.pickup_address }}</td>
<td>{{ parcel.delivery_city.name|default:parcel.delivery_address }}</td>
<td>{{ parcel.price }} OMR</td>
<td>
<span class="badge {% if parcel.status == 'delivered' %}bg-success{% else %}bg-danger{% endif %}">
{{ parcel.get_status_display }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% else %}
<div class="text-center py-5">
<p class="lead">{% trans "No completed deliveries yet." %}</p>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View File

@ -8,50 +8,116 @@
<a href="{% url 'shipment_request' %}" class="btn btn-masarx-primary">{% trans "New Shipment" %}</a>
</div>
{% if parcels %}
<div class="row g-4">
{% for parcel in parcels %}
<div class="col-md-6 col-lg-4">
<div class="card border-0 shadow-sm h-100" style="border-radius: 15px;">
<div class="card-body">
<div class="d-flex justify-content-between mb-2">
<span class="badge bg-light text-dark">#{{ parcel.tracking_number }}</span>
<span class="badge {% if parcel.status == 'delivered' %}bg-success{% elif parcel.status == 'cancelled' %}bg-danger{% else %}bg-warning{% endif %}">
{{ parcel.get_status_display }}
</span>
</div>
<h5 class="card-title">{{ parcel.description|truncatechars:30 }}</h5>
<p class="card-text mb-1 small text-muted"><i class="fas fa-map-marker-alt"></i> <strong>{% trans "From" %}:</strong> {{ parcel.pickup_address }}</p>
<p class="card-text mb-3 small text-muted"><i class="fas fa-flag-checkered"></i> <strong>{% trans "To" %}:</strong> {{ parcel.delivery_address }}</p>
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-primary fw-bold">{{ parcel.price }} OMR</span>
<span class="badge {% if parcel.payment_status == 'paid' %}bg-success{% else %}bg-secondary{% endif %}">
{{ parcel.get_payment_status_display }}
</span>
</div>
<!-- Tabs -->
<ul class="nav nav-pills mb-4" id="pills-tab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="pills-active-tab" data-bs-toggle="pill" data-bs-target="#pills-active" type="button" role="tab">{% trans "Active Shipments" %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="pills-history-tab" data-bs-toggle="pill" data-bs-target="#pills-history" type="button" role="tab">{% trans "Transaction History" %}</button>
</li>
</ul>
{% if parcel.payment_status == 'pending' %}
{% if platform_profile.enable_payment %}
<a href="{% url 'initiate_payment' parcel.id %}" class="btn btn-sm btn-outline-primary w-100 mb-3">
<i class="fas fa-credit-card me-1"></i> {% trans "Pay Now" %}
</a>
{% endif %}
{% endif %}
<div class="tab-content" id="pills-tabContent">
<!-- Active Shipments (Card View) -->
<div class="tab-pane fade show active" id="pills-active" role="tabpanel">
{% if active_parcels %}
<div class="row g-4">
{% for parcel in active_parcels %}
<div class="col-md-6 col-lg-4">
<div class="card border-0 shadow-sm h-100" style="border-radius: 15px;">
<div class="card-body">
<div class="d-flex justify-content-between mb-2">
<span class="badge bg-light text-dark">#{{ parcel.tracking_number }}</span>
<span class="badge {% if parcel.status == 'delivered' %}bg-success{% elif parcel.status == 'cancelled' %}bg-danger{% else %}bg-warning{% endif %}">
{{ parcel.get_status_display }}
</span>
</div>
<h5 class="card-title">{{ parcel.description|truncatechars:30 }}</h5>
<p class="card-text mb-1 small text-muted"><i class="fas fa-map-marker-alt"></i> <strong>{% trans "From" %}:</strong> {{ parcel.pickup_address }}</p>
<p class="card-text mb-3 small text-muted"><i class="fas fa-flag-checkered"></i> <strong>{% trans "To" %}:</strong> {{ parcel.delivery_address }}</p>
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-primary fw-bold">{{ parcel.price }} OMR</span>
<span class="badge {% if parcel.payment_status == 'paid' %}bg-success{% else %}bg-secondary{% endif %}">
{{ parcel.get_payment_status_display }}
</span>
</div>
<hr>
<p class="card-text small mb-0"><strong>{% trans "Receiver" %}:</strong> {{ parcel.receiver_name }}</p>
<p class="card-text small"><strong>{% trans "Carrier" %}:</strong> {% if parcel.carrier %}{{ parcel.carrier.get_full_name|default:parcel.carrier.username }}{% else %}{% trans "Waiting for pickup" %}{% endif %}</p>
{% if parcel.payment_status == 'pending' %}
{% if payments_enabled %}
<a href="{% url 'initiate_payment' parcel.id %}" class="btn btn-sm btn-outline-primary w-100 mb-3">
<i class="fas fa-credit-card me-1"></i> {% trans "Pay Now" %}
</a>
{% endif %}
{% endif %}
<hr>
<p class="card-text small mb-0"><strong>{% trans "Receiver" %}:</strong> {{ parcel.receiver_name }}</p>
<p class="card-text small"><strong>{% trans "Carrier" %}:</strong> {% if parcel.carrier %}{{ parcel.carrier.get_full_name|default:parcel.carrier.username }}{% else %}{% trans "Waiting for pickup" %}{% endif %}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<p class="lead">{% trans "You have no active shipments." %}</p>
<a href="{% url 'shipment_request' %}" class="btn btn-masarx-primary">{% trans "Send your first shipment" %}</a>
</div>
{% endif %}
</div>
<!-- Transaction History (Table View) -->
<div class="tab-pane fade" id="pills-history" role="tabpanel">
{% if history_parcels %}
<div class="card shadow-sm border-0" style="border-radius: 15px;">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="ps-4">{% trans "Date" %}</th>
<th>{% trans "Tracking ID" %}</th>
<th>{% trans "Description" %}</th>
<th>{% trans "Carrier" %}</th>
<th>{% trans "Bid/Price" %}</th>
<th>{% trans "Status" %}</th>
</tr>
</thead>
<tbody>
{% for parcel in history_parcels %}
<tr>
<td class="ps-4">{{ parcel.created_at|date:"Y-m-d" }}</td>
<td><span class="badge bg-light text-dark">#{{ parcel.tracking_number }}</span></td>
<td>{{ parcel.description|truncatechars:30 }}</td>
<td>
{% if parcel.carrier %}
{{ parcel.carrier.get_full_name|default:parcel.carrier.username }}
{% else %}
-
{% endif %}
</td>
<td>{{ parcel.price }} OMR</td>
<td>
<span class="badge {% if parcel.status == 'delivered' %}bg-success{% else %}bg-danger{% endif %}">
{{ parcel.get_status_display }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% else %}
<div class="text-center py-5">
<p class="lead">{% trans "No completed transactions yet." %}</p>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<p class="lead">{% trans "You haven't sent any shipments yet." %}</p>
<a href="{% url 'shipment_request' %}" class="btn btn-masarx-primary">{% trans "Send your first shipment" %}</a>
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -123,15 +123,39 @@ def dashboard(request):
profile, created = Profile.objects.get_or_create(user=request.user)
if profile.role == 'shipper':
parcels = Parcel.objects.filter(shipper=request.user).order_by('-created_at')
return render(request, 'core/shipper_dashboard.html', {'parcels': parcels})
all_parcels = Parcel.objects.filter(shipper=request.user).order_by('-created_at')
active_parcels = all_parcels.exclude(status__in=['delivered', 'cancelled'])
history_parcels = all_parcels.filter(status__in=['delivered', 'cancelled'])
platform_profile = PlatformProfile.objects.first()
payments_enabled = platform_profile.enable_payment if platform_profile else True
return render(request, 'core/shipper_dashboard.html', {
'active_parcels': active_parcels,
'history_parcels': history_parcels,
'payments_enabled': payments_enabled,
'platform_profile': platform_profile # Pass full profile just in case
})
else:
# Car Owner view
available_parcels = Parcel.objects.filter(status='pending', payment_status='paid').order_by('-created_at')
my_parcels = Parcel.objects.filter(carrier=request.user).exclude(status='delivered').order_by('-created_at')
platform_profile = PlatformProfile.objects.first()
payments_enabled = platform_profile.enable_payment if platform_profile else True
if payments_enabled:
available_parcels = Parcel.objects.filter(status='pending', payment_status='paid').order_by('-created_at')
else:
available_parcels = Parcel.objects.filter(status='pending').order_by('-created_at')
# Active: Picked up or In Transit
my_parcels = Parcel.objects.filter(carrier=request.user).exclude(status__in=['delivered', 'cancelled']).order_by('-created_at')
# History: Delivered or Cancelled
completed_parcels = Parcel.objects.filter(carrier=request.user, status__in=['delivered', 'cancelled']).order_by('-created_at')
return render(request, 'core/driver_dashboard.html', {
'available_parcels': available_parcels,
'my_parcels': my_parcels
'my_parcels': my_parcels,
'completed_parcels': completed_parcels
})
@login_required
@ -164,7 +188,14 @@ def accept_parcel(request, parcel_id):
messages.error(request, _("Only car owners can accept shipments."))
return redirect('dashboard')
parcel = get_object_or_404(Parcel, id=parcel_id, status='pending', payment_status='paid')
platform_profile = PlatformProfile.objects.first()
payments_enabled = platform_profile.enable_payment if platform_profile else True
if payments_enabled:
parcel = get_object_or_404(Parcel, id=parcel_id, status='pending', payment_status='paid')
else:
parcel = get_object_or_404(Parcel, id=parcel_id, status='pending')
parcel.carrier = request.user
parcel.status = 'picked_up'
parcel.save()