
from datetime import date
from django.utils import timezone
from datetime import datetime, timedelta
from pyexpat.errors import messages
from django.shortcuts import render, redirect, get_object_or_404
from django.forms import DecimalField, inlineformset_factory, modelformset_factory, formset_factory
from django.core.paginator import Paginator
from django.db.models import Q, Sum,F, DecimalField
from django.http import HttpResponse, JsonResponse
from django.db import transaction
from django.db import transaction as django_transaction
from .models import  PurchaseReturn, PurchaseReturnItem,  JournalEntry,  Transaction, Account
from .models import PurchaseOrder, PurchaseOrderItem
from partners.models import Supplier, Company
from products.models import Product, StockMovement
from projects.models import Project
from .forms import AccountForm, PurchaseOrderForm, PurchaseOrderItemFormSet, PurchaseOrderItemForm, PurchaseReturnItemForm 
from .forms import JournalEntryForm, TransactionForm
from decimal import Decimal
from django.db.models import Case, When, Value, IntegerField
# from reportlab.pdfgen import canvas
from io import BytesIO
from django.template.loader import get_template
from django.contrib.auth.decorators import login_required
from .forms import PurchaseReturnForm, PurchaseReturnItemForm

# from xhtml2pdf import pisa

def create_account(request):
    if request.method == 'POST':
        form = AccountForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('account_list')  # Change this to your actual list page
    else:
        form = AccountForm()
    
    return render(request, 'accounting/create_account.html', {'form': form})


def account_list(request):
    accounts = Account.objects.select_related('parent', 'sub_type').order_by('code')
    return render(request, 'accounting/account_list.html', {'accounts': accounts})



# Add Purchase Order
def purchase_order_list(request):
    # purchase_orders = PurchaseOrder.objects.select_related("supplier", "Project").order_by('-order_date')
    purchase_orders = PurchaseOrder.objects.select_related("supplier", "project").annotate(
                        status_priority=Case(
                            When(status='draft', then=Value(0)),
                            default=Value(1),
                            output_field=IntegerField(),
                        )).order_by('status_priority', '-order_date', '-po_number')
    context = {
        'purchase_orders': purchase_orders,
        'status_choices': PurchaseOrder.STATUS_CHOICES  # If you have status choices defined
    }
    return render(request, "accounting/purchase_order_list.html", context)

import uuid
def generate_po_number():
    return f"PO-{uuid.uuid4().hex[:6].upper()}"  # Example: PO-1A2B3C

# Create purchase order
def create_purchase_order(request):
    PurchaseOrderItemFormSet = formset_factory(PurchaseOrderItemForm, extra=1)

    if request.method == 'POST':
        form = PurchaseOrderForm(request.POST)
        formset = PurchaseOrderItemFormSet(request.POST, prefix='items')
        
        if form.is_valid() and formset.is_valid():
            purchase_order = form.save(commit=False)
            purchase_order.created_by = request.user
            purchase_order.po_number=generate_po_number()
            purchase_order = form.save()
            for item_form in formset:
                if item_form.has_changed():  # Skip empty forms
                    item = item_form.save(commit=False)
                    item.purchase_order = purchase_order
                    item.save()

            # Check if status changed to completed
            new_status = form.cleaned_data['status']
            # Save the form first
            po = form.save(commit=False)
            if  new_status == 'completed':
                create_stock_movements_from_po(po)
                create_accounting_entry_for_po(po, request.user)                
            else:
                print(request, 'Purchase order updated successfully without stock updating!')  # Debug
            return redirect('purchase_order_list')
        else:
            print(form.errors)  # Debug
    else:
        form = PurchaseOrderForm()
        formset = PurchaseOrderItemFormSet(prefix='items')

    return render(request, 'accounting/purchase_order_form.html', {
        'form': form,
        'formset': formset
    })

def load_jobs(request):
    supplier_id = request.GET.get('supplier_id')
    jobs = Project.objects.filter(supplier_id=supplier_id).values('id', 'job_title')
    return JsonResponse(list(jobs), safe=False)

