adding reports
This commit is contained in:
parent
3cf59feab0
commit
7e8ed2b3cb
Binary file not shown.
Binary file not shown.
@ -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 = (
|
||||
|
||||
@ -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 %}
|
||||
@ -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 %}
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user