Browse Source

Nuevo proyecto de finanzas

politica
Celestino Rey 1 year ago
parent
commit
234827ff11
53 changed files with 1411 additions and 0 deletions
  1. +1
    -0
      Finanzas/finanzas/accounts/.gitignore
  2. +0
    -0
      Finanzas/finanzas/accounts/__init__.py
  3. +3
    -0
      Finanzas/finanzas/accounts/admin.py
  4. +6
    -0
      Finanzas/finanzas/accounts/apps.py
  5. +3
    -0
      Finanzas/finanzas/accounts/models.py
  6. +3
    -0
      Finanzas/finanzas/accounts/tests.py
  7. +8
    -0
      Finanzas/finanzas/accounts/urls.py
  8. +1
    -0
      Finanzas/finanzas/accounts/views.py
  9. +0
    -0
      Finanzas/finanzas/apuntes/__init__.py
  10. +3
    -0
      Finanzas/finanzas/apuntes/admin.py
  11. +6
    -0
      Finanzas/finanzas/apuntes/apps.py
  12. +52
    -0
      Finanzas/finanzas/apuntes/forms.py
  13. +34
    -0
      Finanzas/finanzas/apuntes/managers.py
  14. +66
    -0
      Finanzas/finanzas/apuntes/migrations/0001_initial.py
  15. +0
    -0
      Finanzas/finanzas/apuntes/migrations/__init__.py
  16. +37
    -0
      Finanzas/finanzas/apuntes/models.py
  17. +14
    -0
      Finanzas/finanzas/apuntes/templates/404.html
  18. +8
    -0
      Finanzas/finanzas/apuntes/templates/_branding.html
  19. +142
    -0
      Finanzas/finanzas/apuntes/templates/_cabecera.html
  20. +10
    -0
      Finanzas/finanzas/apuntes/templates/_footer.html
  21. +23
    -0
      Finanzas/finanzas/apuntes/templates/_head.html
  22. +32
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/detalle_apunte.html
  23. +72
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/detalle_cuenta.html
  24. +17
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/form_apunte.html
  25. +17
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/form_cuenta.html
  26. +26
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/index.html
  27. +57
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/lista_apuntes.html
  28. +65
    -0
      Finanzas/finanzas/apuntes/templates/apuntes/lista_cuentas.html
  29. +34
    -0
      Finanzas/finanzas/apuntes/templates/base.html
  30. +5
    -0
      Finanzas/finanzas/apuntes/templates/fotoperfil
  31. +89
    -0
      Finanzas/finanzas/apuntes/templates/login.html
  32. +7
    -0
      Finanzas/finanzas/apuntes/templates/registration/logged_out.html
  33. +89
    -0
      Finanzas/finanzas/apuntes/templates/registration/login.html
  34. +10
    -0
      Finanzas/finanzas/apuntes/templates/registration/logout.html
  35. +67
    -0
      Finanzas/finanzas/apuntes/templates/registration/signup.html
  36. +0
    -0
      Finanzas/finanzas/apuntes/templatetags/__init__.py
  37. +9
    -0
      Finanzas/finanzas/apuntes/templatetags/filtros_de_entorno.py
  38. +3
    -0
      Finanzas/finanzas/apuntes/tests.py
  39. +17
    -0
      Finanzas/finanzas/apuntes/urls.py
  40. +145
    -0
      Finanzas/finanzas/apuntes/views.py
  41. BIN
      Finanzas/finanzas/db.sqlite3
  42. +0
    -0
      Finanzas/finanzas/finanzas/__init__.py
  43. +16
    -0
      Finanzas/finanzas/finanzas/asgi.py
  44. +141
    -0
      Finanzas/finanzas/finanzas/settings.py
  45. +35
    -0
      Finanzas/finanzas/finanzas/urls.py
  46. +16
    -0
      Finanzas/finanzas/finanzas/wsgi.py
  47. +22
    -0
      Finanzas/finanzas/manage.py
  48. BIN
      Finanzas/finanzas/mediafiles/profile_images/default.jpg
  49. BIN
      Finanzas/finanzas/mediafiles/profile_images/gravatar-tino.jpeg
  50. BIN
      Finanzas/finanzas/mediafiles/profile_images/gravatar-tino_jqB0Vq4.jpeg
  51. BIN
      Finanzas/finanzas/mediafiles/vehiculos/bmw.jpg
  52. BIN
      Finanzas/finanzas/mediafiles/vehiculos/bmw.png
  53. BIN
      Finanzas/finanzas/mediafiles/vehiculos/bmw_yVyuq4g.jpg

+ 1
- 0
Finanzas/finanzas/accounts/.gitignore View File

@ -0,0 +1 @@
migrations/

+ 0
- 0
Finanzas/finanzas/accounts/__init__.py View File


+ 3
- 0
Finanzas/finanzas/accounts/admin.py View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

+ 6
- 0
Finanzas/finanzas/accounts/apps.py View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'

+ 3
- 0
Finanzas/finanzas/accounts/models.py View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

+ 3
- 0
Finanzas/finanzas/accounts/tests.py View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

+ 8
- 0
Finanzas/finanzas/accounts/urls.py View File

@ -0,0 +1,8 @@
# accounts/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

+ 1
- 0
Finanzas/finanzas/accounts/views.py View File

@ -0,0 +1 @@
from django.shortcuts import render

+ 0
- 0
Finanzas/finanzas/apuntes/__init__.py View File


+ 3
- 0
Finanzas/finanzas/apuntes/admin.py View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

+ 6
- 0
Finanzas/finanzas/apuntes/apps.py View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ApuntesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apuntes'

+ 52
- 0
Finanzas/finanzas/apuntes/forms.py View File