def purchase_order_detail(request, pk):
    purchase_order = get_object_or_404(
        PurchaseOrder.objects.select_related('supplier', 'project')
        .prefetch_related('items__product', 'returns__items__product'), 
        pk=pk
    )
    
    total_amount = sum(item.price * item.quantity for item in purchase_order.items.all())
    purchase_returns = purchase_order.returns.all()

    # New: calculate grand return total
    grand_return_total = sum(
        item.total_amount() for return_entry in purchase_returns for item in return_entry.items.all()
    )
    net_payable = total_amount - grand_return_total
    context = {
        'po': purchase_order,
        'items': purchase_order.items.all(),
        'total_amount': total_amount,
        'purchase_returns': purchase_returns,
        'grand_return_total': grand_return_total,
        'net_payable': net_payable,
    }
    return render(request, 'accounting/purchase_order_detail.html', context)

def purchase_order_edit(request, pk):
    po = get_object_or_404(PurchaseOrder, pk=pk)
    PurchaseOrderItemFormSet = inlineformset_factory(
        PurchaseOrder,
        PurchaseOrderItem,
        form=PurchaseOrderItemForm,
        extra=0,
        can_delete=True
    )
    
    if request.method == 'POST':
        form = PurchaseOrderForm(request.POST, instance=po)
        formset = PurchaseOrderItemFormSet(request.POST, instance=po)
        
        if form.is_valid() and formset.is_valid():
         
            old_status = PurchaseOrder.objects.get(pk=pk).status
            new_status = form.cleaned_data['status']
            # Save the form first
            po = form.save(commit=False)
            po.created_by = request.user
            form.save()
            formset.save()
            
            # Check if status changed to completed
            if old_status != 'completed' and new_status == 'completed':
                create_stock_movements_from_po(po)
                create_accounting_entry_for_po(po, request.user)
                print(request, 'PO marked as completed and stock updated!')  # Debug
            else:
                #messages.success(request, 'Purchase order updated successfully!')
                print(request, 'Purchase order updated successfully without stock updating!')  # Debug
            
            return redirect('purchase_order_detail', pk=po.id)
            
    else:
        form = PurchaseOrderForm(instance=po)
        formset = PurchaseOrderItemFormSet(instance=po)
    
    return render(request, 'accounting/purchase_order_edit.html', {
        'form': form,
        'formset': formset,
        'po': po,
    })

def create_accounting_entry_for_po(po, cUser):
    # ✅ 2. Create accounting journal entry
    total_cost = Decimal('0.00')
    for item in po.items.all():
        total_cost += item.price * item.quantity

    inventory_account = Account.objects.get(pk=4)
    payable_account = Account.objects.get(pk=6)
   
    journal_entry = JournalEntry.objects.create(
        date=po.order_date,
        description=f"Inventory received for {po.po_number}",
        status='posted',
        reference=po.po_number,
        project=po.project,
        supplier=po.supplier,
        created_by=cUser
    )
    # inventroy_account_debit
    Transaction.objects.create(
        journal_entry=journal_entry,
        account=inventory_account,
        debit=total_cost,
        credit=Decimal('0.00'),
        description=f"Inventory received for {po.po_number}"
    )
    # payable_account_credit
    Transaction.objects.create(
        journal_entry=journal_entry,
        account=payable_account,
        debit=Decimal('0.00'),
        credit=total_cost,
        description=f"Amount payable for {po.po_number}"
    )
    
def create_stock_movements_from_po(purchase_order):
    from django.utils import timezone

    for item in purchase_order.items.all():
        print(f"Creating movement for item ID {item.id} - Product: {item.product}")  # ✅ Debug here

        already_exists = StockMovement.objects.filter(
            product=item.product,
            reference=f"PO-{purchase_order.po_number}",
            movement_type='IN'
        ).exists()

        if already_exists:
            print(f"Already exists for {item.product} — Skipping")
            continue

        StockMovement.objects.create(
            product=item.product,
            warehouse=purchase_order.warehouse,
            movement_type='IN',
            quantity=item.quantity,
            purchase_price=item.price,
            reference=f"PO-{purchase_order.po_number}",
            notes=f"Received from purchase order {purchase_order.po_number}",
            date=timezone.now(),
            # user=purchase_order.created_by,
        )

