From b73ba1ef10d3065d2c6fa430896653ea5e0080ae Mon Sep 17 00:00:00 2001 From: Welton Moura Date: Sun, 5 Apr 2026 10:09:37 -0300 Subject: [PATCH] refactor: clean up product models, remove deployment files, and add media static serving configuration --- SYNC_GO_MIDDLEWARE.md | 54 ------------------------------------------- gestaoRaul/urls.py | 32 ++++++++++++++----------- products/models.py | 41 +++++++++++++++----------------- squarecloud.app | 7 ------ 4 files changed, 38 insertions(+), 96 deletions(-) delete mode 100644 SYNC_GO_MIDDLEWARE.md delete mode 100644 squarecloud.app diff --git a/SYNC_GO_MIDDLEWARE.md b/SYNC_GO_MIDDLEWARE.md deleted file mode 100644 index d12fbdd..0000000 --- a/SYNC_GO_MIDDLEWARE.md +++ /dev/null @@ -1,54 +0,0 @@ -# Guia de Sincronização: Django <-> Middleware Go - -Este documento descreve o funcionamento do sistema de **ChangeLog** implementado no Django para permitir que o middleware em Go mantenha uma cópia local (local-first) dos dados de forma eficiente. - -## 1. Funcionamento Técnico - -### Rastreamento de Mudanças (Django Signals) -Foi criada uma aplicação chamada `sync` que utiliza **Django Signals**. Sempre que um dos modelos abaixo é criado, editado ou excluído, uma entrada é gerada automaticamente na tabela `ChangeLog`: - -- `Product` -- `Comanda` -- `ProductComanda` -- `Order` -- `Client` -- `Categories` -- `Mesa` -- `Payments` - -### Tabela de Log (`ChangeLog`) -Cada registro no log contém: -- `id`: Identificador sequencial da mudança. -- `model_name`: Nome do modelo (ex: "Product"). -- `object_id`: ID do objeto que mudou. -- `action`: "SAVE" (para criação/edição) ou "DELETE". -- `timestamp`: Quando a mudança ocorreu. - -## 2. API de Sincronização - -O middleware Go deve consumir o seguinte endpoint: - -**Endpoint:** `GET /api/v1/sync/` - -### Parâmetros: -- `since_id` (opcional): Retorna apenas mudanças com ID maior que este valor. - -### Exemplo de Fluxo no Go: - -1. **Estado Inicial**: O Go armazena o `last_sync_id` (começando em 0). -2. **Polling**: De tempos em tempos (ex: a cada 5 segundos), o Go chama: - `GET http://seu-servidor/api/v1/sync/?since_id=100` (supondo que o último ID processado foi 100). -3. **Processamento**: - - O Django retorna uma lista de mudanças (ex: IDs 101, 102, 103). - - Para cada mudança `SAVE` no log, o Go deve fazer um `GET` no endpoint específico do modelo para buscar os dados atualizados: - - Se `model_name == "Product"`, buscar em `GET /api/v1/products/{object_id}/`. - - Para cada mudança `DELETE`, o Go deve remover o item correspondente do seu banco de dados local. -4. **Atualização**: O Go atualiza seu `last_sync_id` para o maior ID recebido (neste caso, 103). - -## 3. Vantagens -- **Performance**: O Go não precisa baixar todos os produtos/pedidos toda vez. Ele só baixa o que realmente mudou. -- **Detecção de Deleção**: O sistema informa explicitamente o que foi apagado no Django. -- **Resiliência**: Se a conexão cair, ao reconectar, o Go apenas retoma a partir do último ID que ele conhece, garantindo que nenhuma mudança seja perdida. - ---- -*Configurado em: 28 de Março de 2026* diff --git a/gestaoRaul/urls.py b/gestaoRaul/urls.py index 09aaf0c..7d8454b 100644 --- a/gestaoRaul/urls.py +++ b/gestaoRaul/urls.py @@ -14,21 +14,27 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static urlpatterns = [ - path('admin/', admin.site.urls), - path('', include('home.urls')), - path('login/', include('login.urls')), - path('products/', include('products.urls')), - path('mesas/', include('mesas.urls')), - path('typePay/', include('typePay.urls')), - path('clients/', include('clients.urls')), - path('comandas/', include('comandas.urls')), - path('categories/', include('categories.urls')), - path('balcao/', include('balcao.urls')), - path('pedidos/', include('orders.urls')), - path('', include('pwa.urls')), - path('api/v1/', include('gestaoRaul.api_urls')), + path("admin/", admin.site.urls), + path("", include("home.urls")), + path("login/", include("login.urls")), + path("products/", include("products.urls")), + path("mesas/", include("mesas.urls")), + path("typePay/", include("typePay.urls")), + path("clients/", include("clients.urls")), + path("comandas/", include("comandas.urls")), + path("categories/", include("categories.urls")), + path("balcao/", include("balcao.urls")), + path("pedidos/", include("orders.urls")), + path("", include("pwa.urls")), + path("api/v1/", include("gestaoRaul.api_urls")), ] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/products/models.py b/products/models.py index 56fa6c8..dd67669 100644 --- a/products/models.py +++ b/products/models.py @@ -4,11 +4,14 @@ from django.contrib.auth.models import User from categories.models import Categories - 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'") + 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 @@ -19,7 +22,7 @@ class Product(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=100) description = models.TextField(null=True, blank=True) - image = models.ImageField(null=True, blank=True) + image = models.ImageField(upload_to="products/%Y/%m/%d/", null=True, blank=True) price = models.DecimalField(max_digits=10, decimal_places=2) quantity = models.IntegerField(null=False, default=0) category = models.ForeignKey(Categories, on_delete=models.CASCADE) @@ -27,54 +30,48 @@ class Product(models.Model): 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 + 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." + 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'), + "self", + through="ProductComponent", + through_fields=("composite_product", "component_product"), symmetrical=False, - related_name='is_component_of' + related_name="is_component_of", ) - def __str__(self) -> str: return f"{self.name}" - 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." + 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." + 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." + help_text="Quantidade deste componente necessária para o produto composto.", ) class Meta: - unique_together = ('composite_product', 'component_product') + 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}" ) - - - - diff --git a/squarecloud.app b/squarecloud.app deleted file mode 100644 index 4dec696..0000000 --- a/squarecloud.app +++ /dev/null @@ -1,7 +0,0 @@ -DISPLAY_NAME=Gestao Raul API -DESCRIPTION=Sistema de Gestão para Restaurantes/Bares com API REST. -MAIN=gestaoRaul/wsgi.py -MEMORY=512 -VERSION=recommended -SUB_DOMAIN=gestao-raul # Escolha um subdomínio disponível -START=python manage.py collectstatic --noinput && python -m gunicorn gestaoRaul.wsgi:application --bind 0.0.0.0:80 --timeout 120