from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
from .models import CoreUsers, Usermodule, Userpage
from decimal import Decimal
import json


def login_view(request):
    if request.method == 'POST':
        username = request.POST.get('username', '').strip()
        password = request.POST.get('password', '').strip()

        if not username or not password:
            return render(request, 'login.html', {'error': 'Please enter username and password'})

        user = CoreUsers.objects.filter(name=username, password=password).first()

        if user:
            request.session['user_id'] = str(user.id)
            request.session['user_name'] = str(user.name) if user.name else ''
            request.session['user_role'] = str(user.role) if user.role else ''
            return redirect('dashboard')
        else:
            return render(request, 'login.html', {'error': 'Invalid username or password'})

    return render(request, 'login.html')


def get_sidebar_data(user_id):
    """Sidebar data fetch karo - modules aur unke pages"""
    modules = Usermodule.objects.filter(
        userid=user_id, showmodule=True
    ).order_by('displayorder')

    sidebar = []
    for module in modules:
        pages = Userpage.objects.filter(
            userid=user_id,
            moduleid=module.moduleid,
            showpage=True
        ).order_by('displayorder')

        page_list = []
        for page in pages:
            page_list.append({
                'pageid': page.pageid,
                'pagename': page.pagename or '',
                'pageurl': page.pageurl or '#',
                'can_add': page.can_page_add,
                'can_edit': page.can_page_edit,
                'can_delete': page.can_page_delete,
            })

        sidebar.append({
            'moduleid': module.moduleid,
            'modulename': module.modulename or '',
            'module_url': module.module_url or '#',
            'can_add': module.can_module_add,
            'can_edit': module.can_module_edit,
            'can_delete': module.can_module_delete,
            'pages': page_list,
        })

    return sidebar


from datetime import datetime
from decimal import Decimal, InvalidOperation

from django.shortcuts import render
from django.db.models import Sum, Count, DecimalField
from django.db.models.functions import Cast, Coalesce

from .models import (
    PurchaseReceiving,
    PurchaseReceivingView,
    SellsInvoice,
    Expensedetail,
    Mortality,
    Parties,
    Usermodule,
)


