from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.utils import timezone from decimal import Decimal from django.http import HttpResponse from django.contrib.auth import login, authenticate, logout from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from .models import Cuenta, Movimientos, TipoMovimiento from django import forms import openpyxl from django.contrib.auth.models import User from .forms import RegistroCuentaForm, RegistroMovimientosForm def base(request): return render(request, 'index.html') def signin(request): if request.method == 'GET': return render ( request, 'index.html',{ 'form': AuthenticationForm }) else: user=authenticate(request, username=request.POST['username'], password=request.POST['password']) if user is None: return render ( request, 'index.html',{ 'form': AuthenticationForm , 'error': 'Username or password is incorrect' }) else: login(request, user) return redirect('lista_cuentas') def signout(request): logout(request) return redirect('signin') class CustomUserCreationForm(UserCreationForm): email = forms.EmailField(required=True, help_text="Introduce un correo electrónico válido.") class Meta: model = User fields = ('username', 'email', 'password1', 'password2') def save(self, commit=True): user = super().save(commit=False) user.email = self.cleaned_data["email"] if commit: user.save() return user def signup(request): if request.method == 'POST': form = CustomUserCreationForm(request.POST) # Verificamos si el formulario es válido if form.is_valid(): # Guardamos el usuario si todo está bien form.save() # Mensaje de éxito return redirect('signin') # Redirige a la página de inicio de sesión else: # Si el formulario no es válido, mostramos los errores en los campos específicos if 'username' not in form.cleaned_data: form.add_error('username', 'El nombre de usuario es obligatorio.') if 'email' not in form.cleaned_data: form.add_error('email', 'El correo electrónico es obligatorio.') if 'password1' not in form.cleaned_data: form.add_error('password1', 'La contraseña es obligatoria.') if 'password2' not in form.cleaned_data: form.add_error('password2', 'Debes confirmar la contraseña.') return render(request, 'singup.html', {'form': form}) else: # Si es un GET, mostramos un formulario vacío form = CustomUserCreationForm() return render(request, 'singup.html', {'form': form}) @login_required def registrar_cuenta(request): if request.method == "POST": form = RegistroCuentaForm(request.POST) if form.is_valid(): cuenta = form.save(commit=False) cuenta.responsable = request.user cuenta.save() return redirect('lista_cuentas') # Cambia el nombre de la vista destino else: form = RegistroCuentaForm() return render(request, 'cuentas.html', {'form': form}) @login_required def registrar_movimiento(request, cuenta_id): cuenta = get_object_or_404(Cuenta, id=cuenta_id) # Obtiene la cuenta específica if request.method == "POST": form = RegistroMovimientosForm(request.POST) if form.is_valid(): movimiento = form.save(commit=False) movimiento.cuentas = cuenta # Asigna la cuenta automáticamente movimiento.responsable = request.user # Asigna el usuario actual # Ajusta el saldo según el tipo de movimiento if movimiento.tipo_movimiento.id == 1: # Supongamos que ID 1 es ingreso cuenta.saldo += movimiento.saldo elif movimiento.tipo_movimiento.id == 2: # ID 2 es egreso cuenta.saldo -= movimiento.saldo cuenta.save() movimiento.save() return redirect('lista_movimientos', cuenta_id=cuenta.id) else: form = RegistroMovimientosForm() return render(request, 'movimiento.html', {'form': form, 'cuenta': cuenta}) @login_required def actualizar_movimiento(request, movimiento_id): movimiento = get_object_or_404(Movimientos, id=movimiento_id) cuenta = movimiento.cuentas # Obtener la cuenta asociada saldo_anterior = movimiento.saldo # Guardar saldo anterior tipo_movimiento_anterior = movimiento.tipo_movimiento_id # Guardar tipo anterior if request.method == "POST": form = RegistroMovimientosForm(request.POST, instance=movimiento) if form.is_valid(): nuevo_movimiento = form.save(commit=False) # Restaurar saldo antes de actualizar (solo si cambió el tipo o saldo) if tipo_movimiento_anterior == 1: # Ingreso anterior cuenta.saldo -= saldo_anterior elif tipo_movimiento_anterior == 2: # Egreso anterior cuenta.saldo += saldo_anterior # Aplicar nuevo saldo if nuevo_movimiento.tipo_movimiento_id == 1: # Nuevo ingreso cuenta.saldo += nuevo_movimiento.saldo elif nuevo_movimiento.tipo_movimiento_id == 2: # Nuevo egreso cuenta.saldo -= nuevo_movimiento.saldo cuenta.save() # Guardar la cuenta con el saldo actualizado nuevo_movimiento.save() # Guardar el movimiento return redirect('lista_movimientos', cuenta_id=cuenta.id) else: form = RegistroMovimientosForm(instance=movimiento) return render(request, 'movimiento.html', {'form': form, 'cuenta': cuenta, 'movimiento': movimiento}) @login_required def lista_cuentas(request): if request.user.is_superuser: cuentas = Cuenta.objects.all() # Si es superusuario, puede ver todas las cuentas mostrar_todas = request.GET.get('todas', False) # Verifica si quiere ver todas las cuentas if not mostrar_todas: cuentas = cuentas.filter(responsable=request.user) # Muestra solo las propias si no activa la opción else: cuentas = Cuenta.objects.filter(responsable=request.user) # Usuario normal solo ve sus cuentas return render(request, 'lista_cuentas.html', {'cuentas': cuentas, 'es_superusuario': request.user.is_superuser}) @login_required def lista_movimientos(request, cuenta_id): cuenta = get_object_or_404(Cuenta, id=cuenta_id) # Obtiene la cuenta o muestra 404 movimientos = Movimientos.objects.filter(cuentas=cuenta) # Filtra por cuenta return render(request, 'lista_movimientos.html', { 'movimientos': movimientos, 'cuenta': cuenta # Para mostrar el nombre en el template }) @login_required def exportar_movimientos_excel(request, cuenta_id): # Obtener la cuenta cuenta = get_object_or_404(Cuenta, id=cuenta_id) # Obtener los movimientos de la cuenta movimientos = Movimientos.objects.filter(cuentas=cuenta) # Crear el archivo de Excel wb = openpyxl.Workbook() ws = wb.active ws.title = f"Movimientos de {cuenta.cuenta}" # Establecer el nombre de la cuenta en la primera fila ws.append([f"Cuenta: {cuenta.cuenta}"]) ws.append([]) # Espacio vacío antes de la tabla # Agregar encabezados encabezados = ["Fecha Inserción", "Tipo de Movimiento", "N° Factura", "Fecha Factura", "Proveedor", "Responsable", "Responsable Cuenta", "Saldo"] ws.append(encabezados) # Agregar datos de los movimientos for mov in movimientos: ws.append([ mov.fecha_insersion.strftime('%Y-%m-%d'), mov.tipo_movimiento.tipo_movimiento, # Asegúrate de que el modelo tenga 'nombre' mov.n_factura, mov.fecha_factura.strftime('%Y-%m-%d') if mov.fecha_factura else '', mov.proveedor, mov.responsable.username, mov.responsable_cuenta, mov.saldo ]) # Crear la respuesta HTTP con el archivo Excel response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = f'attachment; filename="Movimientos_{cuenta.cuenta}.xlsx"' wb.save(response) return response