update
This commit is contained in:
commit
e441983674
@ -1606,6 +1606,7 @@ class PermissionForm(forms.ModelForm):
|
|||||||
"django_ledger.invoicemodel",
|
"django_ledger.invoicemodel",
|
||||||
"django_ledger.vendormodel",
|
"django_ledger.vendormodel",
|
||||||
"django_ledger.journalentrymodel"
|
"django_ledger.journalentrymodel"
|
||||||
|
# "django_ledger.purchaseordermodel",#TODO add purchase order
|
||||||
]
|
]
|
||||||
|
|
||||||
permissions = cache.get(
|
permissions = cache.get(
|
||||||
|
|||||||
@ -143,7 +143,6 @@ class DealerSlugMiddleware:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if dealer_slug.lower() != request.dealer.slug.lower():
|
if dealer_slug.lower() != request.dealer.slug.lower():
|
||||||
print(dealer_slug)
|
|
||||||
logger.warning(f"Dealer slug mismatch: {dealer_slug} != {request.dealer.slug}")
|
logger.warning(f"Dealer slug mismatch: {dealer_slug} != {request.dealer.slug}")
|
||||||
raise Http404("Dealer slug mismatch")
|
raise Http404("Dealer slug mismatch")
|
||||||
|
|
||||||
|
|||||||
@ -904,15 +904,28 @@ def create_po_item_upload(sender,instance,created,**kwargs):
|
|||||||
models.PoItemsUploaded.objects.create(dealer=dealer,po=instance, item=item, status="fulfilled")
|
models.PoItemsUploaded.objects.create(dealer=dealer,po=instance, item=item, status="fulfilled")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
######################Notification########################
|
######################Notification########################
|
||||||
##########################################################
|
##########################################################
|
||||||
|
|
||||||
|
@receiver(post_save, sender=PurchaseOrderModel)
|
||||||
|
def create_po_fulfilled_notification(sender,instance,created,**kwargs):
|
||||||
|
if instance.po_status == "fulfilled":
|
||||||
|
dealer = models.Dealer.objects.get(entity=instance.entity)
|
||||||
|
accountants = models.CustomGroup.objects.filter(dealer=dealer,name="Inventory").first().group.user_set.exclude(email=dealer.user.email)
|
||||||
|
for accountant in accountants:
|
||||||
|
models.Notification.objects.create(
|
||||||
|
user=accountant,
|
||||||
|
message=f"""
|
||||||
|
New Purchase Order {instance.po_number} has been added to dealer {instance.dealer.name}.
|
||||||
|
<a href="{instance.get_absolute_url()}" target="_blank">View</a>
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
@receiver(post_save, sender=models.Car)
|
@receiver(post_save, sender=models.Car)
|
||||||
def car_created_notification(sender, instance, created, **kwargs):
|
def car_created_notification(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
accountants = models.CustomGroup.objects.filter(dealer=instance.dealer,name="Accountant").first().group.user_set.exclude(email=instance.dealer.user.email)
|
accountants = models.CustomGroup.objects.filter(dealer=instance.dealer,name__in=["Manager","Accountant"]).first().group.user_set.all()
|
||||||
for accountant in accountants:
|
for accountant in accountants:
|
||||||
models.Notification.objects.create(
|
models.Notification.objects.create(
|
||||||
user=accountant,
|
user=accountant,
|
||||||
@ -971,13 +984,18 @@ def lead_created_notification(sender, instance, created, **kwargs):
|
|||||||
<a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
|
<a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
@receiver(post_save, sender=models.Lead)
|
# @receiver(post_save, sender=models.Lead)
|
||||||
def lead_created_notification(sender, instance, created, **kwargs):
|
# def lead_created_notification(sender, instance, created, **kwargs):
|
||||||
if created:
|
# if created:
|
||||||
models.Notification.objects.create(
|
# models.Notification.objects.create(
|
||||||
user=instance.staff.user,
|
# user=instance.staff.user,
|
||||||
message=f"""
|
# message=f"""
|
||||||
New Lead has been added.
|
# New Lead has been added.
|
||||||
<a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
|
# <a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
|
||||||
""",
|
# """,
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
# send notification after car is sold {manager,dealer}
|
||||||
|
# after po review send notification to {manager} to approve po
|
||||||
|
# after estimate review send notification to {manager} to approve estimate
|
||||||
@ -207,11 +207,7 @@ urlpatterns = [
|
|||||||
path("notifications/stream/", views.sse_stream, name="sse_stream"),
|
path("notifications/stream/", views.sse_stream, name="sse_stream"),
|
||||||
path("notifications/fetch/", views.fetch_notifications, name="fetch_notifications"),
|
path("notifications/fetch/", views.fetch_notifications, name="fetch_notifications"),
|
||||||
|
|
||||||
path(
|
path("notifications/list/", views.NotificationListView.as_view(), name="notifications_history"),
|
||||||
"notifications/",
|
|
||||||
views.NotificationListView.as_view(),
|
|
||||||
name="notifications_history",
|
|
||||||
),
|
|
||||||
|
|
||||||
path(
|
path(
|
||||||
"notifications/<int:notification_id>/mark_as_read/",
|
"notifications/<int:notification_id>/mark_as_read/",
|
||||||
@ -1086,17 +1082,17 @@ urlpatterns = [
|
|||||||
#########
|
#########
|
||||||
# Purchase Order
|
# Purchase Order
|
||||||
path(
|
path(
|
||||||
"<slug:dealer_slug>/purchase_orders/",
|
"<slug:dealer_slug>/<slug:entity_slug>/purchase_orders/",
|
||||||
views.PurchaseOrderListView.as_view(),
|
views.PurchaseOrderListView.as_view(),
|
||||||
name="purchase_order_list",
|
name="purchase_order_list",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"<slug:dealer_slug>/purchase_orders/new/",
|
"<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/new/",
|
||||||
views.PurchaseOrderCreateView,
|
views.PurchaseOrderCreateView,
|
||||||
name="purchase_order_create",
|
name="purchase_order_create",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"<slug:dealer_slug>/purchase_orders/<uuid:pk>/detail/",
|
"<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/<uuid:pk>/detail/",
|
||||||
views.PurchaseOrderDetailView.as_view(),
|
views.PurchaseOrderDetailView.as_view(),
|
||||||
name="purchase_order_detail",
|
name="purchase_order_detail",
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3499,6 +3499,20 @@ class BankAccountCreateView(
|
|||||||
kwargs["entity_slug"] = entity.slug
|
kwargs["entity_slug"] = entity.slug
|
||||||
kwargs["user_model"] = entity.admin
|
kwargs["user_model"] = entity.admin
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
account_qs = dealer.entity.get_all_accounts().filter(
|
||||||
|
role__in=[
|
||||||
|
roles.ASSET_CA_CASH,
|
||||||
|
roles.LIABILITY_CL_ACC_PAYABLE,
|
||||||
|
roles.LIABILITY_LTL_MORTGAGE_PAYABLE
|
||||||
|
])
|
||||||
|
form.fields['account_model'].queryset = account_qs
|
||||||
|
|
||||||
|
return form
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy("bank_account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
|
return reverse_lazy("bank_account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
|
||||||
|
|
||||||
@ -3567,7 +3581,18 @@ class BankAccountUpdateView(
|
|||||||
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
|
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
|
||||||
kwargs["user_model"] = entity.admin # Get user_model from the request
|
kwargs["user_model"] = entity.admin # Get user_model from the request
|
||||||
return kwargs
|
return kwargs
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
|
form = super().get_form(form_class)
|
||||||
|
account_qs = dealer.entity.get_all_accounts().filter(
|
||||||
|
role__in=[
|
||||||
|
roles.ASSET_CA_CASH,
|
||||||
|
roles.LIABILITY_CL_ACC_PAYABLE,
|
||||||
|
roles.LIABILITY_LTL_MORTGAGE_PAYABLE
|
||||||
|
])
|
||||||
|
form.fields['account_model'].queryset = account_qs
|
||||||
|
|
||||||
|
return form
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy(
|
return reverse_lazy(
|
||||||
"bank_account_detail",
|
"bank_account_detail",
|
||||||
@ -6320,14 +6345,19 @@ class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateV
|
|||||||
permission_required = ["django_ledger.add_itemmodel"]
|
permission_required = ["django_ledger.add_itemmodel"]
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
kwargs["entity_slug"] = dealer.entity.slug
|
kwargs["entity_slug"] = dealer.entity.slug
|
||||||
kwargs["user_model"] = dealer.entity.admin
|
kwargs["user_model"] = dealer.entity.admin
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
# def get_form(self,form_class=None):
|
||||||
|
# dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
|
# form = super().get_form(form_class)
|
||||||
|
# form.fields["uom"].queryset = dealer.entity.get_uom_all()
|
||||||
|
# return form
|
||||||
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"])
|
||||||
form.instance.entity = dealer.entity
|
form.instance.entity = dealer.entity
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@ -6880,15 +6910,15 @@ class BillModelCreateView(CreateView):
|
|||||||
return {"date_draft": get_localdate()}
|
return {"date_draft": get_localdate()}
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
return BillModelCreateForm(entity_model=dealer.entity, **self.get_form_kwargs())
|
return BillModelCreateForm(entity_model=dealer.entity, **self.get_form_kwargs())
|
||||||
|
|
||||||
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"])
|
||||||
bill_model: BillModel = form.save(commit=False)
|
bill_model: BillModel = form.save(commit=False)
|
||||||
ledger_model, bill_model = bill_model.configure(
|
ledger_model, bill_model = bill_model.configure(
|
||||||
entity_slug=dealer.entity.slug,
|
entity_slug=dealer.entity,
|
||||||
user_model=self.request.user,
|
user_model=dealer.entity.admin,
|
||||||
commit_ledger=True,
|
commit_ledger=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -8836,7 +8866,7 @@ def payment_callback(request,dealer_slug):
|
|||||||
return render(request, "payment_failed.html", {"message": message})
|
return render(request, "payment_failed.html", {"message": message})
|
||||||
|
|
||||||
|
|
||||||
def sse_stream(request):
|
def sse_stream(request):
|
||||||
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:
|
||||||
@ -8895,7 +8925,7 @@ def mark_all_notifications_as_read(request):
|
|||||||
@login_required
|
@login_required
|
||||||
def notifications_history(request):
|
def notifications_history(request):
|
||||||
models.Notification.objects.filter(user=request.user, is_read=False).update(
|
models.Notification.objects.filter(user=request.user, is_read=False).update(
|
||||||
read=True
|
is_read=True
|
||||||
)
|
)
|
||||||
return JsonResponse({"status": "success"})
|
return JsonResponse({"status": "success"})
|
||||||
|
|
||||||
@ -9216,18 +9246,23 @@ def permenant_delete_account(request,dealer_slug, content_type, slug):
|
|||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
|
|
||||||
def PurchaseOrderCreateView(request, dealer_slug):
|
def PurchaseOrderCreateView(request, dealer_slug,entity_slug):
|
||||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||||
entity = dealer.entity
|
entity = dealer.entity
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
po = entity.create_purchase_order(po_title=request.POST.get("po_title"))
|
try:
|
||||||
po.entity = entity
|
po = entity.create_purchase_order(po_title=request.POST.get("po_title"))
|
||||||
po.save()
|
po.entity = entity
|
||||||
|
po.save()
|
||||||
|
except ValidationError as e:
|
||||||
|
messages.error(request, str(e))
|
||||||
|
return redirect("purchase_order_create", dealer_slug=dealer.slug, entity_slug=entity.slug)
|
||||||
messages.success(request, _("Purchase order created successfully"))
|
messages.success(request, _("Purchase order created successfully"))
|
||||||
return redirect("purchase_order_detail", dealer_slug=dealer.slug, pk=po.pk)
|
return redirect("purchase_order_detail", dealer_slug=dealer.slug, entity_slug=entity.slug, pk=po.pk)
|
||||||
|
|
||||||
form = PurchaseOrderModelCreateForm(
|
form = PurchaseOrderModelCreateForm(
|
||||||
entity_slug=entity.slug, user_model=entity.admin
|
entity_slug=entity.slug,
|
||||||
|
user_model=entity.admin,
|
||||||
)
|
)
|
||||||
return render(request, "purchase_orders/po_form.html", {"form": form})
|
return render(request, "purchase_orders/po_form.html", {"form": form})
|
||||||
|
|
||||||
@ -9346,14 +9381,12 @@ class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase):
|
|||||||
context_object_name = "po_model"
|
context_object_name = "po_model"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
self.queryset = PurchaseOrderModel.objects.for_entity(
|
self.queryset = dealer.entity.get_purchase_orders().select_related("entity", "ce_model")
|
||||||
entity_slug=dealer.entity.slug, user_model=dealer.entity.admin
|
|
||||||
).select_related("entity", "ce_model")
|
|
||||||
return super().get_queryset()
|
return super().get_queryset()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context["entity_slug"] = dealer.entity.slug
|
context["entity_slug"] = dealer.entity.slug
|
||||||
return context
|
return context
|
||||||
@ -9367,77 +9400,76 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie
|
|||||||
permission_required = ["inventory.view_carfinance"]
|
permission_required = ["inventory.view_carfinance"]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
entity = dealer.entity
|
return self.model.objects.filter(entity=dealer.entity)
|
||||||
return self.model.objects.filter(entity=entity)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
dealer = get_user_type(self.request)
|
|
||||||
entity = dealer.entity
|
|
||||||
queryset = self.model.objects.filter(entity=entity)
|
|
||||||
|
|
||||||
query = self.request.GET.get('q') # This is generic: looks for 'q' from GET
|
# def get_queryset(self):
|
||||||
|
# dealer = get_user_type(self.request)
|
||||||
|
# entity = dealer.entity
|
||||||
|
# queryset = self.model.objects.filter(entity=entity)
|
||||||
|
|
||||||
if query:
|
# query = self.request.GET.get('q') # This is generic: looks for 'q' from GET
|
||||||
# Start with an empty Q object for the search filters
|
|
||||||
search_filters = Q()
|
|
||||||
|
|
||||||
# 1. Try to parse the query as a date
|
# if query:
|
||||||
parsed_date = None
|
# # Start with an empty Q object for the search filters
|
||||||
date_formats = [
|
# search_filters = Q()
|
||||||
'%Y-%m-%d', # 2023-10-26
|
|
||||||
'%m/%d/%Y', # 10/26/2023
|
|
||||||
'%d-%m-%Y', # 26-10-2023
|
|
||||||
'%B %d, %Y', # October 26, 2023
|
|
||||||
'%b %d, %Y', # Oct 26, 2023
|
|
||||||
'%Y/%m/%d', # 2023/10/26
|
|
||||||
'%Y-%m', # 2023-10 (for year-month search)
|
|
||||||
'%Y',
|
|
||||||
'%b %d',
|
|
||||||
'%B %d' # 2023 (for year search)
|
|
||||||
]
|
|
||||||
|
|
||||||
for fmt in date_formats:
|
# # 1. Try to parse the query as a date
|
||||||
try:
|
# parsed_date = None
|
||||||
# For '%Y-%m' and '%Y', we only care about year/month, not exact day
|
# date_formats = [
|
||||||
if fmt == '%Y-%m':
|
# '%Y-%m-%d', # 2023-10-26
|
||||||
parsed_date = datetime.strptime(query, fmt)
|
# '%m/%d/%Y', # 10/26/2023
|
||||||
search_filters |= Q(created__year=parsed_date.year, created__month=parsed_date.month)
|
# '%d-%m-%Y', # 26-10-2023
|
||||||
break
|
# '%B %d, %Y', # October 26, 2023
|
||||||
elif fmt == '%Y':
|
# '%b %d, %Y', # Oct 26, 2023
|
||||||
parsed_date = datetime.strptime(query, fmt)
|
# '%Y/%m/%d', # 2023/10/26
|
||||||
search_filters |= Q(created__year=parsed_date.year)
|
# '%Y-%m', # 2023-10 (for year-month search)
|
||||||
break
|
# '%Y',
|
||||||
else:
|
# '%b %d',
|
||||||
parsed_date = datetime.strptime(query, fmt).date()
|
# '%B %d' # 2023 (for year search)
|
||||||
search_filters |= Q(created__date=parsed_date) # Matches exact date part of datetime field
|
# ]
|
||||||
break # Found a match, no need to try other formats
|
|
||||||
except ValueError:
|
|
||||||
continue # Try next format
|
|
||||||
|
|
||||||
# 2. Add text-based search filters (always apply these)
|
# for fmt in date_formats:
|
||||||
# Combine them with OR operator
|
# try:
|
||||||
text_filters = (
|
# # For '%Y-%m' and '%Y', we only care about year/month, not exact day
|
||||||
Q(po_number__icontains=query) |
|
# if fmt == '%Y-%m':
|
||||||
Q(po_title__icontains=query) |
|
# parsed_date = datetime.strptime(query, fmt)
|
||||||
Q(po_status__icontains=query) |
|
# search_filters |= Q(created__year=parsed_date.year, created__month=parsed_date.month)
|
||||||
Q(created__icontains=query)
|
# break
|
||||||
|
# elif fmt == '%Y':
|
||||||
|
# parsed_date = datetime.strptime(query, fmt)
|
||||||
|
# search_filters |= Q(created__year=parsed_date.year)
|
||||||
|
# break
|
||||||
|
# else:
|
||||||
|
# parsed_date = datetime.strptime(query, fmt).date()
|
||||||
|
# search_filters |= Q(created__date=parsed_date) # Matches exact date part of datetime field
|
||||||
|
# break # Found a match, no need to try other formats
|
||||||
|
# except ValueError:
|
||||||
|
# continue # Try next format
|
||||||
|
|
||||||
)
|
# # 2. Add text-based search filters (always apply these)
|
||||||
|
# # Combine them with OR operator
|
||||||
|
# text_filters = (
|
||||||
|
# Q(po_number__icontains=query) |
|
||||||
|
# Q(po_title__icontains=query) |
|
||||||
|
# Q(po_status__icontains=query) |
|
||||||
|
# Q(created__icontains=query)
|
||||||
|
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # If a date was successfully parsed, combine with text filters
|
||||||
|
# if parsed_date:
|
||||||
|
# # Use a combined Q object. This means it will search for
|
||||||
|
# # (date_match OR po_number_match OR po_title_match)
|
||||||
|
# queryset = queryset.filter(search_filters | text_filters).distinct()
|
||||||
|
# else:
|
||||||
|
# # If no date was parsed, only apply text filters
|
||||||
|
# queryset = queryset.filter(text_filters).distinct()
|
||||||
|
|
||||||
|
# return queryset
|
||||||
|
|
||||||
# If a date was successfully parsed, combine with text filters
|
|
||||||
if parsed_date:
|
|
||||||
# Use a combined Q object. This means it will search for
|
|
||||||
# (date_match OR po_number_match OR po_title_match)
|
|
||||||
queryset = queryset.filter(search_filters | text_filters).distinct()
|
|
||||||
else:
|
|
||||||
# If no date was parsed, only apply text filters
|
|
||||||
queryset = queryset.filter(text_filters).distinct()
|
|
||||||
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
@ -9451,7 +9483,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
|
|||||||
context_object_name = "po_model"
|
context_object_name = "po_model"
|
||||||
|
|
||||||
def get_context_data(self, itemtxs_formset=None, **kwargs):
|
def get_context_data(self, itemtxs_formset=None, **kwargs):
|
||||||
dealer = self.request.dealer
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context["entity_slug"] = dealer.entity.slug
|
context["entity_slug"] = dealer.entity.slug
|
||||||
po_model: PurchaseOrderModel = self.object
|
po_model: PurchaseOrderModel = self.object
|
||||||
|
|||||||
@ -185,7 +185,7 @@
|
|||||||
<td class="align-items-start white-space-nowrap pe-2">
|
<td class="align-items-start white-space-nowrap pe-2">
|
||||||
{% if bill_item.po_model_id %}
|
{% if bill_item.po_model_id %}
|
||||||
<a class="btn btn-sm btn-phoenix-primary"
|
<a class="btn btn-sm btn-phoenix-primary"
|
||||||
href="{% url 'purchase_order_detail' request.dealer.slug bill_item.po_model_id %}">
|
href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug bill_item.po_model_id %}">
|
||||||
{% trans 'View PO' %}
|
{% trans 'View PO' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -72,7 +72,7 @@
|
|||||||
{% currency_symbol %}{{ f.instance.po_total_amount | currency_format }}
|
{% currency_symbol %}{{ f.instance.po_total_amount | currency_format }}
|
||||||
</span>
|
</span>
|
||||||
<a class="btn btn-sm btn-phoenix-info mt-1"
|
<a class="btn btn-sm btn-phoenix-info mt-1"
|
||||||
href="{% url 'purchase_order_detail' dealer_slug f.instance.po_model_id %}">
|
href="{% url 'purchase_order_detail' dealer_slug entity_slug f.instance.po_model_id %}">
|
||||||
{% trans 'View PO' %}
|
{% trans 'View PO' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="me-3 flex-1 mt-2">
|
<div class="me-3 flex-1 mt-2">
|
||||||
<h4 class="fs-9 text-body-emphasis">{{ _("System")}}:</h4>
|
<h4 class="fs-9 text-body-emphasis">{{ _("System")}}:</h4>
|
||||||
{% if not notification.is_read %}
|
{% if notification.is_read %}
|
||||||
<p class="fs-9 text-body-highlight"><span class="far fa-envelope text-success-dark fs-8 me-1"></span><span class="me-1">{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
<p class="fs-9 text-body-highlight"><span class="far fa-envelope text-success-dark fs-8 me-1"></span><span class="me-1">{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="fs-9 text-body-highlight"><span class="far fa-envelope-open text-danger-dark fs-8 me-1"></span><span>{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
<p class="fs-9 text-body-highlight"><span class="far fa-envelope-open text-danger-dark fs-8 me-1"></span><span>{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
||||||
@ -48,7 +48,5 @@
|
|||||||
<p>No notifications found.</p>
|
<p>No notifications found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
</div>
|
</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 ">
|
<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-receipt-alt text-secondary"></span>
|
<span class="uil fs-5 lh-1 uil-receipt-alt text-secondary"></span>
|
||||||
<a href="{% url 'purchase_order_list' request.dealer.slug %}"><h4 class="fs-6 pt-3">{{ purchase_orders }}</h4></a>
|
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}"><h4 class="fs-6 pt-3">{{ purchase_orders }}</h4></a>
|
||||||
<p class="fs-9 mb-0">{{ _("Purchase Orders")}}</p>
|
<p class="fs-9 mb-0">{{ _("Purchase Orders")}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -108,8 +108,6 @@
|
|||||||
<button type="submit" class="btn btn-primary me-2">
|
<button type="submit" class="btn btn-primary me-2">
|
||||||
<i class="fas fa-save me-1"></i>{% trans "Save Changes" %}
|
<i class="fas fa-save me-1"></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 me-1"></i> {% trans "Cancel"|capfirst %}</a>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -45,13 +45,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
{% if perms.inventory.add_car %}
|
||||||
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
|
<li class="nav-item">
|
||||||
<div class="d-flex align-items-center">
|
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
|
||||||
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
|
<div class="d-flex align-items-center">
|
||||||
</div>
|
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
|
||||||
</a>
|
</div>
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -262,7 +264,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug %}">
|
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}">
|
||||||
<div class="d-flex align-items-center">
|
<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>
|
<span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<p><strong>{{ _("Bank Account Name") }}:</strong> {{ bank_account.name }}</p>
|
<p><strong>{{ _("Bank Account Name") }}:</strong> {{ bank_account.name }}</p>
|
||||||
<p><strong>{{ _("Cash Account") }}:</strong> {{ bank_account.cash_account }}</p>
|
<p><strong>{{ _("Cash Account") }}:</strong> {{ bank_account }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<p><strong>{{ _("Amount") }}:</strong> {{ bank_account.amount }}</p>
|
<p><strong>{{ _("Amount") }}:</strong> {{ bank_account.amount }}</p>
|
||||||
|
|||||||
@ -228,7 +228,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<div class="card border-0 shadow-sm text-center py-5">
|
<div class="card border-0 shadow-sm text-center py-5">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a href="{% url 'purchase_order_create' request.dealer.slug %}" class="text-decoration-none">
|
<a href="{% url 'purchase_order_create' request.dealer.slug request.dealer.entity.slug %}" class="text-decoration-none">
|
||||||
<span class="text-muted mb-3 d-inline-block">{% icon "ic:baseline-add-circle-outline" 48 %}</span>
|
<span class="text-muted mb-3 d-inline-block">{% icon "ic:baseline-add-circle-outline" 48 %}</span>
|
||||||
<h3 class="h4 text-muted">{% trans 'New Purchase Order' %}</h3>
|
<h3 class="h4 text-muted">{% trans 'New Purchase Order' %}</h3>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="btn btn-phoenix-primary w-100 py-2"
|
<a class="btn btn-phoenix-primary w-100 py-2"
|
||||||
href="{% url 'purchase_order_list' request.dealer.slug %}">
|
href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}">
|
||||||
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
|
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<button class="btn btn-phoenix-primary" data-bs-toggle="modal" data-bs-target="#POModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'View Purchase Order' %}</span></button>
|
<button class="btn btn-phoenix-primary" data-bs-toggle="modal" data-bs-target="#POModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'View Purchase Order' %}</span></button>
|
||||||
<a href="{% url 'purchase_order_list' request.dealer.slug %}" class="btn btn-phoenix-secondary">Back to List</a>
|
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}" class="btn btn-phoenix-secondary">Back to List</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
{{ _("Purchase Orders") |capfirst }}
|
{{ _("Purchase Orders") |capfirst }}
|
||||||
</h2>
|
</h2>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'purchase_order_create' request.dealer.slug %}"
|
<a href="{% url 'purchase_order_create' request.dealer.slug request.dealer.entity.slug %}"
|
||||||
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
|
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<div class="btn-reveal-trigger position-static">
|
<div class="btn-reveal-trigger position-static">
|
||||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||||
<div class="dropdown-menu dropdown-menu-end py-2">
|
<div class="dropdown-menu dropdown-menu-end py-2">
|
||||||
<a href="{% url 'purchase_order_detail' request.dealer.slug po.pk %}" class="dropdown-item text-success-dark">{% trans 'Purchase Order Detail' %}</a>
|
<a href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug po.pk %}" class="dropdown-item text-success-dark">{% trans 'Purchase Order Detail' %}</a>
|
||||||
{% if po.po_status == 'fulfilled' %}
|
{% if po.po_status == 'fulfilled' %}
|
||||||
<a href="{% url 'view_items_inventory' dealer_slug=request.dealer.slug entity_slug=entity_slug po_pk=po.pk %}" class="dropdown-item text-success-dark">{% trans 'Add Inventory Items' %}</a>
|
<a href="{% url 'view_items_inventory' dealer_slug=request.dealer.slug entity_slug=entity_slug po_pk=po.pk %}" class="dropdown-item text-success-dark">{% trans 'Add Inventory Items' %}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@ -26,9 +26,9 @@
|
|||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="btn btn-phoenix-success w-100 my-2">{% trans 'Save PO' %}
|
class="btn btn-phoenix-success w-100 my-2">{% trans 'Save PO' %}
|
||||||
</button>
|
</button>
|
||||||
<a href="{% url 'purchase_order_detail' request.dealer.slug po_model.uuid %}"
|
<a href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug po_model.uuid %}"
|
||||||
class="btn btn-phoenix-secondary w-100 my-2">{% trans 'Back to PO Detail' %}</a>
|
class="btn btn-phoenix-secondary w-100 my-2">{% trans 'Back to PO Detail' %}</a>
|
||||||
<a href="{% url 'purchase_order_list' request.dealer.slug %}"
|
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}"
|
||||||
class="btn btn-phoenix-info
|
class="btn btn-phoenix-info
|
||||||
info w-100 my-2">{% trans 'PO List' %}</a>
|
info w-100 my-2">{% trans 'PO List' %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -65,7 +65,9 @@
|
|||||||
{% elif estimate.status == 'in_review' %}
|
{% elif estimate.status == 'in_review' %}
|
||||||
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
||||||
{% elif estimate.status == 'approved' %}
|
{% elif estimate.status == 'approved' %}
|
||||||
<span class="badge text-bg-success">{% trans "Approved" %}</span>
|
{% if perms.django_ledger.change_estimatemodel %}
|
||||||
|
<span class="badge text-bg-success">{% trans "Approved" %}</span>
|
||||||
|
{% endif %}
|
||||||
{% elif estimate.status == 'completed' %}
|
{% elif estimate.status == 'completed' %}
|
||||||
<span class="badge text-bg-success">{% trans "Completed" %}</span>
|
<span class="badge text-bg-success">{% trans "Completed" %}</span>
|
||||||
{% elif estimate.status == 'canceled' %}
|
{% elif estimate.status == 'canceled' %}
|
||||||
@ -83,15 +85,17 @@
|
|||||||
|
|
||||||
{% if estimate.sale_orders.first %}
|
{% if estimate.sale_orders.first %}
|
||||||
<!--if sale order exist-->
|
<!--if sale order exist-->
|
||||||
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
|
{% if perms.djagno_ledger.add_invoice %}
|
||||||
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
||||||
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
|
|
||||||
{% comment %} {% endcomment %}
|
{% else %}
|
||||||
|
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
|
||||||
|
{% comment %} {% endcomment %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% elif estimate.status == 'completed' %}
|
{% elif estimate.status == 'completed' %}
|
||||||
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
||||||
<a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
|
<a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user