def dashboard_view(request):
    if not request.session.get('user_id'):
        return redirect('login')

    # ---------------------------------------------------------
    # USER / SIDEBAR
    # ---------------------------------------------------------
    user_id = request.session.get('user_id')
    user_name = request.session.get('user_name', 'User')
    user_role = request.session.get('user_role', '')

    sidebar = get_sidebar_data(user_id)

    # ---------------------------------------------------------
    # DATE FILTERS
    # ---------------------------------------------------------
    date_from = request.GET.get('date_from', '').strip()
    date_to = request.GET.get('date_to', '').strip()

    try:
        from_date = datetime.strptime(date_from, '%Y-%m-%d').date() if date_from else None
    except ValueError:
        from_date = None
        date_from = ''

    try:
        to_date = datetime.strptime(date_to, '%Y-%m-%d').date() if date_to else None
    except ValueError:
        to_date = None
        date_to = ''

    purchases_qs = PurchaseReceiving.objects.all()
    sales_qs = SellsInvoice.objects.all()
    expenses_qs = Expensedetail.objects.all()
    mortality_qs = Mortality.objects.all()
    wadya_qs = PurchaseReceivingView.objects.all()

    if from_date:
        purchases_qs = purchases_qs.filter(date__date__gte=from_date)
        sales_qs = sales_qs.filter(entry_date__date__gte=from_date)
        expenses_qs = expenses_qs.filter(date__date__gte=from_date)
        mortality_qs = mortality_qs.filter(entry_date__gte=from_date)
        wadya_qs = wadya_qs.filter(date__date__gte=from_date)

    if to_date:
        purchases_qs = purchases_qs.filter(date__date__lte=to_date)
        sales_qs = sales_qs.filter(entry_date__date__lte=to_date)
        expenses_qs = expenses_qs.filter(date__date__lte=to_date)
        mortality_qs = mortality_qs.filter(entry_date__lte=to_date)
        wadya_qs = wadya_qs.filter(date__date__lte=to_date)

    # ---------------------------------------------------------
    # PURCHASE TOTALS
    # ---------------------------------------------------------
    purchase_data = purchases_qs.aggregate(
        total=Coalesce(
            Sum('amount'),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),
        paid=Coalesce(
            Sum('payed_amount'),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),
    )

    total_purchase = purchase_data['total'] or Decimal('0')
    total_purchase_paid = purchase_data['paid'] or Decimal('0')

    # Remaining dynamically calculate kar rahe hain
    total_purchase_remaining = total_purchase - total_purchase_paid

    # ---------------------------------------------------------
    # SALES
    # SellsInvoice amounts CharField hain is liye Cast use ho raha hai
    # ---------------------------------------------------------
    sales_data = sales_qs.aggregate(
        total=Coalesce(
            Sum(
                Cast(
                    'amount',
                    DecimalField(max_digits=30, decimal_places=2)
                )
            ),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),

        received=Coalesce(
            Sum(
                Cast(
                    'received_amount',
                    DecimalField(max_digits=30, decimal_places=2)
                )
            ),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),

        remaining=Coalesce(
            Sum(
                Cast(
                    'remaining_amount',
                    DecimalField(max_digits=30, decimal_places=2)
                )
            ),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),
    )

    total_sales = sales_data['total'] or Decimal('0')
    total_sales_received = sales_data['received'] or Decimal('0')
    total_sales_remaining = sales_data['remaining'] or Decimal('0')

    # ---------------------------------------------------------
    # EXPENSE
    # amount CharField hai
    # ---------------------------------------------------------
    expense_data = expenses_qs.aggregate(
        total=Coalesce(
            Sum(
                Cast(
                    'amount',
                    DecimalField(max_digits=30, decimal_places=2)
                )
            ),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        )
    )

    total_expense = expense_data['total'] or Decimal('0')

    # ---------------------------------------------------------
    # MORTALITY
    # ---------------------------------------------------------
    mortality_data = mortality_qs.aggregate(
        weight=Coalesce(
            Sum('weight'),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),
        amount=Coalesce(
            Sum('amount'),
            Decimal('0'),
            output_field=DecimalField(max_digits=30, decimal_places=2)
        ),
    )

    total_mortality_weight = mortality_data['weight'] or Decimal('0')
    total_mortality_amount = mortality_data['amount'] or Decimal('0')

    # ---------------------------------------------------------
    # NET POSITION
    # Sales - Purchases - Expenses
    # ---------------------------------------------------------
    net_position = total_sales - total_purchase - total_expense

    # ---------------------------------------------------------
    # PARTIES
    # party_type values case-insensitive rakhe hain
    # Apke DB mein agar Vendor/Customer/Trader naming different hai
    # to yahan values change kar dena.
    # ---------------------------------------------------------
    total_vendors = Parties.objects.filter(
        party_type__iexact='Vendor'
    ).count()

    total_customers = Parties.objects.filter(
        party_type__iexact='Customer'
    ).count()

    total_traders = Parties.objects.filter(
        party_type__iexact='Trader'
    ).count()

    # ---------------------------------------------------------
    # WADYA MAAL
    # remaining_weight CharField hai.
    # User requirement:
    # negative sign remove karke absolute values ka sum.
    #
    # Python side parsing rakha gaya hai taake "-100", "50.5" etc
    # safely handle ho saken.
    # ---------------------------------------------------------
    wadya_maal = Decimal('0')

    for value in wadya_qs.values_list('remaining_weight', flat=True):
        if value is None:
            continue

        try:
            cleaned_value = str(value).strip()
            cleaned_value = cleaned_value.replace(',', '')
            cleaned_value = cleaned_value.replace('kg', '')
            cleaned_value = cleaned_value.replace('KG', '')
            cleaned_value = cleaned_value.strip()

            number = Decimal(cleaned_value)

            # Minus remove
            wadya_maal += abs(number)

        except (InvalidOperation, ValueError, TypeError):
            continue

    # ---------------------------------------------------------
    # WASTE / FAT
    # Dummy values as requested
    # ---------------------------------------------------------
    waste_purchase = Decimal('12500')
    waste_sell = Decimal('9800')

    fat_purchase = Decimal('18500')
    fat_sell = Decimal('22100')

    # ---------------------------------------------------------
    # GRAPH
    # Sales + Expense grouped approximately by last records/date.
    # Simple database-independent approach.
    # ---------------------------------------------------------
    chart_labels = []
    chart_sales = []
    chart_expenses = []

    # Last 7 distinct dates from filtered data
    available_dates = set()

    for dt in sales_qs.values_list('entry_date', flat=True):
        if dt:
            available_dates.add(dt.date())

    for dt in expenses_qs.values_list('date', flat=True):
        if dt:
            available_dates.add(dt.date())

    chart_dates = sorted(available_dates)[-7:]

    for chart_date in chart_dates:
        day_sales = sales_qs.filter(
            entry_date__date=chart_date
        ).aggregate(
            total=Coalesce(
                Sum(
                    Cast(
                        'amount',
                        DecimalField(max_digits=30, decimal_places=2)
                    )
                ),
                Decimal('0'),
                output_field=DecimalField(max_digits=30, decimal_places=2)
            )
        )['total']

        day_expense = expenses_qs.filter(
            date__date=chart_date
        ).aggregate(
            total=Coalesce(
                Sum(
                    Cast(
                        'amount',
                        DecimalField(max_digits=30, decimal_places=2)
                    )
                ),
                Decimal('0'),
                output_field=DecimalField(max_digits=30, decimal_places=2)
            )
        )['total']

        chart_labels.append(chart_date.strftime('%d %b'))
        chart_sales.append(float(day_sales or 0))
        chart_expenses.append(float(day_expense or 0))

    context = {
        'user_name': user_name,
        'user_role': user_role,
        'sidebar': sidebar,

        'date_from': date_from,
        'date_to': date_to,

        'total_purchase': total_purchase,
        'total_purchase_paid': total_purchase_paid,
        'total_purchase_remaining': total_purchase_remaining,

        'total_sales': total_sales,
        'total_sales_received': total_sales_received,
        'total_sales_remaining': total_sales_remaining,

        'total_expense': total_expense,

        'total_mortality_weight': total_mortality_weight,
        'total_mortality_amount': total_mortality_amount,

        'net_position': net_position,

        'total_vendors': total_vendors,
        'total_customers': total_customers,
        'total_traders': total_traders,

        'wadya_maal': wadya_maal,

        'waste_purchase': waste_purchase,
        'waste_sell': waste_sell,

        'fat_purchase': fat_purchase,
        'fat_sell': fat_sell,

        'chart_labels': chart_labels,
        'chart_sales': chart_sales,
        'chart_expenses': chart_expenses,
    }

    return render(request, 'dashboard.html', context)





