from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib import messages from django.http import JsonResponse from django.views.generic import TemplateView from django.db import connection from django.conf import settings import sqlite3 import os import shutil from datetime import datetime, timedelta from django.utils import timezone from django.db.models import Sum, Count, Avg from decimal import Decimal from inventory.models import Product, StockMovement from purchase.models import PurchaseOrder, PurchaseOrderItem from manufacture.models import ManufacturingOrder from sales.models import SaleOrder, SaleOrderItem def is_admin(user): return user.is_superuser class DashboardView(TemplateView): template_name = 'core/dashboard.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Get current date and calculate date ranges today = timezone.now().date() week_ago = today - timedelta(days=7) month_ago = today - timedelta(days=30) # Production data context['daily_production'] = ManufacturingOrder.objects.filter( date=today ).aggregate( total_quantity=Sum('quantity'), total_orders=Count('id') ) context['weekly_production'] = ManufacturingOrder.objects.filter( date__gte=week_ago ).aggregate( total_quantity=Sum('quantity'), total_orders=Count('id') ) context['monthly_production'] = ManufacturingOrder.objects.filter( date__gte=month_ago ).aggregate( total_quantity=Sum('quantity'), total_orders=Count('id') ) # Sales data context['daily_sales'] = SaleOrder.objects.filter( date=today ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) context['weekly_sales'] = SaleOrder.objects.filter( date__gte=week_ago ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) context['monthly_sales'] = SaleOrder.objects.filter( date__gte=month_ago ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) # Purchase data context['daily_purchases'] = PurchaseOrder.objects.filter( date=today ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) context['weekly_purchases'] = PurchaseOrder.objects.filter( date__gte=week_ago ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) context['monthly_purchases'] = PurchaseOrder.objects.filter( date__gte=month_ago ).aggregate( total_amount=Sum('total_amount'), total_orders=Count('id') ) # Inventory turnover (last 30 days) context['inventory_turnover'] = StockMovement.objects.filter( date__gte=month_ago ).aggregate( total_movements=Count('id'), total_quantity=Sum('quantity') ) # Profit/Loss calculation (simplified) total_sales = context['monthly_sales']['total_amount'] or Decimal('0') total_purchases = context['monthly_purchases']['total_amount'] or Decimal('0') context['monthly_profit'] = total_sales - total_purchases # Recent activities context['recent_manufacturing'] = ManufacturingOrder.objects.order_by('-date')[:5] context['recent_sales'] = SaleOrder.objects.order_by('-date')[:5] context['recent_purchases'] = PurchaseOrder.objects.order_by('-date')[:5] # Low stock alerts context['low_stock_products'] = Product.objects.filter( current_stock__lte=10 )[:5] return context class DatabaseManagementView(TemplateView): template_name = 'core/database_management.html' def dispatch(self, request, *args, **kwargs): if not is_admin(request.user): messages.error(request, 'Access denied. Admin privileges required.') return redirect('core:dashboard') return super().dispatch(request, *args, **kwargs) @login_required @user_passes_test(is_admin) def backup_database(request): if request.method == 'POST': try: # Create backup directory if it doesn't exist backup_dir = os.path.join(settings.BASE_DIR, 'backups') os.makedirs(backup_dir, exist_ok=True) # Generate backup filename with timestamp timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') backup_filename = f'manufacture_app_backup_{timestamp}.sqlite3' backup_path = os.path.join(backup_dir, backup_filename) # Copy the database file db_path = os.path.join(settings.BASE_DIR, 'db.sqlite3') shutil.copy2(db_path, backup_path) messages.success(request, f'Database backed up successfully to {backup_filename}') except Exception as e: messages.error(request, f'Backup failed: {str(e)}') return redirect('core:database_management') @login_required @user_passes_test(is_admin) def restore_database(request): if request.method == 'POST': try: backup_file = request.FILES.get('backup_file') if backup_file: # Create backup of current database first current_db = os.path.join(settings.BASE_DIR, 'db.sqlite3') timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') safety_backup = os.path.join(settings.BASE_DIR, f'safety_backup_{timestamp}.sqlite3') shutil.copy2(current_db, safety_backup) # Restore from uploaded backup with open(current_db, 'wb') as f: for chunk in backup_file.chunks(): f.write(chunk) messages.success(request, 'Database restored successfully. Previous database backed up as safety measure.') else: messages.error(request, 'No backup file provided.') except Exception as e: messages.error(request, f'Restore failed: {str(e)}') return redirect('core:database_management') @login_required @user_passes_test(is_admin) def duplicate_database(request): if request.method == 'POST': try: # Create backup directory if it doesn't exist backup_dir = os.path.join(settings.BASE_DIR, 'backups') os.makedirs(backup_dir, exist_ok=True) # Generate duplicate filename with timestamp timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') duplicate_filename = f'manufacture_app_duplicate_{timestamp}.sqlite3' duplicate_path = os.path.join(backup_dir, duplicate_filename) # Copy the database file db_path = os.path.join(settings.BASE_DIR, 'db.sqlite3') shutil.copy2(db_path, duplicate_path) messages.success(request, f'Database duplicated successfully to {duplicate_filename}') except Exception as e: messages.error(request, f'Duplication failed: {str(e)}') return redirect('core:database_management')