add user and organization dealer slug

This commit is contained in:
ismail 2025-06-26 11:40:58 +03:00
parent 6c172fce3d
commit 3a5ab31f83
16 changed files with 112 additions and 72 deletions

View File

@ -720,7 +720,9 @@ class Car(Base):
car=self, exterior=exterior, interior=interior
)
self.save()
@property
def logo(self):
return self.id_car_make.logo.url if self.id_car_make.logo else None
class CarTransfer(models.Model):
car = models.ForeignKey(

View File

@ -2662,7 +2662,6 @@ class GroupCreateView(
model = models.CustomGroup
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):
@ -2674,6 +2673,8 @@ class GroupCreateView(
instance.save()
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("group_list", args=[self.request.dealer.slug])
class GroupUpdateView(
LoginRequiredMixin,
@ -2705,20 +2706,20 @@ class GroupUpdateView(
model = models.CustomGroup
form_class = forms.GroupForm
template_name = "groups/group_form.html"
success_url = reverse_lazy("group_list")
success_message = _("Group updated successfully")
def form_valid(self, form):
dealer = get_user_type(self.request)
instance = form.save(commit=False)
instance.set_defualt_permissions()
instance.set_default_permissions()
instance.group.name = f"{dealer.slug}_{instance.name}"
instance.save()
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("group_list", args=[self.request.dealer.slug])
@login_required
def GroupDeleteview(request, pk):
def GroupDeleteview(request, dealer_slug,pk):
"""
Handles the deletion of a specific group instance. This view ensures that only
authenticated users can perform the deletion. Upon successful deletion, a
@ -2731,14 +2732,15 @@ def GroupDeleteview(request, pk):
:return: The HTTP response that redirects the user to the group list page
after the group is successfully deleted.
"""
get_object_or_404(models.Dealer,slug=dealer_slug)
group = get_object_or_404(models.CustomGroup, pk=pk)
group.delete()
messages.success(request, _("Group deleted successfully"))
return redirect("group_list")
return redirect("group_list",dealer_slug=dealer_slug)
@login_required
def GroupPermissionView(request, pk):
def GroupPermissionView(request, dealer_slug,pk):
"""
Handles the view for adding or modifying permissions of a specific group. This view
fetches the group based on the primary key passed as a parameter, and either displays
@ -2760,6 +2762,7 @@ def GroupPermissionView(request, pk):
the group's permissions and redirects to the group's detail page.
:rtype: HttpResponse
"""
get_object_or_404(models.Dealer,slug=dealer_slug)
group = get_object_or_404(models.CustomGroup, pk=pk)
if request.method == "POST":
form = forms.PermissionForm(request.POST)
@ -2768,7 +2771,7 @@ def GroupPermissionView(request, pk):
for i in permissions:
group.add_permission(Permission.objects.get(id=int(i)))
messages.success(request, _("Permission added successfully"))
return redirect("group_detail", pk=group.pk)
return redirect("group_detail", dealer_slug=dealer_slug,pk=group.pk)
form = forms.PermissionForm(initial={"name": group.permissions})
return render(
request, "groups/group_permission_form.html", {"group": group, "form": form}
@ -2777,7 +2780,7 @@ def GroupPermissionView(request, pk):
# Users
@login_required
def UserGroupView(request, slug):
def UserGroupView(request, dealer_slug,slug):
"""
Handles the assignment of user groups to a specific staff member. This view
allows updating the groups a staff member belongs to via a form submission.
@ -2793,6 +2796,7 @@ def UserGroupView(request, slug):
user detail page after successful submission for POST requests.
:rtype: HttpResponse or HttpResponseRedirect
"""
get_object_or_404(models.Dealer,slug=dealer_slug)
staff = get_object_or_404(models.Staff, slug=slug)
if request.method == "POST":
form = forms.UserGroupForm(request.POST)
@ -2804,7 +2808,7 @@ def UserGroupView(request, slug):
staff.add_group(cg.group)
messages.success(request, _("Group added successfully"))
return redirect("user_detail", slug=staff.slug)
return redirect("user_detail",dealer_slug=dealer_slug, slug=staff.slug)
form = forms.UserGroupForm(initial={"name": staff.groups})
form.fields["name"].queryset = models.CustomGroup.objects.filter(
@ -2948,7 +2952,8 @@ class UserCreateView(
if group:
staff.add_group(group)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("user_list", args=[self.request.dealer.slug])
class UserUpdateView(
LoginRequiredMixin,
@ -3015,10 +3020,11 @@ class UserUpdateView(
staff.add_as_manager()
staff.save()
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("user_list", args=[self.request.dealer.slug])
@login_required
def UserDeleteview(request, slug):
def UserDeleteview(request, dealer_slug,slug):
"""
Deletes a user and its associated staff member from the database and redirects
to the user list page. Displays a success message upon successful deletion
@ -3029,10 +3035,11 @@ def UserDeleteview(request, slug):
:return: An HTTP redirect to the user list page.
"""
get_object_or_404(models.Dealer,slug=dealer_slug)
staff = get_object_or_404(models.Staff, slug=slug)
staff.deactivate_account()
messages.success(request, _("User deleted successfully"))
return redirect("user_list")
return redirect("user_list",dealer_slug=dealer_slug)
class OrganizationListView(LoginRequiredMixin, ListView):
@ -9185,6 +9192,9 @@ def InventoryItemCreateView(request, dealer_slug):
cogs_accounts = entity.get_coa_accounts().filter(role="cogs_regular")
if request.method == "POST":
response = HttpResponse()
response["HX-Refresh"] = "true"
name = request.POST.get("name")
account = request.POST.get("account")
account = inventory_accounts.get(pk=account)
@ -9216,10 +9226,11 @@ def InventoryItemCreateView(request, dealer_slug):
.first()
):
messages.error(request, _("Inventory item already exists"))
return redirect(
f"{reverse('inventory_item_create')}?for_po={for_po}",
dealer_slug=dealer.slug,
)
return response
# return redirect(
# f"{reverse('inventory_item_create')}?for_po={for_po}",
# dealer_slug=dealer.slug,
# )
uom = entity.get_uom_all().get(name="Unit")
entity.create_item_inventory(
name=inventory_name,
@ -9229,7 +9240,8 @@ def InventoryItemCreateView(request, dealer_slug):
coa_model=coa,
)
messages.success(request, _("Inventory item created successfully"))
return redirect("purchase_order_list", dealer_slug=dealer.slug)
return response
# return redirect("purchase_order_list", dealer_slug=dealer.slug)
if for_po:
form = forms.CSVUploadForm()
form.fields["vendor"].queryset = dealer.vendors.filter(active=True)

View File

@ -108,3 +108,4 @@ html[dir="rtl"] .form-icon-container .form-control {
padding-right: 35px;
padding-left: 10px;
}

View File

@ -12,7 +12,7 @@
<div class="row justify-content-between mb-2">
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
<span class="uil fs-5 lh-1 uil-users-alt text-success"></span>
<a href="{% url 'user_list' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a>
<a href="{% url 'user_list request.dealer.slug' %}"><h4 class="fs-6 pt-3">{{ staff }}</h4></a>
<p class="fs-9 mb-0">{{ _("Staff")}}</p>
</div>
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">

View File

@ -28,7 +28,7 @@
</button>
<a type="button"
class="btn btn-sm btn-phoenix-danger"
href="{% url 'group_delete' group.id %}">
href="{% url 'group_delete' request.dealer.slug group.id %}">
{% trans 'Yes' %}
</a>
</div>
@ -74,7 +74,7 @@
<div class="card-header ">
</div>
<h4 class="my-4">Permissions</h4>
<a class="btn btn-sm btn-phoenix-primary mt-2 mb-4" href="{% url 'group_permission' group.id %}"><i class="fa-solid fa-unlock"></i> Manage Permissions</a>
<a class="btn btn-sm btn-phoenix-primary mt-2 mb-4" href="{% url 'group_permission' request.dealer.slug 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>
@ -98,7 +98,7 @@
</table>
</div>
<div class="card-footer d-flex ">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'group_update' group.id %}">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'group_update' request.dealer.slug group.id %}">
<i class="fa-solid fa-pen-to-square"></i>
{{ _("Edit") }}
</a>
@ -109,7 +109,7 @@
{{ _("Delete") }}
</a>
<a class="btn btn-sm btn-phoenix-secondary"
href="{% url 'group_list' %}">
href="{% url 'group_list' request.dealer.slug %}">
<i class="fa-solid fa-arrow-left"></i>
{% trans "Back to List" %}
</a>

View File

@ -11,7 +11,7 @@
<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>
<a href="{% url 'group_create' request.dealer.slug %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{% trans "Add Group" %}</a>
</div>
</div>
@ -35,7 +35,7 @@
<td class="align-middle white-space-nowrap"><i class="fa-solid fa-unlock me-1"></i> {{ group.permissions.count }}</td>
<td class="align-middle white-space-nowrap">
<a class="btn btn-phoenix-success"
href="{% url 'group_detail' group.id %}">
href="{% url 'group_detail' request.dealer.slug group.id %}">
<i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %}
</a>

View File

@ -32,7 +32,7 @@
<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 "><i class="fa-solid fa-ban"></i> {% trans "Cancel"|capfirst %}</a>
<a href="{% url 'group_detail' request.dealer.slug group.pk %}" class="btn btn-phoenix-primary me-2 "><i class="fa-solid fa-ban"></i> {% trans "Cancel"|capfirst %}</a>
<button class="btn btn-phoenix-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
{{ _("Save") }}

View File

@ -28,26 +28,6 @@
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'inventory_item_create' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add invenotry item"|capfirst %}</span>
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
<li class="nav-item">
@ -65,6 +45,13 @@
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
</div>
</a>
</li>
</ul>
</div>
</div>
@ -271,6 +258,15 @@
</a>
</li>
{% endif %}
{% if perms.django_ledger.view_purchaseordermodel %}
<li class="nav-item">
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
</ul>
</div>
</div>

View File

@ -1,8 +1,10 @@
{% extends "base.html" %}
{% load static i18n crispy_forms_tags %}
{% block customCSS %}
<style>
.color-card {
{% block content %}
<form hx-boost="true" hx-swap="none" action="{% url 'inventory_item_create' request.dealer.slug %}?for_po=1" method="post">
<style>
.color-card {
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
@ -67,10 +69,7 @@
gap: 10px;
margin-bottom: 20px;
}
</style>
{% endblock %}
{% block content %}
<form action="" method="post">
</style>
{% csrf_token %}
<div class="row g-4">
<div class="col">
@ -139,6 +138,6 @@
</div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-5">Add New Item To Inventory</button>
<button type="submit" class="btn btn-primary mt-5">{% trans 'Save' %}</button>
</form>
{% endblock content %}

View File

@ -18,7 +18,19 @@
<table class="table table-hover table-bordered">
<thead class="">
<tr>
<th>{% trans 'Item' %}</th>
<th class="d-flex justify-content-between align-items-center">
{% trans 'Item' %}
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
data-bs-target="#mainModal"
hx-get="{% url 'inventory_item_create' dealer_slug %}?for_po=1"
hx-target=".main-modal-body"
hx-select="form"
hx-swap="innerHTML">
<i class="fas fa-plus me-1"></i>{% trans 'Add Item' %}
</button>
</th>
<th>{% trans 'Unit Cost' %}</th>
<th>{% trans 'Quantity' %}</th>
<th>{% trans 'Unit' %}</th>

View File

@ -51,7 +51,7 @@
</div>
</div>
</div>
</div>
<div class="col-lg-12">
<!-- PO Details -->
@ -72,9 +72,9 @@
</a>
</div>
</div>
</div>
{% include "purchase_orders/includes/mark_as.html" %}
</div>
{% endblock %}
{% block customJS %}

View File

@ -21,8 +21,6 @@
<div>
<a href="{% url 'purchase_order_create' request.dealer.slug %}"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
<a href="{% url 'inventory_item_create' request.dealer.slug %}?for_po=1"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create Inventory Item for PO") }}</a>
</div>
</div>
{% include "partials/search_box.html" %}

View File

@ -90,6 +90,26 @@
</div>
</div>
{% include "purchase_orders/includes/mark_as.html" %}
<div class="modal fade"
id="mainModal"
tabindex="-1"
aria-labelledby="mainModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mainModalLabel">{% trans 'Add' %}</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="main-modal-body" style="padding: 20px;">
<!-- Content will be loaded here via AJAX -->
</div>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}

View File

@ -136,7 +136,7 @@
<div class="row">
<div class="col-md-6">
<p>
<strong>{% trans "Ledger Number" %}: </strong><a href="{% url 'ledger_detail' entity_slug=sale_order.invoice.ledger.entity.slug pk=sale_order.invoice.ledger.pk %}" target="_blank" rel="noopener noreferrer"> {{ sale_order.invoice.ledger }} <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<strong>{% trans "Ledger Number" %}: </strong><a href="{% url 'ledger_detail' dealer_slug=request.dealer.slug entity_slug=sale_order.invoice.ledger.entity.slug pk=sale_order.invoice.ledger.pk %}" target="_blank" rel="noopener noreferrer"> {{ sale_order.invoice.ledger }} <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<strong>{% trans "Date" %}:</strong> {{ sale_order.invoice.ledger.created|date }}<br>
</p>
</div>

View File

@ -27,7 +27,7 @@
</div>
<h4 class="my-4">Groups</h4>
<a class="btn btn-sm btn-phoenix-primary mt-2 mb-4" href="{% url 'user_groups' user_.slug %}"><i class="fa-solid fa-users"></i> Manage Groups</a>
<a class="btn btn-sm btn-phoenix-primary mt-2 mb-4" href="{% url 'user_groups' request.dealer.slug user_.slug %}"><i class="fa-solid fa-users"></i> Manage Groups</a>
<table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead>
<tr>
@ -48,20 +48,20 @@
</table>
</div>
<div class="card-footer d-flex ">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'user_update' user_.slug %}">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'user_update' request.dealer.slug user_.slug %}">
{{ _("Edit") }}
<i class="fa-solid fa-pen-to-square"></i>
</a>
<button class="btn btn-phoenix-danger btn-sm delete-btn me-1"
data-url="{% url 'user_delete' user_.slug %}"
data-message="{{ _("Are you sure you want to delete this user?")}}"
data-url="{% url 'user_delete' request.dealer.slug user_.slug %}"
data-message='{{ _("Are you sure you want to delete this user?")}}'
data-bs-toggle="modal" data-bs-target="#deleteModal">
{{ _("Delete") }}
<i class="fas fa-trash"></i>
</button>
<a class="btn btn-sm btn-phoenix-secondary"
href="{% url 'user_list' %}">
href="{% url 'user_list' request.dealer.slug %}">
{{ _("Back to List") }}
<i class="fa-regular fa-circle-left"></i>
</a>

View File

@ -12,8 +12,8 @@
<div class="d-md-flex justify-content-between">
<div>
{% if request.user.userplan %}
<a href="{% url 'user_create' %}" class="btn btn-sm btn-phoenix-primary me-4"><i class="fa-solid fa-user-tie me-1"></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 me-1"></i> {% trans "Manage Groups & Permissions" %}</a>
<a href="{% url 'user_create' request.dealer.slug %}" class="btn btn-sm btn-phoenix-primary me-4"><i class="fa-solid fa-user-tie me-1"></i> {% trans "Add New Staff" %}</a>
<a href="{% url 'group_list' request.dealer.slug %}" class="btn btn-sm btn-phoenix-success"><i class="fa-solid fa-user-group me-1"></i> {% trans "Manage Groups & Permissions" %}</a>
{% else %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
@ -41,7 +41,7 @@
<tr>
<td class="align-middle white-space-nowrap ps-1">
<div>
<a class="fs-8 fw-bold" href="{% url 'user_detail' user.slug%}">{{ user.arabic_name }}</a>
<a class="fs-8 fw-bold" href="{% url 'user_detail' request.dealer.slug user.slug%}">{{ user.arabic_name }}</a>
</div>
</td>
@ -53,7 +53,7 @@
<td class="align-middle white-space-nowrap">
<a class="btn btn-phoenix-success"
href="{% url 'user_detail' user.slug %}">
href="{% url 'user_detail' request.dealer.slug user.slug %}">
<i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %}
</a>