This commit is contained in:
Flatlogic Bot 2026-01-28 01:37:14 +00:00
parent 25077f971f
commit d7fc9ac966
13 changed files with 436 additions and 170 deletions

Binary file not shown.

14
core/forms.py Normal file
View File

@ -0,0 +1,14 @@
from django import forms
from .models import ProcurementProposal, Department
class ProcurementProposalForm(forms.ModelForm):
class Meta:
model = ProcurementProposal
fields = ['proposal_number', 'title', 'description', 'estimated_cost', 'department']
widgets = {
'proposal_number': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'e.g., M7-2026-001'}),
'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Proposal Title'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': 'Detailed description...'}),
'estimated_cost': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Amount in AFN'}),
'department': forms.Select(attrs={'class': 'form-select'}),
}

View File

@ -0,0 +1,49 @@
# Generated by Django 5.2.7 on 2026-01-28 01:33
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Department',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('code', models.CharField(max_length=10, unique=True)),
('description', models.TextField(blank=True)),
],
),
migrations.CreateModel(
name='ProcurementProposal',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('proposal_number', models.CharField(max_length=50, unique=True)),
('title', models.CharField(max_length=255)),
('description', models.TextField()),
('estimated_cost', models.DecimalField(decimal_places=2, max_digits=15)),
('status', models.CharField(choices=[('draft', 'Draft'), ('submitted', 'Submitted'), ('under_review', 'Under Review'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='draft', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.department')),
],
),
migrations.CreateModel(
name='Document',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('doc_type', models.CharField(choices=[('M7', 'Form M-7 (Proposal)'), ('M16', 'Form M-16 (Payment)'), ('S16', 'Form S-16 (Invoice)')], max_length=10)),
('file_path', models.CharField(blank=True, max_length=255)),
('metadata', models.JSONField(default=dict)),
('created_at', models.DateTimeField(auto_now_add=True)),
('proposal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='core.procurementproposal')),
],
),
]

View File

@ -1,3 +1,46 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
# Create your models here.
class Department(models.Model):
name = models.CharField(max_length=100)
code = models.CharField(max_length=10, unique=True)
description = models.TextField(blank=True)
def __cl__(self):
return self.name
class ProcurementProposal(models.Model):
STATUS_CHOICES = [
('draft', 'Draft'),
('submitted', 'Submitted'),
('under_review', 'Under Review'),
('approved', 'Approved'),
('rejected', 'Rejected'),
]
proposal_number = models.CharField(max_length=50, unique=True)
title = models.CharField(max_length=255)
description = models.TextField()
estimated_cost = models.DecimalField(max_digits=15, decimal_places=2)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.proposal_number} - {self.title}"
class Document(models.Model):
TYPE_CHOICES = [
('M7', 'Form M-7 (Proposal)'),
('M16', 'Form M-16 (Payment)'),
('S16', 'Form S-16 (Invoice)'),
]
doc_type = models.CharField(max_length=10, choices=TYPE_CHOICES)
proposal = models.ForeignKey(ProcurementProposal, on_delete=models.CASCADE, related_name='documents')
file_path = models.CharField(max_length=255, blank=True) # Cloud path simulation
metadata = models.JSONField(default=dict)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.doc_type} for {self.proposal.proposal_number}"

View File