def logout_view(request):
    request.session.flush()
    return redirect('login')


def user_management(request):
    if not request.session.get('user_id'):
        return redirect('login')

    user_id = request.session.get('user_id')
    sidebar = get_sidebar_data(user_id)

    if request.method == 'GET':
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            users = CoreUsers.objects.all().values(
                'id', 'name', 'role', 'phone_number', 'email', 'address', 'password'
            )
            clean_users = []
            for u in users:
                clean_user = {}
                for key, val in u.items():
                    if isinstance(val, Decimal):
                        clean_user[key] = str(val)
                    else:
                        clean_user[key] = val
                clean_users.append(clean_user)
            return JsonResponse({'users': clean_users})
        return render(request, 'user_management.html', {'sidebar': sidebar})

    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')

            if action == 'save':
                user_id_form = data.get('id')
                if user_id_form:
                    user = get_object_or_404(CoreUsers, id=user_id_form)
                    user.name = data.get('name')
                    user.password = data.get('password')
                    user.role = data.get('role')
                    user.phone_number = data.get('phone_number')
                    user.email = data.get('email')
                    user.address = data.get('address')
                    user.save()
                    return JsonResponse({'status': 'success', 'message': 'User updated successfully!'})
                else:
                    CoreUsers.objects.create(
                        name=data.get('name'),
                        password=data.get('password'),
                        role=data.get('role'),
                        phone_number=data.get('phone_number'),
                        email=data.get('email'),
                        address=data.get('address'),
                    )
                    return JsonResponse({'status': 'success', 'message': 'User saved successfully!'})

            elif action == 'delete':
                del_id = data.get('id')
                user = get_object_or_404(CoreUsers, id=del_id)
                user.delete()
                return JsonResponse({'status': 'success', 'message': 'User deleted successfully!'})

        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})

    return JsonResponse({'status': 'error', 'message': 'Invalid request'})


