from django.shortcuts import render ,redirect from django.db.models import Sum, Value, DecimalField from django.http import JsonResponse from django.db.models import Q from decimal import Decimal, InvalidOperation from django.apps import apps from datetime import date, datetime from django.utils import timezone from .models import Client, SecondTableEntry from django.db.models import Sum from django.urls import reverse from django.db.models.functions import Coalesce from .forms import BetriebskostenForm from .models import Betriebskosten from django.utils.dateparse import parse_date # Clients Page (Main) from django.shortcuts import render from django.db.models import Sum from datetime import datetime from .models import Client, SecondTableEntry def clients_list(request): # Get all clients clients = Client.objects.all() # Get all years available in SecondTableEntry available_years_qs = SecondTableEntry.objects.dates('date', 'year', order='DESC') available_years = [y.year for y in available_years_qs] # Determine selected year year_param = request.GET.get('year') if year_param: selected_year = int(year_param) else: # If no year in GET, default to latest available year or current year if DB empty selected_year = available_years[0] if available_years else datetime.now().year # Prepare monthly totals per client monthly_data = [] for client in clients: monthly_totals = [] for month in range(1, 13): total = SecondTableEntry.objects.filter( client=client, date__year=selected_year, date__month=month ).aggregate( total=Coalesce(Sum('lhe_output'), Value(0, output_field=DecimalField())) )['total'] monthly_totals.append(total) monthly_data.append({ 'client': client, 'monthly_totals': monthly_totals, 'year_total': sum(monthly_totals) }) return render(request, 'clients_table.html', { 'monthly_data': monthly_data, 'current_year': selected_year, 'available_years': available_years, 'months': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] }) # Table One View (ExcelEntry) def table_one_view(request): ExcelEntry = apps.get_model('sheets', 'ExcelEntry') entries_table1 = ExcelEntry.objects.all().select_related('client') clients = Client.objects.all() return render(request, 'table_one.html', { 'entries_table1': entries_table1, 'clients': clients, }) # Table Two View (SecondTableEntry) def table_two_view(request): try: SecondTableEntry = apps.get_model('sheets', 'SecondTableEntry') entries = SecondTableEntry.objects.all().order_by('-date') clients = Client.objects.all() return render(request, 'table_two.html', { 'entries_table2': entries, 'clients': clients, }) except Exception as e: return render(request, 'table_two.html', { 'error_message': f"Failed to load data: {str(e)}", 'entries_table2': [], 'clients': Client.objects.all() }) # Add Entry (Generic) def add_entry(request, model_name): if request.method == 'POST': try: model = apps.get_model('sheets', model_name) if model_name == 'SecondTableEntry': # Handle date conversion date_str = request.POST.get('date') try: date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else None except (ValueError, TypeError): return JsonResponse({ 'status': 'error', 'message': 'Invalid date format. Use YYYY-MM-DD' }, status=400) # Handle Helium Output (Table Two) lhe_output = request.POST.get('lhe_output') entry = model.objects.create( client=Client.objects.get(id=request.POST.get('client_id')), date=date_obj, is_warm=request.POST.get('is_warm') == 'true', lhe_delivery=request.POST.get('lhe_delivery', ''), lhe_output=Decimal(lhe_output) if lhe_output else None, notes=request.POST.get('notes', '') ) return JsonResponse({ 'status': 'success', 'id': entry.id, 'client_name': entry.client.name, 'date': entry.date.strftime('%Y-%m-%d') if entry.date else '', 'is_warm': entry.is_warm, 'lhe_delivery': entry.lhe_delivery, 'lhe_output': str(entry.lhe_output) if entry.lhe_output else '', 'notes': entry.notes }) elif model_name == 'ExcelEntry': # Parse the date string into a date object date_str = request.POST.get('date') try: date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else None except (ValueError, TypeError): date_obj = None # Create the entry entry = model.objects.create( client=Client.objects.get(id=request.POST.get('client_id')), date=date_obj, pressure=Decimal(request.POST.get('pressure', 0)), purity=Decimal(request.POST.get('purity', 0)), notes=request.POST.get('notes', '') ) # Prepare the response response_data = { 'status': 'success', 'id': entry.id, 'client_name': entry.client.name, 'pressure': str(entry.pressure), 'purity': str(entry.purity), 'notes': entry.notes } # Only add date if it exists if entry.date: response_data['date'] = entry.date.strftime('%Y-%m-%d') else: response_data['date'] = None return JsonResponse(response_data) # Keep your existing SecondTableEntry code here... except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}, status=400) return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400) # Update Entry (Generic) def update_entry(request, model_name): if request.method == 'POST': try: model = apps.get_model('sheets', model_name) entry_id = int(request.POST.get('id')) entry = model.objects.get(id=entry_id) # Common updates for both models entry.client = Client.objects.get(id=request.POST.get('client_id')) entry.notes = request.POST.get('notes', '') # Handle date properly for both models date_str = request.POST.get('date') if date_str: try: entry.date = datetime.strptime(date_str, '%Y-%m-%d').date() except ValueError: return JsonResponse({ 'status': 'error', 'message': 'Invalid date format. Use YYYY-MM-DD' }, status=400) if model_name == 'SecondTableEntry': # Handle Helium Output specific fields entry.is_warm = request.POST.get('is_warm') == 'true' entry.lhe_delivery = request.POST.get('lhe_delivery', '') lhe_output = request.POST.get('lhe_output') try: entry.lhe_output = Decimal(lhe_output) if lhe_output else None except InvalidOperation: return JsonResponse({ 'status': 'error', 'message': 'Invalid LHe Output value' }, status=400) entry.save() return JsonResponse({ 'status': 'success', 'id': entry.id, 'client_name': entry.client.name, 'date': entry.date.strftime('%Y-%m-%d') if entry.date else '', 'is_warm': entry.is_warm, 'lhe_delivery': entry.lhe_delivery, 'lhe_output': str(entry.lhe_output) if entry.lhe_output else '', 'notes': entry.notes }) elif model_name == 'ExcelEntry': # Handle Helium Input specific fields try: entry.pressure = Decimal(request.POST.get('pressure', 0)) entry.purity = Decimal(request.POST.get('purity', 0)) except InvalidOperation: return JsonResponse({ 'status': 'error', 'message': 'Invalid pressure or purity value' }, status=400) entry.save() return JsonResponse({ 'status': 'success', 'id': entry.id, 'client_name': entry.client.name, 'date': entry.date.strftime('%Y-%m-%d') if entry.date else '', 'pressure': str(entry.pressure), 'purity': str(entry.purity), 'notes': entry.notes }) except model.DoesNotExist: return JsonResponse({'status': 'error', 'message': 'Entry not found'}, status=404) except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}, status=400) return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400) # Delete Entry (Generic) def delete_entry(request, model_name): if request.method == 'POST': try: model = apps.get_model('sheets', model_name) entry_id = request.POST.get('id') entry = model.objects.get(id=entry_id) entry.delete() return JsonResponse({'status': 'success', 'message': 'Entry deleted'}) except model.DoesNotExist: return JsonResponse({'status': 'error', 'message': 'Entry not found'}, status=404) except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}, status=400) return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400) def betriebskosten_list(request): items = Betriebskosten.objects.all().order_by('-buchungsdatum') return render(request, 'betriebskosten_list.html', {'items': items}) def betriebskosten_create(request): if request.method == 'POST': try: entry_id = request.POST.get('id') if entry_id: # Update existing entry entry = Betriebskosten.objects.get(id=entry_id) else: # Create new entry entry = Betriebskosten() # Get form data buchungsdatum_str = request.POST.get('buchungsdatum') rechnungsnummer = request.POST.get('rechnungsnummer') kostentyp = request.POST.get('kostentyp') betrag = request.POST.get('betrag') beschreibung = request.POST.get('beschreibung') gas_volume = request.POST.get('gas_volume') # Validate required fields if not all([buchungsdatum_str, rechnungsnummer, kostentyp, betrag]): return JsonResponse({'status': 'error', 'message': 'All required fields must be filled'}) # Convert date string to date object try: buchungsdatum = parse_date(buchungsdatum_str) if not buchungsdatum: return JsonResponse({'status': 'error', 'message': 'Invalid date format'}) except (ValueError, TypeError): return JsonResponse({'status': 'error', 'message': 'Invalid date format'}) # Set entry values entry.buchungsdatum = buchungsdatum entry.rechnungsnummer = rechnungsnummer entry.kostentyp = kostentyp entry.betrag = betrag entry.beschreibung = beschreibung # Only set gas_volume if kostentyp is helium and gas_volume is provided if kostentyp == 'helium' and gas_volume: entry.gas_volume = gas_volume else: entry.gas_volume = None entry.save() return JsonResponse({ 'status': 'success', 'id': entry.id, 'buchungsdatum': entry.buchungsdatum.strftime('%Y-%m-%d'), 'rechnungsnummer': entry.rechnungsnummer, 'kostentyp_display': entry.get_kostentyp_display(), 'gas_volume': str(entry.gas_volume) if entry.gas_volume else '-', 'betrag': str(entry.betrag), 'beschreibung': entry.beschreibung or '' }) except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}) return JsonResponse({'status': 'error', 'message': 'Invalid request method'}) def betriebskosten_delete(request): if request.method == 'POST': try: entry_id = request.POST.get('id') entry = Betriebskosten.objects.get(id=entry_id) entry.delete() return JsonResponse({'status': 'success'}) except Betriebskosten.DoesNotExist: return JsonResponse({'status': 'error', 'message': 'Entry not found'}) except Exception as e: return JsonResponse({'status': 'error', 'message': str(e)}) return JsonResponse({'status': 'error', 'message': 'Invalid request method'})