def purchase_order_delete(request, pk):
    purchase_order = get_object_or_404(PurchaseOrder, pk=pk)
    if request.method == "POST":
        purchase_order.delete()
        return redirect('purchase_order_list')
    return render(request, 'purchase_order_confirm_delete.html', {'purchase_order': purchase_order})

def complete_purchase_order(request, po_id):
    po = get_object_or_404(PurchaseOrder, pk=po_id)
    if request.method == 'POST':
        po.status = 'completed'
        po.save()  # This will trigger stock movement creation
        messages.success(request, 'Purchase order completed and stock updated')
        return redirect('purchase_order_detail', pk=po_id)
    return render(request, 'confirm_complete.html', {'po': po})

# Delete Purchase Order
def delete_purchase_order(request, pk):
    order = get_object_or_404(PurchaseOrder, pk=pk)
    if request.method == 'POST':
        order.delete()
        return redirect('purchase_order_list')
    return render(request, 'accounting/delete_purchase_order.html', {'order': order})



# Create Journal Entry
@login_required
def create_journal_entry(request):
    TransactionFormSet = formset_factory(TransactionForm, extra=2)
    
    if request.method == 'POST':
        
        form = JournalEntryForm(request.POST)
        formset = TransactionFormSet(request.POST, prefix='transactions')
        total_debit = Decimal("0.00")
        total_credit = Decimal("0.00")
        
        if form.is_valid() and formset.is_valid():
            
            try:
                with django_transaction.atomic():
                    # Save Journal Entry (entry_number will be auto-generated)
                    
                    journal_entry = form.save(commit=False)
                    journal_entry.created_by = request.user
                    # journal_entry.created_by = request.user
                    # Only auto-generate entry_number if it's not set
                    if not journal_entry.entry_number:
                        last_entry = JournalEntry.objects.order_by('-id').first()
                        last_number = int(last_entry.entry_number.split('-')[1]) if last_entry else 0
                        journal_entry.entry_number = f"JE-{last_number + 1:04d}"
                        
                    journal_entry.save()
                    # Save Transactions
                    for txn_form in formset:
                        if txn_form.has_changed():
                            transaction = txn_form.save(commit=False)
                            transaction.journal_entry = journal_entry
                            transaction.debit = transaction.debit or Decimal("0.00")
                            transaction.credit = transaction.credit or Decimal("0.00")
                            transaction.save()
                            # total_debit += transaction.debit
                            # total_credit += transaction.credit
                           
                    # Validate double-entry
                    # total_debit = sum(t.debit for t in journal_entry.transactions.all())
                    # total_credit = sum(t.credit for t in journal_entry.transactions.all())
                    if total_debit != total_credit:
                        journal_entry.delete()
                        # messages.error(request, "Debits and credits must balance!")
                        return redirect('create_journal_entry')
                    
                    # messages.success(request, "Journal entry created successfully!")
                    return redirect('journal_entry_list')
                    
            except Exception as e:
                print(f"Error creating journal entry: {str(e)}")  # Debug
                # messages.error(request, f"Error creating journal entry: {str(e)}")
        else:
            print(form.errors)  # Debug
            print(formset.errors)  # Debug
    else:
        form = JournalEntryForm(initial={'date': date.today(), 'status': 'draft' })
        formset = TransactionFormSet(prefix='transactions')
    accounts = Account.objects.all().order_by('code')
    return render(request, 'accounting/create_journal_entry.html', {
        'form': form,
        'formset': formset,
        'accounts': accounts,
    })