def today_rate(request):
    if not request.session.get('user_id'):
        return redirect('login')
    user_id = request.session.get('user_id')
    sidebar = get_sidebar_data(user_id)
    return render(request, 'today_rate.html', {'sidebar': sidebar})






def hierarchy_management(request):
    if not request.session.get('user_id'):
        return redirect('login')

    user_id = request.session.get('user_id')
    sidebar = get_sidebar_data(user_id)

    if request.method == 'GET':
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            action = request.GET.get('action')

            if action == 'get_modules':
                modules = Usermodule.objects.all().values(
                    'moduleid', 'userid', 'modulename', 'module_url',
                    'showmodule', 'can_module_add', 'can_module_edit',
                    'can_module_delete', 'is_admin', 'displayorder'
                ).order_by('displayorder')
                clean = []
                for m in modules:
                    cm = {}
                    for k, v in m.items():
                        if isinstance(v, Decimal):
                            cm[k] = str(v)
                        else:
                            cm[k] = v
                    clean.append(cm)
                return JsonResponse({'modules': clean})

            elif action == 'get_pages':
                module_id = request.GET.get('module_id')
                pages = Userpage.objects.filter(moduleid=module_id).values(
                    'pageid', 'moduleid', 'userid', 'modulename', 'pagename',
                    'pageurl', 'showpage', 'can_page_add', 'can_page_edit',
                    'can_page_delete', 'is_admin', 'displayorder'
                ).order_by('displayorder')
                clean = []
                for p in pages:
                    cp = {}
                    for k, v in p.items():
                        if isinstance(v, Decimal):
                            cp[k] = str(v)
                        else:
                            cp[k] = v
                    clean.append(cp)
                return JsonResponse({'pages': clean})

            elif action == 'get_all_users':
                users = CoreUsers.objects.all().values('id', 'name')
                clean = []
                for u in users:
                    cu = {}
                    for k, v in u.items():
                        if isinstance(v, Decimal):
                            cu[k] = str(v)
                        else:
                            cu[k] = v
                    clean.append(cu)
                return JsonResponse({'users': clean})

        return render(request, 'hierarchy.html', {'sidebar': sidebar})

    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')

            if action == 'save_module':
                module_id = data.get('moduleid')
                if module_id:
                    module = get_object_or_404(Usermodule, moduleid=module_id)
                    module.userid = data.get('userid')
                    module.modulename = data.get('modulename')
                    module.module_url = data.get('module_url')
                    module.showmodule = data.get('showmodule', True)
                    module.can_module_add = data.get('can_module_add', False)
                    module.can_module_edit = data.get('can_module_edit', False)
                    module.can_module_delete = data.get('can_module_delete', False)
                    module.is_admin = data.get('is_admin', False)
                    module.displayorder = data.get('displayorder', 0)
                    module.save()
                    return JsonResponse({'status': 'success', 'message': 'Module updated successfully!'})
                else:
                    Usermodule.objects.create(
                        userid=data.get('userid'),
                        modulename=data.get('modulename'),
                        module_url=data.get('module_url'),
                        showmodule=data.get('showmodule', True),
                        can_module_add=data.get('can_module_add', False),
                        can_module_edit=data.get('can_module_edit', False),
                        can_module_delete=data.get('can_module_delete', False),
                        is_admin=data.get('is_admin', False),
                        displayorder=data.get('displayorder', 0),
                    )
                    return JsonResponse({'status': 'success', 'message': 'Module saved successfully!'})

            elif action == 'delete_module':
                module_id = data.get('moduleid')
                module = get_object_or_404(Usermodule, moduleid=module_id)
                Userpage.objects.filter(moduleid=module_id).delete()
                module.delete()
                return JsonResponse({'status': 'success', 'message': 'Module and its pages deleted!'})

            elif action == 'save_page':
                page_id = data.get('pageid')
                module_obj = get_object_or_404(Usermodule, moduleid=data.get('moduleid'))
                if page_id:
                    page = get_object_or_404(Userpage, pageid=page_id)
                    page.moduleid = module_obj
                    page.userid = data.get('userid')
                    page.modulename = module_obj.modulename
                    page.pagename = data.get('pagename')
                    page.pageurl = data.get('pageurl')
                    page.showpage = data.get('showpage', True)
                    page.can_page_add = data.get('can_page_add', False)
                    page.can_page_edit = data.get('can_page_edit', False)
                    page.can_page_delete = data.get('can_page_delete', False)
                    page.is_admin = data.get('is_admin', False)
                    page.displayorder = data.get('displayorder', 0)
                    page.save()
                    return JsonResponse({'status': 'success', 'message': 'Page updated successfully!'})
                else:
                    Userpage.objects.create(
                        moduleid=module_obj,
                        userid=data.get('userid'),
                        modulename=module_obj.modulename,
                        pagename=data.get('pagename'),
                        pageurl=data.get('pageurl'),
                        showpage=data.get('showpage', True),
                        can_page_add=data.get('can_page_add', False),
                        can_page_edit=data.get('can_page_edit', False),
                        can_page_delete=data.get('can_page_delete', False),
                        is_admin=data.get('is_admin', False),
                        displayorder=data.get('displayorder', 0),
                    )
                    return JsonResponse({'status': 'success', 'message': 'Page saved successfully!'})

            elif action == 'delete_page':
                page_id = data.get('pageid')
                page = get_object_or_404(Userpage, pageid=page_id)
                page.delete()
                return JsonResponse({'status': 'success', 'message': 'Page deleted successfully!'})

        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})

    return JsonResponse({'status': 'error', 'message': 'Invalid request'})




