Skip to content

Commit

Permalink
Merge pull request #4 from CrzyHAX91/master
Browse files Browse the repository at this point in the history
Master
  • Loading branch information
CrzyHAX91 authored Nov 22, 2024
2 parents 121e211 + 3a67fda commit 5c392d8
Show file tree
Hide file tree
Showing 68 changed files with 3,460 additions and 228 deletions.
500 changes: 500 additions & 0 deletions .bash_history

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
121 changes: 84 additions & 37 deletions dropship_project/admin.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,94 @@

import csv
from django.contrib import admin
from django.http import HttpResponse
from .models import Category, Product, Order, CartItem
from django.contrib.auth.admin import UserAdmin
from django.db.models import Count, F
from django.utils import timezone
from django.urls import path
from django.shortcuts import render
from .models import CustomUser, Product, Order, CartItem
from .admin_filters import DateRangeFilter
from .admin_widgets import QuickLinksWidget, RecentOrdersWidget, SalesStatisticsWidget
import json

class CustomAdminSite(admin.AdminSite):
site_header = 'Dropship Admin'
site_title = 'Dropship Admin Portal'
index_title = 'Welcome to Dropship Admin Portal'
login_template = 'admin/login.html'
index_template = 'admin/dashboard.html'

def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('order-stats/', self.admin_view(self.order_stats_view), name='order_stats'),
]
return custom_urls + urls

def index(self, request, extra_context=None):
extra_context = extra_context or {}
extra_context['quick_links'] = QuickLinksWidget()
extra_context['recent_orders'] = RecentOrdersWidget()
extra_context['sales_statistics'] = SalesStatisticsWidget()
return super().index(request, extra_context)

def order_stats_view(self, request):
end_date = timezone.now().date()
start_date = end_date - timezone.timedelta(days=6)
order_data = Order.objects.filter(created_at__date__range=[start_date, end_date]) .values('created_at__date') .annotate(count=Count('id')) .order_by('created_at__date')

labels = [(start_date + timezone.timedelta(days=i)).strftime('%Y-%m-%d') for i in range(7)]
data = [0] * 7

for item in order_data:
index = (item['created_at__date'] - start_date).days
data[index] = item['count']

class CartItemInline(admin.TabularInline):
model = CartItem
extra = 0
context = {
'labels': json.dumps(labels),
'data': json.dumps(data),
}
return render(request, 'admin/order_stats.html', context)

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
admin_site = CustomAdminSite(name='customadmin')

@admin.register(Product)
@admin.register(CustomUser, site=admin_site)
class CustomUserAdmin(UserAdmin):
list_display = ('username', 'email', 'is_staff', 'is_active')
list_filter = ('is_staff', 'is_active')
fieldsets = UserAdmin.fieldsets + (
('Additional Info', {'fields': ('phone_number', 'address')}),
)

@admin.register(Product, site=admin_site)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'category', 'cost_price', 'selling_price', 'profit_margin')
list_filter = ('category', 'name')
list_display = ('name', 'price', 'stock', 'category')
list_filter = ('category',)
search_fields = ('name', 'description')
actions = ['increase_stock', 'decrease_stock']

def increase_stock(self, request, queryset):
updated = queryset.update(stock=F('stock') + 10)
self.message_user(request, f'Successfully increased stock for {updated} products.')
increase_stock.short_description = "Increase stock by 10"

@admin.register(CartItem)
def decrease_stock(self, request, queryset):
updated = queryset.update(stock=F('stock') - 10)
self.message_user(request, f'Successfully decreased stock for {updated} products.')
decrease_stock.short_description = "Decrease stock by 10"

@admin.register(Order, site=admin_site)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'total_price', 'status', 'created_at')
list_filter = ('status', DateRangeFilter)
search_fields = ('user__username', 'user__email')
actions = ['mark_as_shipped']

def mark_as_shipped(self, request, queryset):
updated = queryset.update(status='shipped', shipped_at=timezone.now())
self.message_user(request, f'{updated} orders were successfully marked as shipped.')
mark_as_shipped.short_description = "Mark selected orders as shipped"

@admin.register(CartItem, site=admin_site)
class CartItemAdmin(admin.ModelAdmin):
list_display = ('user', 'product', 'quantity', 'total_price')
list_display = ('user', 'product', 'quantity')
list_filter = ('user', 'product')

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('user', 'total_price', 'created_at', 'status', 'is_paid')
list_filter = ('status', 'created_at')
search_fields = ('user__username',)
inlines = [CartItemInline]
actions = ['export_to_csv']

def is_paid(self, obj):
return obj.is_paid
is_paid.boolean = True

def export_to_csv(self, request, queryset):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="orders.csv"'
writer = csv.writer(response)
writer.writerow(['Order ID', 'User', 'Total Price', 'Created At', 'Status', 'Is Paid'])
for order in queryset:
writer.writerow([order.id, order.user.username, order.total_price, order.created_at, order.status, order.is_paid])
return response
export_to_csv.short_description = "Export selected orders to CSV"
36 changes: 36 additions & 0 deletions dropship_project/admin_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from django.contrib import admin
from django.utils import timezone
from datetime import datetime, timedelta