@ -0,0 +1,52 @@
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import Cuentas, Apuntes, ReyMotaUser, Tipos
class CuentasForm(forms.ModelForm):
class Meta:
model = Cuentas
fields = ['nombre', 'saldo_inicial', 'tipo']
nombre = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'}))
saldo_inicial = forms.DecimalField(
widget=forms.TextInput(attrs={'class': 'form-control'}))
tipo = forms.ModelChoiceField(
queryset=Tipos.objects.all(),
widget=forms.TextInput(attrs={'class': 'form-control'}))
class ApuntesForm(forms.ModelForm):
class Meta:
model = Apuntes
fields = ['fecha', 'cta_origen', 'cta_destino', 'importe']
fecha = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}))
cta_origen = forms.ModelChoiceField(
queryset=Cuentas.objects.all(),
widget=forms.Select(attrs={'class': 'form-control'}))
cta_destino = forms.ModelChoiceField(
queryset=Cuentas.objects.all(),
widget=forms.Select(attrs={'class': 'form-control'}))
importe = forms.DecimalField(
widget=forms.NumberInput(attrs={'class': 'form-control'}))
class ReyMotaUserCreationForm(UserCreationForm):
class Meta:
model = ReyMotaUser
fields = ("email", "nombre", "foto")
labels = {'email': 'Dirección de correo'}
class ReyMotaUserChangeForm(UserChangeForm):
class Meta:
model = ReyMotaUser
fields = ("email", "foto")

+ 34
- 0
Finanzas/finanzas/apuntes/managers.py View File

@ -0,0 +1,34 @@
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _
class ReyMotaUserManager(BaseUserManager):
"""
ReyMota user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a user with the given email and password.
"""
if not email:
raise ValueError(_("The Email must be set"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
if extra_fields.get("is_staff") is not True:
raise ValueError(_("Superuser must have is_staff=True."))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must have is_superuser=True."))
return self.create_user(email, password, **extra_fields)

+ 66
- 0
Finanzas/finanzas/apuntes/migrations/0001_initial.py View File

@ -0,0 +1,66 @@
# Generated by Django 5.1 on 2024-09-02 14:10
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='Cuentas',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nombre', models.TextField(max_length=20)),
('saldo_inicial', models.DecimalField(decimal_places=2, max_digits=10)),
('saldo_actual', models.DecimalField(decimal_places=2, max_digits=10)),
],
),
migrations.CreateModel(
name='Tipos',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tipo', models.TextField(max_length=10)),
],
),
migrations.CreateModel(
name='ReyMotaUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
('foto', models.ImageField(blank=True, default='profile_images/default.jpg', upload_to='profile_images')),
('is_staff', models.BooleanField(default=False)),
('is_active', models.BooleanField(default=True)),
('nombre', models.CharField(blank=True, max_length=200, null=True)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Apuntes',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('fecha', models.DateField()),
('importe', models.DecimalField(decimal_places=2, max_digits=10)),
('cta_destino', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='destino', to='apuntes.cuentas')),
('cta_origen', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='origen', to='apuntes.cuentas')),
],
),
migrations.AddField(
model_name='cuentas',
name='tipo',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='apuntes.tipos'),
),
]

+ 0
- 0
Finanzas/finanzas/apuntes/migrations/__init__.py View File


+ 37
- 0
Finanzas/finanzas/apuntes/models.py View File

