from django.db import models from django.contrib.auth.models import User from django.db import transaction # Create your models here. class tipo_articulo(models.Model): tipo_articulo= models.CharField(max_length=40) descripcion=models.TextField(blank=True) def __str__(self): return self.tipo_articulo class proveedor(models.Model): nombre_proveedor=models.CharField(max_length=100) email = models.EmailField(null=True, blank=True) telefono = models.CharField(max_length=20, null=True, blank=True) direccion = models.TextField(null=True, blank=True) def __str__(self): return self.nombre_proveedor class tipo_inv_movimiento(models.Model): tipo_movimiento=models.CharField(max_length=100) def __str__(self): return self.tipo_movimiento class bodega(models.Model): codigo_bodega=models.IntegerField(null=True) nombre_bodega= models.CharField(max_length=40) direccion_bodega=models.TextField(blank=True) estado= models.BooleanField(default=True) def __str__(self): return self.nombre_bodega class articulo(models.Model): nombre_articulo=models.CharField(max_length=100) medida = models.CharField(max_length=100, blank=True, null=True) descripcion = models.TextField(blank=True) precio_compra=models.DecimalField( max_digits=10, decimal_places=2, null=True) precio_venta=models.DecimalField( max_digits=10, decimal_places=2, null=True) proveedor = models.ForeignKey(proveedor, on_delete=models.CASCADE) tipo_articulo=models.ForeignKey(tipo_articulo, on_delete=models.CASCADE) def __str__(self): return self.nombre_articulo class inventario(models.Model): bodega=models.ForeignKey(bodega, on_delete=models.CASCADE) articulo=models.ForeignKey(articulo, on_delete=models.CASCADE) cantidad=models.IntegerField(null=True) class Venta(models.Model): fecha = models.DateTimeField(auto_now_add=True) bodega = models.ForeignKey(bodega, on_delete=models.CASCADE) articulo = models.ForeignKey(articulo, on_delete=models.CASCADE) cantidad = models.PositiveIntegerField() precio_unitario = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True) total = models.DecimalField(max_digits=12, decimal_places=2, blank=True) observaciones = models.TextField(blank=True) def save(self, *args, **kwargs): # Asignar el precio de venta del artículo si no se ha definido if not self.precio_unitario: self.precio_unitario = self.articulo.precio_venta or 0 # Calcular el total antes de guardar if not self.total: self.total = self.cantidad * self.precio_unitario # Usar una transacción atómica para asegurar que todo suceda de forma consistente with transaction.atomic(): # Guardar la venta primero super(Venta, self).save(*args, **kwargs) # Obtener el artículo y bodega para verificar el inventario inventario_item = inventario.objects.get(bodega=self.bodega, articulo=self.articulo) # Verificar que haya suficiente cantidad en el inventario if inventario_item.cantidad >= self.cantidad: # Crear el movimiento de inventario (salida) tipo_salida = tipo_inv_movimiento.objects.get(tipo_movimiento="Salida") movimiento = movimiento_inventario( tipo_inventario=tipo_salida, bodega=self.bodega, articulo=self.articulo, cantidad=self.cantidad, observaciones=f"Salida por venta. {self.observaciones}" ) movimiento.save() # Actualizar el inventario después de la venta inventario_item.cantidad -= self.cantidad inventario_item.save() else: # Si no hay suficiente inventario, lanzar una excepción raise ValueError("No hay suficiente inventario para realizar esta venta.") def __str__(self): return f"Venta de {self.articulo.nombre_articulo} - {self.cantidad} unidades" class movimiento_inventario(models.Model): fecha=models.DateTimeField(null=True, auto_now_add=True) tipo_inventario=models.ForeignKey(tipo_inv_movimiento,on_delete=models.CASCADE) bodega=models.ForeignKey(bodega, on_delete=models.CASCADE) articulo=models.ForeignKey(articulo, on_delete=models.CASCADE) cantidad=models.IntegerField(null=True) observaciones=models.TextField(blank=True)