# View Journal Entry
def journal_entry_list(request):
    # Get filter parameters from request
    date_from = request.GET.get('date_from')
    date_to = request.GET.get('date_to')
    account_id = request.GET.get('account')
    job_id = request.GET.get('project')
    total_debit = Decimal("0.00")
    total_credit = Decimal("0.00")
    # Start with all entries
    entries = JournalEntry.objects.all().order_by('-date', '-id')
    
    # Apply filters
    if date_from:
        entries = entries.filter(date__gte=date_from)
    if date_to:
        entries = entries.filter(date__lte=date_to)
    if account_id:
        entries = entries.filter(transactions__account_id=account_id).distinct()
    if job_id:
        entries = entries.filter(job_id=job_id)
    
    # Pagination
    paginator = Paginator(entries, 25)  # Show 25 entries per page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Get totals for the current page
    for entry in page_obj:
        entry.total_debit = entry.transactions.aggregate(Sum('debit'))['debit__sum'] or 0
        entry.total_credit = entry.transactions.aggregate(Sum('credit'))['credit__sum'] or 0
    
    context = {
        'page_obj': page_obj,
        'accounts': Account.objects.all().order_by('code'),
        'jobs': Project.objects.all(),
        'filter_params': {
            'date_from': date_from,
            'date_to': date_to,
            'account': account_id,
            'Project': job_id,
        }
    }
    return render(request, 'accounting/journal_entry_list.html', context)

# View Journal Entry Detail
def journal_entry_detail(request, pk):
    entry = get_object_or_404(JournalEntry, pk=pk)
    transactions = entry.transactions.all().select_related('account')
    
    return render(request, 'accounting/journal_entry_detail.html', {
        'entry': entry,
        'transactions': transactions,
    })

# Edit Journal Entry
def edit_journal_entry(request, pk):
    entry = get_object_or_404(JournalEntry, pk=pk)
    TransactionFormSet = formset_factory(TransactionForm, extra=0)

    if request.method == 'POST':
        form = JournalEntryForm(request.POST, instance=entry)
        formset = TransactionFormSet(request.POST, prefix='transactions')
        
        if form.is_valid() and formset.is_valid():
            try:
                with transaction.atomic():
                    # Save journal entry
                    entry = form.save(commit=False)
                    
                    # Handle different submit actions
                    if 'post' in request.POST:
                        entry.status = 'posted'
                    else:
                        # Only allow changing from draft if not posting
                        if entry.status == 'draft':
                            entry.status = form.cleaned_data.get('status', 'draft')
                    
                    entry.save()
                    
                    # Get existing transactions to track deletions
                    existing_transactions = list(entry.transactions.all())
                    kept_transactions = []
                    
                    # Process formset
                    for txn_form in formset:
                        if txn_form.cleaned_data.get('id'):
                            # Existing transaction being modified
                            txn = txn_form.cleaned_data['id']
                            if txn_form.cleaned_data.get('DELETE'):
                                # Mark for deletion
                                txn.delete()
                            else:
                                # Update existing transaction
                                txn.account = txn_form.cleaned_data['account']
                                txn.debit = txn_form.cleaned_data['debit'] or Decimal('0.00')
                                txn.credit = txn_form.cleaned_data['credit'] or Decimal('0.00')
                                txn.description = txn_form.cleaned_data['description']
                                txn.save()
                                kept_transactions.append(txn.id)
                        elif txn_form.has_changed() and not txn_form.cleaned_data.get('DELETE', False):
                            # New transaction
                            txn = txn_form.save(commit=False)
                            txn.journal_entry = entry
                            txn.debit = txn.debit or Decimal('0.00')
                            txn.credit = txn.credit or Decimal('0.00')
                            txn.save()
                            kept_transactions.append(txn.id)
                    
                    # Delete transactions not present in the formset
                    for txn in existing_transactions:
                        if txn.id not in kept_transactions:
                            txn.delete()
                    
                    # Validate double-entry
                    transactions = entry.transactions.all()
                    total_debit = sum(t.debit for t in transactions)
                    total_credit = sum(t.credit for t in transactions)
                    
                    if total_debit != total_credit:
                        raise ValueError("Debits and credits must balance")
                    
                    # messages.success(request, "Journal entry updated successfully!")
                    return redirect('journal_entry_list')
                    
            except Exception as e:
                # messages.error(request, f"Error updating journal entry: {str(e)}")
                print(f"Error updating journal entry: {str(e)}")  # Debug
    else:
        
        form = JournalEntryForm(instance=entry)
        formset = TransactionFormSet(
            prefix='transactions',
            initial=[{
                'account': t.account,
                'debit': t.debit,
                'credit': t.credit,
                'description': t.description
            } for t in entry.transactions.all()]
        )
        
    accounts = Account.objects.all().order_by('code')
    return render(request, 'accounting/journal_entry_edit.html', {
        'form': form,
        'formset': formset,
        'entry': entry,
        'accounts': accounts,
    })

