From 6a2911cea4152e292e074d329878d6c554290bf1 Mon Sep 17 00:00:00 2001 From: ismail Date: Mon, 25 Aug 2025 11:52:32 +0300 Subject: [PATCH] update merge --- inventory/admin.py | 1 + inventory/forms.py | 7 +--- inventory/models.py | 5 ++- inventory/override.py | 6 ++- inventory/signals.py | 18 +++++++- inventory/urls.py | 6 +-- inventory/views.py | 41 ++++++++++--------- templates/bill/includes/card_bill.html | 9 ++-- templates/header.html | 2 +- .../purchase_orders/includes/card_po.html | 11 ++++- templates/support/create_ticket.html | 2 +- templates/support/help_center.html | 2 +- templates/support/ticket_detail.html | 15 +++---- templates/support/ticket_list.html | 34 +++++++-------- templates/support/ticket_update.html | 2 +- 15 files changed, 94 insertions(+), 67 deletions(-) diff --git a/inventory/admin.py b/inventory/admin.py index 1bd2956f..31e59ca1 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -71,6 +71,7 @@ admin.site.register(models.Notes) admin.site.register(models.UserActivityLog) admin.site.register(models.DealersMake) admin.site.register(models.ExtraInfo) +admin.site.register(models.Ticket) @admin.register(models.Car) diff --git a/inventory/forms.py b/inventory/forms.py index 151b48c5..1a49882a 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -2214,15 +2214,10 @@ class TicketForm(forms.ModelForm): class TicketResolutionForm(forms.ModelForm): - resolution_notes = forms.CharField( - widget=forms.Textarea(attrs={'rows': 3}), - required=False, - help_text="Optional notes about how the issue was resolved." - ) class Meta: model = Ticket - fields = ['status'] + fields = ['status', 'resolution_notes'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/inventory/models.py b/inventory/models.py index 9616f067..733a1262 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -3220,7 +3220,7 @@ class CustomGroup(models.Model): "activity", "payment", "vendor", - + ], other_perms=[ "view_car", @@ -3232,7 +3232,7 @@ class CustomGroup(models.Model): "view_leads", "view_opportunity", 'view_customer' - + ], ) self.set_permissions( @@ -3679,6 +3679,7 @@ class Ticket(models.Model): dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='tickets') subject = models.CharField(max_length=200) description = models.TextField() + resolution_notes = models.TextField(blank=True, null=True) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='open') priority = models.CharField(max_length=20, choices=PRIORITY_CHOICES, default='medium') created_at = models.DateTimeField(auto_now_add=True) diff --git a/inventory/override.py b/inventory/override.py index 947b0ada..0e66e9be 100644 --- a/inventory/override.py +++ b/inventory/override.py @@ -67,9 +67,12 @@ class PurchaseOrderModelUpdateView( def get_context_data(self, itemtxs_formset=None, **kwargs): dealer = get_object_or_404(Dealer, slug=self.kwargs["dealer_slug"]) + po_model: PurchaseOrderModel = self.object + context = super().get_context_data(**kwargs) context["entity_slug"] = dealer.entity.slug - po_model: PurchaseOrderModel = self.object + context["po_ready_to_fulfill"] = [item for item in po_model.get_itemtxs_data()[0] if item.po_item_status == 'received'] + if not itemtxs_formset: itemtxs_qs = self.get_po_itemtxs_qs(po_model) itemtxs_qs, itemtxs_agg = po_model.get_itemtxs_data(queryset=itemtxs_qs) @@ -530,6 +533,7 @@ class BillModelUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVie context["page_title"] = title context["header_title"] = title context["header_subtitle"] = bill_model.get_bill_status_display() + context["can_mark_as_paid"] = bill_model.amount_paid == bill_model.amount_due if not bill_model.is_configured(): messages.add_message( diff --git a/inventory/signals.py b/inventory/signals.py index 99b8cbfb..6d4aa775 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -1244,4 +1244,20 @@ def send_ticket_notification(sender, instance, created, **kwargs): [settings.SUPPORT_EMAIL], subject, message, - ) \ No newline at end of file + ) + else: + models.Notification.objects.create( + user=instance.dealer.user, + message=_( + """ + Support Ticket #{ticket_number} has been updated. + View. + """ + ).format( + ticket_number=instance.pk, + url=reverse( + "ticket_detail", + kwargs={"dealer_slug": instance.dealer.slug, "ticket_id": instance.pk}, + ), + ), + ) \ No newline at end of file diff --git a/inventory/urls.py b/inventory/urls.py index a6f63fbc..028098d7 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -1322,9 +1322,9 @@ urlpatterns = [ path('/staff/detail/', views.StaffDetailView.as_view(), name='staff_detail'), # tickets path('help_center/view/', views.help_center, name='help_center'), - path('help_center/tickets/', views.ticket_list, name='ticket_list'), - path('help_center/tickets/create/', views.create_ticket, name='create_ticket'), - path('help_center/tickets//', views.ticket_detail, name='ticket_detail'), + path('/help_center/tickets/', views.ticket_list, name='ticket_list'), + path('help_center/tickets//create/', views.create_ticket, name='create_ticket'), + path('/help_center/tickets//', views.ticket_detail, name='ticket_detail'), path('help_center/tickets//update/', views.ticket_update, name='ticket_update'), # path('help_center/tickets//ticket_mark_resolved/', views.ticket_mark_resolved, name='ticket_mark_resolved'), diff --git a/inventory/views.py b/inventory/views.py index 7f716543..3808cddc 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -457,10 +457,10 @@ def general_dashboard(request,dealer_slug): total_vat_collected_from_cars = cars_sold_filtered.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 - + net_profit_from_cars = total_revenue_from_cars - total_cost_of_cars_sold total_discount = cars_sold_filtered.aggregate(total=Sum('discount_amount'))['total'] or 0 - + # Sales breakdown by type new_cars_sold = cars_sold_filtered.filter(stock_type='new') total_new_cars_sold = new_cars_sold.count() @@ -469,13 +469,13 @@ def general_dashboard(request,dealer_slug): total_revenue_from_new_cars = new_cars_sold.aggregate( total=Sum(F('marked_price') - F('discount_amount')) )['total'] or 0 - + total_vat_collected_from_new_cars = new_cars_sold.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 - + net_profit_from_new_cars = total_revenue_from_new_cars - total_cost_of_new_cars_sold - + used_cars_sold = cars_sold_filtered.filter(stock_type='used') @@ -488,7 +488,7 @@ def general_dashboard(request,dealer_slug): total_vat_collected_from_used_cars = used_cars_sold.annotate( final_price=F('marked_price') - F('discount_amount')).aggregate( total=Sum(F('final_price') * VAT_RATE))['total'] or 0 - + net_profit_from_used_cars = total_revenue_from_used_cars - total_cost_of_used_cars_sold # Service & Overall KPIs @@ -1483,7 +1483,7 @@ def inventory_stats_view(request, dealer_slug): """ # Base queryset for cars belonging to the dealer - cars = models.Car.objects.filter(dealer=request.dealer) + cars = models.Car.objects.filter(dealer=request.dealer) # Count for total, reserved, showroom, and unreserved cars total_cars = cars.count() reserved_cars = models.CarReservation.objects.count() @@ -10589,7 +10589,7 @@ class PurchaseOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, Detai title = f"Purchase Order {po_model.po_number}" context["page_title"] = title context["header_title"] = title - + context["po_ready_to_fulfill"] = all([item for item in po_model.get_itemtxs_data()[0] if item.po_item_status == 'received']) po_model: PurchaseOrderModel = self.object po_items_qs, item_data = po_model.get_itemtxs_data( queryset=po_model.itemtransactionmodel_set.all().select_related( @@ -10890,6 +10890,7 @@ def upload_cars(request, dealer_slug, pk=None): year=int(year_model), vendor=vendor, receiving_date=receiving_date, + cost_price=po_item.item.unit_cost, ) # if po_item: #TODO:update # models.CarFinance.objects.create( @@ -11076,7 +11077,7 @@ def car_sale_report_view(request, dealer_slug): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first() VAT_RATE=vat.rate - + cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') @@ -11410,18 +11411,18 @@ def help_center(request): @login_required @permission_required('inventory.add_ticket') -def create_ticket(request): +def create_ticket(request,dealer_slug): if not request.is_dealer: return redirect('home') - + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) if request.method == 'POST': form = forms.TicketForm(request.POST) if form.is_valid(): instance = form.save(commit=False) - instance.dealer = request.dealer + instance.dealer = dealer instance.save() messages.success(request, 'Your support ticket has been submitted successfully!') - return redirect('ticket_list') + return redirect('ticket_list',dealer_slug=dealer.slug) else: form = forms.TicketForm() @@ -11429,16 +11430,16 @@ def create_ticket(request): @login_required @permission_required('inventory.view_ticket') -def ticket_list(request): - tickets = models.Ticket.objects.all().order_by('-created_at') - if request.is_dealer: - tickets = tickets = tickets.filter(dealer=request.dealer) +def ticket_list(request,dealer_slug): + dealer= get_object_or_404(models.Dealer, slug=dealer_slug) + tickets = models.Ticket.objects.filter(dealer=dealer).order_by('-created_at') return render(request, 'support/ticket_list.html', {'tickets': tickets}) @login_required @permission_required('inventory.change_ticket') -def ticket_detail(request, ticket_id): - ticket = models.Ticket.objects.get(id=ticket_id) +def ticket_detail(request, dealer_slug,ticket_id): + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) + ticket = models.Ticket.objects.get(dealer=dealer,id=ticket_id) return render(request, 'support/ticket_detail.html', {'ticket': ticket}) @login_required @@ -11468,7 +11469,7 @@ def ticket_update(request, ticket_id): if form.is_valid(): form.save() messages.success(request, f'Ticket has been marked as {ticket.get_status_display()}.') - return redirect('ticket_detail', ticket_id=ticket.id) + return redirect('ticket_detail',dealer_slug=ticket.dealer.slug, ticket_id=ticket.id) else: form = forms.TicketResolutionForm(instance=ticket) diff --git a/templates/bill/includes/card_bill.html b/templates/bill/includes/card_bill.html index 8d69620e..bd45d003 100644 --- a/templates/bill/includes/card_bill.html +++ b/templates/bill/includes/card_bill.html @@ -4,6 +4,7 @@ {% if not create_bill %} {% if style == 'dashboard' %} +
@@ -50,6 +51,7 @@
{% modal_action bill 'get' entity_slug %} +
{% trans 'View' %} @@ -57,8 +59,7 @@ {% trans 'Update' %} {% if bill.can_pay %} - + {% endif %} {% if bill.can_cancel %} {% modal_action_v2 bill bill.get_mark_as_canceled_url bill.get_mark_as_canceled_message bill.get_mark_as_canceled_html_id %} {% endif %} - + {% endif %}
diff --git a/templates/header.html b/templates/header.html index 3fe083dd..ba9a621d 100644 --- a/templates/header.html +++ b/templates/header.html @@ -533,7 +533,7 @@ {% endif %} {% if request.is_staff %}
diff --git a/templates/support/help_center.html b/templates/support/help_center.html index 0002edcd..fdb638b5 100644 --- a/templates/support/help_center.html +++ b/templates/support/help_center.html @@ -6,7 +6,7 @@
Need help?

Raise a ticket and we will get back to you as soon as possible.

- Raise a Ticket + Raise a Ticket
diff --git a/templates/support/ticket_detail.html b/templates/support/ticket_detail.html index d6b23890..ccf8bede 100644 --- a/templates/support/ticket_detail.html +++ b/templates/support/ticket_detail.html @@ -8,12 +8,7 @@

Ticket #{{ ticket.id }}: {{ ticket.subject }}

- {% if ticket.status != 'resolved' %} - - Update Ticket Status - - {% endif %} - + Back to List
@@ -48,10 +43,16 @@

Description

-
+
{{ ticket.description|linebreaks }}
+
+

Resolution Notes

+
+ {{ ticket.resolution_notes|linebreaks }} +
+
diff --git a/templates/support/ticket_list.html b/templates/support/ticket_list.html index e70b1180..af39a6ac 100644 --- a/templates/support/ticket_list.html +++ b/templates/support/ticket_list.html @@ -3,12 +3,13 @@ {% load i18n %} {% block content %} -
-

My Support Tickets

- - New Ticket - -
+
+
+
Need help?
+

Raise a ticket and we will get back to you as soon as possible.

+ Raise a Ticket +
+
{% if messages %} {% for message in messages %} @@ -19,17 +20,19 @@ {% endfor %} {% endif %} +
+
+
Tickets
- - +
+ - - + @@ -57,14 +60,9 @@ - + @@ -77,4 +75,6 @@
ID Subject Status Priority CreatedResolved AtTime To ResolutionActions
{{ ticket.created_at|date:"M d, Y H:i" }}{{ ticket.updated_at|date:"M d, Y H:i" }} -

-   - {{ ticket.time_to_resolution_display }} -

-
- + View
+
+
{% endblock %} \ No newline at end of file diff --git a/templates/support/ticket_update.html b/templates/support/ticket_update.html index 9a9deb3c..9a79eb45 100644 --- a/templates/support/ticket_update.html +++ b/templates/support/ticket_update.html @@ -13,7 +13,7 @@ {% csrf_token %} {{form|crispy}} - Cancel + Cancel
-- 2.39.5