Django_Basic_Manufacturing_3/reporting_plan.md
2025-08-22 17:05:22 +07:00

35 KiB

Reporting Module Implementation Plan with Excel Export

Overview

This document outlines the implementation plan for the reporting module, including Excel export functionality and various report types for the manufacturing application.

Reporting Models

1. Report Template Model

# reports/models.py

from django.db import models
from django.contrib.auth.models import User

class ReportTemplate(models.Model):
    REPORT_TYPES = [
        ('inventory', 'Inventory Report'),
        ('sales', 'Sales Report'),
        ('purchasing', 'Purchasing Report'),
        ('manufacturing', 'Manufacturing Report'),
        ('financial', 'Financial Report'),
        ('custom', 'Custom Report'),
    ]
    
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    report_type = models.CharField(max_length=20, choices=REPORT_TYPES)
    template_file = models.FileField(upload_to='report_templates/', blank=True, null=True)
    is_active = models.BooleanField(default=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.name

class GeneratedReport(models.Model):
    REPORT_FORMATS = [
        ('pdf', 'PDF'),
        ('excel', 'Excel'),
        ('csv', 'CSV'),
        ('html', 'HTML'),
    ]
    
    report_template = models.ForeignKey(ReportTemplate, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    format = models.CharField(max_length=10, choices=REPORT_FORMATS)
    file_path = models.CharField(max_length=500, blank=True)
    file_size = models.BigIntegerField(default=0)
    generated_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    generated_at = models.DateTimeField(auto_now_add=True)
    parameters = models.JSONField(default=dict, blank=True,
                                help_text="Parameters used to generate this report")
    
    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        from django.urls import reverse
        return reverse('reports:report_detail', kwargs={'report_id': self.id})

Report Generation System

2. Report Generator Classes

# reports/generators.py

import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.utils.dataframe import dataframe_to_rows
from django.http import HttpResponse
from django.template.loader import render_to_string
import io
import csv
from datetime import datetime

class BaseReportGenerator:
    """Base class for all report generators"""
    
    def __init__(self, report_template, parameters=None):
        self.report_template = report_template
        self.parameters = parameters or {}
    
    def generate_data(self):
        """Generate report data - to be implemented by subclasses"""
        raise NotImplementedError
    
    def generate_excel(self, data):
        """Generate Excel report"""
        df = pd.DataFrame(data)
        
        # Create Excel workbook
        wb = Workbook()
        ws = wb.active
        ws.title = self.report_template.name
        
        # Add data to worksheet
        for r in dataframe_to_rows(df, index=False, header=True):
            ws.append(r)
        
        # Style the header row
        header_font = Font(bold=True)
        header_fill = PatternFill(start_color="CCCCCC", end_color="CCCCCC", fill_type="solid")
        
        for cell in ws[1]:
            cell.font = header_font
            cell.fill = header_fill
            cell.alignment = Alignment(horizontal="center")
        
        # Auto-adjust column widths
        for column in ws.columns:
            max_length = 0
            column_letter = column[0].column_letter
            for cell in column:
                try:
                    if len(str(cell.value)) > max_length:
                        max_length = len(str(cell.value))
                except:
                    pass
            adjusted_width = (max_length + 2)
            ws.column_dimensions[column_letter].width = min(adjusted_width, 50)
        
        # Save to bytes
        output = io.BytesIO()
        wb.save(output)
        output.seek(0)
        
        return output
    
    def generate_csv(self, data):
        """Generate CSV report"""
        df = pd.DataFrame(data)
        output = io.StringIO()
        df.to_csv(output, index=False)
        output.seek(0)
        return output
    
    def generate_html(self, data):
        """Generate HTML report"""
        context = {
            'report_template': self.report_template,
            'data': data,
            'generated_at': datetime.now(),
            'parameters': self.parameters,
        }
        html = render_to_string('reports/report_template.html', context)
        return io.StringIO(html)
    
    def generate_report(self, format='excel'):
        """Generate report in specified format"""
        data = self.generate_data()
        
        if format == 'excel':
            return self.generate_excel(data)
        elif format == 'csv':
            return self.generate_csv(data)
        elif format == 'html':
            return self.generate_html(data)
        else:
            raise ValueError(f"Unsupported format: {format}")

class InventoryReportGenerator(BaseReportGenerator):
    """Generate inventory reports"""
    
    def generate_data(self):
        from inventory.models import Product, Inventory, Warehouse
        
        # Get inventory data
        inventory_data = []
        inventories = Inventory.objects.select_related('product', 'warehouse').all()
        
        for inv in inventories:
            inventory_data.append({
                'Product Code': inv.product.code,
                'Product Name': inv.product.name,
                'Warehouse': inv.warehouse.name,
                'Quantity': float(inv.quantity),
                'Reserved Quantity': float(inv.reserved_quantity),
                'Available Quantity': float(inv.available_quantity),
                'Unit of Measure': inv.product.unit_of_measure.name if inv.product.unit_of_measure else '',
                'Reorder Level': float(inv.product.reorder_level),
                'Cost Price': float(inv.product.cost_price) if inv.product.cost_price else 0,
                'Selling Price': float(inv.product.selling_price) if inv.product.selling_price else 0,
            })
        
        return inventory_data

class SalesReportGenerator(BaseReportGenerator):
    """Generate sales reports"""
    
    def generate_data(self):
        from sales.models import SalesOrder, SalesOrderItem, Customer
        
        # Get sales data based on parameters
        start_date = self.parameters.get('start_date')
        end_date = self.parameters.get('end_date')
        customer_id = self.parameters.get('customer_id')
        
        sales_orders = SalesOrder.objects.select_related('customer').prefetch_related('items__product')
        
        if start_date:
            sales_orders = sales_orders.filter(order_date__gte=start_date)
        if end_date:
            sales_orders = sales_orders.filter(order_date__lte=end_date)
        if customer_id:
            sales_orders = sales_orders.filter(customer_id=customer_id)
        
        # Generate sales data
        sales_data = []
        for order in sales_orders:
            for item in order.items.all():
                sales_data.append({
                    'Order Number': order.so_number,
                    'Order Date': order.order_date.strftime('%Y-%m-%d'),
                    'Customer': order.customer.name,
                    'Product Code': item.product.code,
                    'Product Name': item.product.name,
                    'Quantity': float(item.quantity),
                    'Unit Price': float(item.unit_price),
                    'Total Price': float(item.total_price),
                    'Status': order.get_status_display(),
                })
        
        return sales_data

class PurchasingReportGenerator(BaseReportGenerator):
    """Generate purchasing reports"""
    
    def generate_data(self):
        from purchasing.models import PurchaseOrder, PurchaseOrderItem, Supplier
        
        # Get purchasing data based on parameters
        start_date = self.parameters.get('start_date')
        end_date = self.parameters.get('end_date')
        supplier_id = self.parameters.get('supplier_id')
        
        purchase_orders = PurchaseOrder.objects.select_related('supplier').prefetch_related('items__product')
        
        if start_date:
            purchase_orders = purchase_orders.filter(order_date__gte=start_date)
        if end_date:
            purchase_orders = purchase_orders.filter(order_date__lte=end_date)
        if supplier_id:
            purchase_orders = purchase_orders.filter(supplier_id=supplier_id)
        
        # Generate purchasing data
        purchasing_data = []
        for order in purchase_orders:
            for item in order.items.all():
                purchasing_data.append({
                    'PO Number': order.po_number,
                    'Order Date': order.order_date.strftime('%Y-%m-%d'),
                    'Supplier': order.supplier.name,
                    'Product Code': item.product.code,
                    'Product Name': item.product.name,
                    'Quantity': float(item.quantity),
                    'Unit Price': float(item.unit_price),
                    'Total Price': float(item.total_price),
                    'Status': order.get_status_display(),
                })
        
        return purchasing_data

class ManufacturingReportGenerator(BaseReportGenerator):
    """Generate manufacturing reports"""
    
    def generate_data(self):
        from manufacturing.models import ManufacturingOrder, BillOfMaterial
        
        # Get manufacturing data based on parameters
        start_date = self.parameters.get('start_date')
        end_date = self.parameters.get('end_date')
        status = self.parameters.get('status')
        
        mo_queryset = ManufacturingOrder.objects.select_related('bom__product')
        
        if start_date:
            mo_queryset = mo_queryset.filter(scheduled_start_date__gte=start_date)
        if end_date:
            mo_queryset = mo_queryset.filter(scheduled_start_date__lte=end_date)
        if status:
            mo_queryset = mo_queryset.filter(status=status)
        
        # Generate manufacturing data
        manufacturing_data = []
        for mo in mo_queryset:
            manufacturing_data.append({
                'MO Number': mo.mo_number,
                'Product': mo.bom.product.name,
                'Quantity to Produce': float(mo.quantity_to_produce),
                'Scheduled Start': mo.scheduled_start_date.strftime('%Y-%m-%d'),
                'Scheduled End': mo.scheduled_end_date.strftime('%Y-%m-%d'),
                'Actual Start': mo.actual_start_date.strftime('%Y-%m-%d') if mo.actual_start_date else '',
                'Actual End': mo.actual_end_date.strftime('%Y-%m-%d') if mo.actual_end_date else '',
                'Status': mo.get_status_display(),
            })
        
        return manufacturing_data

class FinancialReportGenerator(BaseReportGenerator):
    """Generate financial reports"""
    
    def generate_data(self):
        from sales.models import SalesOrder
        from purchasing.models import PurchaseOrder
        
        # Get date range from parameters
        start_date = self.parameters.get('start_date')
        end_date = self.parameters.get('end_date')
        
        # Get sales data
        sales_queryset = SalesOrder.objects.all()
        if start_date:
            sales_queryset = sales_queryset.filter(order_date__gte=start_date)
        if end_date:
            sales_queryset = sales_queryset.filter(order_date__lte=end_date)
        
        total_sales = sales_queryset.aggregate(
            total=models.Sum('total_amount')
        )['total'] or 0
        
        # Get purchasing data
        purchase_queryset = PurchaseOrder.objects.all()
        if start_date:
            purchase_queryset = purchase_queryset.filter(order_date__gte=start_date)
        if end_date:
            purchase_queryset = purchase_queryset.filter(order_date__lte=end_date)
        
        total_purchases = purchase_queryset.aggregate(
            total=models.Sum('total_amount')
        )['total'] or 0
        
        # Generate financial summary
        financial_data = [{
            'Period': f"{start_date} to {end_date}" if start_date and end_date else 'All Time',
            'Total Sales': float(total_sales),
            'Total Purchases': float(total_purchases),
            'Net Profit/Loss': float(total_sales - total_purchases),
        }]
        
        return financial_data

# Factory for creating report generators
class ReportGeneratorFactory:
    """Factory for creating report generators"""
    
    generators = {
        'inventory': InventoryReportGenerator,
        'sales': SalesReportGenerator,
        'purchasing': PurchasingReportGenerator,
        'manufacturing': ManufacturingReportGenerator,
        'financial': FinancialReportGenerator,
    }
    
    @classmethod
    def create_generator(cls, report_type, report_template, parameters=None):
        generator_class = cls.generators.get(report_type)
        if not generator_class:
            raise ValueError(f"Unsupported report type: {report_type}")
        return generator_class(report_template, parameters)

Report Views

3. Report Views Implementation

# reports/views.py

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, permission_required
from django.http import HttpResponse, JsonResponse
from django.contrib import messages
from django.db.models import Q
from .models import ReportTemplate, GeneratedReport
from .generators import ReportGeneratorFactory
from .forms import ReportParametersForm
import os

@login_required
@permission_required('reports.view_report', raise_exception=True)
def reports_dashboard(request):
    """Main reports dashboard view"""
    # Get recent reports
    recent_reports = GeneratedReport.objects.select_related(
        'report_template', 'generated_by'
    ).order_by('-generated_at')[:10]
    
    # Get available report templates
    report_templates = ReportTemplate.objects.filter(is_active=True)
    
    context = {
        'recent_reports': recent_reports,
        'report_templates': report_templates,
    }
    
    return render(request, 'reports/dashboard.html', context)

@login_required
@permission_required('reports.view_report', raise_exception=True)
def inventory_report_view(request):
    """Inventory report view"""
    template = get_object_or_404(ReportTemplate, report_type='inventory', is_active=True)
    
    if request.method == 'POST':
        # Generate report
        return generate_report_view(request, template.id)
    
    context = {
        'report_template': template,
        'report_type': 'inventory',
    }
    
    return render(request, 'reports/inventory_report.html', context)

@login_required
@permission_required('reports.view_report', raise_exception=True)
def sales_report_view(request):
    """Sales report view"""
    template = get_object_or_404(ReportTemplate, report_type='sales', is_active=True)
    
    if request.method == 'POST':
        # Generate report
        return generate_report_view(request, template.id)
    
    context = {
        'report_template': template,
        'report_type': 'sales',
    }
    
    return render(request, 'reports/sales_report.html', context)

@login_required
@permission_required('reports.view_report', raise_exception=True)
def purchasing_report_view(request):
    """Purchasing report view"""
    template = get_object_or_404(ReportTemplate, report_type='purchasing', is_active=True)
    
    if request.method == 'POST':
        # Generate report
        return generate_report_view(request, template.id)
    
    context = {
        'report_template': template,
        'report_type': 'purchasing',
    }
    
    return render(request, 'reports/purchasing_report.html', context)

@login_required
@permission_required('reports.view_report', raise_exception=True)
def manufacturing_report_view(request):
    """Manufacturing report view"""
    template = get_object_or_404(ReportTemplate, report_type='manufacturing', is_active=True)
    
    if request.method == 'POST':
        # Generate report
        return generate_report_view(request, template.id)
    
    context = {
        'report_template': template,
        'report_type': 'manufacturing',
    }
    
    return render(request, 'reports/manufacturing_report.html', context)

@login_required
@permission_required('reports.view_report', raise_exception=True)
def financial_report_view(request):
    """Financial report view"""
    template = get_object_or_404(ReportTemplate, report_type='financial', is_active=True)
    
    if request.method == 'POST':
        # Generate report
        return generate_report_view(request, template.id)
    
    context = {
        'report_template': template,
        'report_type': 'financial',
    }
    
    return render(request, 'reports/financial_report.html', context)

@login_required
@permission_required('reports.generate_report', raise_exception=True)
def generate_report_view(request, template_id):
    """Generate a report"""
    template = get_object_or_404(ReportTemplate, id=template_id)
    
    # Get parameters from POST data
    parameters = {}
    for key, value in request.POST.items():
        if key not in ['csrfmiddlewaretoken', 'format']:
            parameters[key] = value
    
    # Get format
    format = request.POST.get('format', 'excel')
    
    try:
        # Create report generator
        generator = ReportGeneratorFactory.create_generator(
            template.report_type, template, parameters
        )
        
        # Generate report data
        output = generator.generate_report(format)
        
        # Create GeneratedReport record
        report_name = f"{template.name} - {datetime.now().strftime('%Y%m%d_%H%M%S')}"
        
        generated_report = GeneratedReport.objects.create(
            report_template=template,
            name=report_name,
            format=format,
            generated_by=request.user,
            parameters=parameters,
        )
        
        # Return file response
        if format == 'excel':
            response = HttpResponse(
                output.getvalue(),
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename="{report_name}.xlsx"'
        elif format == 'csv':
            response = HttpResponse(
                output.getvalue(),
                content_type='text/csv'
            )
            response['Content-Disposition'] = f'attachment; filename="{report_name}.csv"'
        else:
            response = HttpResponse(
                output.getvalue(),
                content_type='text/html'
            )
        
        return response
        
    except Exception as e:
        messages.error(request, f"Error generating report: {str(e)}")
        return redirect('reports:dashboard')

@login_required
@permission_required('reports.view_report', raise_exception=True)
def report_detail_view(request, report_id):
    """View details of a generated report"""
    report = get_object_or_404(GeneratedReport, id=report_id)
    
    context = {
        'report': report,
    }
    
    return render(request, 'reports/report_detail.html', context)

@login_required
@permission_required('reports.export_report', raise_exception=True)
def export_to_excel_view(request, report_id):
    """Export a report to Excel"""
    report = get_object_or_404(GeneratedReport, id=report_id)
    
    # Check if file exists
    if report.file_path and os.path.exists(report.file_path):
        with open(report.file_path, 'rb') as f:
            response = HttpResponse(
                f.read(),
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename="{report.name}.xlsx"'
            return response
    else:
        messages.error(request, "Report file not found.")
        return redirect('reports:report_detail', report_id=report_id)

@login_required
@permission_required('reports.export_report', raise_exception=True)
def export_to_pdf_view(request, report_id):
    """Export a report to PDF"""
    # Implementation would require a PDF generation library like WeasyPrint or ReportLab
    # This is a placeholder for future implementation
    messages.info(request, "PDF export is not yet implemented.")
    return redirect('reports:report_detail', report_id=report_id)

Report Forms

4. Report Parameter Forms

# reports/forms.py

from django import forms
from django.forms.widgets import DateInput
from inventory.models import Product, Warehouse
from sales.models import Customer
from purchasing.models import Supplier

class BaseReportForm(forms.Form):
    """Base form for report parameters"""
    start_date = forms.DateField(
        required=False,
        widget=DateInput(attrs={'type': 'date', 'class': 'form-control'}),
        label='Start Date'
    )
    end_date = forms.DateField(
        required=False,
        widget=DateInput(attrs={'type': 'date', 'class': 'form-control'}),
        label='End Date'
    )

class InventoryReportForm(BaseReportForm):
    """Form for inventory report parameters"""
    product = forms.ModelChoiceField(
        queryset=Product.objects.all(),
        required=False,
        empty_label="All Products",
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    warehouse = forms.ModelChoiceField(
        queryset=Warehouse.objects.all(),
        required=False,
        empty_label="All Warehouses",
        widget=forms.Select(attrs={'class': 'form-control'})
    )

class SalesReportForm(BaseReportForm):
    """Form for sales report parameters"""
    customer = forms.ModelChoiceField(
        queryset=Customer.objects.all(),
        required=False,
        empty_label="All Customers",
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    product = forms.ModelChoiceField(
        queryset=Product.objects.all(),
        required=False,
        empty_label="All Products",
        widget=forms.Select(attrs={'class': 'form-control'})
    )

class PurchasingReportForm(BaseReportForm):
    """Form for purchasing report parameters"""
    supplier = forms.ModelChoiceField(
        queryset=Supplier.objects.all(),
        required=False,
        empty_label="All Suppliers",
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    product = forms.ModelChoiceField(
        queryset=Product.objects.all(),
        required=False,
        empty_label="All Products",
        widget=forms.Select(attrs={'class': 'form-control'})
    )

class ManufacturingReportForm(BaseReportForm):
    """Form for manufacturing report parameters"""
    product = forms.ModelChoiceField(
        queryset=Product.objects.all(),
        required=False,
        empty_label="All Products",
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    status = forms.ChoiceField(
        choices=[
            ('', 'All Statuses'),
            ('draft', 'Draft'),
            ('planned', 'Planned'),
            ('in_progress', 'In Progress'),
            ('completed', 'Completed'),
            ('cancelled', 'Cancelled'),
        ],
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'})
    )

class FinancialReportForm(BaseReportForm):
    """Form for financial report parameters"""
    pass  # Uses base form fields

Report Templates

5. Report Dashboard Template

<!-- templates/reports/dashboard.html -->

{% extends 'base.html' %}

{% block title %}Reports - Manufacturing App{% endblock %}

{% block content %}
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
    <h1 class="h2">Reports</h1>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="card">
            <div class="card-header">
                <h5 class="card-title mb-0">Report Types</h5>
            </div>
            <div class="card-body">
                <div class="row">
                    <div class="col-md-6 mb-3">
                        <div class="card">
                            <div class="card-body text-center">
                                <i class="fas fa-boxes fa-2x mb-2 text-primary"></i>
                                <h6 class="card-title">Inventory Report</h6>
                                <p class="card-text">Detailed inventory status and stock levels</p>
                                <a href="{% url 'reports:inventory_report' %}" class="btn btn-primary btn-sm">
                                    Generate Report
                                </a>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-6 mb-3">
                        <div class="card">
                            <div class="card-body text-center">
                                <i class="fas fa-dollar-sign fa-2x mb-2 text-success"></i>
                                <h6 class="card-title">Sales Report</h6>
                                <p class="card-text">Sales orders, revenue, and customer analysis</p>
                                <a href="{% url 'reports:sales_report' %}" class="btn btn-success btn-sm">
                                    Generate Report
                                </a>
                            </div>
                        </div>
                    <div class="col-md-6 mb-3">
                        <div class="card">
                            <div class="card-body text-center">
                                <i class="fas fa-shopping-cart fa-2x mb-2 text-info"></i>
                                <h6 class="card-title">Purchasing Report</h6>
                                <p class="card-text">Purchase orders and supplier analysis</p>
                                <a href="{% url 'reports:purchasing_report' %}" class="btn btn-info btn-sm">
                                    Generate Report
                                </a>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-6 mb-3">
                        <div class="card">
                            <div class="card-body text-center">
                                <i class="fas fa-cogs fa-2x mb-2 text-warning"></i>
                                <h6 class="card-title">Manufacturing Report</h6>
                                <p class="card-text">Production orders and manufacturing analysis</p>
                                <a href="{% url 'reports:manufacturing_report' %}" class="btn btn-warning btn-sm">
                                    Generate Report
                                </a>
                            </div>
                        </div>
                    <div class="col-md-6 mb-3">
                        <div class="card">
                            <div class="card-body text-center">
                                <i class="fas fa-chart-line fa-2x mb-2 text-danger"></i>
                                <h6 class="card-title">Financial Report</h6>
                                <p class="card-text">Financial summary and profit/loss analysis</p>
                                <a href="{% url 'reports:financial_report' %}" class="btn btn-danger btn-sm">
                                    Generate Report
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <div class="col-md-4">
        <div class="card">
            <div class="card-header">
                <h5 class="card-title mb-0">Recent Reports</h5>
            </div>
            <div class="card-body">
                {% if recent_reports %}
                <div class="list-group">
                    {% for report in recent_reports %}
                    <a href="{% url 'reports:report_detail' report.id %}" 
                       class="list-group-item list-group-item-action">
                        <div class="d-flex w-100 justify-content-between">
                            <h6 class="mb-1">{{ report.name }}</h6>
                            <small>{{ report.generated_at|date:"d M Y H:i" }}</small>
                        </div>
                        <small>{{ report.report_template.name }} ({{ report.get_format_display }})</small>
                    </a>
                    {% endfor %}
                </div>
                {% else %}
                <p class="text-muted">No recent reports generated.</p>
                {% endif %}
            </div>
        </div>
    </div>
</div>
{% endblock %}

6. Report Generation Template

<!-- templates/reports/generate_report.html -->

{% extends 'base.html' %}

{% block title %}Generate {{ report_template.name }} - Manufacturing App{% endblock %}

{% block content %}
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
    <h1 class="h2">Generate {{ report_template.name }}</h1>
    <div class="btn-toolbar mb-2 mb-md-0">
        <a href="{% url 'reports:dashboard' %}" class="btn btn-sm btn-outline-secondary">
            <i class="fas fa-arrow-left"></i> Back to Reports
        </a>
    </div>
</div>

<div class="row">
    <div class="col-md-8">
        <div class="card">
            <div class="card-header">
                <h5 class="card-title mb-0">Report Parameters</h5>
            </div>
            <div class="card-body">
                <form method="post">
                    {% csrf_token %}
                    
                    {% if form.non_field_errors %}
                    <div class="alert alert-danger">
                        {{ form.non_field_errors }}
                    </div>
                    {% endif %}
                    
                    <div class="row">
                        <div class="col-md-6">
                            <div class="mb-3">
                                <label for="{{ form.start_date.id_for_label }}" class="form-label">
                                    {{ form.start_date.label }}
                                </label>
                                {{ form.start_date }}
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="mb-3">
                                <label for="{{ form.end_date.id_for_label }}" class="form-label">
                                    {{ form.end_date.label }}
                                </label>
                                {{ form.end_date }}
                            </div>
                        </div>
                    
                    <!-- Additional form fields based on report type -->
                    {% for field in form %}
                        {% if field.name not in ['start_date', 'end_date'] %}
                        <div class="mb-3">
                            <label for="{{ field.id_for_label }}" class="form-label">
                                {{ field.label }}
                            </label>
                            {{ field }}
                        </div>
                        {% endif %}
                    {% endfor %}
                    
                    <div class="mb-3">
                        <label class="form-label">Export Format</label>
                        <div>
                            <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" name="format" 
                                       id="formatExcel" value="excel" checked>
                                <label class="form-check-label" for="formatExcel">
                                    <i class="fas fa-file-excel text-success"></i> Excel
                                </label>
                            </div>
                            <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" name="format" 
                                       id="formatCsv" value="csv">
                                <label class="form-check-label" for="formatCsv">
                                    <i class="fas fa-file-csv text-info"></i> CSV
                                </label>
                            </div>
                            <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" name="format" 
                                       id="formatPdf" value="pdf" disabled>
                                <label class="form-check-label" for="formatPdf">
                                    <i class="fas fa-file-pdf text-danger"></i> PDF (Coming Soon)
                                </label>
                            </div>
                        </div>
                    
                    <button type="submit" class="btn btn-primary">
                        <i class="fas fa-file-export"></i> Generate Report
                    </button>
                </form>
            </div>
        </div>
    </div>
    
    <div class="col-md-4">
        <div class="card">
            <div class="card-header">
                <h5 class="card-title mb-0">Report Information</h5>
            </div>
            <div class="card-body">
                <h6>{{ report_template.name }}</h6>
                <p>{{ report_template.description }}</p>
                
                <hr>
                
                <h6>Instructions</h6>
                <ul>
                    <li>Select the date range for your report</li>
                    <li>Choose any additional filters</li>
                    <li>Select your preferred export format</li>
                    <li>Click "Generate Report" to download</li>
                </ul>
            </div>
        </div>
    </div>
</div>
{% endblock %}

Report URLs

7. Report URL Configuration

# reports/urls.py

from django.urls import path
from . import views

app_name = 'reports'
urlpatterns = [
    path('', views.reports_dashboard, name='dashboard'),
    path('inventory/', views.inventory_report_view, name='inventory_report'),
    path('sales/', views.sales_report_view, name='sales_report'),
    path('purchasing/', views.purchasing_report_view, name='purchasing_report'),
    path('manufacturing/', views.manufacturing_report_view, name='manufacturing_report'),
    path('financial/', views.financial_report_view, name='financial_report'),
    path('<int:report_id>/', views.report_detail_view, name='report_detail'),
    path('<int:report_id>/export/excel/', views.export_to_excel_view, name='export_excel'),
    path('<int:report_id>/export/pdf/', views.export_to_pdf_view, name='export_pdf'),
    path('generate/<int:template_id>/', views.generate_report_view, name='generate_report'),
]

This reporting module implementation plan provides a comprehensive solution for generating various types of reports with Excel export capability. The modular design allows for easy extension to support additional report types and export formats in the future.