def general_ledger(request):
    account_ids = request.GET.getlist('account_ids')
    selected_account_ids = account_ids
    ledger_data = {}

    if account_ids:
        accounts = Account.objects.filter(id__in=account_ids)
    else:
        accounts = Account.objects.all()

    for account in accounts:
        transactions = Transaction.objects.filter(account=account).select_related('journal_entry').order_by('journal_entry__date')
        if transactions.exists():
            total_debit = transactions.aggregate(total=Sum('debit'))['total'] or 0
            total_credit = transactions.aggregate(total=Sum('credit'))['total'] or 0

            ledger_data[account] = {
                'transactions': transactions,
                'total_debit': total_debit,
                'total_credit': total_credit,
            }
            
            
            

    context = {
        'ledger_data': ledger_data,
        'all_accounts': Account.objects.all().order_by('code'),
        'selected_account_ids': account_ids,
        
    }

    return render(request, 'accounting/general_ledger.html', context)

def trial_balance(request):
    try:
        date_str = request.GET.get('date')
        date = datetime.strptime(date_str, '%Y-%m-%d') if date_str else datetime.now()
    except ValueError:
        date = datetime.now()
    
    date_str = date.strftime('%Y-%m-%d')  # Ensure proper format
    
    # Step 1: Get all transactions up to the selected date
    transactions = Transaction.objects.filter(
        journal_entry__date__lte=date,
        journal_entry__status='posted'
    )

    # Step 2: Group transactions by account and calculate net balance
    account_balances = transactions.values(
        'account_id', 'account__name', 'account__code'
    ).annotate(
        total_debit=Sum('debit'),
        total_credit=Sum('credit')
    ).order_by('account__code')

    report = []
    total_debit = 0
    total_credit = 0

    for item in account_balances:
        debit = item['total_debit'] or 0
        credit = item['total_credit'] or 0
        balance = debit - credit

        if balance >= 0:
            debit_amount = balance
            credit_amount = 0
        else:
            debit_amount = 0
            credit_amount = abs(balance)

        total_debit += debit_amount
        total_credit += credit_amount

        report.append({
            'code': item['account__code'],
            'name': item['account__name'],
            'debit': debit_amount,
            'credit': credit_amount,
        })

    context = {
        'report': report,
        'date': date,
        'total_debit': total_debit,
        'total_credit': total_credit,
    }

    if 'export' in request.GET:
        return generate_pdf(request, context)
    
    return render(request, 'accounting/trial_balance.html', context)

def generate_pdf(request, context):
    template = get_template('accounting/trial_balance_pdf.html')
    html = template.render(context)
    
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="trial_balance.pdf"'
    
    # pisa_status = pisa.CreatePDF(html, dest=response)
    
    # if pisa_status.err:
    #     return HttpResponse('PDF generation error')
    return response

def load_jobs_for_supplier(request):
    supplier_id = request.GET.get('supplier_id')
    jobs = Project.objects.filter(supplier_id=supplier_id, end_date__isnull=True).values('id', 'job_title')
    return JsonResponse(list(jobs), safe=False)

