This commit is contained in:
gitea 2025-02-19 13:56:19 +00:00
parent 7d93bfde9f
commit fe0f0d836d
14 changed files with 536 additions and 20 deletions

View File

@ -1,3 +1,5 @@
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group
from appointment.models import Appointment, Service, StaffMember from appointment.models import Appointment, Service, StaffMember
from django.urls import reverse from django.urls import reverse
from django_countries.widgets import CountrySelectWidget from django_countries.widgets import CountrySelectWidget
@ -896,3 +898,27 @@ class OpportunityStatusForm(forms.Form):
required=True, required=True,
) )
class GroupForm(forms.ModelForm):
class Meta:
model = Group
fields = ["name"]
class PermissionForm(forms.ModelForm):
name = forms.ModelMultipleChoiceField(
queryset=Permission.objects.filter(content_type__app_label='inventory'),
widget=forms.CheckboxSelectMultiple(),
required=True
)
class Meta:
model = Permission
fields = ["name"]
class UserGroupForm(forms.ModelForm):
name = forms.ModelMultipleChoiceField(
queryset= Group.objects.all(),
widget=forms.CheckboxSelectMultiple(),
required=True
)
class Meta:
model = Group
fields = ["name"]

View File

@ -54,7 +54,6 @@ class InjectDealerMiddleware:
try: try:
dealer = get_user_type(request) dealer = get_user_type(request)
request.user.dealer = dealer request.user.dealer = dealer
except Exception as e: except Exception as e:
pass pass
response = self.get_response(request) response = self.get_response(request)

View File

@ -938,6 +938,13 @@ class Staff(models.Model, LocalizedNameMixin):
objects = StaffUserManager() objects = StaffUserManager()
@property
def user(self):
return self.staff_member.user
@property
def groups(self):
return self.staff_member.user.groups
class Meta: class Meta:
verbose_name = _("Staff") verbose_name = _("Staff")
verbose_name_plural = _("Staff") verbose_name_plural = _("Staff")

View File