@ -0,0 +1,37 @@
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .managers import ReyMotaUserManager
# Create your models here.
class ReyMotaUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("email address"), unique=True)
foto = models.ImageField(upload_to="profile_images", default="profile_images/default.jpg", blank=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
nombre = models.CharField(max_length=200, blank=True, null=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = ReyMotaUserManager()
def __str__(self):
return self.email
class Tipos(models.Model):
tipo = models.TextField(max_length=10)
class Cuentas(models.Model):
nombre = models.TextField(max_length=20)
saldo_inicial = models.DecimalField(max_digits=10, decimal_places=2)
saldo_actual = models.DecimalField(max_digits=10, decimal_places=2)
tipo = models.ForeignKey(Tipos, on_delete=models.CASCADE)
class Apuntes(models.Model):
fecha = models.DateField()
cta_origen = models.ForeignKey(Cuentas, on_delete=models.CASCADE, related_name='origen')
cta_destino = models.ForeignKey(Cuentas, on_delete=models.CASCADE, related_name='destino')
importe = models.DecimalField(max_digits=10, decimal_places=2)

+ 14
- 0
Finanzas/finanzas/apuntes/templates/404.html View File

@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% block content %}
<div class="app-card p-5 text-center shadow-sm">
<h1 class="page-title mb-4">404<br><span class="font-weight-light">Página no encontrada</span></h1>
<div class="mb-4">
Lo siento, no hemos podido encontrar la página que buscas.
</div>
<a class="btn app-btn-primary" href="{{ url_for('paginas.index') }}">Ir a la página de inicio</a>
</div>
{% endblock %}

+ 8
- 0
Finanzas/finanzas/apuntes/templates/_branding.html View File

@ -0,0 +1,8 @@
{% load static %}
{% load filtros_de_entorno %}
<div class="app-branding">
<a class="app-logo" href="{% url 'principal' %}"><img class="logo-icon me-2" src="{% static 'images/reymota-logo.svg' %}" alt="logo"><span class="logo-text">FINANZAS</span><span style="color: blue; font-size: 14px;"> v {{ "VERSION"|muestra_version }}</span></a>
</div><!--//app-branding-->

+ 142
- 0
Finanzas/finanzas/apuntes/templates/_cabecera.html View File

@ -0,0 +1,142 @@
{% load static %}
<header class="app-header fixed-top">
<div class="app-header-inner">
<div class="container-fluid py-2">
<div class="app-header-content">
<div class="row justify-content-between align-items-center">
<div class="col-auto">
<a id="sidepanel-toggler" class="sidepanel-toggler d-inline-block d-xl-none" href="#">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg>
</a>
</div><!--//col-->
<div class="app-utilities col-auto">
<div class="app-utility-item app-user-dropdown dropdown">
{% if user.is_authenticated %}
<a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src=" {{user.foto.url }}"></a>
{% else %}
<a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Sin usuario</a>
{% endif %}
<ul class="dropdown-menu" aria-labelledby="user-dropdown-toggle">
{% if user.is_authenticated %}
<li>
<a class="dropdown-item">{{ user.nombre }}</a>
</li>
<li><a class="dropdown-item">
<form method="post" action="{% url 'logout' %}" >
{% csrf_token %}
<button
style="background: none!important;
border: none;
padding: 0!important;
/*optional*/
font-family: arial, sans-serif;
/*input has OS specific font-family*/
/*color: #069;
text-decoration: underline;*/
cursor: pointer;"
type="submit">Salir</button>
</form></a>
</li>
{% else %}
<li><a class="dropdown-item" href="{% url 'login' %}">Entrar</a></li>
{% endif %}
</ul>
</div><!--//app-user-dropdown-->
</div><!--//app-utilities-->
</div><!--//row-->
</div><!--//app-header-content-->
</div><!--//container-fluid-->
</div><!--//app-header-inner-->
<div id="app-sidepanel" class="app-sidepanel">
<div id="sidepanel-drop" class="sidepanel-drop"></div>
<div class="sidepanel-inner d-flex flex-column">
<a href="#" id="sidepanel-close" class="sidepanel-close d-xl-none">&times;</a>
{% include "_branding.html" %}
<nav id="app-nav-main" class="app-nav app-nav-main flex-grow-1">
<ul class="app-menu list-unstyled accordion" id="menu-accordion">
<li class="nav-item">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<a class="nav-link active" href="{% url 'principal' %}">
<span class="nav-icon">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-house-door" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M7.646 1.146a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 .146.354v7a.5.5 0 0 1-.5.5H9.5a.5.5 0 0 1-.5-.5v-4H7v4a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .146-.354l6-6zM2.5 7.707V14H6v-4a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v4h3.5V7.707L8 2.207l-5.5 5.5z"/>
<path fill-rule="evenodd" d="M13 2.5V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
</svg>
</span>
<span class="nav-link-text">Principal</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
<li class="nav-item">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<a class="nav-link" href="{% url 'lista_apuntes' %}">
<span class="nav-icon">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-card-list" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M14.5 3h-13a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
<path fill-rule="evenodd" d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5z"/>
<circle cx="3.5" cy="5.5" r=".5"/>
<circle cx="3.5" cy="8" r=".5"/>
<circle cx="3.5" cy="10.5" r=".5"/>
</svg>
</span>
<span class="nav-link-text">Apuntes</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
<li class="nav-item">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<a class="nav-link" href="{% url 'lista_cuentas' %}">
<span class="nav-icon">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-card-list" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M14.5 3h-13a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
<path fill-rule="evenodd" d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5z"/>
<circle cx="3.5" cy="5.5" r=".5"/>
<circle cx="3.5" cy="8" r=".5"/>
<circle cx="3.5" cy="10.5" r=".5"/>
</svg>
</span>
<span class="nav-link-text">Cuentas</span>
</a><!--//nav-link-->
</li><!--//nav-item-->
{% if user.is_authenticated %}
<li class="nav-item has-submenu">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<a class="nav-link submenu-toggle" href="#" data-bs-toggle="collapse" data-bs-target="#submenu-1" aria-expanded="false" aria-controls="submenu-1">
<span class="nav-icon">
<!--//Bootstrap Icons: https://icons.getbootstrap.com/ -->
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-files" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4 2h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zm0 1a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4z"/>
<path d="M6 0h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2v-1a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H6a1 1 0 0 0-1 1H4a2 2 0 0 1 2-2z"/>
</svg>
</span>
<span class="nav-link-text">Añadir</span>
<span class="submenu-arrow">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-chevron-down" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
</svg>
</span><!--//submenu-arrow-->
</a><!--//nav-link-->
<div id="submenu-1" class="collapse submenu submenu-1" data-bs-parent="#menu-accordion">
<ul class="submenu-list list-unstyled">
<li class="submenu-item"><a class="submenu-link" href="{% url 'nuevo_apunte' %}">Apuntes</a></li>
<li class="submenu-item"><a class="submenu-link" href="{% url 'nueva_cuenta' %}">Cuenta</a></li>
</ul>
</div>
</li><!--//nav-item-->
{% endif %}
</ul><!--//app-menu-->
</nav><!--//app-nav-->
</div><!--//sidepanel-inner-->
</div><!--//app-sidepanel-->
</header><!--//app-header-->

+ 10
- 0
Finanzas/finanzas/apuntes/templates/_footer.html View File

@ -0,0 +1,10 @@
<!--
La clase app-auth-footer hace algo que implica que el texto quede
en la parte de abajo de la ventana con el tamaño que esta tenga en el momento
de renderizar el texto. En algunos casos esto causa un efecto no deseado. Por ejemplo en letras.html
-->
<!--<footer class="app-auth-footer">-->
<div class="container text-center py-3">
<small class="copyright">(c) <a class="app-link" href="http://reymota.es" target="_blank">Celestino Rey</a></small>
</div>
<!--</footer>//app-auth-footer-->

+ 23
- 0
Finanzas/finanzas/apuntes/templates/_head.html View File

@ -0,0 +1,23 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Registro de vehículos y sus apuntes</title>
<!-- Meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Portal - Bootstrap 5 Admin Dashboard Template For Developers">
<meta name="author" content="Xiaoying Riley at 3rd Wave Media">
<link rel="shortcut icon" href="{% static 'images/favicon.ico' %}">
<!-- FontAwesome JS-->
<script defer src="{% static 'plugins/fontawesome/js/all.min.js' %}"></script>
<!-- App CSS -->
<link id="theme-style" rel="stylesheet" href="{% static 'css/portal.css' %}">
</head>

+ 32
- 0
Finanzas/finanzas/apuntes/templates/apuntes/detalle_apunte.html View File

@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% block content %}
<div class="container-xl">
<div class="app-card app-card-notification shadow-sm mb-4">
<div class="app-card-header px-4 py-3">
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-auto text-center text-lg-start">
<h4 class="notification-title mb-1">{{ apunte.fecha }}</h4>
<ul class="notification-meta list-inline mb-0">
<li class="list-inline-item"><a href="{% url 'detalle_cuenta' apunte.cuenta_id %}">{{ apunte.cuenta.matricula }}</a></li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.kms }} kms</li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.litros }} litros</li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.importe }} €</li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.kmsrecorridos }} kms. recorridos</li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.consumo }} litros/100 kms</li>
<li class="list-inline-item">|</li>
<li class="list-inline-item">{{ apunte.precioxlitro }} €/litros</li>
</ul>
</div><!--//col-->
</tr>
</div><!--//row-->
</div><!--//app-card-header-->
</div><!--//app-card-->
{% endblock %}

