diff --git a/gestaoRaul/comandas/__pycache__/models.cpython-312.pyc b/gestaoRaul/comandas/__pycache__/models.cpython-312.pyc index 6b5b583..3c572ee 100644 Binary files a/gestaoRaul/comandas/__pycache__/models.cpython-312.pyc and b/gestaoRaul/comandas/__pycache__/models.cpython-312.pyc differ diff --git a/gestaoRaul/comandas/migrations/0005_stockmovementtype_stockmovement.py b/gestaoRaul/comandas/migrations/0005_stockmovementtype_stockmovement.py new file mode 100644 index 0000000..1dd6d62 --- /dev/null +++ b/gestaoRaul/comandas/migrations/0005_stockmovementtype_stockmovement.py @@ -0,0 +1,42 @@ +# Generated by Django 5.1.4 on 2025-07-22 18:36 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comandas', '0004_comanda_user'), + ('products', '0004_unitofmeasure_productcomponent_product_components_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='StockMovementType', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(help_text="Ex: 'Entrada por Compra', 'Saída por Venda', 'Ajuste de Estoque'", max_length=100, unique=True)), + ('observation', models.TextField(blank=True, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='StockMovement', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('quantity', models.IntegerField(help_text='Quantidade movimentada. Use valores negativos para saídas.')), + ('observation', models.TextField(blank=True, null=True)), + ('movement_date', models.DateTimeField(auto_now_add=True)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_movements', to='products.product')), + ('related_comanda', models.ForeignKey(blank=True, help_text='Comanda relacionada à movimentação (opcional).', null=True, on_delete=django.db.models.deletion.SET_NULL, to='comandas.comanda')), + ('user', models.ForeignKey(blank=True, help_text='Usuário que realizou a movimentação.', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('movement_type', models.ForeignKey(help_text='Tipo de movimentação (entrada, saída, ajuste).', on_delete=django.db.models.deletion.PROTECT, to='comandas.stockmovementtype')), + ], + options={ + 'ordering': ['-movement_date'], + }, + ), + ] diff --git a/gestaoRaul/comandas/migrations/__pycache__/0005_stockmovementtype_stockmovement.cpython-312.pyc b/gestaoRaul/comandas/migrations/__pycache__/0005_stockmovementtype_stockmovement.cpython-312.pyc new file mode 100644 index 0000000..a1c63ed Binary files /dev/null and b/gestaoRaul/comandas/migrations/__pycache__/0005_stockmovementtype_stockmovement.cpython-312.pyc differ diff --git a/gestaoRaul/comandas/models.py b/gestaoRaul/comandas/models.py index 6e6bf59..56235be 100644 --- a/gestaoRaul/comandas/models.py +++ b/gestaoRaul/comandas/models.py @@ -43,4 +43,39 @@ class ProductComanda(models.Model): for p in products: if p.name == produto['nome'] and p.active == True: products_ordenados.append(p) - return products_ordenados[:15] \ No newline at end of file + return products_ordenados[:15] + + +class StockMovementType(models.Model): + id = models.AutoField(primary_key=True) + name = models.CharField(max_length=100, unique=True, help_text="Ex: 'Entrada por Compra', 'Saída por Venda', 'Ajuste de Estoque'") + observation = models.TextField(null=True, blank=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class StockMovement(models.Model): + id = models.AutoField(primary_key=True) + product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='stock_movements') + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, help_text="Usuário que realizou a movimentação.") + related_comanda = models.ForeignKey( + Comanda, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Comanda relacionada à movimentação (opcional)." + ) + movement_type = models.ForeignKey(StockMovementType, on_delete=models.PROTECT, help_text="Tipo de movimentação (entrada, saída, ajuste).") + quantity = models.IntegerField(help_text="Quantidade movimentada. Use valores negativos para saídas.") + observation = models.TextField(null=True, blank=True) + movement_date = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return ( + f"Movimentação de {self.quantity} de {self.product.name} " + f"({self.movement_type.name}) em {self.movement_date.strftime('%d/%m/%Y %H:%M')}" + ) + + class Meta: + ordering = ['-movement_date'] \ No newline at end of file diff --git a/gestaoRaul/db.sqlite3 b/gestaoRaul/db.sqlite3 index d6770f1..663c5a7 100644 Binary files a/gestaoRaul/db.sqlite3 and b/gestaoRaul/db.sqlite3 differ diff --git a/gestaoRaul/products/__pycache__/models.cpython-312.pyc b/gestaoRaul/products/__pycache__/models.cpython-312.pyc index 11aac8f..a9e6b0d 100644 Binary files a/gestaoRaul/products/__pycache__/models.cpython-312.pyc and b/gestaoRaul/products/__pycache__/models.cpython-312.pyc differ diff --git a/gestaoRaul/products/migrations/0004_unitofmeasure_productcomponent_product_components_and_more.py b/gestaoRaul/products/migrations/0004_unitofmeasure_productcomponent_product_components_and_more.py new file mode 100644 index 0000000..c8c7a3a --- /dev/null +++ b/gestaoRaul/products/migrations/0004_unitofmeasure_productcomponent_product_components_and_more.py @@ -0,0 +1,44 @@ +# Generated by Django 5.1.4 on 2025-07-22 18:36 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('products', '0003_product_cuisine'), + ] + + operations = [ + migrations.CreateModel( + name='UnitOfMeasure', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(help_text="Ex: 'Unidade', 'Kg', 'Litro'", max_length=50, unique=True)), + ('abbreviation', models.CharField(help_text="Ex: 'un', 'kg', 'L'", max_length=10, unique=True)), + ], + ), + migrations.CreateModel( + name='ProductComponent', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity_required', models.PositiveIntegerField(default=1, help_text='Quantidade deste componente necessária para o produto composto.')), + ('component_product', models.ForeignKey(help_text='Um produto que é componente de outro produto.', on_delete=django.db.models.deletion.CASCADE, related_name='used_as_component_in', to='products.product')), + ('composite_product', models.ForeignKey(help_text='O produto que é composto por outros produtos.', on_delete=django.db.models.deletion.CASCADE, related_name='composition_entries', to='products.product')), + ], + options={ + 'unique_together': {('composite_product', 'component_product')}, + }, + ), + migrations.AddField( + model_name='product', + name='components', + field=models.ManyToManyField(related_name='is_component_of', through='products.ProductComponent', to='products.product'), + ), + migrations.AddField( + model_name='product', + name='unit_of_measure', + field=models.ForeignKey(blank=True, help_text='Unidade de medida para este produto.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='products.unitofmeasure'), + ), + ] diff --git a/gestaoRaul/products/migrations/__pycache__/0004_unitofmeasure_productcomponent_product_components_and_more.cpython-312.pyc b/gestaoRaul/products/migrations/__pycache__/0004_unitofmeasure_productcomponent_product_components_and_more.cpython-312.pyc new file mode 100644 index 0000000..9ada42c Binary files /dev/null and b/gestaoRaul/products/migrations/__pycache__/0004_unitofmeasure_productcomponent_product_components_and_more.cpython-312.pyc differ diff --git a/gestaoRaul/products/models.py b/gestaoRaul/products/models.py index 93e978b..7d3c312 100644 --- a/gestaoRaul/products/models.py +++ b/gestaoRaul/products/models.py @@ -1,6 +1,18 @@ from django.db import models +from django.contrib.auth.models import User from categories.models import Categories +# from comandas.models import Comanda + + + +class UnitOfMeasure(models.Model): + id = models.AutoField(primary_key=True) + name = models.CharField(max_length=50, unique=True, help_text="Ex: 'Unidade', 'Kg', 'Litro'") + abbreviation = models.CharField(max_length=10, unique=True, help_text="Ex: 'un', 'kg', 'L'") + + def __str__(self): + return self.abbreviation # Create your models here. @@ -14,6 +26,23 @@ class Product(models.Model): category = models.ForeignKey(Categories, on_delete=models.CASCADE) cuisine = models.BooleanField(default=False) active = models.BooleanField(default=True) + unit_of_measure = models.ForeignKey( + UnitOfMeasure, + on_delete=models.SET_NULL, # Define como NULL se a unidade de medida for excluída + null=True, + blank=True, + help_text="Unidade de medida para este produto." + ) + + # Campo de composição (mantido da resposta anterior) + components = models.ManyToManyField( + 'self', + through='ProductComponent', + through_fields=('composite_product', 'component_product'), + symmetrical=False, + related_name='is_component_of' + ) + def __str__(self) -> str: return f"{self.name}" @@ -25,3 +54,36 @@ class Product(models.Model): def addStock(self, qtd): self.quantity += qtd self.save() + + + +class ProductComponent(models.Model): + composite_product = models.ForeignKey( + Product, + on_delete=models.CASCADE, + related_name='composition_entries', + help_text="O produto que é composto por outros produtos." + ) + component_product = models.ForeignKey( + Product, + on_delete=models.CASCADE, + related_name='used_as_component_in', + help_text="Um produto que é componente de outro produto." + ) + quantity_required = models.PositiveIntegerField( + default=1, + help_text="Quantidade deste componente necessária para o produto composto." + ) + + class Meta: + unique_together = ('composite_product', 'component_product') + + def __str__(self): + return ( + f"{self.composite_product.name} requer " + f"{self.quantity_required} de {self.component_product.name}" + ) + + + +