2026-05-20 10:50:30 +00:00

161 lines
5.8 KiB
Python

from django.contrib import admin
from django.db.models import Q
from django.template.defaultfilters import linebreaksbr
from django.utils import timezone
from django.utils.html import format_html, format_html_join
from .models import Order, OrderItem
class GPSAvailabilityFilter(admin.SimpleListFilter):
title = 'GPS availability'
parameter_name = 'gps'
def lookups(self, request, model_admin):
return (
('yes', 'With GPS'),
('no', 'Manual only'),
)
def queryset(self, request, queryset):
if self.value() == 'yes':
return queryset.filter(latitude__isnull=False, longitude__isnull=False)
if self.value() == 'no':
return queryset.filter(Q(latitude__isnull=True) | Q(longitude__isnull=True))
return queryset
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = (
'id',
'user',
'status',
'payment_status',
'payment_method',
'payment_provider_label',
'short_location',
'has_precise_location',
'total_price',
'created_at',
'paid_at',
)
list_select_related = ('user',)
list_filter = ('status', 'payment_status', 'payment_provider', 'payment_method', GPSAvailabilityFilter)
search_fields = (
'user__username',
'user__email',
'id',
'payment_reference',
'payment_session_id',
'full_name',
'phone',
'address',
'location_label',
'delivery_notes',
)
readonly_fields = ('created_at', 'payment_reference', 'payment_session_id', 'paid_at', 'delivery_snapshot', 'maps_link')
date_hierarchy = 'created_at'
autocomplete_fields = ('user',)
actions = ('mark_payment_pending', 'mark_payment_paid', 'mark_status_shipped', 'mark_status_delivered')
fieldsets = (
('Order', {'fields': ('user', 'status', 'created_at', 'total_price')}),
(
'Payment',
{
'fields': (
'payment_status',
'payment_method',
'payment_provider',
'payment_currency',
'payment_reference',
'payment_session_id',
'paid_at',
)
},
),
('Delivery snapshot', {'fields': ('full_name', 'phone', 'location_label', 'address', 'delivery_notes', 'delivery_snapshot')}),
('GPS', {'fields': ('latitude', 'longitude', 'location_accuracy_m', 'maps_link')}),
)
inlines = [OrderItemInline]
@admin.display(description='Location')
def short_location(self, obj):
return obj.location_label or (obj.address.splitlines()[0].strip() if obj.address else '-')
@admin.display(boolean=True, description='GPS')
def has_precise_location(self, obj):
return obj.has_precise_location
@admin.display(description='Payment provider')
def payment_provider_label(self, obj):
return obj.payment_provider_label
@admin.display(description='Delivery summary')
def delivery_snapshot(self, obj):
lines = []
if obj.full_name:
lines.append(format_html('<strong>{}</strong>', obj.full_name))
if obj.phone:
lines.append(obj.phone)
if obj.location_label:
lines.append(obj.location_label)
if obj.address:
lines.append(linebreaksbr(obj.address))
if obj.delivery_notes:
lines.append(format_html('<em>Notes:</em> {}', obj.delivery_notes))
if not lines:
return '-'
return format_html_join(format_html('<br>'), '{}', ((line,) for line in lines))
@admin.display(description='Map')
def maps_link(self, obj):
if not obj.has_precise_location:
return '-'
return format_html(
'<a href="https://maps.google.com/?q={},{}" target="_blank" rel="noopener">Open map</a>',
obj.latitude,
obj.longitude,
)
@admin.action(description='Mark selected orders as payment pending')
def mark_payment_pending(self, request, queryset):
updated = queryset.exclude(payment_status='Pending').update(payment_status='Pending')
self.message_user(request, f'{updated} order(s) marked as payment pending.')
@admin.action(description='Mark selected orders as paid')
def mark_payment_paid(self, request, queryset):
now = timezone.now()
updated = queryset.exclude(payment_status='Paid').update(payment_status='Paid', paid_at=now)
queryset.filter(status='Pending').update(status='Paid')
self.message_user(request, f'{updated} order(s) marked as paid.')
@admin.action(description='Mark selected orders as shipped')
def mark_status_shipped(self, request, queryset):
updated = queryset.exclude(status__in=['Shipped', 'Delivered']).update(status='Shipped')
self.message_user(request, f'{updated} order(s) marked as shipped.')
@admin.action(description='Mark selected orders as delivered')
def mark_status_delivered(self, request, queryset):
updated = queryset.exclude(status='Delivered').update(status='Delivered')
cod_collected = queryset.filter(payment_method='Cash on Delivery').exclude(payment_status='Paid').update(
payment_status='Paid',
paid_at=timezone.now(),
)
message = f'{updated} order(s) marked as delivered.'
if cod_collected:
message += f' {cod_collected} COD payment(s) were also marked paid.'
self.message_user(request, message)
@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
list_display = ('order', 'product', 'quantity', 'price')
search_fields = ('order__id', 'product__name')
autocomplete_fields = ('order', 'product')