+ 72
- 0
Finanzas/finanzas/apuntes/templates/apuntes/detalle_cuenta.html View File

@ -0,0 +1,72 @@
{% extends 'base.html' %}
{% block content %}
<div class="container-xl">
<div class="app-card app-card-notification shadow-sm mb-4">
<div class="app-card-header px-4 py-3">
<div class="row g-3 align-items-center">
<div class="col-12 col-lg-auto text-center text-lg-start">
{% if cuenta.foto %}
<p><img src="{{ cuenta.foto.url }}" alt="{{ cuenta.matricula}}" style="width:200px;height:200px;"></p>
{% else %}
<p>No hay imágen disponible</p>
{% endif %}
</div>
<div class="col-12 col-lg-auto text-center text-lg-start">
<h4>{{ cuenta.matricula }}</h4>
<ul class="notification-meta list-inline mb-0">
<li class="list-inline-item">{{ cuenta.matricula }}</li>
</ul>
</div>
</div>
</div>
<div class="app-card-body p-4">
{% if apuntes %}
<table class="table app-table-hover mb-0 text-left">
<thead>
<tr>
<th class="cell">Fecha</th>
<th class="cell">Kilómetros</th>
<th class="cell">Litros</th>
<th class="cell">Importe</th>
<th class="cell">Descuento</th>
<th class="cell">Precio por litro</th>
<th class="cell">Kms recorridos</th>
<th class="cell">Consumo/100 kms</th>
</tr>
</thead>
<tbody>
{% for apunte in apuntes %}
<tr>
<td class="cell"><a href="{% url 'detalle_apunte' apunte.id %}">{{ apunte.fecha }}</a></td>
<td class="cell">{{ apunte.kms }}</td>
<td class="cell">{{ apunte.litros }}</td>
<td class="cell">{{ apunte.importe }}</td>
<td class="cell">{{ apunte.descuento }}</td>
<td class="cell">{{ apunte.precioxlitro }}</td>
<td class="cell">{{ apunte.kmsrecorridos }}</td>
<td class="cell">{{ apunte.consumo }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No se han encontrado apuntes para este cuenta</p>
{% endif %}
</div>
</div>
<div class="row g-3 mb-4 align-items-center justify-content-between">
<div class="col-auto">
<a class="btn app-btn-secondary" href="{% url 'lista_apuntes' %}">Volver al inicio</a>
</div>
<div class="col-auto">
<a class="btn app-btn-primary" href="{% url 'nuevo_apunte' %}">Añadir apunte</a> <!-- Faltaría poner el id del cuenta-->
</div>
</div>
</div>
{% endblock %}

+ 17
- 0
Finanzas/finanzas/apuntes/templates/apuntes/form_apunte.html View File

@ -0,0 +1,17 @@
{% extends 'base.html' %}
{% block content %}
<div class="column is-4 is-offset-4">
<h3>{% if form.instance.pk %}Editar apunte{% else %}Nuevo apunte{% endif %}</h3>
<div class="box">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="text mb-3">
<button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Guardar</button>
</div>
</form>
{{ form.media }}
</div>
</div>
{% endblock %}

+ 17
- 0
Finanzas/finanzas/apuntes/templates/apuntes/form_cuenta.html View File

@ -0,0 +1,17 @@
{% extends 'base.html' %}
{% block content %}
<div class="column is-4 is-offset-4">
<h3>{% if form.instance.pk %}Editar vehículo{% else %}Nuevo vehículo{% endif %}</h3>
<div class="box">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="text mb-3">
<button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Guardar</button>
</div>
</form>
</div>
</div>
{% endblock %}

+ 26
- 0
Finanzas/finanzas/apuntes/templates/apuntes/index.html View File

@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block content %}
<div class="container-xl">
<h1 class="app-page-title">Introducción</h1>
<div class="app-card alert alert-dismissible shadow-sm mb-4 border-left-decoration" role="alert">
<div class="inner">
<div class="app-card-body p-3 p-lg-4">
<h3 class="mb-3">¡Bienvenido a la gestión financiera personal!</h3>
<div class="row gx-5 gy-3">
<!--
<div class="col-12 col-lg-9">
<div>Pensado inicialmente para guardar las letras de las canciones de Bruce Springsteen.</div>
</div>--><!--//col-->
</div><!--//row-->
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div><!--//app-card-body-->
</div><!--//inner-->
</div><!--//app-card-->
</div><!--//container-fluid-->
{% endblock %}

