haikal/inventory/views.py
2024-12-17 13:33:59 +00:00

777 lines
29 KiB
Python

import logging
import json
from django.views.decorators.csrf import csrf_exempt
from vin import VIN
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.utils.translation import gettext_lazy as _
from django.db.models import Q
from django.views.generic import (
View,
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView,
TemplateView
)
from django.utils import timezone, translation
from django.conf import settings
from urllib.parse import urlparse, urlunparse
from django.forms import ChoiceField, ModelForm, RadioSelect
from django.urls import reverse, reverse_lazy
from django.contrib import messages
from django.db.models import Sum, F, Count
from inventory.mixins import AddDealerInstanceMixin
from .services import elm, decodevin,get_make,get_model,normalize_name
from . import models, forms
from django_tables2.export.views import ExportMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.decorators import user_passes_test
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
User = get_user_model()
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def switch_language(request):
language = request.GET.get('language', 'en')
referer = request.META.get('HTTP_REFERER', '/')
parsed_url = urlparse(referer)
path_parts = parsed_url.path.split('/')
if path_parts[1] in dict(settings.LANGUAGES):
path_parts.pop(1)
new_path = '/'.join(path_parts)
new_url = urlunparse(
(parsed_url.scheme, parsed_url.netloc, new_path, parsed_url.params, parsed_url.query, parsed_url.fragment)
)
if language in dict(settings.LANGUAGES):
logger.debug(f"Switching language to: {language}")
response = redirect(new_url)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
translation.activate(language)
request.session[settings.LANGUAGE_COOKIE_NAME] = language
logger.debug(f"Language switched to: {language}, Session: {request.session[settings.LANGUAGE_COOKIE_NAME]}")
return response
else:
logger.warning(f"Invalid language code: {language}")
return redirect('/')
class HomeView(LoginRequiredMixin, TemplateView):
template_name = 'index.html'
def dispatch(self, request, *args, **kwargs):
if not any(hasattr(request.user, attr) for attr in ['dealer', 'subdealer']) or not request.user.is_authenticated:
messages.error(request, _('You are not associated with any dealer.'))
return redirect('welcome')
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
total_cars = models.Car.objects.count()
total_reservations = models.CarReservation.objects.filter(reserved_until__gte=timezone.now()).count()
stats = models.CarFinance.objects.aggregate(
total_cost_price=Sum('cost_price'),
total_selling_price=Sum('selling_price'),
)
total_cost_price = stats['total_cost_price'] or 0
total_selling_price = stats['total_selling_price'] or 0
total_profit = total_selling_price - total_cost_price
context['total_cars'] = total_cars
context['total_reservations'] = total_reservations
context['total_cost_price'] = total_cost_price
context['total_selling_price'] = total_selling_price
context['total_profit'] = total_profit
return context
class WelcomeView(TemplateView):
template_name = "welcome.html"
class CarCreateView(LoginRequiredMixin, CreateView):
model = models.Car
form_class = forms.CarForm
template_name = 'inventory/car_form.html'
# success_url = reverse_lazy('inventory_stats')
def get_success_url(self):
"""Determine the redirect URL based on user choice."""
if self.request.POST.get('add_another'):
return reverse('car_add')
return reverse('inventory_stats')
def form_valid(self, form):
form.instance.dealer = self.request.user.dealer.get_parent_or_self
form.save()
messages.success(self.request, 'Car saved successfully.')
return super().form_valid(form)
class AjaxHandlerView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
action = request.GET.get('action')
handlers = {
'decode_vin': self.decode_vin,
'get_models': self.get_models,
'get_series': self.get_series,
'get_trims': self.get_trims,
'get_specifications': self.get_specifications,
}
handler = handlers.get(action)
if handler:
return handler(request)
else:
return JsonResponse({'error': 'Invalid action'}, status=400)
def decode_vin(self, request):
vin_no = request.GET.get('vin_no')
if not vin_no or len(vin_no.strip()) != 17:
return JsonResponse({'success': False, 'error': 'Invalid VIN number provided.'}, status=400)
vin_no = vin_no.strip()
vin_data = {}
decoding_method = ''
manufacturer_name = model_name = year_model = None
if not (result :=decodevin(vin_no)):
return JsonResponse({'success': False, 'error': 'VIN not found in all sources.'}, status=404)
manufacturer_name,model_name,year_model = result.values()
make = get_make(manufacturer_name)
model = get_model(model_name,make)
logger.info(
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
)
car_model = model
car_make = make
if not car_make:
return JsonResponse({'success': False, 'error': 'Manufacturer not found in the database.'}, status=404)
vin_data['make_id'] = car_make.id_car_make
vin_data['name'] = car_make.name
vin_data['arabic_name'] = car_make.arabic_name
if not car_model:
vin_data['model_id'] = ""
else:
vin_data['model_id'] = car_model.id_car_model
vin_data['year'] = year_model
return JsonResponse({'success': True, 'data': vin_data})
def get_models(self, request):
make_id = request.GET.get('make_id')
car_models = models.CarModel.objects.filter(id_car_make=make_id).values('id_car_model', 'name', 'arabic_name')
return JsonResponse(list(car_models), safe=False)
def get_series(self, request):
model_id = request.GET.get('model_id')
series = models.CarSerie.objects.filter(
id_car_model=model_id,
).values('id_car_serie', 'name', 'arabic_name')
return JsonResponse(list(series), safe=False)
def get_trims(self, request):
serie_id = request.GET.get('serie_id')
trims = models.CarTrim.objects.filter(
id_car_serie=serie_id
).values('id_car_trim', 'name', 'arabic_name')
return JsonResponse(list(trims), safe=False)
def get_specifications(self, request):
trim_id = request.GET.get('trim_id')
car_spec_values = models.CarSpecificationValue.objects.filter(id_car_trim=trim_id)
lang = translation.get_language()
specs_by_parent = {}
for value in car_spec_values:
specification = value.id_car_specification
parent = specification.id_parent
parent_id = parent.id_car_specification if parent else 0
if lang == 'ar':
parent_name = parent.arabic_name if parent else "Root"
else:
parent_name = parent.name if parent else "Root"
if parent_id not in specs_by_parent:
specs_by_parent[parent_id] = {'parent_name': parent_name, 'specifications': []}
spec_data = {
'specification_id': specification.id_car_specification,
's_name': specification.arabic_name if lang == 'ar' else specification.name,
's_value': value.value,
's_unit': value.unit if value.unit else "",
'trim_name': value.id_car_trim.name
}
specs_by_parent[parent_id]['specifications'].append(spec_data)
serialized_specs = [
{'parent_name': v['parent_name'], 'specifications': v['specifications']}
for v in specs_by_parent.values()
]
return JsonResponse(serialized_specs, safe=False)
class CarInventory(LoginRequiredMixin, ListView):
model = models.Car
home_label = _('inventory')
template_name = 'inventory/car_inventory.html'
context_object_name = 'cars'
paginate_by = 10
ordering = ['receiving_date']
def get_queryset(self, *args, **kwargs):
query = self.request.GET.get('q')
make_id = self.kwargs['make_id']
model_id = self.kwargs['model_id']
trim_id = self.kwargs['trim_id']
cars = models.Car.objects.filter(
dealer=self.request.user.dealer.get_parent_or_self,
id_car_make=make_id,
id_car_model=model_id,
id_car_trim=trim_id,).order_by('receiving_date')
if query:
cars = cars.filter(Q(vin__icontains=query))
return cars
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query'] = self.request.GET.get('q', '')
context['make_id'] = self.kwargs['make_id']
context['model_id'] = self.kwargs['model_id']
context['trim_id'] = self.kwargs['trim_id']
return context
class CarColorCreate(LoginRequiredMixin, CreateView):
model = models.CarColors
form_class = forms.CarColorsForm
template_name = "inventory/add_colors.html"
def form_valid(self, form):
car = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
form.instance.car = car
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('car_detail', kwargs={'pk': self.kwargs['car_pk']})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['car'] = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
return context
@login_required
def inventory_stats_view(request):
dealer = request.user.dealer
# Annotate total cars by make, model, and trim
cars = (
models.Car.objects.filter(dealer=dealer.get_parent_or_self)
.select_related('id_car_make', 'id_car_model', 'id_car_trim')
.annotate(
make_total=Count('id_car_make'),
model_total=Count('id_car_model'),
trim_total=Count('id_car_trim')
)
)
# Prepare the nested structure
inventory = {}
for car in cars:
# Make Level
make = car.id_car_make
if make.id_car_make not in inventory:
inventory[make.id_car_make] = {
'make_id': make.id_car_make,
'make_name': make.get_local_name(),
'total_cars': 0,
'models': {}
}
inventory[make.id_car_make]['total_cars'] += 1
# Model Level
model = car.id_car_model
if model and model.id_car_model not in inventory[make.id_car_make]['models']:
inventory[make.id_car_make]['models'][model.id_car_model] = {
'model_id': model.id_car_model,
'model_name': model.get_local_name(),
'total_cars': 0,
'trims': {}
}
inventory[make.id_car_make]['models'][model.id_car_model]['total_cars'] += 1
# Trim Level
trim = car.id_car_trim
if trim and trim.id_car_trim not in inventory[make.id_car_make]['models'][model.id_car_model]['trims']:
inventory[make.id_car_make]['models'][model.id_car_model]['trims'][trim.id_car_trim] = {
'trim_id': trim.id_car_trim,
'trim_name': trim.name,
'total_cars': 0
}
inventory[make.id_car_make]['models'][model.id_car_model]['trims'][trim.id_car_trim]['total_cars'] += 1
# Convert to a list for easier template rendering
result = {
'total_cars': cars.count(),
'makes': [
{
'make_id': make_data['make_id'],
'make_name': make_data['make_name'],
'total_cars': make_data['total_cars'],
'models': [
{
'model_id': model_data['model_id'],
'model_name': model_data['model_name'],
'total_cars': model_data['total_cars'],
'trims': list(model_data['trims'].values())
}
for model_data in make_data['models'].values()
]
}
for make_data in inventory.values()
]
}
return render(request, 'inventory/inventory_stats.html', {'inventory': result})
class CarDetailView(LoginRequiredMixin, DetailView):
model = models.Car
template_name = 'inventory/car_detail.html'
context_object_name = 'car'
class CarFinanceCreateView(LoginRequiredMixin, CreateView):
model = models.CarFinance
form_class = forms.CarFinanceForm
template_name = 'inventory/car_finance_form.html'
def dispatch(self, request, *args, **kwargs):
self.car = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form):
form.instance.car = self.car
messages.success(self.request, _('Car finance details saved successfully.'))
return super().form_valid(form)
def get_success_url(self):
return reverse('car_detail', kwargs={'pk': self.car.pk})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['car'] = self.car
return context
class CarFinanceUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
model = models.CarFinance
form_class = forms.CarFinanceForm
template_name = 'inventory/car_finance_form.html'
success_message = _('Car finance details updated successfully.')
def get_success_url(self):
return reverse('car_detail', kwargs={'pk': self.object.car.pk})
class CarUpdateView(LoginRequiredMixin, SuccessMessageMixin,UpdateView):
model = models.Car
form_class = forms.CarUpdateForm
template_name = 'inventory/car_edit.html'
success_message = _('Car updated successfully.')
def get_success_url(self):
return reverse('car_detail', kwargs={'pk': self.object.pk})
class CarDeleteView(LoginRequiredMixin,SuccessMessageMixin, DeleteView):
model = models.Car
template_name = 'inventory/car_confirm_delete.html'
success_url = reverse_lazy('inventory_stats')
class CustomCardCreateView(LoginRequiredMixin, CreateView):
model = models.CustomCard
form_class = forms.CustomCardForm
template_name = "inventory/add_custom_card.html"
def form_valid(self, form):
car = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
form.instance.car = car
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['car'] = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
return context
def get_success_url(self):
messages.success(self.request, _("Custom Card added successfully."))
return reverse_lazy('car_detail', kwargs={'pk': self.kwargs['car_pk']})
@login_required()
def reserve_car_view(request, car_id):
if request.method == "POST":
car = get_object_or_404(models.Car, pk=car_id)
if car.is_reserved():
messages.error(request, _("This car is already reserved."))
return redirect('car_detail', pk=car.pk)
try:
reserved_until = timezone.now() + timezone.timedelta(hours=24)
models.CarReservation.objects.create(
car=car,
reserved_by=request.user,
reserved_until=reserved_until
)
messages.success(request, _("Car reserved successfully."))
except Exception as e:
messages.error(request, f"Error reserving car: {e}")
return redirect('car_detail', pk=car.pk)
return JsonResponse({"success": False, "message": "Invalid request method."}, status=400)
@login_required
def manage_reservation(request, reservation_id):
reservation = get_object_or_404(models.CarReservation, pk=reservation_id, reserved_by=request.user)
if request.method == "POST":
action = request.POST.get("action")
if action == "renew":
reservation.reserved_until = timezone.now() + timezone.timedelta(hours=24)
reservation.save()
messages.success(request, _("Reservation renewed successfully."))
return redirect('car_detail', pk=reservation.car.pk)
elif action == "cancel":
reservation.delete()
messages.success(request, _("Reservation canceled successfully."))
return redirect('car_detail', pk=reservation.car.pk)
else:
return JsonResponse({"success": False, "message": _("Invalid action.")}, status=400)
return JsonResponse({"success": False, "message": _("Invalid request method.")}, status=400)
class DealerListView(LoginRequiredMixin, ListView):
model = models.Dealer
template_name = 'dealer_list.html'
context_object_name = 'dealers'
class DealerDetailView(LoginRequiredMixin, DetailView):
model = models.Dealer
template_name = 'dealers/dealer_detail.html'
context_object_name = 'dealer'
class DealerCreateView(LoginRequiredMixin, SuccessMessageMixin,CreateView):
model = models.Dealer
form_class = forms.DealerForm
template_name = 'dealer_form.html'
success_url = reverse_lazy('dealer_list')
success_message = _('Dealer created successfully.')
class DealerUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
model = models.Dealer
form_class = forms.DealerForm
template_name = 'dealers/dealer_form.html'
success_url = reverse_lazy('dealer_detail')
success_message = _('Dealer updated successfully.')
def get_success_url(self):
return reverse('dealer_detail', kwargs={'pk': self.object.pk})
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields.pop('dealer_type')
return form
def get_form_class(self):
if self.request.user.dealer.is_parent:
return forms.DealerForm
else:
return forms.UserForm
class DealerDeleteView(LoginRequiredMixin,SuccessMessageMixin, DeleteView):
model = models.Dealer
template_name = 'dealer_confirm_delete.html'
success_url = reverse_lazy('dealer_list')
success_message = _('Dealer deleted successfully.')
class CustomerListView(LoginRequiredMixin,PermissionRequiredMixin, ListView):
model = models.Customer
home_label = _('customers')
context_object_name = 'customers'
paginate_by = 10
template_name = "customers/customer_list.html"
permission_required = ('inventory.view_customer',)
def get_queryset(self):
query = self.request.GET.get('q')
customers = models.Customer.objects.filter(dealer=self.request.user.dealer.get_parent_or_self)
if query:
customers = customers.filter(
Q(national_id__icontains=query) |
Q(first_name__icontains=query) |
Q(last_name__icontains=query)
)
return customers
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query'] = self.request.GET.get('q', '')
return context
class CustomerDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView):
model = models.Customer
template_name = 'customers/view_customer.html'
context_object_name = 'customer'
permission_required = ('inventory.view_customer',)
class CustomerCreateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, CreateView):
model = models.Customer
form_class = forms.CustomerForm
template_name = 'customers/customer_form.html'
success_url = reverse_lazy('customer_list')
permission_required = ('inventory.add_customer',)
success_message = _('Customer created successfully.')
class CustomerUpdateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, UpdateView):
model = models.Customer
form_class = forms.CustomerForm
template_name = 'customers/customer_form.html'
success_url = reverse_lazy('customer_list')
permission_required = ('inventory.change_customer',)
success_message = _('Customer updated successfully.')
@login_required
def delete_customer(request, pk):
customer = get_object_or_404(models.Customer, pk=pk)
customer.delete()
messages.success(request, _('Customer deleted successfully.'))
return redirect('customer_list')
class VendorListView(LoginRequiredMixin,PermissionRequiredMixin, ListView):
model = models.Vendor
context_object_name = 'vendors'
paginate_by = 10
template_name = "vendors/vendors_list.html"
permission_required = ('inventory.view_vendor',)
class VendorDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView):
model = models.Vendor
template_name = "vendors/view_vendor.html"
permission_required = ('inventory.view_vendor',)
class VendorCreateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, CreateView):
model = models.Vendor
form_class = forms.VendorForm
template_name = 'vendors/vendor_form.html'
success_url = reverse_lazy('vendor_list')
permission_required = ('inventory.add_vendor',)
success_message = _('Vendor created successfully.')
class VendorUpdateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, UpdateView):
model = models.Vendor
form_class = forms.VendorForm
template_name = 'vendors/vendor_form.html'
success_url = reverse_lazy('vendor_list')
permission_required = ('inventory.change_vendor',)
success_message = _('Vendor updated successfully.')
@login_required
def delete_vendor(request, pk):
vendor = get_object_or_404(models.Vendor, pk=pk)
vendor.delete()
messages.success(request, _('Vendor deleted successfully.'))
return redirect('vendor_list')
class QuotationCreateView(LoginRequiredMixin,PermissionRequiredMixin, CreateView):
model = models.SaleQuotation
form_class = forms.QuotationForm
template_name = 'sales/quotation_form.html'
permission_required = ('inventory.add_salequotation',)
def form_valid(self, form):
quotation = form.save()
selected_cars = form.cleaned_data.get("cars")
for car in selected_cars:
car_finance = car.finances.first()
if car_finance:
models.SaleQuotationCar.objects.create(
quotation=quotation,
car=car,
)
messages.success(self.request, _("Quotation created successfully."))
return redirect('quotation_list')
class QuotationListView(LoginRequiredMixin,PermissionRequiredMixin, ListView):
model = models.SaleQuotation
template_name = "sales/quotation_list.html"
context_object_name = "quotations"
paginate_by = 10
permission_required = ('inventory.view_salequotation',)
def get_queryset(self):
status = self.request.GET.get("status")
queryset = models.SaleQuotation.objects.all()
if status:
queryset = queryset.filter(status=status)
return queryset
class QuotationDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView):
model = models.SaleQuotation
template_name = "sales/quotation_detail.html"
context_object_name = "quotation"
permission_required = ('inventory.view_salequotation',)
@login_required
def confirm_quotation(request, pk):
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
try:
quotation.confirm()
models.SalesOrder.objects.create(
quotation=quotation,
total_amount=quotation.quotation_cars.aggregate(Sum("total_amount"))["total_amount__sum"],
)
messages.success(request, _("Quotation confirmed and sales order created."))
except ValueError as e:
messages.error(request, str(e))
return redirect("quotation_detail", pk=pk)
class SalesOrderDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView):
model = models.SalesOrder
template_name = "sales/sales_order_detail.html"
context_object_name = "sales_order"
permission_required = ('inventory.view_salequotation',)
slug_field = 'order_id'
slug_url_kwarg = 'order_id'
#Users
class UserListView(LoginRequiredMixin,PermissionRequiredMixin, ListView):
model = models.Dealer
context_object_name = 'users'
paginate_by = 10
template_name = "users/user_list.html"
permission_required = ('inventory.view_dealer',)
def get_queryset(self):
query = self.request.GET.get('q')
users = self.request.user.dealer.sub_dealers
if query:
users = users.filter(
Q(name__icontains=query) |
Q(arabic_name__icontains=query) |
Q(phone_number__icontains=query)|
Q(address__icontains=query)
)
return users.all()
class UserDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView):
model = models.Dealer
template_name = "users/user_detail.html"
context_object_name = "user"
permission_required = ('inventory.view_dealer',)
class UserCreateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, CreateView):
model = models.Dealer
form_class = forms.UserForm
template_name = 'users/user_form.html'
success_url = reverse_lazy('user_list')
permission_required = ('inventory.add_dealer',)
success_message = _('User created successfully.')
def get_form(self, form_class = None):
form = super().get_form(form_class)
form.fields['dealer_type'].choices = [t for t in form.fields['dealer_type'].choices if t[0] != 'Owner']
return form
def form_valid(self, form):
dealer = self.request.user.dealer.get_parent_or_self
if dealer.sub_dealers.count() >= dealer.get_active_plan.max_users:
messages.error(self.request, _("You have reached the maximum number of users."))
return redirect('user_list')
user = User.objects.create_user(username=form.cleaned_data['name'])
user.set_password("Tenhal@123")
user.save()
form.instance.user = user
form.instance.parent_dealer = dealer
for group in user.groups.all():
group.user_set.remove(user)
Group.objects.get(name=form.cleaned_data['dealer_type'].lower()).user_set.add(user)
form.save()
return super().form_valid(form)
class UserUpdateView(LoginRequiredMixin,PermissionRequiredMixin,SuccessMessageMixin,AddDealerInstanceMixin, UpdateView):
model = models.Dealer
form_class = forms.UserForm
template_name = 'users/user_form.html'
success_url = reverse_lazy('user_list')
permission_required = ('inventory.change_dealer',)
success_message = _('User updated successfully.')
def get_form(self, form_class = None):
form = super().get_form(form_class)
if not self.request.user.has_perms(["inventory.change_dealer_type"]):
field = form.fields['dealer_type']
field.widget = field.hidden_widget()
form.fields['dealer_type'].choices = [t for t in form.fields['dealer_type'].choices if t[0] != 'Owner']
return form
def form_valid(self, form):
user = form.instance.user
for group in user.groups.all():
group.user_set.remove(user)
Group.objects.get(name=form.cleaned_data['dealer_type'].lower()).user_set.add(user)
form.save()
return super().form_valid(form)
def UserDeleteview(request, pk):
user = get_object_or_404(models.Dealer, pk=pk)
user.delete()
messages.success(request, _('User deleted successfully.'))
return redirect('user_list')
#errors
def custom_page_not_found_view(request, exception):
return render(request, "errors/404.html", {})
def custom_error_view(request, exception=None):
return render(request, "errors/500.html", {})
def custom_permission_denied_view(request, exception=None):
return render(request, "errors/403.html", {})
def custom_bad_request_view(request, exception=None):
return render(request, "errors/400.html", {})