You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

107 lines
4.5 KiB

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)