from django.shortcuts import render, redirect
from django.contrib import messages
from django.utils import timezone
from django.http import JsonResponse
from . models import *
from django.db import transaction

def receipt(request):
    if not request.session.get('user_id'):
        return redirect('login')

    if request.method == 'POST':
        sell_no = request.POST.get('sell_no')
        received_amt_input = request.POST.get('amount')
        payment_method = request.POST.get('payment_mode')
        description = request.POST.get('description')
        entry_date = request.POST.get('date')

        try:
            with transaction.atomic():
                # 1. Get the original Invoice
                invoice = SellsInvoice.objects.get(sells_no=sell_no)

                # Convert CharFields to float for calculation
                amt_to_receive = float(received_amt_input or 0)
                inv_total = float(invoice.amount or 0)
                inv_received = float(invoice.received_amount or 0)
                inv_remaining = float(invoice.remaining_amount or 0)

                # 2. Update SellsInvoice Balances
                new_received_total = inv_received + amt_to_receive
                new_remaining = inv_remaining - amt_to_receive

                invoice.received_amount = str(new_received_total)
                invoice.remaining_amount = str(new_remaining)
                invoice.save()

                # 3. Create Sellspayment Record (Copying data from Invoice)
                Sellspayment.objects.create(
                    sell_no=invoice.sells_no,
                    customer_name=invoice.customer_name,
                    weight=invoice.weight,
                    rate=invoice.rate,
                    vehicle_no=invoice.vehicle_no,
                    amount=invoice.amount, # Original Total
                    received_amount=str(amt_to_receive), # Current payment
                    description=description,
                    payment_method=payment_method,
                    entry_date=entry_date
                )

                return JsonResponse({'success': True})
        except SellsInvoice.DoesNotExist:
            return JsonResponse({'success': False, 'message': 'Invoice not found'})
        except Exception as e:
            return JsonResponse({'success': False, 'message': str(e)})

    # ============ GET ALL SALES FOR MODAL (AJAX) ============
    if request.GET.get('action') == 'get_sales':
        # ... (your existing AJAX logic here) ...
        sales = SellsInvoice.objects.all().order_by('-entry_date')
        data = []
        for sale in sales:
            try:
                rem_amt = float(sale.remaining_amount or 0)
            except: rem_amt = 0
            
            if rem_amt > 0:
                data.append({
                    'id': sale.id,
                    'sells_no': sale.sells_no,
                    'customer_name': sale.customer_name,
                    'remaining_amount': rem_amt,
                    'vehicle_no': sale.vehicle_no,
                    'date': sale.entry_date.strftime('%d %b %Y') if sale.entry_date else '-',
                })
        return JsonResponse({'success': True, 'data': data})

    # Default Page Load
    parties = Parties.objects.all().order_by('company_name')
    context = {'parties': parties, 'today_date': timezone.now().date().strftime('%Y-%m-%d')}
    return render(request, 'receipt.html', context)