# Generate Income Statement
def income_statement(request):
    try:
        start_date = request.GET.get('start_date', (datetime.now().replace(month=1, day=1)).strftime('%Y-%m-%d'))
        end_date = request.GET.get('end_date', datetime.now().strftime('%Y-%m-%d'))
        start_date = datetime.strptime(start_date, '%Y-%m-%d')
        end_date = datetime.strptime(end_date, '%Y-%m-%d')
    except ValueError:
        start_date = datetime.now().replace(month=1, day=1)
        end_date = datetime.now()

    # Get revenue accounts (assuming they have code starting with 4)
    revenues = Account.objects.filter(
        code__startswith='4',  # Revenue accounts typically start with 4
        transaction__journal_entry__date__range=[start_date, end_date]
    ).annotate(
        total=Sum('transaction__credit') - Sum('transaction__debit')
    ).order_by('code')

    # Get expense accounts (assuming they have code starting with 5 or 6)
    expenses = Account.objects.filter(
        code__regex=r'^[56]',  # Expense accounts typically start with 5 or 6
        transaction__journal_entry__date__range=[start_date, end_date]
    ).annotate(
        total=Sum('transaction__debit') - Sum('transaction__credit')
    ).order_by('code')

    # Calculate totals
    total_revenue = sum(revenue.total or 0 for revenue in revenues)
    total_expenses = sum(expense.total or 0 for expense in expenses)
    net_income = total_revenue - total_expenses

    context = {
        'start_date': start_date,
        'end_date': end_date,
        'revenues': revenues,
        'expenses': expenses,
        'total_revenue': total_revenue,
        'total_expenses': total_expenses,
        'net_income': net_income,
    }

    if 'export' in request.GET:
        return generate_income_statement_pdf(request, context)

    return render(request, 'accounting/income_statement.html', context)

def generate_income_statement_pdf(request, context):
    template = get_template('accounting/income_statement_pdf.html')
    html = template.render(context)
    
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="income_statement.pdf"'
    
    # pisa_status = pisa.CreatePDF(html, dest=response)
    
    # if pisa_status.err:
    #     return HttpResponse('PDF generation error')
    return response

def accounting_dashboard(request):
    # Date ranges
    today = timezone.now().date()
    month_start = today.replace(day=1)
    year_start = today.replace(month=1, day=1)
    
    # Recent Journal Entries
    recent_entries = JournalEntry.objects.order_by('-date')[:5]
    
    # Trial Balance Summary
    trial_balance = {
        'total_debit': Transaction.objects.aggregate(Sum('debit'))['debit__sum'] or 0,
        'total_credit': Transaction.objects.aggregate(Sum('credit'))['credit__sum'] or 0,
    }
    
    # Income Statement Summary (current month)
    revenue = Account.objects.filter(
        code__startswith='4',
        transaction__journal_entry__date__range=[month_start, today]
    ).aggregate(total=Sum('transaction__credit') - Sum('transaction__debit'))['total'] or 0
    
    expenses = Account.objects.filter(
        code__regex=r'^[56]',
        transaction__journal_entry__date__range=[month_start, today]
    ).aggregate(total=Sum('transaction__debit') - Sum('transaction__credit'))['total'] or 0
    
    net_income = revenue - expenses
    
    # Account Balances
    top_accounts = Account.objects.annotate(
        account_balance=Sum('transaction__debit') - Sum('transaction__credit')
    ).order_by('-account_balance')[:5]
    
    context = {
        'today': today,
        'recent_entries': recent_entries,
        'trial_balance': trial_balance,
        'revenue': revenue,
        'expenses': expenses,
        'net_income': net_income,
        'top_accounts': top_accounts,
    }
    return render(request, 'accounting/dashboard.html', context)

# Project Profit and Loss Report
def job_profit_loss(request, job_id):
    Project = get_object_or_404(Project, pk=job_id)

    # Get journal entries for this Project
    journal_entries = JournalEntry.objects.filter(Project=Project)

    # Get all related transactions
    transactions = Transaction.objects.filter(journal_entry__in=journal_entries).select_related(
        'account__sub_type__category'
    )

    revenue_total = Decimal('0.00')
    expense_total = Decimal('0.00')
    revenue_breakdown = []
    expense_breakdown = []

    for txn in transactions:
        category = txn.account.sub_type.category.name
        account_name = txn.account.name

        if category == 'Revenue':
            amount = txn.credit or Decimal('0.00')
            revenue_total += amount
            revenue_breakdown.append((account_name, amount))

        elif category == 'Expense':
            amount = txn.debit or Decimal('0.00')
            expense_total += amount
            expense_breakdown.append((account_name, amount))

    profit_or_loss = revenue_total - expense_total

    context = {
        'Project': Project,
        'revenue': revenue_total,
        'expenses': expense_total,
        'profit_or_loss': profit_or_loss,
        'revenue_breakdown': revenue_breakdown,
        'expense_breakdown': expense_breakdown,
    }

    return render(request, 'accounting/job_profit_loss.html', context)

