289 lines
16 KiB
HTML
289 lines
16 KiB
HTML
{% extends "module_base.html" %}
|
|
{% load static %}
|
|
{% load indonesian_filters %}
|
|
|
|
{% block title %}Financial Report{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title mb-0">
|
|
<i class="fas fa-chart-line me-2"></i>Financial Report
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Report Filters -->
|
|
<form method="get" class="row mb-4 g-3">
|
|
<div class="col-md-3">
|
|
<label for="date_from" class="form-label">Date From</label>
|
|
<input type="date" class="form-control" id="date_from" name="date_from" value="{{ date_from }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="date_to" class="form-label">Date To</label>
|
|
<input type="date" class="form-control" id="date_to" name="date_to" value="{{ date_to }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="period" class="form-label">Quick Period</label>
|
|
<select class="form-select" id="period" name="period">
|
|
<option value="7" {% if period == '7' %}selected{% endif %}>Last 7 days</option>
|
|
<option value="30" {% if period == '30' %}selected{% endif %}>Last 30 days</option>
|
|
<option value="90" {% if period == '90' %}selected{% endif %}>Last 90 days</option>
|
|
<option value="180" {% if period == '180' %}selected{% endif %}>Last 6 months</option>
|
|
<option value="365" {% if period == '365' %}selected{% endif %}>Last year</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label"> </label>
|
|
<div class="d-grid">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-search"></i> Generate Report
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Financial Overview Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">Total Revenue</h5>
|
|
<h3>{{ total_revenue|format_rupiah:0 }}</h3>
|
|
<small>{{ total_orders }} orders</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-danger text-white">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">Total Costs</h5>
|
|
<h3>{{ total_costs|format_rupiah:0 }}</h3>
|
|
<small>Purchases + Manufacturing</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">Gross Profit</h5>
|
|
<h3>{{ gross_profit|format_rupiah:0 }}</h3>
|
|
<small class="{% if profit_margin >= 0 %}text-success{% else %}text-danger{% endif %}">
|
|
{{ profit_margin|floatformat:1 }}%
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">Inventory Value</h5>
|
|
<h3>{{ total_inventory_value|format_rupiah:0 }}</h3>
|
|
<small>Current stock value</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cost Breakdown -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Cost Breakdown</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Cost Type</th>
|
|
<th class="text-end">Amount</th>
|
|
<th class="text-end">% of Total</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Purchase Costs</td>
|
|
<td class="text-end">{{ total_purchase_cost|format_rupiah }}</td>
|
|
<td class="text-end">
|
|
{% widthratio total_purchase_cost total_costs 100 %}%
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Manufacturing Costs</td>
|
|
<td class="text-end">{{ total_manufacturing_cost|format_rupiah }}</td>
|
|
<td class="text-end">
|
|
{% widthratio total_manufacturing_cost total_costs 100 %}%
|
|
</td>
|
|
</tr>
|
|
<tr class="table-info">
|
|
<th>Total Costs</th>
|
|
<th class="text-end">{{ total_costs|format_rupiah }}</th>
|
|
<th class="text-end">100.0%</th>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Profitability Analysis</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Profit Margin</label>
|
|
<div class="progress" style="height: 25px;">
|
|
<div class="progress-bar {% if profit_margin >= 20 %}bg-success{% elif profit_margin >= 10 %}bg-warning{% else %}bg-danger{% endif %}"
|
|
role="progressbar"
|
|
style="width: {{ profit_margin|default:0 }}%;"
|
|
aria-valuenow="{{ profit_margin|default:0 }}"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100">
|
|
{{ profit_margin|floatformat:1 }}%
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row text-center">
|
|
<div class="col-4">
|
|
<div class="border rounded p-2">
|
|
<h6 class="text-muted">Revenue</h6>
|
|
<h5 class="text-success">{{ total_revenue|format_rupiah:0 }}</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="border rounded p-2">
|
|
<h6 class="text-muted">Costs</h6>
|
|
<h5 class="text-danger">{{ total_costs|format_rupiah:0 }}</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="border rounded p-2">
|
|
<h6 class="text-muted">Profit</h6>
|
|
<h5 class="{% if gross_profit >= 0 %}text-success{% else %}text-danger{% endif %}">{{ gross_profit|format_rupiah:0 }}</h5>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Monthly Trends -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Monthly Financial Trends</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Period</th>
|
|
<th class="text-end">Revenue</th>
|
|
<th class="text-end">Costs</th>
|
|
<th class="text-end">Profit</th>
|
|
<th class="text-end">Margin</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for trend in monthly_trends %}
|
|
<tr>
|
|
<td>{{ trend.period }}</td>
|
|
<td class="text-end">{{ trend.revenue|format_rupiah }}</td>
|
|
<td class="text-end">{{ trend.costs|format_rupiah }}</td>
|
|
<td class="text-end {% if trend.profit >= 0 %}text-success{% else %}text-danger{% endif %}">
|
|
{{ trend.profit|format_rupiah }}
|
|
</td>
|
|
<td class="text-end">
|
|
{% if trend.revenue > 0 %}
|
|
<span class="{% if trend.profit >= 0 %}text-success{% else %}text-danger{% endif %}">
|
|
{% widthratio trend.profit trend.revenue 100 %}%
|
|
</span>
|
|
{% else %}
|
|
<span class="text-muted">N/A</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="5" class="text-center text-muted">
|
|
No trend data available.
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Options -->
|
|
<div class="mt-4 text-center">
|
|
<div class="btn-group">
|
|
<button class="btn btn-outline-primary" onclick="exportToExcel()">
|
|
<i class="fas fa-file-excel me-2"></i>Export to Excel
|
|
</button>
|
|
<button class="btn btn-outline-danger" onclick="exportToPDF()">
|
|
<i class="fas fa-file-pdf me-2"></i>Export to PDF
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="printReport()">
|
|
<i class="fas fa-print me-2"></i>Print Report
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Set default date range (last 30 days)
|
|
const today = new Date();
|
|
const thirtyDaysAgo = new Date();
|
|
thirtyDaysAgo.setDate(today.getDate() - 30);
|
|
|
|
const dateFromInput = document.getElementById('date_from');
|
|
const dateToInput = document.getElementById('date_to');
|
|
|
|
if (dateFromInput && !dateFromInput.value) {
|
|
dateFromInput.value = thirtyDaysAgo.toISOString().split('T')[0];
|
|
}
|
|
if (dateToInput && !dateToInput.value) {
|
|
dateToInput.value = today.toISOString().split('T')[0];
|
|
}
|
|
|
|
// Auto-submit form when filters change
|
|
document.querySelectorAll('select').forEach(select => {
|
|
select.addEventListener('change', function() {
|
|
this.closest('form').submit();
|
|
});
|
|
});
|
|
});
|
|
|
|
function exportToExcel() {
|
|
// Get current filter parameters
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
urlParams.set('export', 'excel');
|
|
|
|
// Create export URL with current filters
|
|
const exportUrl = window.location.pathname + '?' + urlParams.toString();
|
|
window.location.href = exportUrl;
|
|
}
|
|
|
|
function exportToPDF() {
|
|
alert('PDF export functionality would be implemented here');
|
|
}
|
|
|
|
function printReport() {
|
|
window.print();
|
|
}
|
|
</script>
|
|
{% endblock %} |