Compare commits
10 Commits
5fe6ee8d17
...
390acab166
| Author | SHA1 | Date | |
|---|---|---|---|
| 390acab166 | |||
| c2d288907a | |||
| af7c336288 | |||
| 0930e15a14 | |||
| 09c390ca81 | |||
| a0087d1188 | |||
| e5d0602eb9 | |||
| 6436649488 | |||
| 4cc10b48c1 | |||
| 85c151a112 |
@ -135,10 +135,15 @@ class StaffForm(forms.ModelForm):
|
|||||||
),
|
),
|
||||||
label=_("Phone Number"),
|
label=_("Phone Number"),
|
||||||
)
|
)
|
||||||
|
group = forms.ModelMultipleChoiceField(
|
||||||
|
label=_("Group"),
|
||||||
|
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
|
||||||
|
queryset=CustomGroup.objects.all(),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Staff
|
model = Staff
|
||||||
fields = ["name", "arabic_name", "phone_number", "staff_type"]
|
fields = ["name", "arabic_name", "phone_number", "group"]
|
||||||
|
|
||||||
|
|
||||||
# Dealer Form
|
# Dealer Form
|
||||||
@ -1523,44 +1528,116 @@ class GroupForm(forms.ModelForm):
|
|||||||
fields = ["name"]
|
fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
# class PermissionForm(forms.ModelForm):
|
||||||
|
# """
|
||||||
|
# Represents a form for managing permissions using a multiple-choice field.
|
||||||
|
|
||||||
|
# This class is a Django ModelForm that is used to handle permission
|
||||||
|
# assignments. It provides a multiple selection widget pre-populated with
|
||||||
|
# permissions based on specific app labels. The form offers a way to submit
|
||||||
|
# and validate permission data for further processing.
|
||||||
|
|
||||||
|
# :ivar name: A multiple-choice field that allows users to select permissions
|
||||||
|
# related to specific app labels (`inventory` and `django_ledger`).
|
||||||
|
# :type name: ModelMultipleChoiceField
|
||||||
|
# """
|
||||||
|
|
||||||
|
# name = forms.ModelMultipleChoiceField(
|
||||||
|
# queryset=cache.get(
|
||||||
|
# "permissions_queryset",
|
||||||
|
# Permission.objects.filter(
|
||||||
|
# content_type__app_label__in=["inventory", "django_ledger"]
|
||||||
|
# ),
|
||||||
|
# ),
|
||||||
|
# widget=forms.CheckboxSelectMultiple(),
|
||||||
|
# required=True,
|
||||||
|
# )
|
||||||
|
|
||||||
|
# def __init__(self, *args, **kwargs):
|
||||||
|
# super().__init__(*args, **kwargs)
|
||||||
|
# cache.set(
|
||||||
|
# "permissions_queryset",
|
||||||
|
# Permission.objects.filter(
|
||||||
|
# content_type__app_label__in=["inventory", "django_ledger"]
|
||||||
|
# ),
|
||||||
|
# 60 * 60,
|
||||||
|
# )
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# model = Permission
|
||||||
|
# fields = ["name"]
|
||||||
class PermissionForm(forms.ModelForm):
|
class PermissionForm(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
Represents a form for managing permissions using a multiple-choice field.
|
Form for managing permissions with grouped checkboxes by app and model.
|
||||||
|
|
||||||
This class is a Django ModelForm that is used to handle permission
|
|
||||||
assignments. It provides a multiple selection widget pre-populated with
|
|
||||||
permissions based on specific app labels. The form offers a way to submit
|
|
||||||
and validate permission data for further processing.
|
|
||||||
|
|
||||||
:ivar name: A multiple-choice field that allows users to select permissions
|
|
||||||
related to specific app labels (`inventory` and `django_ledger`).
|
|
||||||
:type name: ModelMultipleChoiceField
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = forms.ModelMultipleChoiceField(
|
|
||||||
queryset=cache.get(
|
|
||||||
"permissions_queryset",
|
|
||||||
Permission.objects.filter(
|
|
||||||
content_type__app_label__in=["inventory", "django_ledger"]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
widget=forms.CheckboxSelectMultiple(),
|
|
||||||
required=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
cache.set(
|
EXCLUDED_MODELS = [
|
||||||
|
"inventory.car",
|
||||||
|
"inventory.carfinance",
|
||||||
|
"inventory.carlocation",
|
||||||
|
"inventory.customcard",
|
||||||
|
"inventory.cartransfer",
|
||||||
|
"inventory.carcolors",
|
||||||
|
"inventory.carequipment",
|
||||||
|
"inventory.interiorcolors",
|
||||||
|
"inventory.exteriorcolors",
|
||||||
|
"inventory.lead",
|
||||||
|
"inventory.customgroup",
|
||||||
|
"inventory.saleorder",
|
||||||
|
"inventory.payment",
|
||||||
|
"inventory.staff",
|
||||||
|
"inventory.schedule",
|
||||||
|
"inventory.activity",
|
||||||
|
"inventory.opportunity",
|
||||||
|
"inventory.carreservation"
|
||||||
|
"inventory.customer",
|
||||||
|
"inventory.organization",
|
||||||
|
# "inventory.salequotation",
|
||||||
|
# "inventory.salequotationcar"
|
||||||
|
|
||||||
|
"django_ledger.bankaccountmodel",
|
||||||
|
"django_ledger.chartofaccountmodel",
|
||||||
|
"django_ledger.estimatemodel",
|
||||||
|
"django_ledger.accountmodel",
|
||||||
|
"django_ledger.chartofaccountmodel",
|
||||||
|
"django_ledger.billmodel"
|
||||||
|
"django_ledger.itemmodel",
|
||||||
|
"django_ledger.invoicemodel",
|
||||||
|
"django_ledger.vendormodel",
|
||||||
|
"django_ledger.journalentrymodel"
|
||||||
|
]
|
||||||
|
|
||||||
|
permissions = cache.get(
|
||||||
"permissions_queryset",
|
"permissions_queryset",
|
||||||
Permission.objects.filter(
|
Permission.objects.filter(
|
||||||
content_type__app_label__in=["inventory", "django_ledger"]
|
content_type__app_label__in=[m.split('.')[0] for m in EXCLUDED_MODELS],
|
||||||
),
|
content_type__model__in=[m.split('.')[1] for m in EXCLUDED_MODELS]
|
||||||
60 * 60,
|
).select_related('content_type')
|
||||||
|
)
|
||||||
|
|
||||||
|
# Group permissions by app_label and model
|
||||||
|
self.grouped_permissions = {}
|
||||||
|
for perm in permissions:
|
||||||
|
app_label = perm.content_type.app_label
|
||||||
|
model = perm.content_type.model
|
||||||
|
if app_label not in self.grouped_permissions:
|
||||||
|
self.grouped_permissions[app_label] = {}
|
||||||
|
if model not in self.grouped_permissions[app_label]:
|
||||||
|
self.grouped_permissions[app_label][model] = []
|
||||||
|
self.grouped_permissions[app_label][model].append(perm)
|
||||||
|
|
||||||
|
# Create a multiple choice field (hidden, will use custom rendering)
|
||||||
|
self.fields['permissions'] = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=permissions,
|
||||||
|
widget=forms.MultipleHiddenInput(),
|
||||||
|
required=False,
|
||||||
|
initial=self.instance.permissions.all() if self.instance.pk else []
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Permission
|
model = Permission
|
||||||
fields = ["name"]
|
fields = []
|
||||||
|
|
||||||
|
|
||||||
class UserGroupForm(forms.ModelForm):
|
class UserGroupForm(forms.ModelForm):
|
||||||
|
|||||||
@ -1188,31 +1188,33 @@ class Staff(models.Model, LocalizedNameMixin):
|
|||||||
return [x.customgroup for x in self.user.groups.all()]
|
return [x.customgroup for x in self.user.groups.all()]
|
||||||
|
|
||||||
def clear_groups(self):
|
def clear_groups(self):
|
||||||
EntityManagementModel.objects.filter(
|
self.remove_superuser_permission()
|
||||||
user=self.user, entity=self.dealer.entity
|
|
||||||
).delete()
|
|
||||||
return self.user.groups.clear()
|
return self.user.groups.clear()
|
||||||
|
|
||||||
def add_group(self, group):
|
def add_group(self, group,clean=False):
|
||||||
|
if clean:
|
||||||
|
self.clear_groups()
|
||||||
try:
|
try:
|
||||||
self.user.groups.add(group)
|
self.user.groups.add(group)
|
||||||
if self.staff_type in ["accountant", "manager"]:
|
if "accountant" in group.name.lower() or "manager" in group.name.lower():
|
||||||
self.add_as_manager()
|
self.add_as_superuser()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
def add_as_manager(self):
|
def add_as_superuser(self):
|
||||||
if self.staff_type in ["accountant", "manager"]:
|
EntityManagementModel.objects.get_or_create(
|
||||||
EntityManagementModel.objects.get_or_create(
|
user=self.user, entity=self.dealer.entity
|
||||||
user=self.user, entity=self.dealer.entity
|
)
|
||||||
)
|
def remove_superuser_permission(self):
|
||||||
else:
|
EntityManagementModel.objects.filter(
|
||||||
self.user.groups.clear()
|
user=self.user, entity=self.dealer.entity
|
||||||
group = Group.objects.filter(
|
).delete()
|
||||||
customgroup__name__iexact=self.staff_type
|
# self.user.groups.clear()
|
||||||
).first()
|
# group = Group.objects.filter(
|
||||||
if group:
|
# customgroup__name__iexact=self.staff_type
|
||||||
self.add_group(group)
|
# ).first()
|
||||||
|
# if group:
|
||||||
|
# self.add_group(group)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Staff")
|
verbose_name = _("Staff")
|
||||||
@ -2519,7 +2521,7 @@ class CustomGroup(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def entity(self):
|
def entity(self):
|
||||||
return self.invoice.entity
|
return self.dealer.entity
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def users(self):
|
def users(self):
|
||||||
|
|||||||
@ -528,25 +528,25 @@ def track_lead_status_change(sender, instance, **kwargs):
|
|||||||
pass # Ignore if the lead doesn't exist (e.g., during initial creation)
|
pass # Ignore if the lead doesn't exist (e.g., during initial creation)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=models.Lead)
|
# @receiver(post_save, sender=models.Lead)
|
||||||
def notify_assigned_staff(sender, instance, created, **kwargs):
|
# def notify_assigned_staff(sender, instance, created, **kwargs):
|
||||||
"""
|
# """
|
||||||
Signal handler that sends a notification to the staff member when a new lead is assigned.
|
# Signal handler that sends a notification to the staff member when a new lead is assigned.
|
||||||
This function is triggered when a Lead instance is saved. If the lead has been assigned
|
# This function is triggered when a Lead instance is saved. If the lead has been assigned
|
||||||
to a staff member, it creates a Notification object, notifying the staff member of the
|
# to a staff member, it creates a Notification object, notifying the staff member of the
|
||||||
new assignment.
|
# new assignment.
|
||||||
|
|
||||||
:param sender: The model class that sent the signal.
|
# :param sender: The model class that sent the signal.
|
||||||
:param instance: The instance of the model that was saved.
|
# :param instance: The instance of the model that was saved.
|
||||||
:param created: A boolean indicating whether a new instance was created.
|
# :param created: A boolean indicating whether a new instance was created.
|
||||||
:param kwargs: Additional keyword arguments.
|
# :param kwargs: Additional keyword arguments.
|
||||||
:return: None
|
# :return: None
|
||||||
"""
|
# """
|
||||||
if instance.staff: # Check if the lead is assigned
|
# if instance.staff: # Check if the lead is assigned
|
||||||
models.Notification.objects.create(
|
# models.Notification.objects.create(
|
||||||
user=instance.staff.staff_member.user,
|
# user=instance.staff.staff_member.user,
|
||||||
message=f"You have been assigned a new lead: {instance.full_name}.",
|
# message=f"You have been assigned a new lead: {instance.full_name}.",
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=models.CarReservation)
|
@receiver(post_save, sender=models.CarReservation)
|
||||||
|
|||||||
@ -645,3 +645,10 @@ def inventory_table(context, queryset):
|
|||||||
}
|
}
|
||||||
ctx.update(queryset.aggregate(inventory_total_value=Sum("total_value")))
|
ctx.update(queryset.aggregate(inventory_total_value=Sum("total_value")))
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def count_checked(permissions):
|
||||||
|
"""Count how many permissions are marked as checked"""
|
||||||
|
print(permissions)
|
||||||
|
return sum(1 for perm in permissions if getattr(perm, 'is_checked', False))
|
||||||
@ -913,7 +913,6 @@ urlpatterns = [
|
|||||||
name="bill-action-force-migrate",
|
name="bill-action-force-migrate",
|
||||||
),
|
),
|
||||||
# path("items/bills/create/", views.bill_create, name="bill_create"),
|
# path("items/bills/create/", views.bill_create, name="bill_create"),
|
||||||
# >>>>>>>>>>>>>>>>>>>>>>...
|
|
||||||
path(
|
path(
|
||||||
"items/bills/<uuid:pk>/bill_detail/",
|
"items/bills/<uuid:pk>/bill_detail/",
|
||||||
views.BillDetailView.as_view(),
|
views.BillDetailView.as_view(),
|
||||||
|
|||||||
@ -318,6 +318,7 @@ def dealer_signup(request):
|
|||||||
if password != password_confirm:
|
if password != password_confirm:
|
||||||
return JsonResponse({"error": _("Passwords do not match")}, status=400)
|
return JsonResponse({"error": _("Passwords do not match")}, status=400)
|
||||||
try:
|
try:
|
||||||
|
#TODO make this a django-q task
|
||||||
create_user_dealer(
|
create_user_dealer(
|
||||||
email, password, name, arabic_name, phone, crn, vrn, address
|
email, password, name, arabic_name, phone, crn, vrn, address
|
||||||
)
|
)
|
||||||
@ -2666,20 +2667,26 @@ class GroupCreateView(
|
|||||||
success_message = _("Group created successfully")
|
success_message = _("Group created successfully")
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
instance = form.save(commit=False)
|
instance = form.save(commit=False)
|
||||||
group_name = f"{dealer.slug}_{instance.name}"
|
group_name = f"{dealer.slug}_{instance.name}"
|
||||||
group,created = Group.objects.get_or_create(name=group_name)
|
try:
|
||||||
|
group, created = Group.objects.get_or_create(name=group_name)
|
||||||
|
instance.dealer = dealer
|
||||||
|
instance.group = group
|
||||||
|
instance.save()
|
||||||
|
except IntegrityError as e:
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
print(e)
|
||||||
|
messages.error(self.request, _("Group name already exists"))
|
||||||
|
return redirect("group_create", dealer_slug=dealer.slug)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
group_manager, created = models.CustomGroup.objects.get_or_create(
|
group_manager, _ = models.CustomGroup.objects.get_or_create(
|
||||||
name=group_name, dealer=dealer, group=group
|
name=instance.name, dealer=dealer, group=group
|
||||||
)
|
)
|
||||||
group_manager.set_default_permissions()
|
group_manager.set_default_permissions()
|
||||||
dealer.user.groups.add(group)
|
dealer.user.groups.add(group)
|
||||||
else:
|
|
||||||
instance.dealer = dealer
|
|
||||||
instance.group = group
|
|
||||||
instance.save()
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@ -2749,42 +2756,78 @@ def GroupDeleteview(request, dealer_slug,pk):
|
|||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def GroupPermissionView(request, dealer_slug,pk):
|
def GroupPermissionView(request, dealer_slug, pk):
|
||||||
"""
|
# Verify dealer and group exist
|
||||||
Handles the view for adding or modifying permissions of a specific group. This view
|
get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
fetches the group based on the primary key passed as a parameter, and either displays
|
customgroup = get_object_or_404(models.CustomGroup, pk=pk)
|
||||||
a form for editing permissions or processes the submitted permissions.
|
|
||||||
|
|
||||||
If the request method is POST, the permissions of the group are cleared and updated
|
|
||||||
based on the submitted data. A success message is displayed upon completion, and
|
|
||||||
the user is redirected to the group's detail page.
|
|
||||||
|
|
||||||
In case of a GET request, the view renders the form pre-filled with the group's
|
|
||||||
current permissions.
|
|
||||||
|
|
||||||
:param request: The HTTP request object.
|
|
||||||
:type request: HttpRequest
|
|
||||||
:param pk: The primary key of the group whose permissions are being modified.
|
|
||||||
:type pk: int
|
|
||||||
:return: The HTTP response depending on the request type. For GET requests, renders
|
|
||||||
the permission form for the specified group. For POST requests, clears and updates
|
|
||||||
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":
|
if request.method == "POST":
|
||||||
form = forms.PermissionForm(request.POST)
|
form = forms.PermissionForm(request.POST, instance=customgroup)
|
||||||
group.clear_permissions()
|
if form.is_valid():
|
||||||
permissions = request.POST.getlist("name")
|
# Clear existing permissions
|
||||||
for i in permissions:
|
customgroup.clear_permissions()
|
||||||
group.add_permission(Permission.objects.get(id=int(i)))
|
|
||||||
messages.success(request, _("Permission added successfully"))
|
# Add new permissions from form
|
||||||
return redirect("group_detail", dealer_slug=dealer_slug,pk=group.pk)
|
permissions = form.cleaned_data.get('permissions', [])
|
||||||
form = forms.PermissionForm(initial={"name": group.permissions})
|
for permission in permissions:
|
||||||
return render(
|
customgroup.add_permission(permission)
|
||||||
request, "groups/group_permission_form.html", {"group": group, "form": form}
|
|
||||||
)
|
messages.success(request, _("Permissions updated successfully"))
|
||||||
|
return redirect("group_detail", dealer_slug=dealer_slug, pk=customgroup.pk)
|
||||||
|
else:
|
||||||
|
# Initial form with current permissions
|
||||||
|
form = forms.PermissionForm(instance=customgroup)
|
||||||
|
|
||||||
|
group_permission_ids = set(customgroup.permissions.values_list('id', flat=True))
|
||||||
|
|
||||||
|
# Mark permissions as checked in the form data
|
||||||
|
for app_label, model in form.grouped_permissions.items():
|
||||||
|
for mo, perms in model.items():
|
||||||
|
for perm in perms:
|
||||||
|
perm.is_checked = perm.id in group_permission_ids
|
||||||
|
|
||||||
|
return render(request,"groups/group_permission_form.html", {
|
||||||
|
"group": customgroup,
|
||||||
|
"form": form,
|
||||||
|
"group_permission_apps": set(customgroup.group.permissions.values_list('content_type__app_label', flat=True)),
|
||||||
|
"group_permission_models": set(customgroup.group.permissions.values_list('content_type__model', flat=True))
|
||||||
|
})
|
||||||
|
# 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
|
||||||
|
# a form for editing permissions or processes the submitted permissions.
|
||||||
|
|
||||||
|
# If the request method is POST, the permissions of the group are cleared and updated
|
||||||
|
# based on the submitted data. A success message is displayed upon completion, and
|
||||||
|
# the user is redirected to the group's detail page.
|
||||||
|
|
||||||
|
# In case of a GET request, the view renders the form pre-filled with the group's
|
||||||
|
# current permissions.
|
||||||
|
|
||||||
|
# :param request: The HTTP request object.
|
||||||
|
# :type request: HttpRequest
|
||||||
|
# :param pk: The primary key of the group whose permissions are being modified.
|
||||||
|
# :type pk: int
|
||||||
|
# :return: The HTTP response depending on the request type. For GET requests, renders
|
||||||
|
# the permission form for the specified group. For POST requests, clears and updates
|
||||||
|
# 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)
|
||||||
|
# group.clear_permissions()
|
||||||
|
# permissions = request.POST.getlist("name")
|
||||||
|
# for i in permissions:
|
||||||
|
# group.add_permission(Permission.objects.get(id=int(i)))
|
||||||
|
# messages.success(request, _("Permission added successfully"))
|
||||||
|
# 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}
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
@ -2915,6 +2958,12 @@ class UserCreateView(
|
|||||||
success_url = reverse_lazy("user_list")
|
success_url = reverse_lazy("user_list")
|
||||||
success_message = _("User created successfully")
|
success_message = _("User created successfully")
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
|
form.fields["group"].queryset = models.CustomGroup.objects.filter(dealer=dealer)
|
||||||
|
return form
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
# quota_dict = get_user_quota(dealer.user)
|
# quota_dict = get_user_quota(dealer.user)
|
||||||
@ -2956,11 +3005,9 @@ class UserCreateView(
|
|||||||
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
|
||||||
staff.add_as_manager()
|
|
||||||
group = models.CustomGroup.objects.filter(dealer=dealer,name__iexact=staff.staff_type).first()
|
|
||||||
staff.save()
|
staff.save()
|
||||||
if group:
|
for customgroup in form.cleaned_data["group"]:
|
||||||
staff.add_group(group.group)
|
staff.add_group(customgroup.group)
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("user_list", args=[self.request.dealer.slug])
|
return reverse_lazy("user_list", args=[self.request.dealer.slug])
|
||||||
@ -3004,30 +3051,32 @@ class UserUpdateView(
|
|||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
form = super().get_form(form_class)
|
form = super().get_form(form_class)
|
||||||
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
|
form.fields["group"].queryset = models.CustomGroup.objects.filter(dealer=dealer)
|
||||||
form.fields["email"].disabled = True
|
form.fields["email"].disabled = True
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
initial = super().get_initial()
|
initial = super().get_initial()
|
||||||
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()
|
initial["group"] = self.object.groups
|
||||||
|
|
||||||
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"]
|
||||||
if not services:
|
# if not services:
|
||||||
self.object.staff_member.services_offered.clear()
|
# self.object.staff_member.services_offered.clear()
|
||||||
else:
|
# else:
|
||||||
for service in services:
|
# for service in services:
|
||||||
self.object.staff_member.services_offered.add(service)
|
# self.object.staff_member.services_offered.add(service)
|
||||||
|
|
||||||
staff = form.save(commit=False)
|
staff = form.save(commit=False)
|
||||||
staff.name = form.cleaned_data["name"]
|
staff.name = form.cleaned_data["name"]
|
||||||
staff.arabic_name = form.cleaned_data["arabic_name"]
|
staff.arabic_name = form.cleaned_data["arabic_name"]
|
||||||
staff.phone_number = form.cleaned_data["phone_number"]
|
staff.phone_number = form.cleaned_data["phone_number"]
|
||||||
staff.staff_type = form.cleaned_data["staff_type"]
|
for customgroup in form.cleaned_data["group"]:
|
||||||
|
staff.add_group(customgroup.group,True)
|
||||||
staff.add_as_manager()
|
|
||||||
staff.save()
|
staff.save()
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@ -5180,7 +5229,7 @@ def lead_create(request,dealer_slug):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
instance = form.save(commit=False)
|
instance = form.save(commit=False)
|
||||||
instance.dealer = dealer
|
instance.dealer = dealer
|
||||||
instance.staff = form.cleaned_data.get("staff")
|
# instance.staff = form.cleaned_data.get("staff")
|
||||||
|
|
||||||
if instance.lead_type == "customer":
|
if instance.lead_type == "customer":
|
||||||
customer = models.Customer.objects.filter(
|
customer = models.Customer.objects.filter(
|
||||||
@ -5252,12 +5301,12 @@ def lead_create(request,dealer_slug):
|
|||||||
is_sa_import=True, pk__in=dealer_make_list
|
is_sa_import=True, pk__in=dealer_make_list
|
||||||
)
|
)
|
||||||
form.fields["staff"].queryset = form.fields["staff"].queryset.filter(
|
form.fields["staff"].queryset = form.fields["staff"].queryset.filter(
|
||||||
dealer=dealer, staff_type="sales"
|
dealer=dealer
|
||||||
)
|
)
|
||||||
|
|
||||||
if hasattr(request.user.staffmember, "staff"):
|
if hasattr(request.user.staffmember, "staff"):
|
||||||
form.initial["staff"] = request.user.staffmember.staff
|
form.initial["staff"] = request.user.staffmember.staff
|
||||||
form.fields["staff"].widget.attrs["disabled"] = True
|
form.fields["staff"].widget = HiddenInput()
|
||||||
form.fields["id_car_make"].queryset = qs
|
form.fields["id_car_make"].queryset = qs
|
||||||
form.fields["id_car_make"].choices = [
|
form.fields["id_car_make"].choices = [
|
||||||
(obj.id_car_make, obj.get_local_name()) for obj in qs
|
(obj.id_car_make, obj.get_local_name()) for obj in qs
|
||||||
@ -5817,6 +5866,13 @@ class OpportunityCreateView(CreateView, SuccessMessageMixin, LoginRequiredMixin)
|
|||||||
initial["stage"] = models.Stage.QUALIFICATION
|
initial["stage"] = models.Stage.QUALIFICATION
|
||||||
return initial
|
return initial
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
dealer = get_object_or_404(models.Dealer,slug=self.kwargs.get("dealer_slug"))
|
||||||
|
form.fields['car'].queryset = models.Car.objects.filter(dealer=dealer)
|
||||||
|
form.fields['lead'].queryset = models.Lead.objects.filter(dealer=dealer)
|
||||||
|
return form
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
dealer = get_object_or_404(models.Dealer,slug=self.kwargs.get("dealer_slug"))
|
dealer = get_object_or_404(models.Dealer,slug=self.kwargs.get("dealer_slug"))
|
||||||
instance = form.save(commit=False)
|
instance = form.save(commit=False)
|
||||||
@ -5859,6 +5915,13 @@ class OpportunityUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView)
|
|||||||
template_name = "crm/opportunities/opportunity_form.html"
|
template_name = "crm/opportunities/opportunity_form.html"
|
||||||
success_message = "Opportunity updated successfully."
|
success_message = "Opportunity updated successfully."
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
dealer = get_object_or_404(models.Dealer,slug=self.kwargs.get("dealer_slug"))
|
||||||
|
form.fields['car'].queryset = models.Car.objects.filter(dealer=dealer)
|
||||||
|
form.fields['lead'].queryset = models.Lead.objects.filter(dealer=dealer)
|
||||||
|
return form
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("opportunity_detail", kwargs={"dealer_slug":self.kwargs.get("dealer_slug"),"slug": self.object.slug})
|
return reverse_lazy("opportunity_detail", kwargs={"dealer_slug":self.kwargs.get("dealer_slug"),"slug": self.object.slug})
|
||||||
|
|
||||||
@ -8788,7 +8851,6 @@ def payment_callback(request,dealer_slug):
|
|||||||
|
|
||||||
|
|
||||||
def sse_stream(request):
|
def sse_stream(request):
|
||||||
print("hi")
|
|
||||||
def event_stream():
|
def event_stream():
|
||||||
last_id = request.GET.get("last_id", 0)
|
last_id = request.GET.get("last_id", 0)
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@ -11,7 +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 'group_create' request.dealer.slug %}" 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 me-5"><span class="fas fa-plus me-2"></span>{% trans "Add Group" %}</a>
|
||||||
|
<a href="{% url 'user_list' request.dealer.slug %}" class="btn btn-sm btn-phoenix-secondary"><span class="fas fas fa-arrow-left me-2"></span>{% trans "Back to Staffs" %}</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
45
templates/groups/group_permission_form-copy.html
Normal file
45
templates/groups/group_permission_form-copy.html
Normal 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' 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") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -1,46 +1,157 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load crispy_forms_filters %}
|
{% load custom_filters %}
|
||||||
{% block title %}{% trans "Permission" %}{% endblock title %}
|
|
||||||
|
{% block title %}{% trans "Permission Management" %}{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-sm-flex justify-content-between align-items-center">
|
||||||
|
<h3 class="mb-0">
|
||||||
|
{% if group %}
|
||||||
|
{{ _("Edit Permissions for") }}: <strong>{{ group.name }}</strong>
|
||||||
|
{% else %}
|
||||||
|
{{ _("Add Permissions") }}
|
||||||
|
{% endif %}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
<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>
|
</div>
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="col-sm-9">
|
|
||||||
|
|
||||||
<form class="row g-3 mb-9" method="post" class="form" novalidate>
|
<form method="post" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ redirect_field }}
|
|
||||||
{{ form|crispy }}
|
<!-- Permissions Grid -->
|
||||||
{% for error in form.errors %}
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4" id="permissionsGrid">
|
||||||
<div class="text-danger">{{ error }}</div>
|
{% for app_label, models in form.grouped_permissions.items %}
|
||||||
{% endfor %}
|
<div class="col">
|
||||||
<div class="d-flex mb-3">
|
<div class="card h-100 border-{% if app_label in group_permission_apps %}primary{% else %}light{% endif %}">
|
||||||
<button class="btn btn-phoenix-primary me-2" type="submit">
|
<div class="card-header bg-{% if app_label in group_permission_apps %}primary text-white{% else %}light{% endif %}">
|
||||||
<i class="fa-solid fa-floppy-disk"></i>
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
{{ _("Save") }}
|
<h5 class="card-title mb-0">
|
||||||
|
<i class="fas fa-{% if app_label in group_permission_apps %}check-circle{% else %}cube{% endif %} me-2"></i>
|
||||||
|
{{ app_label|capfirst }}
|
||||||
|
</h5>
|
||||||
|
<span class="badge bg-{% if app_label in group_permission_apps %}light text-primary{% else %}secondary{% endif %}">
|
||||||
|
{{ models|length }} {% trans "models" %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="accordion">
|
||||||
|
{% for model, perms in models.items %}
|
||||||
|
<div class="accordion-item border-0">
|
||||||
|
<h6 class="accordion-header" id="heading-{{ app_label|slugify }}-{{ model|slugify }}">
|
||||||
|
<button class="accordion-button collapsed bg-white shadow-none py-2"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#collapse-{{ app_label|slugify }}-{{ model|slugify }}"
|
||||||
|
aria-expanded="false">
|
||||||
|
<i class="fas fa-table me-2"></i>{{ model|capfirst }}
|
||||||
|
<span class="badge bg-{% if model in group_permission_models %}primary{% else %}secondary{% endif %} rounded-pill ms-2">
|
||||||
|
{{ perms|length }} / {{ perms|count_checked }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</h6>
|
||||||
|
<div id="collapse-{{ app_label|slugify }}-{{ model|slugify }}"
|
||||||
|
class="accordion-collapse collapse"
|
||||||
|
aria-labelledby="heading-{{ app_label|slugify }}-{{ model|slugify }}">
|
||||||
|
<div class="accordion-body pt-0">
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
{% for perm in perms %}
|
||||||
|
<label class="list-group-item d-flex gap-2 {% if perm.is_checked %}bg-light-primary{% endif %}">
|
||||||
|
<input class="form-check-input flex-shrink-0 mt-0"
|
||||||
|
type="checkbox"
|
||||||
|
name="permissions"
|
||||||
|
value="{{ perm.id }}"
|
||||||
|
id="perm_{{ perm.id }}"
|
||||||
|
{% if perm.is_checked %}checked{% endif %}>
|
||||||
|
<span>
|
||||||
|
<span class="d-block fw-bold">{{ perm.name|capfirst }}</span>
|
||||||
|
<small class="d-block text-muted">{{ perm.codename }}</small>
|
||||||
|
{% if perm.is_checked %}
|
||||||
|
<span class="badge bg-success mt-1">
|
||||||
|
<i class="fas fa-check me-1"></i>{% trans "Assigned" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<span class="badge bg-primary rounded-pill me-2">
|
||||||
|
{{ group.permissions.count }} {% trans "selected" %}
|
||||||
|
</span>
|
||||||
|
<span class="text-muted">
|
||||||
|
{% trans "Permissions will be updated immediately" %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'group_detail' request.dealer.slug group.pk %}"
|
||||||
|
class="btn btn-outline-secondary me-2">
|
||||||
|
<i class="fas fa-ban me-2"></i>{% trans "Cancel" %}
|
||||||
|
</a>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save me-2"></i>{% trans "Save Changes" %}
|
||||||
</button>
|
</button>
|
||||||
<a href="{% url 'group_detail' request.dealer.slug group.pk %}" class="btn btn-phoenix-secondary "><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-secondary "><i class="fa-solid fa-ban"></i> {% trans "Cancel"|capfirst %}</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.bg-light-primary {
|
||||||
|
background-color: rgba(13, 110, 253, 0.1);
|
||||||
|
}
|
||||||
|
.list-group-item:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Search functionality
|
||||||
|
document.getElementById('permissionSearch').addEventListener('input', function(e) {
|
||||||
|
const searchTerm = e.target.value.toLowerCase();
|
||||||
|
document.querySelectorAll('.accordion-body .list-group-item').forEach(item => {
|
||||||
|
const text = item.textContent.toLowerCase();
|
||||||
|
item.style.display = text.includes(searchTerm) ? '' : 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open relevant accordions
|
||||||
|
document.querySelectorAll('.accordion-collapse').forEach(collapse => {
|
||||||
|
const visibleItems = collapse.querySelectorAll('.list-group-item[style=""]');
|
||||||
|
if (visibleItems.length > 0) {
|
||||||
|
const button = document.querySelector(
|
||||||
|
`button[data-bs-target="#${collapse.id}"]`
|
||||||
|
);
|
||||||
|
if (button && !button.classList.contains('collapsed')) {
|
||||||
|
new bootstrap.Collapse(collapse, {toggle: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -81,10 +81,6 @@
|
|||||||
{{ _("Sale Order")}} #{{ saleorder.formatted_order_id }}
|
{{ _("Sale Order")}} #{{ saleorder.formatted_order_id }}
|
||||||
</h1>
|
</h1>
|
||||||
<div>
|
<div>
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
<button class="btn btn-sm btn-outline-light me-2">
|
<button class="btn btn-sm btn-outline-light me-2">
|
||||||
<i class="fas fa-print me-1"></i> {{ _("Print") }}
|
<i class="fas fa-print me-1"></i> {{ _("Print") }}
|
||||||
</button>
|
</button>
|
||||||
@ -275,18 +271,10 @@
|
|||||||
<!-- Documents Card -->
|
<!-- Documents Card -->
|
||||||
<div class="card mb-4 shadow-sm">
|
<div class="card mb-4 shadow-sm">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<<<<<<< HEAD
|
|
||||||
<h5 class="mb-0">{{ _("Documents") }}</h5>
|
<h5 class="mb-0">{{ _("Documents") }}</h5>
|
||||||
<button class="btn btn-sm btn-primary">
|
<button class="btn btn-sm btn-primary">
|
||||||
<i class="fas fa-plus me-1"></i> {{ _("Add Document")}}
|
<i class="fas fa-plus me-1"></i> {{ _("Add Document")}}
|
||||||
=======
|
</button>
|
||||||
|
|
||||||
<h5 class="mb-0">{{ _("Documents") }}</h5>
|
|
||||||
<button class="btn btn-sm btn-primary">
|
|
||||||
<i class="fas fa-plus me-1"></i> {{ _("Add Document")}}
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="file-upload mb-3">
|
<div class="file-upload mb-3">
|
||||||
@ -330,13 +318,7 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<textarea class="form-control" name="comment" rows="3" placeholder="Add a comment or note..." required></textarea>
|
<textarea class="form-control" name="comment" rows="3" placeholder="Add a comment or note..." required></textarea>
|
||||||
<div class="d-flex justify-content-end mt-2">
|
<div class="d-flex justify-content-end mt-2">
|
||||||
<<<<<<< HEAD
|
|
||||||
<button type="submit" class="btn btn-primary btn-sm">{{ _("Post Comment")}}</button>
|
<button type="submit" class="btn btn-primary btn-sm">{{ _("Post Comment")}}</button>
|
||||||
=======
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary btn-sm">{{ _("Post Comment")}}</button>
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -379,52 +361,27 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% comment %} <a href="{% url 'edit_sale_order' saleorder.pk %}" class="btn btn-primary"> {% endcomment %}
|
{% comment %} <a href="{% url 'edit_sale_order' saleorder.pk %}" class="btn btn-primary"> {% endcomment %}
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
<a href="" class="btn btn-primary">
|
<a href="" class="btn btn-primary">
|
||||||
<i class="fas fa-edit me-2"></i> {{ _("Edit Order")}}
|
<i class="fas fa-edit me-2"></i> {{ _("Edit Order")}}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% if not saleorder.invoice %}
|
{% if not saleorder.invoice %}
|
||||||
{% comment %} <a href="{% url 'create_invoice_from_order' saleorder.pk %}" class="btn btn-info"> {% endcomment %}
|
{% comment %} <a href="{% url 'create_invoice_from_order' saleorder.pk %}" class="btn btn-info"> {% endcomment %}
|
||||||
<<<<<<< HEAD
|
|
||||||
<a href="" class="btn btn-info">
|
<a href="" class="btn btn-info">
|
||||||
<i class="fas fa-file-invoice-dollar me-2"></i> {{ _("Create Invoice")}}
|
<i class="fas fa-file-invoice-dollar me-2"></i> {{ _("Create Invoice")}}
|
||||||
=======
|
</a>
|
||||||
|
|
||||||
<a href="" class="btn btn-info">
|
|
||||||
<i class="fas fa-file-invoice-dollar me-2"></i> {{ _("Create Invoice")}}
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if saleorder.status == 'approved' and not saleorder.actual_delivery_date %}
|
{% if saleorder.status == 'approved' and not saleorder.actual_delivery_date %}
|
||||||
<<<<<<< HEAD
|
|
||||||
<button class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#deliveryModal">
|
<button class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#deliveryModal">
|
||||||
<i class="fas fa-truck me-2"></i> {{ _("Schedule Delivery")}}
|
<i class="fas fa-truck me-2"></i> {{ _("Schedule Delivery")}}
|
||||||
=======
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#deliveryModal">
|
|
||||||
<i class="fas fa-truck me-2"></i> {{ _("Schedule Delivery")}}
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if saleorder.status != 'cancelled' %}
|
{% if saleorder.status != 'cancelled' %}
|
||||||
<<<<<<< HEAD
|
|
||||||
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#cancelModal">
|
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#cancelModal">
|
||||||
<i class="fas fa-times-circle me-2"></i> {{ _("Cancel Order")}}
|
<i class="fas fa-times-circle me-2"></i> {{ _("Cancel Order")}}
|
||||||
=======
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#cancelModal">
|
|
||||||
<i class="fas fa-times-circle me-2"></i> {{ _("Cancel Order")}}
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -575,15 +532,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<<<<<<< HEAD
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
||||||
<button type="submit" class="btn btn-danger">{{ _("Confirm Cancellation")}}</button>
|
<button type="submit" class="btn btn-danger">{{ _("Confirm Cancellation")}}</button>
|
||||||
=======
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
|
||||||
<button type="submit" class="btn btn-danger">{{ _("Confirm Cancellation")}}</button>
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -612,15 +562,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<<<<<<< HEAD
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
||||||
<button type="submit" class="btn btn-primary">{{ _("Schedule Delivery")}}</button>
|
<button type="submit" class="btn btn-primary">{{ _("Schedule Delivery")}}</button>
|
||||||
=======
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
|
||||||
<button type="submit" class="btn btn-primary">{{ _("Schedule Delivery")}}</button>
|
|
||||||
|
|
||||||
>>>>>>> e9e2fd3 (add bulk insert + po item insert)
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,7 +18,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<p><strong>{{ _("Phone Number") }}:</strong> {{ user_.phone_number }}</p>
|
<p><strong>{{ _("Phone Number") }}:</strong> {{ user_.phone_number }}</p>
|
||||||
<p><strong>{{ _("Role") }}:</strong> {{ user_.staff_type }}</p>
|
<div>
|
||||||
|
<span><strong>{{ _("Roles") }}:</strong></span>
|
||||||
|
{% for group in user_.groups %}
|
||||||
|
<span><strong>{{ group.name }}</strong></span>
|
||||||
|
{% if not forloop.last %}
|
||||||
|
<span>&</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -39,8 +39,7 @@
|
|||||||
{{ form.arabic_name|as_crispy_field }}
|
{{ form.arabic_name|as_crispy_field }}
|
||||||
{{ form.email|as_crispy_field }}
|
{{ form.email|as_crispy_field }}
|
||||||
{{ form.phone_number|as_crispy_field }}
|
{{ form.phone_number|as_crispy_field }}
|
||||||
{{ form.staff_type|as_crispy_field }}
|
{{ form.group|as_crispy_field }}
|
||||||
{{ form.service_offered|as_crispy_field }}
|
|
||||||
{% for error in form.errors %}
|
{% for error in form.errors %}
|
||||||
<div class="text-danger">{{ error }}</div>
|
<div class="text-danger">{{ error }}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -56,3 +55,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="">
|
<section class="">
|
||||||
|
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<div class="d-md-flex justify-content-between">
|
<div class="d-md-flex justify-content-between">
|
||||||
@ -47,7 +46,10 @@
|
|||||||
<td class="align-middle white-space-nowrap align-items-center">{{ user.email }}</td>
|
<td class="align-middle white-space-nowrap align-items-center">{{ user.email }}</td>
|
||||||
<td class="align-middle white-space-nowrap align-items-center justify-content-center">{{ user.phone_number }}</td>
|
<td class="align-middle white-space-nowrap align-items-center justify-content-center">{{ user.phone_number }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge badge-sm bg-primary text-center"><i class="fa-solid fa-scroll"></i> {% trans user.staff_type|title %}</span>
|
|
||||||
|
{% for group in user.groups %}
|
||||||
|
<span class="badge badge-sm bg-primary text-center"><i class="fa-solid fa-scroll"></i> {% trans group.name|title %}</span>
|
||||||
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="align-middle white-space-nowrap">
|
<td class="align-middle white-space-nowrap">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user