+ 57
- 0
Finanzas/finanzas/apuntes/templates/apuntes/lista_apuntes.html View File

@ -0,0 +1,57 @@
{% extends 'base.html' %}
{% block content %}
<div class="container-xl">
<div class="row g-3 mb-4 align-items-center justify-content-between">
<div class="col-auto">
<h1 class="app-page-title mb-0">apuntes</h1>
</div>
</div><!--//row-->
<div class="col-auto">
<div class="page-utilities">
<div class="row g-4 justify-content-start justify-content-md-end align-items-center">
<div class="col-auto">
<a class="btn app-btn-primary" href="{% url 'nuevo_apunte' %}">Añadir apunte</a>
</div>
</div><!--//row-->
</div><!--//table-utilities-->
</div><!--//col-auto-->
<div class="app-card app-card-notification shadow-sm mb-4">
<div class="app-card-body p-4">
<table class="table app-table-hover mb-0 text-left">
<thead>
<tr>
<th class="cell">Fecha</th>
<th class="cell">Cuenta</th>
<th class="cell">Kilómetros</th>
<th class="cell">Litros</th>
<th class="cell">Importe</th>
<th class="cell">Descuento</th>
<th class="cell">Precio por litro</th>
<th class="cell">Kms recorridos</th>
<th class="cell">Consumo/100 kms</th>
</tr>
</thead>
{% for apunte in apuntes %}
<tbody>
<tr>
<td class="cell"><a href="{% url 'detalle_apunte' apunte.id %}">{{ apunte.fecha }}</a></td>
<td class="cell"><a href="{% url 'detalle_cuenta' apunte.cuenta.id %}">{{ apunte.cuenta.matricula }}</a></td>
<td class="cell">{{ apunte.kms }}</td>
<td class="cell">{{ apunte.litros }}</td>
<td class="cell">{{ apunte.importe }} €</td>
<td class="cell">{{ apunte.descuento }} €</td>
<td class="cell">{{ apunte.precioxlitro }} €</td>
<td class="cell">{{ apunte.kmsrecorridos }}</td>
<td class="cell">{{ apunte.consumo }}</td>
</tr>
</tbody>
{% endfor %}
</table>
</div>
</div><!--//container-fluid-->
{% endblock %}

+ 65
- 0
Finanzas/finanzas/apuntes/templates/apuntes/lista_cuentas.html View File

@ -0,0 +1,65 @@
{% extends 'base.html' %}
{% block content %}
<div class="container-xl">
<div class="row g-3 mb-4 align-items-center justify-content-between">
<div class="col-auto">
<h1 class="app-page-title mb-0">Cuentas</h1>
</div>
</div><!--//row-->
<div class="col-auto">
<div class="page-utilities">
<div class="row g-4 justify-content-start justify-content-md-end align-items-center">
<div class="col-auto">
<a class="btn app-btn-primary" href="{% url 'nueva_cuenta' %}">Añadir cuenta</a>
</div>
</div><!--//row-->
</div><!--//table-utilities-->
</div><!--//col-auto-->
<div class="row g-4">
{% for cuenta in cuentas %}
<div class="col-6 col-md-4 col-xl-3 col-xxl-2">
<div class="app-card app-card-doc shadow-sm h-100">
<div class="app-card-body p-3 has-card-actions">
<h4 class="app-doc-title truncate mb-0"><a href="{% url 'detalle_cuenta' cuenta.id %}">{{ cuenta.matricula}}</a></h4>
<div class="app-card-actions">
<div class="dropdown">
<div class="dropdown-toggle no-toggle-arrow" data-bs-toggle="dropdown" aria-expanded="false">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-three-dots-vertical" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
</svg>
</div><!--//dropdown-toggle-->
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'detalle_cuenta' cuenta.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-eye me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.134 13.134 0 0 0 1.66 2.043C4.12 11.332 5.88 12.5 8 12.5c2.12 0 3.879-1.168 5.168-2.457A13.134 13.134 0 0 0 14.828 8a13.133 13.133 0 0 0-1.66-2.043C11.879 4.668 10.119 3.5 8 3.5c-2.12 0-3.879 1.168-5.168 2.457A13.133 13.133 0 0 0 1.172 8z"/>
<path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
</svg>Ver</a></li>
<li><a class="dropdown-item" href="{% url 'editar_cuenta' cuenta.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5L13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175l-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
</svg>Editar</a></li>
<li><a class="dropdown-item" href="{% url 'eliminar_cuenta' cuenta.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
<path fill-rule="evenodd" d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/>
</svg>Eliminar</a></li>
<!--
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-trash me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>Delete</a></li>
-->
</ul>
</div><!--//dropdown-->
</div><!--//app-card-actions-->
</div><!--//app-card-body-->
</div>
</div>
{% endfor %}
</div>
</div><!--//container-fluid-->
{% endblock %}

+ 34
- 0
Finanzas/finanzas/apuntes/templates/base.html View File

