Overview
Inventario implements a role-based access control (RBAC) system with two primary roles: Admin and Vendedor (Salesperson). Each role has distinct permissions and access levels throughout the system.
User Model
Roles are defined directly in the Usuario model:
applications/cuentas/models.py
class Usuario ( AbstractUser ):
ROLES = (
( 'admin' , 'Administrador' ),
( 'vendedor' , 'Vendedor' ),
)
rol = models.CharField( max_length = 20 , choices = ROLES , default = 'admin' )
# Hierarchical relationship
creado_por = models.ForeignKey(
'self' ,
on_delete = models. CASCADE ,
null = True ,
blank = True ,
related_name = 'vendedores_creados'
)
def __str__ ( self ):
return f " { self .username } ( { self .get_rol_display() } )"
The creado_por field creates a hierarchical relationship where admins can create and manage their vendedor accounts.
Admin Role
Capabilities
Administrators have full access to the system:
User Management Create, edit, and delete vendedor accounts
Dashboard Access View comprehensive analytics and insights
Inventory Control Manage products, suppliers, and stock levels
Financial Reports Access sales reports, expenses, and profit analysis
Configuration Configure invoice settings and system preferences
Purchase Management Record purchases and manage expenses
Client Management Manage client database and relationships
AI Features Access AI-powered insights and recommendations
Admin-Only Views
Certain views are restricted to admins using the @admin_required decorator:
applications/cuentas/decorators.py
def admin_required ( view_func ):
"""🔒 Permite acceso solo a administradores"""
def wrapper ( request , * args , ** kwargs ):
if not request.user.is_authenticated:
messages.error(request, 'Debes iniciar sesión para continuar.' )
return redirect( 'login' )
if request.user.rol == 'admin' :
return view_func(request, * args, ** kwargs)
else :
messages.warning(request, 'Acceso restringido a administradores.' )
return redirect( 'ventas:lista_ventas' )
return wrapper
applications/cuentas/views.py
@admin_required
@login_required
@no_cache
def dashboard ( request ):
# Dashboard logic with hierarchical data filtering
usuarios_ids = get_subordinate_ids(request.user)
# ... analytics and reporting logic
The dashboard uses get_subordinate_ids() to show data only for the admin and their vendedores.
Vendedor Role
Capabilities
Vendedores (Salespeople) have focused access to sales operations:
Sales Management Create and view their own sales transactions
Product Catalog View available products and inventory
Client Information Access client information for sales
Invoice Generation Generate invoices for their sales
Vendedor Restrictions
Vendedores cannot :
Access the admin dashboard
Create or manage other users
Modify product inventory or prices
View financial reports or analytics
Access purchase management
Change system configuration
View sales from other vendedores
Vendedor-Only Decorator
applications/cuentas/decorators.py
def vendedor_required ( view_func ):
"""🛒 Permite acceso solo a vendedores"""
def wrapper ( request , * args , ** kwargs ):
if not request.user.is_authenticated:
messages.error(request, 'Debes iniciar sesión para continuar.' )
return redirect( 'login' )
if request.user.rol == 'vendedor' :
return view_func(request, * args, ** kwargs)
else :
messages.warning(request, 'Acceso restringido a vendedores.' )
return redirect( 'dashboard' )
return wrapper
Role Assignment
Creating Vendedor Accounts
Only admins can create vendedor accounts through the user management interface:
Admin Accesses User List
Navigate to the user management section (restricted to admins).
Create New User
Fill out the user creation form: class UsuarioForm ( forms . ModelForm ):
def __init__ ( self , * args , ** kwargs ):
super (). __init__ ( * args, ** kwargs)
# Limit role choices to 'Vendedor' only
self .fields[ 'rol' ].choices = [( 'vendedor' , 'Vendedor' )]
Automatic Assignment
The system automatically assigns the creating admin as the vendedor’s supervisor: nuevo_usuario = form.save( commit = False )
nuevo_usuario.creado_por = request.user
nuevo_usuario.save()
Password Setup
New vendedores receive a temporary password and are required to change it on first login: nuevo_usuario.debe_cambiar_password = True
Security Note : The user creation form only allows admins to create vendedor accounts. Admins cannot create other admin accounts through the UI.
applications/usuarios/forms.py
class UsuarioForm ( forms . ModelForm ):
password = forms.CharField(
widget = forms.PasswordInput( attrs = {
'class' : 'form-control password-input' ,
'placeholder' : 'Dejar vacío para no cambiar'
}),
label = "Contraseña" ,
required = False
)
def __init__ ( self , * args , ** kwargs ):
super (). __init__ ( * args, ** kwargs)
if not self .instance.pk:
self .fields[ 'password' ].required = True
# 🔹 Limit role options to 'Vendedor' only
self .fields[ 'rol' ].choices = [( 'vendedor' , 'Vendedor' )]
class Meta :
model = Usuario
fields = [ 'username' , 'nombre' , 'apellido' , 'email' , 'telefono' , 'rol' , 'password' ]
Hierarchical Data Access
Subordinate Filtering
Admins only see data for themselves and their vendedores:
applications/cuentas/utils.py
def get_subordinate_ids ( user ):
"""
Returns list of user IDs including the user and all vendedores created by them.
"""
if user.rol == 'admin' :
subordinates = Usuario.objects.filter( creado_por = user).values_list( 'id' , flat = True )
return [user.id] + list (subordinates)
return [user.id]
Application in Views
applications/cuentas/views.py
applications/usuarios/views.py
@admin_required
@login_required
def dashboard ( request ):
# Filter data hierarchically
usuarios_ids = get_subordinate_ids(request.user)
# Query only relevant data
detalles = DetalleVenta.objects.filter(
venta__fecha_venta__gte = inicio,
venta__vendedor__id__in = usuarios_ids
)
This hierarchical model ensures data isolation between different admin accounts and their vendedor teams.
Multi-User Workflows
Sales Attribution
Each sale is automatically attributed to the logged-in user:
venta.vendedor = request.user
venta.save()
Reporting & Analytics
Admins can:
View aggregated sales across their team
Compare performance between vendedores
Filter reports by vendedor
Track individual contributions
The dashboard automatically aggregates data from all subordinate vendedores, providing a complete view of team performance.
Login Redirects
Users are automatically redirected based on their role after login:
applications/cuentas/views.py
if usuario:
login(request, usuario)
messages.success(request, f 'Bienvenido { usuario.username } ' )
# Role-based redirect
if usuario.is_superuser:
return redirect( '/admin/' )
elif usuario.rol == 'admin' :
return redirect( 'dashboard' )
elif usuario.rol == 'vendedor' :
return redirect( 'ventas:lista_ventas' )
return redirect( 'home' )
Superuser → /admin/ (Django admin panel)
Admin → /dashboard/ (Analytics dashboard)
Vendedor → Sales list (Operational view)
Permission Management
User List Access Control
applications/usuarios/views.py
@login_required
@admin_required
def lista_usuarios ( request ):
# Show only users created by the current admin
usuarios_list = Usuario.objects.filter( creado_por = request.user)
paginator = Paginator(usuarios_list, 7 )
# ... pagination logic
Edit/Delete Restrictions
Admins can only edit/delete vendedores they created:
applications/usuarios/views.py
@login_required
@admin_required
def editar_usuario ( request , id ):
# Ensures admin can only edit their own vendedores
usuario = get_object_or_404(Usuario, id = id , creado_por = request.user)
# ... edit logic
@login_required
@admin_required
def eliminar_usuario ( request , id ):
# Ensures admin can only delete their own vendedores
usuario = get_object_or_404(Usuario, id = id , creado_por = request.user)
# ... delete logic
Cascade Deletion : When an admin account is deleted, all vendedor accounts created by that admin are also deleted due to the on_delete=models.CASCADE relationship.
Best Practices
Always assign vendedores to the correct admin supervisor
Require password changes for new vendedor accounts
Use strong password validation rules
Regularly audit user accounts and permissions
Always filter queries using get_subordinate_ids()
Verify ownership before allowing edits/deletes
Use get_object_or_404 with ownership filters
Test multi-admin scenarios thoroughly
Apply @admin_required to sensitive views
Use @vendedor_required for role-specific features
Combine with @login_required for authentication
Implement proper error messages for unauthorized access
Authentication Learn about login methods and security
Profile Management Manage user profiles and settings
Security Configuration Advanced security and access control
Authentication API Programmatic authentication and user management