290 lines
17 KiB
HTML
290 lines
17 KiB
HTML
{% extends 'base.html' %}
|
|
{% load i18n static %}
|
|
|
|
{% block title %}{% trans "Expenses" %} | {{ site_settings.business_name }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h2 class="fw-bold mb-1">{% trans "Expenses" %}</h2>
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'index' %}">{% trans "Dashboard" %}</a></li>
|
|
<li class="breadcrumb-item active" aria-current="page">{% trans "Expenses" %}</li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
<div class="btn-group">
|
|
<button class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#addExpenseModal">
|
|
<i class="bi bi-plus-lg me-2"></i>{% trans "Record Expense" %}
|
|
</button>
|
|
<a href="{% url 'expense_categories' %}" class="btn btn-outline-primary shadow-sm">
|
|
<i class="bi bi-tags me-2"></i>{% trans "Expense Categories" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% if messages %}
|
|
<div class="mb-4">
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show rounded-3" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Summary Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-4">
|
|
<div class="card border-0 shadow-sm rounded-4 bg-primary text-white">
|
|
<div class="card-body p-4 text-center">
|
|
<h6 class="text-white-50 mb-2">{% trans "Total Expenses" %}</h6>
|
|
<h2 class="fw-bold mb-0">{{ site_settings.currency_symbol }} {{ total_expenses|floatformat:site_settings.decimal_places }}</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Bar -->
|
|
<div class="card border-0 shadow-sm rounded-4 mb-4">
|
|
<div class="card-body p-3">
|
|
<form method="get" class="row g-3">
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted">{% trans "Start Date" %}</label>
|
|
<input type="date" name="start_date" class="form-control" value="{{ request.GET.start_date }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted">{% trans "End Date" %}</label>
|
|
<input type="date" name="end_date" class="form-control" value="{{ request.GET.end_date }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted">{% trans "Category" %}</label>
|
|
<select name="category" class="form-select">
|
|
<option value="">{% trans "All Categories" %}</option>
|
|
{% for category in categories %}
|
|
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:"s" %}selected{% endif %}>
|
|
{{ category.name_en }} / {{ category.name_ar }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3 d-flex align-items-end">
|
|
<button type="submit" class="btn btn-light w-100 me-2">{% trans "Filter" %}</button>
|
|
<a href="{% url 'expenses' %}" class="btn btn-outline-secondary">{% trans "Reset" %}</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Expenses Table -->
|
|
<div class="card border-0 shadow-sm rounded-4">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">{% trans "Date" %}</th>
|
|
<th>{% trans "Category" %}</th>
|
|
<th>{% trans "Description" %}</th>
|
|
<th>{% trans "Payment Method" %}</th>
|
|
<th>{% trans "Amount" %}</th>
|
|
<th class="text-end pe-4">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for expense in expenses %}
|
|
<tr>
|
|
<td class="ps-4">
|
|
<span class="fw-medium">{{ expense.date|date:"Y-m-d" }}</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-light text-primary rounded-pill px-3">
|
|
{{ expense.category.name_en }} / {{ expense.category.name_ar }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<div class="text-truncate" style="max-width: 250px;">
|
|
{{ expense.description|default:"-" }}
|
|
</div>
|
|
</td>
|
|
<td>{{ expense.payment_method.name_en|default:"-" }}</td>
|
|
<td class="fw-bold">{{ site_settings.currency_symbol }} {{ expense.amount|floatformat:site_settings.decimal_places }}</td>
|
|
<td class="text-end pe-4">
|
|
{% if expense.attachment %}
|
|
<a href="{{ expense.attachment.url }}" target="_blank" class="btn btn-sm btn-light rounded-circle me-1" title="{% trans 'View Attachment' %}">
|
|
<i class="bi bi-paperclip"></i>
|
|
</a>
|
|
{% endif %}
|
|
<button class="btn btn-sm btn-light rounded-circle me-1" data-bs-toggle="modal" data-bs-target="#editExpenseModal{{ expense.id }}">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-light rounded-circle text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal{{ expense.id }}">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Edit Modal -->
|
|
<div class="modal fade" id="editExpenseModal{{ expense.id }}" tabindex="-1">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content border-0 rounded-4 shadow">
|
|
<div class="modal-header p-4 border-0">
|
|
<h5 class="modal-title fw-bold">{% trans "Edit Expense" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form action="{% url 'expense_edit' expense.pk %}" method="post" enctype="multipart/form-data">
|
|
{% csrf_token %}
|
|
<div class="modal-body p-4 text-start">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Category" %}</label>
|
|
<select name="category" class="form-select rounded-3" required>
|
|
<option value="">{% trans "Select Category" %}</option>
|
|
{% for category in categories %}
|
|
<option value="{{ category.id }}" {% if expense.category.id == category.id %}selected{% endif %}>{{ category.name_en }} / {{ category.name_ar }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Amount" %}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">{{ site_settings.currency_symbol }}</span>
|
|
<input type="number" step="0.001" name="amount" class="form-control rounded-end-3" value="{{ expense.amount|stringformat:'f' }}" required>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">{% trans "Date" %}</label>
|
|
<input type="date" name="date" class="form-control rounded-3" value="{{ expense.date|date:'Y-m-d' }}" required>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">{% trans "Payment Method" %}</label>
|
|
<select name="payment_method" class="form-select rounded-3">
|
|
<option value="">{% trans "None" %}</option>
|
|
{% for pm in payment_methods %}
|
|
<option value="{{ pm.id }}" {% if expense.payment_method.id == pm.id %}selected{% endif %}>{{ pm.name_en }} / {{ pm.name_ar }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Description" %}</label>
|
|
<textarea name="description" class="form-control rounded-3" rows="3">{{ expense.description|default_if_none:"" }}</textarea>
|
|
</div>
|
|
<div class="mb-0">
|
|
<label class="form-label fw-bold">{% trans "Attachment" %} <small class="text-muted fw-normal">({% trans "Optional" %})</small></label>
|
|
{% if expense.attachment %}
|
|
<div class="mb-2">
|
|
<a href="{{ expense.attachment.url }}" target="_blank" class="small text-decoration-none">
|
|
<i class="bi bi-paperclip me-1"></i>{% trans "Current Attachment" %}
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
<input type="file" name="attachment" class="form-control rounded-3">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer p-4 border-0">
|
|
<button type="button" class="btn btn-light rounded-3 px-4" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary rounded-3 px-4">{% trans "Update Expense" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Modal -->
|
|
<div class="modal fade" id="deleteModal{{ expense.id }}" tabindex="-1">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content border-0 rounded-4">
|
|
<div class="modal-header border-0">
|
|
<h5 class="modal-title fw-bold">{% trans "Confirm Delete" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body py-4">
|
|
<p class="text-muted">{% trans "Are you sure you want to delete this expense record?" %}</p>
|
|
<h5 class="fw-bold">{{ site_settings.currency_symbol }} {{ expense.amount }} - {{ expense.category.name_en }}</h5>
|
|
</div>
|
|
<div class="modal-footer border-0">
|
|
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<a href="{% url 'expense_delete' expense.pk %}" class="btn btn-danger rounded-3 px-4">{% trans "Delete" %}</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="6" class="text-center py-5">
|
|
<div class="py-4">
|
|
<i class="bi bi-receipt text-muted display-1"></i>
|
|
<p class="text-muted mt-3">{% trans "No expense records found." %}</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% include "core/pagination.html" with page_obj=expenses %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Record Expense Modal -->
|
|
<div class="modal fade" id="addExpenseModal" tabindex="-1">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content border-0 rounded-4 shadow">
|
|
<div class="modal-header p-4 border-0">
|
|
<h5 class="modal-title fw-bold">{% trans "Record New Expense" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form action="{% url 'expense_create' %}" method="post" enctype="multipart/form-data">
|
|
{% csrf_token %}
|
|
<div class="modal-body p-4">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Category" %}</label>
|
|
<select name="category" class="form-select rounded-3" required>
|
|
<option value="">{% trans "Select Category" %}</option>
|
|
{% for category in categories %}
|
|
<option value="{{ category.id }}">{{ category.name_en }} / {{ category.name_ar }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Amount" %}</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">{{ site_settings.currency_symbol }}</span>
|
|
<input type="number" step="0.001" name="amount" class="form-control rounded-end-3" required>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">{% trans "Date" %}</label>
|
|
<input type="date" name="date" class="form-control rounded-3" value="{% now 'Y-m-d' %}" required>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label fw-bold">{% trans "Payment Method" %}</label>
|
|
<select name="payment_method" class="form-select rounded-3">
|
|
{% for pm in payment_methods %}
|
|
<option value="{{ pm.id }}">{{ pm.name_en }} / {{ pm.name_ar }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">{% trans "Description" %}</label>
|
|
<textarea name="description" class="form-control rounded-3" rows="3"></textarea>
|
|
</div>
|
|
<div class="mb-0">
|
|
<label class="form-label fw-bold">{% trans "Attachment" %}</label>
|
|
<input type="file" name="attachment" class="form-control rounded-3">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer p-4 border-0">
|
|
<button type="button" class="btn btn-light rounded-3 px-4" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary rounded-3 px-4">{% trans "Save Expense" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %} |