@ -336,6 +336,14 @@ urlpatterns = [
path("user/<int:pk>/", views.UserDetailView.as_view(), name="user_detail"), path("user/<int:pk>/", views.UserDetailView.as_view(), name="user_detail"),
path("user/", views.UserListView.as_view(), name="user_list"), path("user/", views.UserListView.as_view(), name="user_list"),
path("user/<int:pk>/confirm/", views.UserDeleteview, name="user_delete"), path("user/<int:pk>/confirm/", views.UserDeleteview, name="user_delete"),
path("user/<int:pk>/groups/", views.UserGroupView, name="user_groups"),
# Group URLs
path("group/create/", views.GroupCreateView.as_view(), name="group_create"),
path("group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"),
path("group/<int:pk>/", views.GroupDetailView.as_view(), name="group_detail"),
path("group/", views.GroupListView.as_view(), name="group_list"),
path("group/<int:pk>/confirm/", views.GroupDeleteview, name="group_delete"),
path("group/<int:pk>/permission/", views.GroupPermissionView, name="group_permission"),
# Organization URLs # Organization URLs
path( path(
"organizations/", views.OrganizationListView.as_view(), name="organization_list" "organizations/", views.OrganizationListView.as_view(), name="organization_list"

View File

@ -1,4 +1,5 @@
from django.db.models import Func from django.db.models import Func
from django.contrib.auth.models import Permission
from appointment.models import Appointment,AppointmentRequest,Service,StaffMember from appointment.models import Appointment,AppointmentRequest,Service,StaffMember
from datetime import timedelta from datetime import timedelta
from calendar import month_name from calendar import month_name
@ -1845,8 +1846,142 @@ def delete_vendor(request, pk):
# slug_field = "order_id" # slug_field = "order_id"
# slug_url_kwarg = "order_id" # slug_url_kwarg = "order_id"
#group
class GroupListView(LoginRequiredMixin, ListView):
model = Group
context_object_name = "groups"
paginate_by = 10
template_name = "groups/group_list.html"
# def get_queryset(self):
# query = self.request.GET.get("q")
# dealer = get_user_type(self.request)
# staff = models.Staff.objects.filter(dealer=dealer).all()
# return apply_search_filters(staff, query)
class GroupDetailView(LoginRequiredMixin, DetailView):
model = Group
template_name = "groups/group_detail.html"
context_object_name = "group"
class GroupCreateView(
LoginRequiredMixin,
SuccessMessageMixin,
CreateView,
):
model = Group
form_class = forms.GroupForm
template_name = "groups/group_form.html"
success_url = reverse_lazy("group_list")
success_message = _("Group created successfully.")
# def form_valid(self, form):
# dealer = get_user_type(self.request)
# email = form.cleaned_data["email"]
# password = "Tenhal@123"
# user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password)
# user.is_staff = True
# user.save()
# staff_member = StaffMember.objects.create(user=user)
# services = form.cleaned_data["service_offered"]
# if services:
# for service in services:
# staff_member.services_offered.add(service)
# staff = form.save(commit=False)
# staff.staff_member = staff_member
# staff.dealer = dealer
# staff.save()
# return super().form_valid(form)
class GroupUpdateView(
LoginRequiredMixin,
SuccessMessageMixin,
UpdateView,
):
model = Group
form_class = forms.GroupForm
template_name = "groups/group_form.html"
success_url = reverse_lazy("group_list")
success_message = _("Group updated successfully.")
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# kwargs["instance"] = self.get_object() # Pass the Staff instance to the form
# return kwargs
# def get_form(self, form_class = None):
# form = super().get_form(form_class)
# form.fields['email'].disabled = True
# return form
# def get_initial(self):
# initial = super().get_initial()
# initial['service_offered'] = self.object.staff_member.services_offered.all()
# initial['email'] = self.object.staff_member.user.email
# return initial
# def form_valid(self, form):
# services = form.cleaned_data["service_offered"]
# if not services:
# self.object.staff_member.services_offered.clear()
# else:
# for service in services:
# self.object.staff_member.services_offered.add(service)
# staff = form.save(commit=False)
# staff.name = form.cleaned_data["name"]
# staff.arabic_name = form.cleaned_data["arabic_name"]
# staff.phone_number = form.cleaned_data["phone_number"]
# staff.staff_type = form.cleaned_data["staff_type"]
# staff.save()
# return super().form_valid(form)
def GroupDeleteview(request, pk):
group = get_object_or_404(Group, pk=pk)
group.delete()
messages.success(request, _("Group deleted successfully."))
return redirect("group_list")
def GroupPermissionView(request, pk):
group = get_object_or_404(Group, pk=pk)
if request.method == "POST":
form = forms.PermissionForm(request.POST)
group.permissions.clear()
permissions = request.POST.getlist("name")
for i in permissions:
try:
group.permissions.add(Permission.objects.get(id=int(i)))
except Permission.DoesNotExist:
continue
messages.success(request, _("Permission added successfully."))
return redirect("group_detail", pk=group.pk)
form = forms.PermissionForm(initial={"name": group.permissions.all()})
return render(request,"groups/group_permission_form.html",{"group": group, "form": form})
# Users # Users
def UserGroupView(request, pk):
staff = get_object_or_404(models.Staff, pk=pk)
if request.method == "POST":
form = forms.UserGroupForm(request.POST)
groups = request.POST.getlist("name")
staff.groups.clear()
for i in groups:
try:
staff.groups.add(Group.objects.get(id=int(i)))
except Group.DoesNotExist:
continue
messages.success(request, _("Group added successfully."))
return redirect("user_detail", pk=staff.pk)
form = forms.UserGroupForm(initial={"name": staff.user.groups.all()})
return render(request,"users/user_group_form.html",{"staff": staff, "form": form})
class UserListView(LoginRequiredMixin, ListView): class UserListView(LoginRequiredMixin, ListView):
model = models.Staff model = models.Staff
context_object_name = "users" context_object_name = "users"
@ -1886,13 +2021,14 @@ class UserCreateView(
user.is_staff = True user.is_staff = True
user.save() user.save()
staff_member = StaffMember.objects.create(user=user) staff_member = StaffMember.objects.create(user=user)
services = form.cleaned_data["service_offered"] for service in form.cleaned_data["service_offered"]:
if services: staff_member.services_offered.add(service)
for service in services:
staff_member.services_offered.add(service)
staff = form.save(commit=False) staff = form.save(commit=False)
staff.staff_member = staff_member staff.staff_member = staff_member
staff.dealer = dealer staff.dealer = dealer
group = Group.objects.filter(name__iexact=staff.staff_type).first()
if group:
staff.groups.add(group)
staff.save() staff.save()
return super().form_valid(form) return super().form_valid(form)
@ -1919,8 +2055,8 @@ class UserUpdateView(
return form return form
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['service_offered'] = self.object.staff_member.services_offered.all()
initial['email'] = self.object.staff_member.user.email initial['email'] = self.object.staff_member.user.email
initial['service_offered'] = self.object.staff_member.services_offered.all()
return initial return initial
def form_valid(self, form): def form_valid(self, form):
services = form.cleaned_data["service_offered"] services = form.cleaned_data["service_offered"]
@ -1940,6 +2076,7 @@ class UserUpdateView(
def UserDeleteview(request, pk): def UserDeleteview(request, pk):
user = get_object_or_404(models.Staff, pk=pk) user = get_object_or_404(models.Staff, pk=pk)
user.staff_member.delete()
user.delete() user.delete()
messages.success(request, _("User deleted successfully.")) messages.success(request, _("User deleted successfully."))
return redirect("user_list") return redirect("user_list")

View File

@ -0,0 +1,119 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}{{ _("View Group") }}{% endblock title %}
{% block content %}
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm ">
<div class="modal-content rounded">
<div class="modal-body d-flex justify-content-center">
<h1 class="text-danger me-2"><i class="bi bi-exclamation-diamond-fill"></i></h1>
<span class="text-danger">
{% trans "Are you sure you want to delete this group?" %}
</span>
</div>
<div class="btn-group">
<button type="button"
class="btn btn-sm btn-secondary"
data-bs-dismiss="modal">
{% trans 'No' %}
</button>
<a type="button"
class="btn btn-sm btn-danger"
href="{% url 'group_delete' group.id %}">
{% trans 'Yes' %}
</a>
</div>
</div>
</div>
</div>
<div class="row my-5">
<div class="card rounded ">
<div class="card-header ">
<p class="mb-0">{{ _("Group Details") }}</p>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<p><strong>{{ _("Name") }}:</strong> {{ group.name }}</p>
</div>
<div class="col-md-6">
<table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead>
<tr>
<th><h4>{% trans 'Users'|capfirst %}</h4></th>
<th></th>
</tr>
</thead>
<tbody>
{% for user in group.user_set.all %}
<tr>
<td><p><strong>{{ _("Name") }}:</strong> {{ user.staffmember.staff }}</p></td>
<td><p><strong>{{ _("Email") }}:</strong> {{ user }}</p></td>
</tr>
{% empty %}
<tr>
<td>{% trans "No Permissions" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="table-responsive scrollbar mx-n1 px-1">
<div class="card-header ">
</div>
<h4 class="my-4">Permissions</h4>
<a class="btn btn-sm btn-primary mt-2 mb-4" href="{% url 'group_permission' group.id %}"><i class="fa-solid fa-unlock"></i> Manage Permissions</a>
<table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead>
<tr>
<th>{% trans 'name'|capfirst %}</th>
<th>{% trans 'Action'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for permission in group.permissions.all %}
<tr>
<td>{{ permission.codename }}</td>
<td>{{ permission.name }}</td>
</tr>
{% empty %}
<tr>
<td>{% trans "No Permissions" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="card-footer d-flex ">
<a class="btn btn-sm btn-primary me-1" href="{% url 'group_update' group.id %}">
<i class="fa-solid fa-pen-to-square"></i>
{{ _("Edit") }}
</a>
<a class="btn btn-sm btn-danger me-1"
data-bs-toggle="modal"
data-bs-target="#deleteModal">
<i class="fa-solid fa-trash"></i>
{{ _("Delete") }}
</a>
<a class="btn btn-sm btn-secondary"
href="{% url 'group_list' %}">
<i class="fa-solid fa-arrow-left"></i>
{% trans "Back to List" %}
</a>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,45 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}{% trans "Group" %}{% endblock title %}
{% block content %}
<div class="row">
<div class="row">
<div class="col-sm-9">
<div class="d-sm-flex justify-content-between">
<h3 class="mb-3">
{% if staff.created %}
{{ _("Edit Group") }}
{% else %}
{{ _("Add Group") }}
{% endif %}
</h3>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-9">
<form class="row g-3 mb-9" method="post" class="form" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex mb-3">
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-phoenix-primary me-2 px-6"><i class="fa-solid fa-ban"></i> {% trans "cancel"|capfirst %}</a>
<button class="btn btn-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
{{ _("Save") }}
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,57 @@
{% extends "base.html" %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% block title %}{% trans "Group" %}{% endblock title %}
{% block content %}
<section class="">
<div class="row">
<div class="col-auto">
<div class="d-md-flex justify-content-between">
<div>
<a href="{% url 'group_create' %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{% trans "Add Group" %}</a>
</div>
</div>
</div>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead>
<tr>
<th>{% trans 'name'|capfirst %}</th>
<th>{% trans 'total Users'|capfirst %}</th>
<th>{% trans 'total permission'|capfirst %}</th>
<th>{% trans 'actions'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td>{{ group.name }}</td>
<td><i class="fa-solid fa-users"></i> {{ group.user_set.count }}</td>
<td><i class="fa-solid fa-unlock"></i> {{ group.permissions.count }}</td>
<td>
<a class="btn btn-phoenix-success"
href="{% url 'group_detail' group.id %}">
<i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-center">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div>
</section>
{% endblock %}

View File

@ -0,0 +1,45 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}{% trans "Permission" %}{% endblock title %}
{% block content %}
<div class="row">
<div class="row">
<div class="col-sm-9">
<div class="d-sm-flex justify-content-between">
<h3 class="mb-3">
{% if group.created %}
{{ _("Edit Permission") }}
{% else %}
{{ _("Add Permission") }}
{% endif %}
</h3>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-9">
<form class="row g-3 mb-9" method="post" class="form" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex mb-3">
<a href="{% url 'group_detail' group.pk %}" class="btn btn-phoenix-primary me-2 px-6"><i class="fa-solid fa-ban"></i> {% trans "cancel"|capfirst %}</a>
<button class="btn btn-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
{{ _("Save") }}
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -441,7 +441,7 @@
{% endif %} {% endif %}
{% if user.dealer %} {% if user.dealer %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff") }}</a> <a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff & Group") }}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'dealer_activity' %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activity") }}</a> <a class="nav-link px-3 d-block" href="{% url 'dealer_activity' %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activity") }}</a>

View File

@ -39,7 +39,7 @@
<div class="row my-5"> <div class="row my-5">
<div class="card rounded "> <div class="card rounded ">
<div class="card-header "> <div class="card-header ">
<p class="mb-0">{{ _("User Details") }}</p> <p class="mb-0"><i class="fa-solid fa-user"></i> {{ _("User Details") }}</p>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
@ -53,20 +53,45 @@
</div> </div>
</div> </div>
</div> </div>
<div class="table-responsive scrollbar mx-n1 px-1">
<div class="card-header ">
</div>
<h4 class="my-4">Groups</h4>
<a class="btn btn-sm btn-primary mt-2 mb-4" href="{% url 'user_groups' user_.pk %}"><i class="fa-solid fa-users"></i> Manage Groups</a>
<table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead>
<tr>
<th>{% trans 'name'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for group in user_.groups.all %}
<tr>
<td>{{ group }}</td>
</tr>
{% empty %}
<tr>
<td>{% trans "No Group" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="card-footer d-flex "> <div class="card-footer d-flex ">
<a class="btn btn-sm btn-primary me-1" href="{% url 'user_update' user_.id %}"> <a class="btn btn-sm btn-primary me-1" href="{% url 'user_update' user_.id %}">
<!--<i class="bi bi-pencil-square"></i> --> <i class="fa-solid fa-pen-to-square"></i>
{{ _("Edit") }} {{ _("Edit") }}
</a> </a>
<a class="btn btn-sm btn-danger me-1" <a class="btn btn-sm btn-danger me-1"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#deleteModal"> data-bs-target="#deleteModal">
<!--<i class="bi bi-trash-fill"></i>--> <i class="fa-solid fa-trash"></i>
{{ _("Delete") }} {{ _("Delete") }}
</a> </a>
<a class="btn btn-sm btn-secondary" <a class="btn btn-sm btn-secondary"
href="{% url 'user_list' %}"> href="{% url 'user_list' %}">
<!--<i class="bi bi-arrow-left-square-fill"></i>--> <i class="fa-regular fa-circle-left"></i>
{% trans "Back to List" %} {% trans "Back to List" %}
</a> </a>
</div> </div>

View File

@ -12,6 +12,7 @@
<div class="d-sm-flex justify-content-between"> <div class="d-sm-flex justify-content-between">
<h3 class="mb-3"> <h3 class="mb-3">
<i class="fa-solid fa-user-tie"></i>
{% if staff.created %} {% if staff.created %}
{{ _("Edit Staff") }} {{ _("Edit Staff") }}
{% else %} {% else %}
@ -32,9 +33,9 @@
<div class="text-danger">{{ error }}</div> <div class="text-danger">{{ error }}</div>
{% endfor %} {% endfor %}
<div class="d-flex mb-3"> <div class="d-flex mb-3">
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-phoenix-primary me-2 px-6">{% trans "cancel"|capfirst %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-phoenix-primary me-2 px-6"><i class="fa-solid fa-ban"></i> {% trans "cancel"|capfirst %}</a>
<button class="btn btn-primary" type="submit"> <button class="btn btn-primary" type="submit">
<!--<i class="bi bi-save"></i> --> <i class="fa-solid fa-floppy-disk"></i>
{{ _("Save") }} {{ _("Save") }}
</button> </button>
</div> </div>

View File

@ -0,0 +1,38 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}{% trans "Group" %}{% endblock title %}
{% block content %}
<div class="row">
<div class="row">
<div class="col-sm-9">
<div class="d-sm-flex justify-content-between">
<h3 class="mb-3"><i class="fa-solid fa-users"></i> {{ _("Manage Groups") }}</h3>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-9">
<form class="row g-3 mb-9" method="post" class="form" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex mb-3">
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-phoenix-primary me-2 px-6"><i class="fa-solid fa-ban"></i> {% trans "cancel"|capfirst %}</a>
<button class="btn btn-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
{{ _("Save") }}
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -11,8 +11,8 @@
<div class="col-auto"> <div class="col-auto">
<div class="d-md-flex justify-content-between"> <div class="d-md-flex justify-content-between">
<div> <div>
<a href="{% url 'user_create' %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{% trans "Add Staff" %}</a> <a href="{% url 'user_create' %}" class="btn btn-sm btn-phoenix-primary"><i class="fa-solid fa-user-tie"></i> {% trans "Add New Staff" %}</a>
<a href="{% url 'group_list' %}" class="btn btn-sm btn-phoenix-success"><i class="fa-solid fa-user-group"></i> {% trans "Manage Groups & Permissions" %}</a>
</div> </div>
</div> </div>
</div> </div>
@ -25,6 +25,7 @@
<th>{% trans 'arabic name'|capfirst %}</th> <th>{% trans 'arabic name'|capfirst %}</th>
<th>{% trans 'phone number'|capfirst %}</th> <th>{% trans 'phone number'|capfirst %}</th>
<th>{% trans 'role'|capfirst %}</th> <th>{% trans 'role'|capfirst %}</th>
<th>{% trans 'groups'|capfirst %}</th>
<th>{% trans 'actions'|capfirst %}</th> <th>{% trans 'actions'|capfirst %}</th>
</tr> </tr>
</thead> </thead>
@ -34,10 +35,18 @@
<td>{{ user.name }}</td> <td>{{ user.name }}</td>
<td>{{ user.arabic_name }}</td> <td>{{ user.arabic_name }}</td>
<td>{{ user.phone_number }}</td> <td>{{ user.phone_number }}</td>
<td>{% trans user.staff_type %}</td> <td>
<span class="badge badge-sm bg-primary"><i class="fa-solid fa-scroll"></i> {% trans user.staff_type|title %}</span>
</td>
<td>
{% for group in user.groups.all %}
<span class="badge badge-sm bg-info"><i class="fa-solid fa-user-group"></i> {{ group.name }}</span>
{% endfor %}
</td>
<td> <td>
<a class="btn btn-phoenix-success" <a class="btn btn-phoenix-success"
href="{% url 'user_detail' user.id %}"> href="{% url 'user_detail' user.id %}">
<i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %} {% trans 'view'|capfirst %}
</a> </a>
</td> </td>