from decimal import Decimal, InvalidOperation

from django.contrib import messages
from django.db import transaction
from django.db.models import DecimalField, ExpressionWrapper, F, Value
from django.db.models.functions import Coalesce
from django.shortcuts import redirect, render
from django.utils import timezone

from .models import PurchaseReceiving, PurchasePayments, Parties


def payment(request):
    # Login check
    if not request.session.get('user_id'):
        return redirect('login')

    # ==========================
    # SAVE PAYMENT
    # ==========================
    if request.method == 'POST':
        party_name = (request.POST.get('party_name') or '').strip()
        purchase_no = (request.POST.get('purchase_number') or '').strip()
        payment_date = request.POST.get('payment_date')
        paying_amount_raw = (request.POST.get('paying_amount') or '').strip()
        payment_mode = (request.POST.get('payment_mode') or '').strip()
        remarks = (request.POST.get('remarks') or '').strip()

        try:
            # Amount validation
            try:
                paying_amount = Decimal(paying_amount_raw)
            except (InvalidOperation, TypeError, ValueError):
                raise ValueError("Please enter a valid payment amount.")

            if paying_amount <= 0:
                raise ValueError("Payment amount must be greater than 0.")

            if not party_name:
                raise ValueError("Please select a party.")

            if not purchase_no:
                raise ValueError(
                    "Please select a purchase from Unpaid Records before adding payment."
                )

            with transaction.atomic():

                # Same purchase ko transaction ke andar lock karein
                purchase_obj = (
                    PurchaseReceiving.objects
                    .select_for_update()
                    .filter(purchase_number=purchase_no)
                    .first()
                )

                if not purchase_obj:
                    raise ValueError(
                        f"Purchase #{purchase_no} was not found."
                    )

                # Decimal values
                total_amount = purchase_obj.amount or Decimal('0')
                old_paid = purchase_obj.payed_amount or Decimal('0')

                remaining_amount = total_amount - old_paid

                # Already fully paid
                if remaining_amount <= 0:
                    raise ValueError(
                        f"Purchase #{purchase_no} is already fully paid."
                    )

                # Overpayment prevent
                if paying_amount > remaining_amount:
                    raise ValueError(
                        f"Maximum allowed payment is {remaining_amount}."
                    )

                # ==========================
                # PURCHASE PAYMENT INSERT
                # ==========================
                pay_obj = PurchasePayments.objects.create(
                    purchase_number=purchase_no,
                    part_name=party_name,
                    date=payment_date if payment_date else timezone.now(),
                    amount=str(paying_amount),
                    payment_mood=payment_mode,
                    remarks=remarks[:50]
                )

                # ==========================
                # UPDATE PURCHASE RECEIVING
                # ==========================
                new_paid = old_paid + paying_amount
                new_remaining = total_amount - new_paid

                purchase_obj.payed_amount = new_paid

                if new_remaining <= 0:
                    purchase_obj.status = 'Paid'
                else:
                    purchase_obj.status = 'Partial'

                # IMPORTANT:
                # Aapke PurchaseReceiving model mein remaining_amount field nahi hai.
                # Isliye remaining amount amount - payed_amount se calculate ho rahi hai.

                purchase_obj.save(
                    update_fields=['payed_amount', 'status']
                )

            messages.success(
                request,
                f'Payment Saved! Purchase #{purchase_no} | '
                f'Paid: {paying_amount} | '
                f'Remaining: {max(new_remaining, Decimal("0"))}'
            )

            return redirect('payment')

        except Exception as e:
            messages.error(request, f'Error: {str(e)}')
            return redirect('payment')

    # ==========================
    # LOAD ONLY UNPAID PURCHASES
    # ==========================

    decimal_field = DecimalField(
        max_digits=18,
        decimal_places=0
    )

    unpaid_purchases = (
        PurchaseReceiving.objects
        .annotate(
            calculated_paid=Coalesce(
                F('payed_amount'),
                Value(Decimal('0')),
                output_field=decimal_field
            )
        )
        .annotate(
            remaining_amount=ExpressionWrapper(
                Coalesce(
                    F('amount'),
                    Value(Decimal('0')),
                    output_field=decimal_field
                ) - F('calculated_paid'),
                output_field=decimal_field
            )
        )
        .filter(remaining_amount__gt=0)
        .order_by('-id')
    )

    parties = Parties.objects.all().order_by('company_name')

    return render(
        request,
        'payment.html',
        {
            'unpaid_purchases': unpaid_purchases,
            'parties': parties
        }
    )



    