@ -0,0 +1,34 @@
{% load static %}
{% include "_head.html" %}
<body class="app">
{% include "_cabecera.html" %}
<div class="app-wrapper">
<div class="app-content pt-3 p-md-3 p-lg-4">
{% block content %}{% endblock %}
</div><!--//app-content-->
{% include "_footer.html" %}
</div><!--//app-wrapper-->
<!-- Javascript -->
<script src="{% static 'plugins/popper.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap/js/bootstrap.min.js' %}"></script>
<!-- Charts JS -->
<script src="{% static 'plugins/chart.js/chart.min.js' %}"></script>
<script src="{% static 'js/index-charts.js' %}"></script>
<!-- La línea siguiente es para la demo de los charts en charts.html -->
<script src="{% static 'js/charts-demo.js' %}"></script>
<!-- Page Specific JS -->
<script src="{% static 'js/app.js' %}"></script>
</body>
</html>

+ 5
- 0
Finanzas/finanzas/apuntes/templates/fotoperfil View File

@ -0,0 +1,5 @@
{% if user.is_authenticated %}
<a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src="{{ url_for('paginas.uploaded_file', filename=current_user.photo) }}" alt="user profile"></a>
{% else %}
<a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src="{{ url_for('static', filename='images/reymota-logo.svg') }}" alt="user profile"></a>
{% endif %}

+ 89
- 0
Finanzas/finanzas/apuntes/templates/login.html View File

