feat: agrega rol 'publico' con UserProfile y permisos diferenciados

- Crea modelo UserProfile (OneToOne con User) con user_type: publico/user/administrator
- Señal post_save que crea UserProfile automáticamente al crear User
- UserSerializer.get_role() lee desde profile.user_type
- Nuevos permisos: IsNotPublico, IsPublico y actualiza IsAdministrator
- IsNotPublico restringe acceso a vistas de gestión (productos, clientes, ventas)
- CatalogSaleView.create permite publico; otras acciones requieren IsNotPublico
- UserProfile inline en admin de Usuarios
- Data migration para backfill de usuarios existentes
This commit is contained in:
2026-06-22 12:27:23 -05:00
parent 27b68a9ac2
commit 5b373bd15f
12 changed files with 177 additions and 15 deletions

View File

@@ -5,7 +5,7 @@ from rest_framework.permissions import IsAuthenticated
from ..models.customers import Customer
from ..serializers import CustomerSerializer
from ..permissions import IsAdministrator
from ..permissions import IsAdministrator, IsNotPublico
from ..services.tryton.customers import CustomerTrytonService
from ..services.tryton.client import get_tryton_client
@@ -13,7 +13,7 @@ from ..services.tryton.client import get_tryton_client
class CustomerView(viewsets.ModelViewSet):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
permission_classes = [IsAuthenticated]
permission_classes = [IsNotPublico]
class CustomersFromTrytonView(APIView):

View File

@@ -5,7 +5,7 @@ from rest_framework.permissions import AllowAny, IsAuthenticated
from ..models.products import Product
from ..serializers import ProductSerializer
from ..permissions import IsAdministrator
from ..permissions import IsAdministrator, IsNotPublico
from ..services.tryton.products import ProductTrytonService
from ..services.tryton.client import get_tryton_client
@@ -17,7 +17,7 @@ class ProductView(viewsets.ModelViewSet):
def get_permissions(self):
if self.action in ("list", "retrieve"):
return [AllowAny()]
return [IsAuthenticated()]
return [IsNotPublico()]
def get_queryset(self):
"""

View File

@@ -14,7 +14,7 @@ from ..serializers import (
SaleSummarySerializer,
CatalogSaleSummarySerializer,
)
from ..permissions import IsAdministrator
from ..permissions import IsAdministrator, IsNotPublico
from ..services.tryton.sales import SaleTrytonService
from ..services.tryton.client import get_tryton_client
from ..views import sales_to_tryton_csv
@@ -23,7 +23,7 @@ from ..views import sales_to_tryton_csv
class SaleView(viewsets.ModelViewSet):
queryset = Sale.objects.all()
serializer_class = SaleSerializer
permission_classes = [IsAuthenticated]
permission_classes = [IsNotPublico]
def create(self, request):
data = request.data
@@ -59,11 +59,15 @@ class SaleView(viewsets.ModelViewSet):
class CatalogSaleView(viewsets.ModelViewSet):
queryset = CatalogSale.objects.all()
serializer_class = CatalogSaleSerializer
permission_classes = [IsAuthenticated]
def get_permissions(self):
if self.action == "create":
return [IsAuthenticated()]
return [IsNotPublico()]
class SaleSummary(APIView):
permission_classes = [IsAuthenticated]
permission_classes = [IsNotPublico]
def get(self, request, id):
sale = Sale.objects.get(pk=id)
@@ -72,7 +76,7 @@ class SaleSummary(APIView):
class CatalogSaleSummary(APIView):
permission_classes = [IsAuthenticated]
permission_classes = [IsNotPublico]
def get(self, request, id):
catalog_sale = CatalogSale.objects.get(pk=id)

View File

@@ -1,6 +1,26 @@
from rest_framework.permissions import BasePermission
def _get_user_type(user):
if not user or not user.is_authenticated:
return None
profile = getattr(user, "profile", None)
if profile:
return profile.user_type
return "administrator" if user.is_staff else "user"
class IsAdministrator(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff
return _get_user_type(request.user) == "administrator"
class IsNotPublico(BasePermission):
def has_permission(self, request, view):
user_type = _get_user_type(request.user)
return user_type is not None and user_type != "publico"
class IsPublico(BasePermission):
def has_permission(self, request, view):
return _get_user_type(request.user) == "publico"