updates 27
This commit is contained in:
parent
4cbc936312
commit
bbe3291894
Binary file not shown.
Binary file not shown.
Binary file not shown.
37
core/migrations/0019_transaction.py
Normal file
37
core/migrations/0019_transaction.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-24 04:34
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0018_remove_appsetting_annual_fee_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Transaction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Amount')),
|
||||
('transaction_type', models.CharField(choices=[('PAYMENT', 'Payment'), ('REFUND', 'Refund')], default='PAYMENT', max_length=20)),
|
||||
('status', models.CharField(choices=[('PENDING', 'Pending'), ('COMPLETED', 'Completed'), ('FAILED', 'Failed'), ('CANCELLED', 'Cancelled')], default='COMPLETED', max_length=20)),
|
||||
('description', models.TextField(blank=True, verbose_name='Description')),
|
||||
('payment_method', models.CharField(blank=True, max_length=100, verbose_name='Payment Method')),
|
||||
('reference_number', models.CharField(blank=True, max_length=100, verbose_name='Reference Number')),
|
||||
('receipt_number', models.CharField(blank=True, max_length=20, unique=True, verbose_name='Receipt Number')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transactions', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Transaction',
|
||||
'verbose_name_plural': 'Transactions',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0019_transaction.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0019_transaction.cpython-311.pyc
Normal file
Binary file not shown.
@ -380,4 +380,42 @@ def sync_user_groups(sender, instance, **kwargs):
|
||||
instance.user.groups.remove(*other_groups)
|
||||
|
||||
# Add user to the correct group
|
||||
instance.user.groups.add(group)
|
||||
instance.user.groups.add(group)
|
||||
class Transaction(models.Model):
|
||||
TRANSACTION_TYPES = (
|
||||
('PAYMENT', _('Payment')),
|
||||
('REFUND', _('Refund')),
|
||||
)
|
||||
STATUS_CHOICES = (
|
||||
('PENDING', _('Pending')),
|
||||
('COMPLETED', _('Completed')),
|
||||
('FAILED', _('Failed')),
|
||||
('CANCELLED', _('Cancelled')),
|
||||
)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='transactions')
|
||||
amount = models.DecimalField(_('Amount'), max_digits=10, decimal_places=2)
|
||||
transaction_type = models.CharField(max_length=20, choices=TRANSACTION_TYPES, default='PAYMENT')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='COMPLETED')
|
||||
description = models.TextField(_('Description'), blank=True)
|
||||
payment_method = models.CharField(_('Payment Method'), max_length=100, blank=True)
|
||||
reference_number = models.CharField(_('Reference Number'), max_length=100, blank=True)
|
||||
receipt_number = models.CharField(_('Receipt Number'), max_length=20, unique=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Transaction')
|
||||
verbose_name_plural = _('Transactions')
|
||||
ordering = ['-created_at']
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.receipt_number:
|
||||
# Generate a unique receipt number: REC-YYYYMMDD-XXXX
|
||||
date_str = timezone.now().strftime('%Y%m%d')
|
||||
random_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
|
||||
self.receipt_number = f"REC-{date_str}-{random_str}"
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.receipt_number} - {self.user.username} ({self.amount})"
|
||||
|
||||
@ -303,6 +303,19 @@
|
||||
<div class="mt-5">
|
||||
<h4 class="fw-bold mb-4">{% trans "Quick Actions" %}</h4>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<a href="{% url 'admin_financials' %}" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="rounded-circle bg-light p-3 me-3 text-info">
|
||||
<i class="fa-solid fa-money-bill-trend-up"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0 fw-bold">{% trans "Financial Overview" %}</h6>
|
||||
<small class="text-muted">{% trans "Track payments and platform revenue" %}</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="/" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
@ -316,6 +329,19 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="{% url 'admin_financials' %}" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="rounded-circle bg-light p-3 me-3 text-info">
|
||||
<i class="fa-solid fa-money-bill-trend-up"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0 fw-bold">{% trans "Financial Overview" %}</h6>
|
||||
<small class="text-muted">{% trans "Track payments and platform revenue" %}</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="/admin/core/shipment/" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
@ -329,6 +355,19 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="{% url 'admin_financials' %}" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="rounded-circle bg-light p-3 me-3 text-info">
|
||||
<i class="fa-solid fa-money-bill-trend-up"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0 fw-bold">{% trans "Financial Overview" %}</h6>
|
||||
<small class="text-muted">{% trans "Track payments and platform revenue" %}</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="/admin/auth/user/" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
71
core/templates/core/admin_financials.html
Normal file
71
core/templates/core/admin_financials.html
Normal file
@ -0,0 +1,71 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h2 class="mb-1">{% trans "Financial Overview" %}</h2>
|
||||
<p class="text-muted">{% trans "Manage all platform transactions, payments, and revenue." %}</p>
|
||||
</div>
|
||||
<div class="card bg-primary text-white border-0 shadow-sm p-3">
|
||||
<h6 class="text-uppercase small mb-1">{% trans "Total Revenue" %}</h6>
|
||||
<h3 class="mb-0">{{ total_revenue }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="mb-0">{% trans "Recent Transactions" %}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>{% trans "User" %}</th>
|
||||
<th>{% trans "Role" %}</th>
|
||||
<th>{% trans "Receipt #" %}</th>
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Amount" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for transaction in transactions %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ transaction.user.username }}</strong><br>
|
||||
<small class="text-muted">{{ transaction.user.email }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark">{{ transaction.user.profile.get_role_display }}</span>
|
||||
</td>
|
||||
<td><code>{{ transaction.receipt_number }}</code></td>
|
||||
<td>{{ transaction.created_at|date:"Y-m-d" }}</td>
|
||||
<td><strong>{{ transaction.amount }}</strong></td>
|
||||
<td>
|
||||
<span class="badge {% if transaction.status == 'COMPLETED' %}bg-success{% elif transaction.status == 'PENDING' %}bg-warning{% else %}bg-danger{% endif %}">
|
||||
{{ transaction.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'transaction_receipt' transaction.receipt_number %}" class="btn btn-sm btn-outline-info me-1" title="{% trans 'View Receipt' %}" target="_blank">
|
||||
<i class="fas fa-eye"></i>
|
||||
{% if transaction.transaction_type == 'PAYMENT' and transaction.status == 'COMPLETED' %}
|
||||
<a href="{% url 'issue_refund' transaction.receipt_number %}" class="btn btn-sm btn-outline-danger" onclick="return confirm('{% trans 'Are you sure you want to issue a refund?' %}')" title="{% trans 'Issue Refund' %}">
|
||||
<i class="fas fa-undo"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
67
core/templates/core/financial_history.html
Normal file
67
core/templates/core/financial_history.html
Normal file
@ -0,0 +1,67 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>{% trans "Financial History" %}</h2>
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="fas fa-arrow-left"></i> {% trans "Back to Dashboard" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
{% if transactions %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>{% trans "Receipt #" %}</th>
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Description" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th>{% trans "Amount" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for transaction in transactions %}
|
||||
<tr>
|
||||
<td><code>{{ transaction.receipt_number }}</code></td>
|
||||
<td>{{ transaction.created_at|date:"Y-m-d H:i" }}</td>
|
||||
<td>{{ transaction.description }}</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type == 'PAYMENT' %}
|
||||
<span class="badge bg-success">{% trans "Payment" %}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-warning text-dark">{% trans "Refund" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><strong>{{ transaction.amount }}</strong></td>
|
||||
<td>
|
||||
<span class="badge {% if transaction.status == 'COMPLETED' %}bg-info{% elif transaction.status == 'PENDING' %}bg-secondary{% else %}bg-danger{% endif %}">
|
||||
{{ transaction.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'transaction_receipt' transaction.receipt_number %}" class="btn btn-sm btn-outline-primary" target="_blank">
|
||||
<i class="fas fa-file-invoice-dollar"></i> {% trans "Receipt" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-receipt fa-3x text-muted mb-3"></i>
|
||||
<p class="text-muted">{% trans "No transactions found." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
111
core/templates/core/receipt.html
Normal file
111
core/templates/core/receipt.html
Normal file
@ -0,0 +1,111 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div id="receipt-content" class="card shadow border-0 p-4 p-md-5">
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
{% if app_settings.logo %}
|
||||
<img src="{{ app_settings.logo.url }}" alt="{{ app_settings.app_name }}" style="height: 60px;">
|
||||
{% else %}
|
||||
<h2 class="text-primary fw-bold">{{ app_settings.app_name|default:"MASAR CARGO" }}</h2>
|
||||
{% endif %}
|
||||
<p class="text-muted small mt-2">
|
||||
{{ app_settings.contact_address|linebreaksbr }}<br>
|
||||
{% trans "Phone:" %} {{ app_settings.contact_phone }}<br>
|
||||
{% trans "Email:" %} {{ app_settings.contact_email }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<h3 class="text-uppercase text-muted">{% trans "Receipt" %}</h3>
|
||||
<p class="mb-0"><strong>{% trans "Receipt #" %}:</strong> {{ transaction.receipt_number }}</p>
|
||||
<p class="mb-0"><strong>{% trans "Date" %}:</strong> {{ transaction.created_at|date:"Y-m-d" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-6">
|
||||
<h6 class="text-uppercase text-muted small">{% trans "Bill To" %}</h6>
|
||||
<p class="mb-0"><strong>{{ transaction.user.get_full_name|default:transaction.user.username }}</strong></p>
|
||||
<p class="mb-0">{{ transaction.user.email }}</p>
|
||||
<p class="mb-0">{{ transaction.user.profile.full_phone_number }}</p>
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<h6 class="text-uppercase text-muted small">{% trans "Payment Method" %}</h6>
|
||||
<p>{{ transaction.payment_method|default:"N/A" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive mb-4">
|
||||
<table class="table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>{% trans "Description" %}</th>
|
||||
<th class="text-end">{% trans "Total" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ transaction.description }}</td>
|
||||
<td class="text-end">{{ transaction.amount }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th class="text-end">{% trans "Total Paid" %}</th>
|
||||
<th class="text-end text-primary h4">{{ transaction.amount }}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="bg-light p-3 rounded mb-4">
|
||||
<p class="small mb-0"><strong>{% trans "Note:" %}</strong> {% trans "This is an electronically generated receipt and does not require a physical signature." %}</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center text-muted small">
|
||||
<p>{% trans "Thank you for choosing MASAR CARGO!" %}</p>
|
||||
{% if app_settings.registration_number %}
|
||||
<p class="mb-0">{% trans "CR:" %} {{ app_settings.registration_number }} | {% trans "VAT:" %} {{ app_settings.tax_number }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 d-flex justify-content-center gap-3 no-print">
|
||||
<button onclick="window.print()" class="btn btn-primary">
|
||||
<i class="fas fa-print"></i> {% trans "Print Receipt" %}
|
||||
</button>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-outline-secondary">
|
||||
{% trans "Back to History" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@media print {
|
||||
.no-print, nav, footer, .btn-scroll-top {
|
||||
display: none !important;
|
||||
}
|
||||
body {
|
||||
background: white !important;
|
||||
}
|
||||
.card {
|
||||
box-shadow: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.container {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@ -17,10 +17,65 @@
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h2 class="mb-1">{% trans "Shipper Dashboard" %}</h2>
|
||||
<p class="text-muted">{% trans "Manage your shipping offers and active shipments." %}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="mb-1">{% trans "Shipper Dashboard" %}</h2>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">{% trans "Manage your shipping offers and active shipments." %}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'post_shipment' %}" class="btn btn-success btn-lg">
|
||||
<i class="fa-solid fa-plus me-2"></i> {% trans "Add A Bid" %}
|
||||
|
||||
@ -18,10 +18,65 @@
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h2 class="mb-1">{% trans "Truck Owner Dashboard" %}</h2>
|
||||
<p class="text-muted">{% trans "Manage your fleet and incoming shipping offers." %}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="mb-1">{% trans "Truck Owner Dashboard" %}</h2>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">{% trans "Manage your fleet and incoming shipping offers." %}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm border-0 bg-primary text-white h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="text-uppercase small">{% trans "Financials" %}</h6>
|
||||
<h4 class="mb-3">{% trans "Payments" %}</h4>
|
||||
<a href="{% url 'financial_history' %}" class="btn btn-light btn-sm">{% trans "View History" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{% url 'truck_register' %}" class="btn btn-success btn-lg">
|
||||
<i class="fa-solid fa-plus me-2"></i> {% trans "Add New Truck" %}
|
||||
|
||||
@ -24,4 +24,8 @@ urlpatterns = [
|
||||
path("terms-of-service/", views.terms_of_service, name="terms_of_service"),
|
||||
path("subscription-expired/", views.subscription_expired, name="subscription_expired"),
|
||||
path("subscription-renew/", views.renew_subscription, name="renew_subscription"),
|
||||
path("financial-history/", views.financial_history, name="financial_history"),
|
||||
path("receipt/<str:receipt_number>/", views.transaction_receipt, name="transaction_receipt"),
|
||||
path("admin/financials/", views.admin_financials, name="admin_financials"),
|
||||
path("admin/refund/<str:receipt_number>/", views.issue_refund, name="issue_refund"),
|
||||
]
|
||||
@ -3,7 +3,7 @@ from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth import login, authenticate, logout
|
||||
from django.utils import timezone
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction
|
||||
from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext as _
|
||||
@ -485,6 +485,15 @@ def renew_subscription(request):
|
||||
if form.is_valid():
|
||||
profile = request.user.profile
|
||||
plan = form.cleaned_data['subscription_plan']
|
||||
|
||||
# Calculate amount based on role and plan
|
||||
app_settings = AppSetting.objects.first()
|
||||
amount = 0
|
||||
if profile.role == 'SHIPPER':
|
||||
amount = app_settings.shipper_monthly_fee if plan == 'MONTHLY' else app_settings.shipper_annual_fee
|
||||
elif profile.role == 'TRUCK_OWNER':
|
||||
amount = app_settings.truck_owner_monthly_fee if plan == 'MONTHLY' else app_settings.truck_owner_annual_fee
|
||||
|
||||
profile.subscription_plan = plan
|
||||
profile.is_subscription_active = True
|
||||
|
||||
@ -494,7 +503,17 @@ def renew_subscription(request):
|
||||
profile.subscription_expiry = timezone.now().date() + timedelta(days=365)
|
||||
|
||||
profile.save()
|
||||
|
||||
|
||||
# Create Transaction record
|
||||
Transaction.objects.create(
|
||||
user=request.user,
|
||||
amount=amount,
|
||||
transaction_type='PAYMENT',
|
||||
status='COMPLETED',
|
||||
description=f"Subscription Renewal: {plan}",
|
||||
payment_method="Online Payment"
|
||||
)
|
||||
|
||||
# Notifications
|
||||
expiry_date = profile.subscription_expiry.strftime('%Y-%m-%d')
|
||||
msg = _("Your subscription for MASAR CARGO has been successfully renewed! Your new expiry date is %(date)s. Thank you for using our service.") % {"date": expiry_date}
|
||||
@ -512,7 +531,55 @@ def renew_subscription(request):
|
||||
[request.user.email],
|
||||
fail_silently=True,
|
||||
)
|
||||
|
||||
|
||||
messages.success(request, _("Subscription renewed successfully!"))
|
||||
return redirect('dashboard')
|
||||
return redirect('subscription_expired')
|
||||
|
||||
@login_required
|
||||
def financial_history(request):
|
||||
transactions = Transaction.objects.filter(user=request.user)
|
||||
return render(request, 'core/financial_history.html', {'transactions': transactions})
|
||||
|
||||
@login_required
|
||||
def transaction_receipt(request, receipt_number):
|
||||
transaction = get_object_or_404(Transaction, receipt_number=receipt_number, user=request.user)
|
||||
app_settings = AppSetting.objects.first()
|
||||
return render(request, 'core/receipt.html', {
|
||||
'transaction': transaction,
|
||||
'app_settings': app_settings
|
||||
})
|
||||
|
||||
@login_required
|
||||
def admin_financials(request):
|
||||
if request.user.profile.role != 'ADMIN':
|
||||
return redirect('dashboard')
|
||||
transactions = Transaction.objects.all()
|
||||
total_revenue = sum(t.amount for t in transactions if t.transaction_type == 'PAYMENT' and t.status == 'COMPLETED')
|
||||
return render(request, 'core/admin_financials.html', {
|
||||
'transactions': transactions,
|
||||
'total_revenue': total_revenue
|
||||
})
|
||||
|
||||
@login_required
|
||||
def issue_refund(request, receipt_number):
|
||||
if request.user.profile.role != 'ADMIN':
|
||||
return redirect('dashboard')
|
||||
|
||||
transaction = get_object_or_404(Transaction, receipt_number=receipt_number)
|
||||
if transaction.transaction_type == 'REFUND':
|
||||
messages.error(request, _("This is already a refund transaction."))
|
||||
return redirect('admin_financials')
|
||||
|
||||
# Create a refund transaction
|
||||
refund = Transaction.objects.create(
|
||||
user=transaction.user,
|
||||
amount=transaction.amount,
|
||||
transaction_type='REFUND',
|
||||
status='COMPLETED',
|
||||
description=f"Refund for Receipt: {transaction.receipt_number}",
|
||||
payment_method=transaction.payment_method
|
||||
)
|
||||
|
||||
messages.success(request, _("Refund issued successfully! Receipt: %(receipt)s") % {'receipt': refund.receipt_number})
|
||||
return redirect('admin_financials')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user