@ -0,0 +1,89 @@
{% load i18n static %}
{% include "_head.html" %}
<body class="app app-login p-0">
<div class="row g-0 app-auth-wrapper">
<div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5">
<div class="d-flex flex-column align-content-end">
<div class="app-auth-body mx-auto">
{% include "_branding.html" %}
<h2 class="auth-heading text-center mb-5">Entrar en Finanzas</h2>
{% if form.errors and not form.non_field_errors %}
<p class="errornote">
{% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %}
</p>
{% endif %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p class="errornote">
{{ error }}
</p>
{% endfor %}
{% endif %}
<div class="auth-form-container text-start" id="content-main">
{% if user.is_authenticated %}
<p class="errornote">
{% blocktranslate trimmed %}
You are authenticated as {{ username }}, but are not authorized to
access this page. Would you like to login to a different account?
{% endblocktranslate %}
</p>
{% endif %}
<form class="auth-form login-form" action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
<div class="text mb-3">
{{ form.username.errors }}
{{ form.username.label_tag }}
</div>
<div class="text mb-3">
{{ form.username }}
</div>
<div class="password mb-3">
{{ form.password.errors }}
{{ form.password.label_tag }}
</div>
<div class="password mb-3">
{{ form.password }}
<input type="hidden" name="next" value="{{ next }}">
</div>
{% url 'admin_password_reset' as password_reset_url %}
{% if password_reset_url %}
<div class="password-reset-link">
<a href="{{ password_reset_url }}">{% translate 'Forgotten your password or username?' %}</a>
</div>
{% endif %}
<div class="text-center">
<input type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto" value="{% translate 'Log in' %}">
</div>
</form>
</div>
</div>
{% include "_footer.html" %}
</div>
</div>
<div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col">
<div class="auth-background-holder">
</div>
<div class="auth-background-mask"></div>
<div class="auth-background-overlay p-3 p-lg-5">
<div class="d-flex flex-column align-content-end h-100">
<div class="h-100"></div>
<!--
<div class="overlay-content p-3 p-lg-4 rounded">
<h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5>
<div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div>
</div>
-->
</div>
</div><!--//auth-background-overlay-->
</div><!--//auth-background-col-->
</div><!--//row-->
</body>
</html>

+ 7
- 0
Finanzas/finanzas/apuntes/templates/registration/logged_out.html View File

@ -0,0 +1,7 @@
{% block title %}Logged out{% endblock %}
{% block content %}
Logged out
You have been successfully logged out. You can log-in again.
{% endblock %}

+ 89
- 0
Finanzas/finanzas/apuntes/templates/registration/login.html View File

@ -0,0 +1,89 @@
{% load i18n static %}
{% include "_head.html" %}
<body class="app app-login p-0">
<div class="row g-0 app-auth-wrapper">
<div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5">
<div class="d-flex flex-column align-content-end">
<div class="app-auth-body mx-auto">
{% include "_branding.html" %}
<h2 class="auth-heading text-center mb-5">Entrar en Finanzas</h2>
{% if form.errors and not form.non_field_errors %}
<p class="errornote">
{% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %}
</p>
{% endif %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p class="errornote">
{{ error }}
</p>
{% endfor %}
{% endif %}
<div class="auth-form-container text-start" id="content-main">
{% if user.is_authenticated %}
<p class="errornote">
{% blocktranslate trimmed %}
You are authenticated as {{ username }}, but are not authorized to
access this page. Would you like to login to a different account?
{% endblocktranslate %}
</p>
{% endif %}
<form class="auth-form login-form" action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
<div class="text mb-3">
{{ form.username.errors }}
{{ form.username.label_tag }}
</div>
<div class="text mb-3">
{{ form.username }}
</div>
<div class="password mb-3">
{{ form.password.errors }}
{{ form.password.label_tag }}
</div>
<div class="password mb-3">
{{ form.password }}
<input type="hidden" name="next" value="{{ next }}">
</div>
{% url 'admin_password_reset' as password_reset_url %}
{% if password_reset_url %}
<div class="password-reset-link">
<a href="{{ password_reset_url }}">{% translate 'Forgotten your password or username?' %}</a>
</div>
{% endif %}
<div class="text-center">
<input type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto" value="{% translate 'Log in' %}">
</div>
</form>
</div>
</div>
{% include "_footer.html" %}
</div>
</div>
<div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col">
<div class="auth-background-holder">
</div>
<div class="auth-background-mask"></div>
<div class="auth-background-overlay p-3 p-lg-5">
<div class="d-flex flex-column align-content-end h-100">
<div class="h-100"></div>
<!--
<div class="overlay-content p-3 p-lg-4 rounded">
<h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5>
<div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div>
</div>
-->
</div>
</div><!--//auth-background-overlay-->
</div><!--//auth-background-col-->
</div><!--//row-->
</body>
</html>

+ 10
- 0
Finanzas/finanzas/apuntes/templates/registration/logout.html View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Cerrar Sesión</title>
</head>
<body>
<h2>Has cerrado sesión con éxito</h2>
<a href="{% url 'login' %}">Iniciar sesión nuevamente</a>
</body>
</html>

+ 67
- 0
Finanzas/finanzas/apuntes/templates/registration/signup.html View File

@ -0,0 +1,67 @@
{% include "_head.html" %}
<body class="app app-signup p-0">
<div class="row g-0 app-auth-wrapper">
<div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5">
<div class="d-flex flex-column align-content-end">
<div class="app-auth-body mx-auto">
{% include "_branding.html" %}
<h2 class="auth-heading text-center mb-4">Registrarse en Finanzas</h2>
<div class="auth-form-container text-start mx-auto">
<form class="auth-form auth-signup-form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<div class="item border-bottom py-3"></div>
<div class="text-center">
<button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Sign Up</button>
</div>
</form><!--//auth-form-->
<div class="auth-option text-center pt-5">¿Ya tienes una cuenta? <a class="text-link" href="{% url 'login' %}" >Entra</a></div>
</div><!--//auth-form-container-->
</div><!--//auth-body-->
{% include "_footer.html" %}
</div><!--//flex-column-->
</div><!--//auth-main-col-->
<div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col">
<div class="auth-background-holder">
</div>
<div class="auth-background-mask"></div>
<div class="auth-background-overlay p-3 p-lg-5">
<div class="d-flex flex-column align-content-end h-100">
<div class="h-100"></div>
<!--
<div class="overlay-content p-3 p-lg-4 rounded">
<h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5>
<div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div>
</div>
-->
</div>
</div><!--//auth-background-overlay-->
</div><!--//auth-background-col-->
</div><!--//row-->
</body>
</html>

+ 0
- 0
Finanzas/finanzas/apuntes/templatetags/__init__.py View File


+ 9
- 0
Finanzas/finanzas/apuntes/templatetags/filtros_de_entorno.py View File

@ -0,0 +1,9 @@
import os
from django import template
register = template.Library()
@register.filter
def muestra_version(clave):
return os.getenv(clave, '')

+ 3
- 0
Finanzas/finanzas/apuntes/tests.py View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

+ 17
- 0
Finanzas/finanzas/apuntes/urls.py View File

@ -0,0 +1,17 @@
from django.urls import path
from . import views
urlpatterns = [
path('cuentas/', views.lista_cuentas, name='lista_cuentas'),
path('cuentas/nuevo/', views.nueva_cuenta, name='nueva_cuenta'),
path('cuentas/<int:cuenta_id>/', views.detalle_cuenta, name='detalle_cuenta'),
path('cuentas/<int:cuenta_id>/editar/', views.editar_cuenta, name='editar_cuenta'),
path('cuentas/<int:cuenta_id>/eliminar/', views.eliminar_cuenta, name='eliminar_cuenta'),
path('apuntes/', views.lista_apuntes, name='lista_apuntes'),
path('apuntes/nuevo/', views.nuevo_apunte, name='nuevo_apunte'),
path('apuntes/<int:apunte_id>/', views.detalle_apunte, name='detalle_apunte'),
path('apuntes/<int:apunte_id>/editar/', views.editar_apunte, name='editar_apunte'),
path('apuntes/<int:apunte_id>/eliminar/', views.eliminar_apunte, name='eliminar_apunte'),
]

+ 145
- 0
Finanzas/finanzas/apuntes/views.py View File

@ -0,0 +1,145 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404, redirect
# Create your views here.
from .models import Cuentas, Apuntes
from .forms import CuentasForm, ApuntesForm
@login_required
def principal(request):
cuentas = Cuentas.objects.all()
apuntes = Apuntes.objects.all()
return render(request, 'apuntes/index.html', {'cuentas': cuentas, 'apuntes': apuntes})
# Vistas para los cuentas
@login_required
def lista_cuentas(request):
cuentas = Cuentas.objects.all()
return render(request, 'apuntes/lista_cuentas.html', {'cuentas': cuentas})
@login_required
def detalle_cuenta(request, cuenta_id):
cuenta = get_object_or_404(Cuentas, pk=cuenta_id)
apuntes = Apuntes.objects.filter(cuenta=cuenta_id)
return render(request, 'apuntes/detalle_cuenta.html', {'cuenta': cuenta, 'apuntes': apuntes})
@login_required
def nueva_cuenta(request):
if request.method == 'POST':
form = CuentasForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('lista_cuentas')
else:
form = CuentasForm()
return render(request, 'apuntes/form_cuenta.html', {'form': form})
@login_required
def editar_cuenta(request, cuenta_id):
cuenta = get_object_or_404(Cuentas, pk=cuenta_id)
if request.method == 'POST':
form = CuentasForm(request.POST, request.FILES, instance=cuenta)
if form.is_valid():
form.save()
return redirect('lista_cuentas')
else:
form = CuentasForm(instance=cuenta)
return render(request, 'apuntes/form_cuenta.html', {'form': form})
@login_required
def eliminar_cuenta(request, cuenta_id):
cuenta = get_object_or_404(Cuentas, pk=cuenta_id)
cuenta.delete()
return redirect('lista_cuentas')
# Vistas para los apuntes
@login_required
def lista_apuntes(request):
apuntes = Apuntes.objects.all()
return render(request, 'apuntes/lista_apuntes.html', {'apuntes': apuntes})
@login_required
def detalle_apunte(request, apunte_id):
apunte = get_object_or_404(Apuntes, pk=apunte_id)
return render(request, 'apuntes/detalle_apunte.html', {'apunte': apunte})
@login_required
def nuevo_apunte(request):
cuentas = Cuentas.objects.all() # vamos a ver si hay vehículos dados de alta
if cuentas:
if request.method == 'POST':
form = ApuntesForm(request.POST, request.FILES)
if form.is_valid():
instancia = form.save(commit=False)
aplica_descuento = form.cleaned_data['aplica_descuento']
if aplica_descuento:
instancia.descuento = float(instancia.importe) * 0.03
else:
instancia.descuento = 0.0
instancia.importe = float(instancia.importe) - instancia.descuento
if instancia.litros > 0:
instancia.precioxlitro = round(instancia.importe / float(instancia.litros), 2)
else:
instancia.precioxlitro = 0
# lee todos los apuntes del vehículo
# apuntes = Apuntes.query.filter_by(cuenta_id=cuenta_id).all()
if Apuntes.objects.filter(cuenta_id=instancia.cuenta):
apuntes = Apuntes.objects.filter(cuenta_id=instancia.cuenta).order_by('-fecha')[0]
instancia.kmsrecorridos = instancia.kms - apuntes.kms
if instancia.kmsrecorridos > 0:
instancia.consumo = round(instancia.litros * 100 / instancia.kmsrecorridos, 2)
else:
instancia.kmsrecorridos = 0
instancia.consumo = 0
instancia.save()
return redirect('lista_apuntes')
else:
form = ApuntesForm()
return render(request, 'apuntes/form_apunte.html', {'form': form})
else:
return render(request, 'apuntes/index.html')
@login_required
def editar_apunte(request, apunte_id):
apunte = get_object_or_404(Apuntes, pk=apunte_id)
if request.method == 'POST':
form = ApuntesForm(request.POST, request.FILES, instance=apunte)
if form.is_valid():
form.save()
return redirect('lista_apuntes')
else:
form = ApuntesForm(instance=apunte)
return render(request, 'apuntes/form_apunte.html', {'form': form})
@login_required
def eliminar_apunte(request, apunte_id):
apunte = Apuntes.objects.get(pk=apunte_id)
apunte.delete()
return redirect('lista_apuntes')

BIN
Finanzas/finanzas/db.sqlite3 View File


+ 0
- 0
Finanzas/finanzas/finanzas/__init__.py View File


+ 16
- 0
Finanzas/finanzas/finanzas/asgi.py View File

@ -0,0 +1,16 @@
"""
ASGI config for finanzas project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'finanzas.settings')
application = get_asgi_application()

+ 141
- 0
Finanzas/finanzas/finanzas/settings.py View File

@ -0,0 +1,141 @@
"""
Django settings for finanzas project.
Generated by 'django-admin startproject' using Django 5.1.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-vu#zk4g8pj-qoov#8^i$&s8n_ipp2r3h+o$z1w(1%d=6+i@erm'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apuntes',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'finanzas.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'finanzas.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = 'es-es'
TIME_ZONE = 'Europe/Madrid'
USE_I18N = True
USE_TZ = True
I18N = True
L10N = True
DECIMAL_SEPARATOR = ','
THOUSAND_SEPARATOR = '.'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / "staticfiles"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = 'principal'
LOGOUT_REDIRECT_URL = 'principal'
AUTH_USER_MODEL = "apuntes.ReyMotaUser"
MEDIA_ROOT = BASE_DIR / "mediafiles"
MEDIA_URL = '/media/'
if DEBUG is False:
CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ")

+ 35
- 0
Finanzas/finanzas/finanzas/urls.py View File

@ -0,0 +1,35 @@
"""
URL configuration for finanzas project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('obreros/', admin.site.urls),
path('apuntes/', include('apuntes.urls')),
path("accounts/", include("accounts.urls")), # new
path("accounts/", include("django.contrib.auth.urls")),
path("", TemplateView.as_view(template_name="apuntes/index.html"),
name="principal"), # new
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 16
- 0
Finanzas/finanzas/finanzas/wsgi.py View File

@ -0,0 +1,16 @@
"""
WSGI config for finanzas project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'finanzas.settings')
application = get_wsgi_application()

+ 22
- 0
Finanzas/finanzas/manage.py View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'finanzas.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

BIN
Finanzas/finanzas/mediafiles/profile_images/default.jpg View File

Before After
Width: 826  |  Height: 826  |  Size: 20 KiB

BIN
Finanzas/finanzas/mediafiles/profile_images/gravatar-tino.jpeg View File

Before After
Width: 256  |  Height: 256  |  Size: 29 KiB

BIN
Finanzas/finanzas/mediafiles/profile_images/gravatar-tino_jqB0Vq4.jpeg View File

Before After
Width: 256  |  Height: 256  |  Size: 29 KiB

BIN
Finanzas/finanzas/mediafiles/vehiculos/bmw.jpg View File

Before After
Width: 500  |  Height: 500  |  Size: 18 KiB

BIN
Finanzas/finanzas/mediafiles/vehiculos/bmw.png View File

Before After
Width: 360  |  Height: 225  |  Size: 9.5 KiB

BIN
Finanzas/finanzas/mediafiles/vehiculos/bmw_yVyuq4g.jpg View File

Before After
Width: 500  |  Height: 500  |  Size: 18 KiB

Loading…
Cancel
Save