def create_stock_movements_for_return(purchase_return):
    for item in purchase_return.items.all():
        StockMovement.objects.create(
            product=item.product,
            warehouse=purchase_return.purchase_order.warehouse,
            movement_type='OUT',
            quantity=item.quantity,
            purchase_price=item.price,
            reference=purchase_return.return_number,
            notes=f"Purchase return from {purchase_return.purchase_order.po_number}",
        )

def create_accounting_entry_for_purchase_return(purchase_return):
    from accounting.models import JournalEntry, Transaction, Account

    total = sum(item.total_amount() for item in purchase_return.items.all())

    journal = JournalEntry.objects.create(
        entry_number=f"PR-{purchase_return.return_number}",
        date=purchase_return.return_date,
        description=f"Return for {purchase_return.purchase_order.po_number}",
        reference=purchase_return.return_number,
        status='posted',
        Project=purchase_return.purchase_order.Project,
    )

    inventory_account = Account.objects.get(code='1400')  # Inventory
    payable_account = Account.objects.get(code='2010')   # Payable

    Transaction.objects.create(
        journal_entry=journal,
        account=inventory_account,
        credit=total,
        description=f"Inventory returned for {purchase_return.purchase_order.po_number}"
    )
    Transaction.objects.create(
        journal_entry=journal,
        account=payable_account,
        debit=total,
        description=f"Payable reduced for {purchase_return.purchase_order.po_number}"
    )


def purchase_return_view(request, pk):
    po = get_object_or_404(PurchaseOrder, pk=pk, status='completed')

    PurchaseReturnItemFormSet = formset_factory(PurchaseReturnItemForm, extra=0, can_delete=False)

    po_items = po.items.all()
    initial_data = [
        {'product': item.product.id, 'quantity': 0, 'price': item.price}
        for item in po_items
    ]
    
    if request.method == 'POST':
        formset = PurchaseReturnItemFormSet(request.POST)
        notes = request.POST.get('notes', '')

        if formset.is_valid():
            return_entry = PurchaseReturn.objects.create(
                return_number=f"PR-{po.po_number}",
                purchase_order=po,
                notes=notes
            )

            total_amount = Decimal('0.00')

            for form in formset:
                product = form.cleaned_data.get('product')
                quantity = form.cleaned_data.get('quantity')
                price = form.cleaned_data.get('price')
                
                if product and quantity:
                    PurchaseReturnItem.objects.create(
                        return_entry=return_entry,
                        product=product,
                        quantity=quantity,
                        price=price
                    )

                    total_amount += quantity * price

                    StockMovement.objects.create(
                        product=product,
                        warehouse=po.warehouse,
                        movement_type='OUT',
                        quantity=quantity,
                        purchase_price=price,
                        reference=f"RETURN-PO-{po.po_number}",
                        notes=f"Purchase return for {po.po_number}",
                        date=timezone.now()
                    )

            je = JournalEntry.objects.create(
                date=timezone.now().date(),
                description=f"Purchase return for {po.po_number}",
                status='posted',
                reference=f"RETURN-PO-{po.po_number}",
                Project=po.Project
            )

            inventory_account = Account.objects.get(code='1400')
            payable_account = Account.objects.get(code='2010')

            Transaction.objects.create(journal_entry=je, account=payable_account, debit=total_amount, credit=Decimal('0.00'))
            Transaction.objects.create(journal_entry=je, account=inventory_account, debit=Decimal('0.00'), credit=total_amount)

            return redirect('purchase_order_detail', pk=po.id)

    else:
        formset = PurchaseReturnItemFormSet(initial=initial_data)

    return render(request, 'accounting/purchase_return_form.html', {
        'formset': formset,
        'po': po
    })

def get_companies_by_supplier(request, supplier_id):
    companies = Company.objects.filter(supplier_id=supplier_id).values('id', 'company_name')
    return JsonResponse(list(companies), safe=False)


def get_companies_by_customer(request, customer_id):
    companies = Company.objects.filter(customer_id=customer_id).values('id', 'company_name')
    return JsonResponse(list(companies), safe=False)