class DateRangeFilter(admin.SimpleListFilter):
title = 'Date Range'
parameter_name = 'date_range'

def lookups(self, request, model_admin):
return (
('today', 'Today'),
('yesterday', 'Yesterday'),
('this_week', 'This week'),
('last_week', 'Last week'),
('this_month', 'This month'),
('last_month', 'Last month'),
)

def queryset(self, request, queryset):
if self.value() == 'today':
return queryset.filter(created_at__date=timezone.now().date())
if self.value() == 'yesterday':
return queryset.filter(created_at__date=timezone.now().date() - timedelta(days=1))
if self.value() == 'this_week':
return queryset.filter(created_at__date__gte=timezone.now().date() - timedelta(days=7))
if self.value() == 'last_week':
start_of_last_week = timezone.now().date() - timedelta(days=14)
end_of_last_week = timezone.now().date() - timedelta(days=7)
return queryset.filter(created_at__date__range=[start_of_last_week, end_of_last_week])
if self.value() == 'this_month':
return queryset.filter(created_at__date__gte=timezone.now().date().replace(day=1))
if self.value() == 'last_month':
last_month = timezone.now().date().replace(day=1) - timedelta(days=1)
start_of_last_month = last_month.replace(day=1)
return queryset.filter(created_at__date__range=[start_of_last_month, last_month])

57 changes: 57 additions & 0 deletions dropship_project/admin_widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from django.utils.html import format_html
from django.contrib.admin.widgets import AdminDateWidget
from django.forms.widgets import Media, MEDIA_TYPES

class QuickLinksWidget:
title = _('Quick Links')
template = 'admin/widgets/quick_links.html'

def __init__(self):
self.children = [
{
'title': _('Add New Product'),
'url': reverse('admin:dropship_project_product_add'),
},
{
'title': _('View Recent Orders'),
'url': reverse('admin:dropship_project_order_changelist') + '?status__exact=pending',
},
{
'title': _('User Statistics'),
'url': reverse('admin:dropship_project_customuser_changelist'),
},
]

class RecentOrdersWidget:
title = _('Recent Orders')
template = 'admin/widgets/recent_orders.html'

def __init__(self):
self.limit = 5

def get_context(self):
from .models import Order
return {
'orders': Order.objects.order_by('-created_at')[:self.limit]
}

class SalesStatisticsWidget:
title = _('Sales Statistics')
template = 'admin/widgets/sales_statistics.html'

def get_context(self):
from .models import Order
from django.db.models import Sum
from django.utils import timezone

today = timezone.now().date()
this_month = today.replace(day=1)

return {
'total_sales': Order.objects.aggregate(total=Sum('total_price'))['total'] or 0,
'today_sales': Order.objects.filter(created_at__date=today).aggregate(total=Sum('total_price'))['total'] or 0,
'month_sales': Order.objects.filter(created_at__date__gte=this_month).aggregate(total=Sum('total_price'))['total'] or 0,
}

58 changes: 22 additions & 36 deletions dropship_project/forms.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,35 @@
from django import forms
from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm, AuthenticationForm
from django.contrib.auth import password_validation
from captcha.fields import ReCaptchaField
from captcha.widgets import ReCaptchaV2Checkbox
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from .models import CustomUser

class CustomAuthenticationForm(AuthenticationForm):
remember_me = forms.BooleanField(required=False, initial=False)
captcha = ReCaptchaField(widget=ReCaptchaV2Checkbox)
class UserRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)

class CustomPasswordChangeForm(PasswordChangeForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['old_password'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Current Password'})
self.fields['new_password1'].widget.attrs.update({'class': 'form-control', 'placeholder': 'New Password'})
self.fields['new_password2'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Confirm New Password'})
class Meta:
model = CustomUser
fields = ('username', 'email', 'password1', 'password2')

def clean_new_password1(self):
password1 = self.cleaned_data.get('new_password1')
def clean_password1(self):
password1 = self.cleaned_data.get('password1')
try:
password_validation.validate_password(password1, self.user)
except forms.ValidationError as error:
self.add_error('new_password1', error)
validate_password(password1, self.instance)
except ValidationError as error:
self.add_error('password1', error)
return password1

class UserProfileForm(forms.ModelForm):
class Meta:
model = CustomUser
fields = ['username', 'email', 'first_name', 'last_name', 'phone_number', 'address', 'date_of_birth']
widgets = {
'date_of_birth': forms.DateInput(attrs={'type': 'date'}),
}

class UserRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
captcha = ReCaptchaField(widget=ReCaptchaV2Checkbox)
class CustomAuthenticationForm(AuthenticationForm):
remember_me = forms.BooleanField(required=False, initial=False)

class UserProfileForm(forms.ModelForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'password1', 'password2', 'captcha')
fields = ('username', 'email', 'first_name', 'last_name')

def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
def clean_email(self):
email = self.cleaned_data['email']
if CustomUser.objects.filter(email=email).exclude(pk=self.instance.pk).exists():
raise forms.ValidationError('This email address is already in use.')
return email

Loading

0 comments on commit 5c392d8

Please sign in to comment.