From 63f051c566056eaab6516c0d9de33f9800388505 Mon Sep 17 00:00:00 2001 From: Dulce Date: Mon, 18 May 2026 11:47:41 -0600 Subject: [PATCH] feature/T2026-05-031 agregar multiples rfc's a un usuario --- api/cuser/admin.py | 3 ++- api/cuser/models.py | 2 +- api/cuser/serializers.py | 27 ++++++++++++++++++-- api/notificaciones/signals/notificaciones.py | 2 +- api/vucem/views.py | 2 +- mixins/filtrado_organizacion.py | 10 ++++---- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/api/cuser/admin.py b/api/cuser/admin.py index d4553d9..bad0b2f 100644 --- a/api/cuser/admin.py +++ b/api/cuser/admin.py @@ -13,7 +13,7 @@ class CustomUserCreationForm(UserCreationForm): class CustomUserChangeForm(UserChangeForm): class Meta: model = CustomUser - fields = ('username', 'email', 'first_name', 'last_name', 'organizacion', 'profile_picture') + fields = ('username', 'email', 'first_name', 'last_name', 'organizacion', 'profile_picture', 'is_importador', 'rfc') class CustomUserAdmin(UserAdmin): @@ -25,6 +25,7 @@ class CustomUserAdmin(UserAdmin): list_filter = ('is_staff', 'is_active', 'organizacion') search_fields = ('username', 'email', 'first_name', 'last_name') ordering = ('username',) + filter_horizontal = ('rfc', 'groups', 'user_permissions') # Fieldsets para editar un usuario fieldsets = ( diff --git a/api/cuser/models.py b/api/cuser/models.py index fae5055..cdea1c9 100644 --- a/api/cuser/models.py +++ b/api/cuser/models.py @@ -12,7 +12,7 @@ class CustomUser(AbstractUser): profile_picture = models.ImageField(upload_to='profile_pictures/', null=True, blank=True) is_importador = models.BooleanField(default=False, help_text="Indicates if the user is an importer") - rfc = models.ForeignKey('customs.Importador', on_delete=models.SET_NULL, null=True, blank=True, related_name='users', help_text="RFC associated with the user if they are an importer") + rfc = models.ManyToManyField('customs.Importador', blank=True, related_name='users', help_text="RFCs de importadores asociados al usuario") def __str__(self): return self.username diff --git a/api/cuser/serializers.py b/api/cuser/serializers.py index 5549ab1..4fe722b 100644 --- a/api/cuser/serializers.py +++ b/api/cuser/serializers.py @@ -2,6 +2,7 @@ from rest_framework import serializers from .models import CustomUser from django.contrib.auth.models import Group +from api.customs.models import Importador class CustomUserSerializer(serializers.ModelSerializer): """ @@ -10,8 +11,12 @@ class CustomUserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) groups = serializers.PrimaryKeyRelatedField(queryset=Group.objects.all(), many=True, required=False) - rfc = serializers.CharField(max_length=20, required=False, allow_blank=True) - + rfc = serializers.PrimaryKeyRelatedField( + queryset=Importador.objects.all(), + many=True, + required=False, + pk_field=serializers.CharField(), + ) class Meta: model = CustomUser @@ -20,10 +25,28 @@ class CustomUserSerializer(serializers.ModelSerializer): def create(self, validated_data): groups = validated_data.pop('groups', []) + rfcs = validated_data.pop('rfc', []) password = validated_data.pop('password') user = CustomUser(**validated_data) user.set_password(password) user.save() if groups: user.groups.set(groups) + if rfcs: + user.rfc.set(rfcs) return user + + def update(self, instance, validated_data): + groups = validated_data.pop('groups', None) + rfcs = validated_data.pop('rfc', None) + password = validated_data.pop('password', None) + for attr, value in validated_data.items(): + setattr(instance, attr, value) + if password: + instance.set_password(password) + instance.save() + if groups is not None: + instance.groups.set(groups) + if rfcs is not None: + instance.rfc.set(rfcs) + return instance diff --git a/api/notificaciones/signals/notificaciones.py b/api/notificaciones/signals/notificaciones.py index 4878401..506f58c 100644 --- a/api/notificaciones/signals/notificaciones.py +++ b/api/notificaciones/signals/notificaciones.py @@ -19,7 +19,7 @@ def trigger_notificacion(sender, instance, created, **kwargs): for usuario in usuarios_org: # Notificar solo a importadores cuyo RFC coincide if (usuario.is_importador or usuario.groups.filter(name='Importador').exists()): - if usuario.rfc == instance.pedimento.contribuyente: + if instance.pedimento.contribuyente in usuario.rfc.all(): Notificacion.objects.create( tipo=tipo_info, dirigido=usuario, diff --git a/api/vucem/views.py b/api/vucem/views.py index 704c638..e37a1e7 100644 --- a/api/vucem/views.py +++ b/api/vucem/views.py @@ -84,7 +84,7 @@ class VucemView(viewsets.ModelViewSet): elif not hasattr(self.request.user, 'organizacion') or not self.request.user.organizacion: return queryset.none() elif self.request.user.groups.filter(name='Importador').exists(): - queryset = queryset.filter(organizacion=self.request.user.organizacion, usuario=self.request.user.rfc) + queryset = queryset.filter(organizacion=self.request.user.organizacion, usuario__in=self.request.user.rfc.all()) else: queryset = queryset.filter(organizacion=self.request.user.organizacion) diff --git a/mixins/filtrado_organizacion.py b/mixins/filtrado_organizacion.py index be52701..c708e2a 100644 --- a/mixins/filtrado_organizacion.py +++ b/mixins/filtrado_organizacion.py @@ -62,8 +62,8 @@ class OrganizacionFiltradaMixin: return model.objects.filter(**filtros_base) # if hasattr(model, self.campo_contribuyente): - if self.request.user.is_authenticated and 'Importador' in grupos : - filtros_base[f"{self.campo_contribuyente}__rfc"] = self.request.user.rfc.rfc + if self.request.user.is_authenticated and 'Importador' in grupos: + filtros_base[f"{self.campo_contribuyente}__in"] = self.request.user.rfc.all() return model.objects.filter(**filtros_base) # Si no entra en los roles válidos @@ -98,7 +98,7 @@ class DocumentosFiltradosMixin: if hasattr(model, self.campo_contribuyente): if self.request.user.is_authenticated and 'Importador' in grupos and getattr(self.request.user, 'is_importador', False): - filtros_base[f"{self.campo_contribuyente}__contribuyente"] = self.request.user.rfc + filtros_base[f"{self.campo_contribuyente}__contribuyente__in"] = self.request.user.rfc.all() return model.objects.filter(**filtros_base) # Si no entra en los roles válidos @@ -133,8 +133,8 @@ class ProcesosPorOrganizacionMixin: return model.objects.filter(**filtros_base) if hasattr(model, self.campo_pedimento): - if self.request.user.is_authenticated and'Importador' in grupos and getattr(self.request.user, 'is_importador', False): - filtros_base[f"{self.campo_pedimento}__contribuyente"] = self.request.user.rfc + if self.request.user.is_authenticated and 'Importador' in grupos and getattr(self.request.user, 'is_importador', False): + filtros_base[f"{self.campo_pedimento}__contribuyente__in"] = self.request.user.rfc.all() return model.objects.filter(**filtros_base) # Si no entra en los roles válidos