def waste_payment(request):
    if not request.session.get('user_id'):
        return redirect('login')
    return render(request, 'waste_payment.html')


from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.utils import timezone
from django.http import JsonResponse
from django.db.models import Q
from datetime import datetime
from .models import ExpenseHead, Expensedetail

def expenses(request):
    if not request.session.get('user_id'):
        return redirect('login')

    # ============ HANDLE ALL ACTIONS ============
    
    # 1. DELETE EXPENSE
    if request.method == 'POST' and request.POST.get('action') == 'delete':
        try:
            expense_id = request.POST.get('expense_id')
            expense = get_object_or_404(Expensedetail, id=expense_id)
            expense.delete()
            messages.success(request, '🗑️ Expense deleted successfully!')
        except Exception as e:
            messages.error(request, f'❌ Error deleting: {str(e)}')
        return redirect('expenses')

    # 2. UPDATE EXPENSE
    if request.method == 'POST' and request.POST.get('action') == 'update':
        try:
            expense_id = request.POST.get('expense_id')
            head_code = request.POST.get('head_code')
            head_name = request.POST.get('head_name')
            expense_date = request.POST.get('expense_date')
            amount = request.POST.get('amount')
            remarks = request.POST.get('remarks', '')

            expense = get_object_or_404(Expensedetail, id=expense_id)
            expense.head_code = head_code
            expense.head_name = head_name
            expense.date = expense_date if expense_date else timezone.now()
            expense.amount = amount
            expense.remarks = remarks
            expense.save()
            
            messages.success(request, '✏️ Expense updated successfully!')
        except Exception as e:
            messages.error(request, f'❌ Error updating: {str(e)}')
        return redirect('expenses')

    # 3. SAVE NEW EXPENSE
    if request.method == 'POST':
        try:
            head_code = request.POST.get('head_code')
            head_name = request.POST.get('head_name')
            expense_date = request.POST.get('expense_date')
            amount = request.POST.get('amount')
            remarks = request.POST.get('remarks', '')

            if not head_code or not amount:
                messages.error(request, '⚠️ Head and Amount are required!')
                return redirect('expenses')

            Expensedetail.objects.create(
                head_code=head_code,
                head_name=head_name,
                date=expense_date if expense_date else timezone.now(),
                amount=amount,
                remarks=remarks
            )

            messages.success(request, '✅ Expense saved successfully!')
        except Exception as e:
            messages.error(request, f'❌ Error saving: {str(e)}')
        return redirect('expenses')

    # ============ GET REQUEST - LOAD PAGE ============
    
    # Get filter parameters
    from_date = request.GET.get('from_date')
    to_date = request.GET.get('to_date')
    head_code = request.GET.get('head_code')
    search = request.GET.get('search')
    edit_id = request.GET.get('edit_id')
    action = request.GET.get('action')
    
    # 4. GET SINGLE EXPENSE FOR EDIT (AJAX)
    if action == 'get_expense' and edit_id:
        try:
            expense = get_object_or_404(Expensedetail, id=edit_id)
            data = {
                'success': True,
                'id': expense.id,
                'head_code': expense.head_code,
                'head_name': expense.head_name,
                'date': expense.date.strftime('%Y-%m-%d') if expense.date else '',
                'amount': expense.amount or '0',
                'remarks': expense.remarks or '',
            }
            return JsonResponse(data)
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)})

    # 5. GET FILTERED EXPENSES (AJAX)
    if action == 'get_expenses':
        expenses = Expensedetail.objects.all()

        # Apply date filters
        if from_date:
            from_date_obj = datetime.strptime(from_date, '%Y-%m-%d').date()
            expenses = expenses.filter(date__date__gte=from_date_obj)
        
        if to_date:
            to_date_obj = datetime.strptime(to_date, '%Y-%m-%d').date()
            expenses = expenses.filter(date__date__lte=to_date_obj)

        # Apply head code filter
        if head_code:
            expenses = expenses.filter(head_code__icontains=head_code)

        # Apply search filter
        if search:
            expenses = expenses.filter(
                Q(head_name__icontains=search) |
                Q(head_code__icontains=search) |
                Q(remarks__icontains=search)
            )

        expenses = expenses.order_by('-date')

        # Prepare JSON response
        data = []
        total = 0
        for exp in expenses:
            amount_val = float(exp.amount or 0)
            total += amount_val
            data.append({
                'id': exp.id,
                'date': exp.date.strftime('%d %b %Y') if exp.date else '-',
                'date_str': exp.date.strftime('%Y-%m-%d') if exp.date else '',
                'head_code': exp.head_code or '',
                'head_name': exp.head_name or '',
                'remarks': exp.remarks or '',
                'amount': amount_val,
                'amount_formatted': f'Rs {amount_val:,.2f}',
            })

        return JsonResponse({
            'success': True,
            'data': data,
            'total': total,
            'count': len(data),
            'total_formatted': f'Rs {total:,.2f}'
        })

    # 6. DEFAULT PAGE LOAD
    # Fetch all expense heads for dropdown
    expense_heads = ExpenseHead.objects.all().order_by('name')
    
    # Get today's date
    today = timezone.now().date()
    today_str = today.strftime('%Y-%m-%d')
    
    # Fetch expenses - by default current date
    expenses_list = Expensedetail.objects.filter(
        date__date=today
    ).order_by('-date')
    
    # Calculate total
    total_amount = 0
    for exp in expenses_list:
        try:
            total_amount += float(exp.amount or 0)
        except:
            pass

    context = {
        'expense_heads': expense_heads,
        'expenses': expenses_list,
        'total_amount': total_amount,
        'today_date': today_str,
        'from_date': today_str,
        'to_date': today_str,
    }
    return render(request, 'expenses.html', context)



def waste_entry(request):
    if not request.session.get('user_id'):
        return redirect('login')

    return render(request, 'waste_entry.html')