@ -1,25 +1,165 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Qosh Tepa Project{% endblock %}</title>
{% if project_description %}
<meta name="description" content="{{ project_description }}">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}">
{% endif %}
{% if project_image_url %}
<meta property="og:image" content="{{ project_image_url }}">
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %}
{% load static %}
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&family=Inter:wght@400;500&display=swap" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
<style>
:root {
--primary-gradient: linear-gradient(135deg, #8E2DE2 0%, #F000B8 100%);
--bg-dark: #0f0c29;
--glass-bg: rgba(255, 255, 255, 0.1);
--glass-border: rgba(255, 255, 255, 0.2);
}
body {
font-family: 'Inter', sans-serif;
background: var(--bg-dark);
background: linear-gradient(to right, #24243e, #302b63, #0f0c29);
color: #fff;
min-height: 100vh;
overflow-x: hidden;
}
h1, h2, h3, h4, .navbar-brand {
font-family: 'Poppins', sans-serif;
font-weight: 700;
}
.navbar {
background: rgba(15, 12, 41, 0.8) !important;
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--glass-border);
}
.navbar-brand {
background: var(--primary-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 1.5rem;
}
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(15px);
border: 1px solid var(--glass-border);
border-radius: 20px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.glass-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(142, 45, 226, 0.3);
}
.btn-primary-gradient {
background: var(--primary-gradient);
border: none;
color: white;
font-weight: 600;
padding: 10px 25px;
border-radius: 12px;
transition: opacity 0.3s;
}
.btn-primary-gradient:hover {
opacity: 0.9;
color: white;
}
.sidebar-link {
color: rgba(255, 255, 255, 0.7);
text-decoration: none;
padding: 10px 15px;
display: block;
border-radius: 10px;
transition: all 0.3s;
}
.sidebar-link:hover, .sidebar-link.active {
background: var(--glass-bg);
color: #fff;
}
.stat-icon {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
background: var(--primary-gradient);
font-size: 1.5rem;
margin-bottom: 15px;
}
</style>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
<div class="container-fluid">
<a class="navbar-brand" href="/">Qosh Tepa Management</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href="/"><i class="fas fa-home me-1"></i> Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/"><i class="fas fa-user-shield me-1"></i> Admin</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid py-4">
<div class="row">
<!-- Sidebar -->
<div class="col-md-3 col-lg-2 d-none d-md-block">
<div class="glass-card p-3 h-100">
<h6 class="text-uppercase text-muted mb-3 small fw-bold">Departments</h6>
<nav class="nav flex-column">
<a class="sidebar-link active mb-2" href="#"><i class="fas fa-chart-line me-2"></i> Overview</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-building me-2"></i> Admin</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-shopping-cart me-2"></i> Procurement</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-boxes me-2"></i> Assets</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-truck me-2"></i> Transport</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-money-bill-wave me-2"></i> Finance</a>
<a class="sidebar-link mb-2" href="#"><i class="fas fa-check-circle me-2"></i> Control</a>
<a class="sidebar-link" href="#"><i class="fas fa-file-invoice me-2"></i> Invoices</a>
</nav>
</div>
</div>
<!-- Main Content -->
<div class="col-md-9 col-lg-10">
{% block content %}{% endblock %}
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>
</html>

View File

@ -1,145 +1,101 @@
{% extends "base.html" %}
{% block title %}{{ project_name }}{% endblock %}
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
}
</style>
{% endblock %}
{% block title %}Dashboard | Qosh Tepa Management{% endblock %}
{% block content %}
<main>
<div class="card">
<h1>Analyzing your requirements and generating your app…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<div class="row g-4 mb-4">
<div class="col-md-4">
<div class="glass-card p-4">
<div class="stat-icon"><i class="fas fa-wallet"></i></div>
<h3 class="mb-1">{{ total_budget }} AFN</h3>
<p class="text-muted mb-0">Total Estimated Budget</p>
</div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
</p>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
<div class="col-md-4">
<div class="glass-card p-4">
<div class="stat-icon"><i class="fas fa-file-alt"></i></div>
<h3 class="mb-1">{{ active_proposals }}</h3>
<p class="text-muted mb-0">Active Proposals</p>
</div>
</div>
<div class="col-md-4">
<div class="glass-card p-4">
<div class="stat-icon"><i class="fas fa-clock"></i></div>
<h3 class="mb-1">{{ pending_documents }}</h3>
<p class="text-muted mb-0">Pending Documents</p>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<div class="glass-card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="mb-0">Project Branches</h4>
<a href="{% url 'proposal_create' %}" class="btn btn-primary-gradient btn-sm"><i class="fas fa-plus me-1"></i> New M-7 Proposal</a>
</div>
<div class="row g-3">
{% for dept in departments %}
<div class="col-6 col-md-4 col-lg-3">
<div class="glass-card p-3 text-center border-0 bg-opacity-25" style="background: rgba(255,255,255,0.05);">
<div class="h3 mb-2"><i class="fas fa-folder-open text-info"></i></div>
<h6 class="mb-0">{{ dept.name }}</h6>
<span class="badge bg-dark mt-2">{{ dept.code }}</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="glass-card p-4 h-100">
<h4 class="mb-4">Recent Procurement Proposals</h4>
<div class="table-responsive">
<table class="table table-dark table-hover mb-0">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Budget</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for proposal in proposals %}
<tr>
<td>{{ proposal.proposal_number }}</td>
<td>{{ proposal.title }}</td>
<td>{{ proposal.estimated_cost }} AFN</td>
<td>
<span class="badge rounded-pill {% if proposal.status == 'approved' %}bg-success{% elif proposal.status == 'rejected' %}bg-danger{% else %}bg-warning{% endif %}">
{{ proposal.get_status_display }}
</span>
</td>
<td><a href="#" class="btn btn-sm btn-outline-light">View</a></td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center py-4 text-muted">No proposals found. Start by creating one!</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="glass-card p-4 h-100">
<h4 class="mb-4">Quick Actions</h4>
<div class="d-grid gap-3">
<a href="{% url 'proposal_create' %}" class="btn btn-outline-light text-start py-3"><i class="fas fa-file-invoice me-2"></i> Create M-7 Proposal</a>
<button class="btn btn-outline-light text-start py-3"><i class="fas fa-money-check-alt me-2"></i> Create M-16 Payment</button>
<button class="btn btn-outline-light text-start py-3"><i class="fas fa-history me-2"></i> Routing History</button>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,50 @@
{% extends "base.html" %}
{% block title %}New Proposal | Qosh Tepa Management{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="glass-card p-5">
<div class="d-flex align-items-center mb-4">
<div class="stat-icon me-3"><i class="fas fa-file-invoice"></i></div>
<h2 class="mb-0">Form M-7: Procurement Proposal</h2>
</div>
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Proposal Number</label>
{{ form.proposal_number }}
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Department</label>
{{ form.department }}
</div>
</div>
<div class="mb-3">
<label class="form-label">Title</label>
{{ form.title }}
</div>
<div class="mb-3">
<label class="form-label">Description</label>
{{ form.description }}
</div>
<div class="mb-4">
<label class="form-label">Estimated Cost (AFN)</label>
{{ form.estimated_cost }}
</div>
<div class="d-flex gap-3">
<button type="submit" class="btn btn-primary-gradient px-5">Submit Proposal</button>
<a href="{% url 'home' %}" class="btn btn-outline-light px-5">Cancel</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,7 +1,7 @@
from django.urls import path
from .views import home
from . import views
urlpatterns = [
path("", home, name="home"),
]
path('', views.home, name='home'),
path('proposal/new/', views.proposal_create, name='proposal_create'),
]

View File

@ -1,25 +1,39 @@
import os
import platform
from django import get_version as django_version
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.utils import timezone
from .models import Department, ProcurementProposal, Document
from .forms import ProcurementProposalForm
from django.db.models import Sum, Count
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
"""Render the Qosh Tepa Central Management Dashboard."""
departments = Department.objects.all()
proposals = ProcurementProposal.objects.all().order_by('-created_at')[:5]
total_budget = ProcurementProposal.objects.aggregate(Sum('estimated_cost'))['estimated_cost__sum'] or 0
active_proposals = ProcurementProposal.objects.exclude(status='rejected').count()
pending_documents = Document.objects.count()
context = {
"project_name": "New Style",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
"project_name": "Qosh Tepa Finance & Admin",
"departments": departments,
"proposals": proposals,
"total_budget": total_budget,
"active_proposals": active_proposals,
"pending_documents": pending_documents,
"current_time": timezone.now(),
}
return render(request, "core/index.html", context)
def proposal_create(request):
"""View to create a new M-7 Procurement Proposal."""
if request.method == 'POST':
form = ProcurementProposalForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ProcurementProposalForm()
return render(request, "core/proposal_form.html", {"form": form})