from django.shortcuts import render,redirect,get_object_or_404 from django.template.loader import get_template from django.http import HttpResponse from django.contrib import messages from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import login, logout, authenticate from django.db import transaction from django.utils import timezone from django.contrib.auth.decorators import login_required from django.db.models import Avg, Sum from decimal import Decimal from django.db.models import F from .forms import formulario_proveedor,formulario_bodega, formulario_tipo, formulario_articulo,formilario_inventario,VentaForm from .models import proveedor, bodega, tipo_articulo, articulo,inventario,tipo_inv_movimiento,movimiento_inventario,Venta # Create your views here. def base(request): return render(request, 'index.html') def graficos_view(request): # 1. Ventas por bodega ventas_por_bodega = ( Venta.objects.values("bodega__nombre_bodega") .annotate(total_ventas=Sum("total")) ) for item in ventas_por_bodega: item["total_ventas"] = float(Decimal(item["total_ventas"] or 0)) # Convertir a float # 2. Inventario total por artículo inventario_total = ( inventario.objects.values("articulo__nombre_articulo") .annotate(total=Sum("cantidad")) ) # 3. Ventas por artículo ventas_por_articulo = ( Venta.objects.values("articulo__nombre_articulo") .annotate(total=Sum("cantidad")) ) # 4. Comparación de precios de artículos precios_articulos = list(articulo.objects.values( "nombre_articulo", "precio_compra", "precio_venta", )) for item in precios_articulos: item["precio_compra"] = float(Decimal(item["precio_compra"] or 0)) # Convertir a float item["precio_venta"] = float(Decimal(item["precio_venta"] or 0)) # Convertir a float # Calcular el total de ventas total_ventas = Venta.objects.aggregate(total_ventas=Sum('total'))['total_ventas'] or Decimal(0) # Calcular el total de productos en inventario total_productos_en_inventario = inventario.objects.aggregate(total_productos=Sum('cantidad'))['total_productos'] or 0 # Calcular el total de artículos vendidos total_articulos_vendidos = ventas_por_articulo.aggregate(total_vendidos=Sum('total'))['total_vendidos'] or 0 # Calcular el total de proveedores total_proveedores = proveedor.objects.count() context = { "ventas_por_bodega": list(ventas_por_bodega), "inventario_total": list(inventario_total), "ventas_por_articulo": list(ventas_por_articulo), "precios_articulos": precios_articulos, "total_ventas": float(total_ventas), # Sumar todas las ventas totales "total_productos_en_inventario": total_productos_en_inventario, # Número total de productos en inventario "total_articulos_vendidos": total_articulos_vendidos, # Total de unidades vendidas "total_proveedores": total_proveedores, # Número de proveedores } return render(request, "index.html", context) def signin(request): if request.method == 'GET': return render ( request, 'signin.html',{ 'form': AuthenticationForm }) else: user=authenticate(request, username=request.POST['username'], password=request.POST['password']) if user is None: return render ( request, 'signin.html',{ 'form': AuthenticationForm , 'error': 'Username or password is incorrect' }) else: login(request, user) return redirect('home') @login_required def signout(request): logout(request) return redirect('home') @login_required def proveedor_registro(request): if request.method=='GET': return render(request, 'proveedor_nuevo.html',{ 'form': formulario_proveedor }) else: try: form = formulario_proveedor (request.POST) new_proveedor=form.save(commit=False) new_proveedor.save() return redirect('proveedor') except ValueError: return render(request, 'proveedor_nuevo.html',{ 'form': formulario_proveedor, 'error':'porfavor ingrese bien los datos' }) @login_required def proveedor_lista(request): persona = proveedor.objects.all return render(request,"proveedor_registro.html", {'persona':persona}) @login_required def Proveedor_update(request,task_id): if request.method == 'GET': tarea = get_object_or_404 (proveedor, pk=task_id) form = formulario_proveedor(instance=tarea) return render(request, 'proveedor_update.html',{'tasks':tarea, 'form':form} ) else: try: tarea=get_object_or_404(proveedor,pk=task_id) form = formulario_proveedor(request.POST, instance=tarea) form.save() return redirect('proveedor') except ValueError: return render(request, 'proveedor_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} ) @login_required def bodega_registro(request): if request.method=='GET': return render(request, 'bodega_nuevo.html',{ 'form': formulario_bodega }) else: try: form = formulario_bodega (request.POST) new_bodega=form.save(commit=False) new_bodega.save() return redirect('bodega_vista') except ValueError: return render(request, 'bodega_nuevo.html',{ 'form': formulario_bodega, 'error':'Please provide valid data' }) @login_required def bodega_vista(request): persona = bodega.objects.all return render(request,"bodega_registro.html", {'persona':persona}) @login_required def bodega_update(request,task_id): if request.method == 'GET': tarea = get_object_or_404 (bodega, pk=task_id) form = formulario_bodega(instance=tarea) return render(request, 'bodega_update.html',{'tasks':tarea, 'form':form} ) else: try: tarea=get_object_or_404(bodega,pk=task_id) form = formulario_bodega(request.POST, instance=tarea) form.save() return redirect('bodega_vista') except ValueError: return render(request, 'bodega_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} ) @login_required def tipo_registro(request): if request.method=='GET': return render(request, 'tipo_articulo_nuevo.html',{ 'form': formulario_tipo }) else: try: form = formulario_tipo (request.POST) new_tipo=form.save(commit=False) new_tipo.save() return redirect('tipo_vista') except ValueError: return render(request, 'tipo_articulo_nuevo.html',{ 'form': formulario_tipo, 'error':'Please provide valid data' }) @login_required def tipo_vista(request): persona = tipo_articulo.objects.all return render(request,"tipo_articulo_registro.html", {'persona':persona}) @login_required def tipo_update(request,task_id): if request.method == 'GET': tarea = get_object_or_404 (tipo_articulo, pk=task_id) form = formulario_tipo(instance=tarea) return render(request, 'tipo_articulo_update.html',{'tasks':tarea, 'form':form} ) else: try: tarea=get_object_or_404(tipo_articulo,pk=task_id) form = formulario_tipo(request.POST, instance=tarea) form.save() return redirect('tipo_vista') except ValueError: return render(request, 'tipo_articulo_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} ) @login_required def articulo_registro(request): if request.method=='GET': return render(request, 'articulo_nuevo.html',{ 'form': formulario_articulo }) else: try: form = formulario_articulo (request.POST) form.save() return redirect('articulo_vista') except ValueError: return render(request, 'articulo_nuevo.html',{ 'form': formulario_articulo, 'error':'Please provide valid data' }) @login_required def articulo_vista(request): persona = articulo.objects.select_related('tipo_articulo','proveedor').all() return render(request,"articulo_registro.html", {'persona':persona}) @login_required def articulo_update(request,task_id): if request.method == 'GET': tarea = get_object_or_404 (articulo, pk=task_id) form = formulario_articulo(instance=tarea) return render(request, 'articulo_update.html',{'tasks':tarea, 'form':form} ) else: try: tarea=get_object_or_404(articulo,pk=task_id) form = formulario_articulo(request.POST, instance=tarea) form.save() return redirect('articulo_vista') except ValueError: return render(request, 'articulo_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating'} ) @login_required def inventario_registro(request): if request.method=='GET': return render(request, 'inventario_nuevo.html',{ 'form': formilario_inventario }) else: try: form = formilario_inventario (request.POST) form.save() form = formilario_inventario () return render(request, 'inventario_nuevo.html',{ 'form': formilario_inventario, 'mensaje':'Please provide valid data' }) except ValueError: return render(request, 'inventario_nuevo.html',{ 'form': formilario_inventario, 'error':'Please provide valid data' }) @login_required def inventario_vista(request): persona = inventario.objects.select_related('articulo','bodega').all() return render(request,"inventario_registro.html", {'persona':persona}) def registrar_movimiento_y_actualizar_inventario(movimiento_data): """ Registra un movimiento de inventario y actualiza el inventario relacionado. """ try: with transaction.atomic(): # Registrar el movimiento de inventario movimiento = movimiento_inventario.objects.create( articulo=movimiento_data['articulo'], bodega=movimiento_data['bodega'], tipo_inventario=movimiento_data['tipo_inventario'], cantidad=movimiento_data['cantidad'], observaciones=movimiento_data.get('observaciones', '') ) # Buscar o crear el inventario correspondiente inventario_obj, created = inventario.objects.get_or_create( articulo=movimiento.articulo, bodega=movimiento.bodega, defaults={'cantidad': 0} ) # Comprobación y actualización según el tipo de movimiento if movimiento.tipo_inventario.id == 1: inventario_obj.cantidad += movimiento.cantidad elif movimiento.tipo_inventario.id == 2: if inventario_obj.cantidad < movimiento.cantidad: raise ValueError( f"No hay suficiente stock. Disponible: {inventario_obj.cantidad}, solicitado: {movimiento.cantidad}" ) inventario_obj.cantidad -= movimiento.cantidad # Guardar los cambios en el inventario inventario_obj.save() return movimiento, inventario_obj except Exception as e: raise ValueError(f"Error al registrar movimiento y actualizar inventario: {str(e)}") def nueva_venta(request): if request.method == 'POST': form = VentaForm(request.POST) if form.is_valid(): venta = form.save(commit=False) # Verificar si el artículo existe en la bodega seleccionada try: inventario_item = inventario.objects.get( bodega=venta.bodega, articulo=venta.articulo ) except inventario.DoesNotExist: form.add_error('articulo', 'El artículo no existe en la bodega seleccionada.') return render(request, 'nueva_venta.html', {'form': form}) # Validar que haya suficiente cantidad en el inventario if inventario_item.cantidad >= venta.cantidad: # Guardar la venta venta.save() return redirect('lista_ventas') # Redirigir al listado de ventas else: form.add_error('cantidad', 'Cantidad en inventario insuficiente.') else: form = VentaForm() return render(request, 'nueva_venta.html', {'form': form}) def registrar_movimiento(request): """ Vista para registrar un nuevo movimiento de inventario. """ if request.method == 'POST': form = formilario_inventario(request.POST) if form.is_valid(): movimiento_data = form.cleaned_data try: movimiento, inventario_obj = registrar_movimiento_y_actualizar_inventario(movimiento_data) return redirect('vista_inventario_mov') # Redirigir a una página de éxito except ValueError as e: return render(request, 'inventario_nuevo.html', { 'form': form, 'error': str(e) }) else: form = formilario_inventario() return render(request, 'inventario_nuevo.html', {'form': form}) @login_required def vista_inventario_mov(request): persona = movimiento_inventario.objects.select_related('articulo','bodega','tipo_inventario').all() return render(request,"mov_inventario_registro.html", {'persona':persona}) def lista_ventas(request): ventas = Venta.objects.all() return render(request, 'ventas.html', {'ventas': ventas})