diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc
index cd6f855..40d07e7 100644
Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ
diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc
new file mode 100644
index 0000000..bc7a61e
Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ
diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc
index 9aa598b..9f1dce4 100644
Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 6867ddf..3977a45 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/admin.py b/core/admin.py
index 8c38f3f..a9113b6 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,3 +1,13 @@
from django.contrib import admin
+from .models import Category, Expense
-# Register your models here.
+@admin.register(Category)
+class CategoryAdmin(admin.ModelAdmin):
+ list_display = ('name',)
+ search_fields = ('name',)
+
+@admin.register(Expense)
+class ExpenseAdmin(admin.ModelAdmin):
+ list_display = ('date', 'category', 'amount', 'currency', 'payer')
+ list_filter = ('date', 'category', 'currency', 'payer')
+ search_fields = ('description',)
\ No newline at end of file
diff --git a/core/forms.py b/core/forms.py
new file mode 100644
index 0000000..1653d3d
--- /dev/null
+++ b/core/forms.py
@@ -0,0 +1,7 @@
+from django import forms
+from .models import Expense
+
+class ExpenseForm(forms.ModelForm):
+ class Meta:
+ model = Expense
+ fields = ['payer', 'amount', 'currency', 'category', 'description', 'date']
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..cf9581d
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,39 @@
+# Generated by Django 5.2.7 on 2026-01-10 16:57
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Category',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100, unique=True)),
+ ],
+ options={
+ 'verbose_name_plural': 'Categories',
+ },
+ ),
+ migrations.CreateModel(
+ name='Expense',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('amount', models.DecimalField(decimal_places=2, max_digits=10)),
+ ('currency', models.CharField(choices=[('COP', 'Colombian Pesos'), ('EUR', 'Euros'), ('USD', 'US Dollars')], max_length=3)),
+ ('date', models.DateField()),
+ ('description', models.TextField(blank=True)),
+ ('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='core.category')),
+ ('payer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc
new file mode 100644
index 0000000..5c03095
Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index 71a8362..7780abd 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,3 +1,28 @@
from django.db import models
+from django.contrib.auth.models import User
-# Create your models here.
+class Category(models.Model):
+ name = models.CharField(max_length=100, unique=True)
+
+ def __str__(self):
+ return self.name
+
+ class Meta:
+ verbose_name_plural = "Categories"
+
+class Expense(models.Model):
+ CURRENCY_CHOICES = [
+ ('COP', 'Colombian Pesos'),
+ ('EUR', 'Euros'),
+ ('USD', 'US Dollars'),
+ ]
+
+ amount = models.DecimalField(max_digits=10, decimal_places=2)
+ currency = models.CharField(max_length=3, choices=CURRENCY_CHOICES)
+ category = models.ForeignKey(Category, on_delete=models.PROTECT)
+ payer = models.ForeignKey(User, on_delete=models.CASCADE)
+ date = models.DateField()
+ description = models.TextField(blank=True)
+
+ def __str__(self):
+ return f'{self.amount} {self.currency} - {self.category} - {self.date}'
\ No newline at end of file
diff --git a/core/templates/base.html b/core/templates/base.html
index 1e7e5fb..38d947a 100644
--- a/core/templates/base.html
+++ b/core/templates/base.html
@@ -1,9 +1,10 @@
-
+
- {% block title %}Knowledge Base{% endblock %}
+
+ {% block title %}Gastos Familiares{% endblock %}
{% if project_description %}
@@ -13,13 +14,50 @@
{% endif %}
+
+
+
+
+
+
{% load static %}
+
{% block head %}{% endblock %}
- {% block content %}{% endblock %}
+
+
+
+ {% block content %}{% endblock %}
+
+
+
+
+
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index faec813..d2e428d 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -1,145 +1,102 @@
-{% extends "base.html" %}
+{% extends 'base.html' %}
-{% block title %}{{ project_name }}{% endblock %}
-
-{% block head %}
-
-
-
-
-{% endblock %}
+{% block title %}Inicio - Gastos Familiares{% endblock %}
{% block content %}
-
-
-
Analyzing your requirements and generating your app…
-
-
Loading…
+
+
+
+
Agregar Nuevo Gasto
+
+
+
+
+
+
Tus Gastos Recientes
+
+
+
+ {% if expenses %}
+
+ {% else %}
+
+ Aún no has agregado ningún gasto. ¡Comienza agregando uno!
+
+ {% endif %}
+
+
+
Análisis de Gastos
+
+
+
Total de Gastos
+
${{ total_expenses|floatformat:2 }}
+
+
+
+
Gastos por Categoría
+
+ {% for item in category_summary %}
+ -
+ {{ item.category__name }}
+ ${{ item.total|floatformat:2 }}
+
+ {% endfor %}
+
+
+
-
AppWizzy AI is collecting your requirements and applying the first changes.
-
This page will refresh automatically as the plan is implemented.
-
- Runtime: Django {{ django_version }} · Python {{ python_version }}
- — UTC {{ current_time|date:"Y-m-d H:i:s" }}
-
-
-
-{% endblock %}
\ No newline at end of file
+
+{% endblock %}
diff --git a/core/views.py b/core/views.py
index c9aed12..68a0713 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,25 +1,38 @@
-import os
-import platform
-
-from django import get_version as django_version
-from django.shortcuts import render
-from django.utils import timezone
-
+from django.shortcuts import render, redirect
+from .forms import ExpenseForm
+from .models import Expense, Category
+from django.db.models import Sum
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 landing screen and handle expense form submission."""
+ if request.method == 'POST':
+ form = ExpenseForm(request.POST)
+ if form.is_valid():
+ form.save()
+ return redirect('home')
+ else:
+ form = ExpenseForm()
+
+ expenses = Expense.objects.all()
+
+ # Filtering logic
+ category_id = request.GET.get('category')
+ if category_id:
+ expenses = expenses.filter(category_id=category_id)
+
+ expenses = expenses.order_by('-date')
+
+ # Analysis
+ total_expenses = expenses.aggregate(Sum('amount'))['amount__sum'] or 0
+ category_summary = expenses.values('category__name').annotate(total=Sum('amount')).order_by('-total')
+
+ categories = Category.objects.all()
+
+ return render(request, "core/index.html", {
+ 'form': form,
+ 'expenses': expenses,
+ 'categories': categories,
+ 'total_expenses': total_expenses,
+ 'category_summary': category_summary,
+ })
- 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", ""),
- }
- return render(request, "core/index.html", context)
diff --git a/static/css/custom.css b/static/css/custom.css
index 925f6ed..b095735 100644
--- a/static/css/custom.css
+++ b/static/css/custom.css
@@ -1,4 +1,58 @@
-/* Custom styles for the application */
-body {
- font-family: system-ui, -apple-system, sans-serif;
+:root {
+ --bs-primary: #0D47A1;
+ --bs-secondary: #42A5F5;
+ --bs-accent: #FFC107;
+ --bs-background: #F5F5F5;
+ --bs-text: #212121;
}
+
+body {
+ font-family: 'Roboto', sans-serif;
+ background-color: var(--bs-background);
+ color: var(--bs-text);
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+h1, h2, h3, h4, h5, h6, .navbar-brand {
+ font-family: 'Montserrat', sans-serif;
+}
+
+.bg-primary {
+ background-color: var(--bs-primary) !important;
+}
+
+.navbar-brand {
+ font-weight: 700;
+}
+
+.hero-section {
+ background: linear-gradient(45deg, var(--bs-primary), var(--bs-secondary));
+ color: white;
+ padding: 100px 0;
+ text-align: center;
+}
+
+.hero-section h1 {
+ font-weight: 700;
+ font-size: 3.5rem;
+}
+
+.hero-section .btn-accent {
+ background-color: var(--bs-accent);
+ color: var(--bs-text);
+ font-weight: 700;
+ padding: 15px 30px;
+ font-size: 1.2rem;
+ border-radius: 50px;
+ transition: transform 0.2s;
+}
+
+.hero-section .btn-accent:hover {
+ transform: scale(1.05);
+}
+
+.content-section {
+ padding: 60px 0;
+}
\ No newline at end of file
diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css
index 108056f..b095735 100644
--- a/staticfiles/css/custom.css
+++ b/staticfiles/css/custom.css
@@ -1,21 +1,58 @@
-
: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);
+ --bs-primary: #0D47A1;
+ --bs-secondary: #42A5F5;
+ --bs-accent: #FFC107;
+ --bs-background: #F5F5F5;
+ --bs-text: #212121;
}
+
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;
+ font-family: 'Roboto', sans-serif;
+ background-color: var(--bs-background);
+ color: var(--bs-text);
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
}
+
+h1, h2, h3, h4, h5, h6, .navbar-brand {
+ font-family: 'Montserrat', sans-serif;
+}
+
+.bg-primary {
+ background-color: var(--bs-primary) !important;
+}
+
+.navbar-brand {
+ font-weight: 700;
+}
+
+.hero-section {
+ background: linear-gradient(45deg, var(--bs-primary), var(--bs-secondary));
+ color: white;
+ padding: 100px 0;
+ text-align: center;
+}
+
+.hero-section h1 {
+ font-weight: 700;
+ font-size: 3.5rem;
+}
+
+.hero-section .btn-accent {
+ background-color: var(--bs-accent);
+ color: var(--bs-text);
+ font-weight: 700;
+ padding: 15px 30px;
+ font-size: 1.2rem;
+ border-radius: 50px;
+ transition: transform 0.2s;
+}
+
+.hero-section .btn-accent:hover {
+ transform: scale(1.05);
+}
+
+.content-section {
+ padding: 60px 0;
+}
\ No newline at end of file