diff --git a/inventory/models.py b/inventory/models.py index aecd91f0..4f20430a 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -2002,7 +2002,13 @@ class Opportunity(models.Model): return self.lead.get_calls() def get_schedules(self): + # qs = Schedule.objects.filter( + # dealer=self.dealer, + # content_type__model__in=["lead"], object_id=self.object.id, + # scheduled_by=self.request.user + # ) return ( + self.lead.get_all_schedules() .filter(scheduled_at__gt=timezone.now()) .order_by("scheduled_at") @@ -2323,6 +2329,14 @@ class Payment(models.Model): max_length=100, null=True, blank=True, verbose_name=_("reference number") ) payment_date = models.DateField(auto_now_add=True, verbose_name=_("date")) + invoice = models.ForeignKey( + InvoiceModel, + on_delete=models.CASCADE, + related_name="payments", + verbose_name=_("invoice"), + null=True, + blank=True, + ) class Meta: verbose_name = _("payment") @@ -2646,7 +2660,7 @@ class CustomGroup(models.Model): allowed_models=[], other_perms=[ "view_purchaseordermodel", - + ] ) ###################################### @@ -2724,7 +2738,7 @@ class CustomGroup(models.Model): "itemmodel", "invoicemodel", "vendormodel", - + "journalentrymodel", "purchaseordermodel", "estimatemodel", @@ -2982,4 +2996,50 @@ class ExtraInfo(models.Model): verbose_name_plural = "Extra Info" def __str__(self): - return f"ExtraInfo for {self.content_object} ({self.content_type})" \ No newline at end of file + return f"ExtraInfo for {self.content_object} ({self.content_type})" + + + @classmethod + def get_sale_orders(cls, staff=None, is_dealer=False): + if not staff and not is_dealer: + return [] + + content_type = ContentType.objects.get_for_model(EstimateModel) + related_content_type = ContentType.objects.get_for_model(Staff) + + if is_dealer: + qs = cls.objects.filter( + content_type=content_type, + related_content_type=related_content_type, + related_object_id__isnull=False + ) + else: + qs = cls.objects.filter( + content_type=content_type, + related_content_type=related_content_type, + related_object_id=staff.pk + ) + + return [x.content_object.sale_orders.first() for x in qs if x.content_object.sale_orders.first()] + @classmethod + def get_invoices(cls, staff=None, is_dealer=False): + if not staff and not is_dealer: + return [] + + content_type = ContentType.objects.get_for_model(EstimateModel) + related_content_type = ContentType.objects.get_for_model(Staff) + + if is_dealer: + qs = cls.objects.filter( + content_type=content_type, + related_content_type=related_content_type, + related_object_id__isnull=False + ) + else: + qs = cls.objects.filter( + content_type=content_type, + related_content_type=related_content_type, + related_object_id=staff.pk + ) + print(qs[0].content_object.invoicemodel_set.first()) + return [x.content_object.invoicemodel_set.first() for x in qs if x.content_object.invoicemodel_set.first()] diff --git a/inventory/override.py b/inventory/override.py index ccf3ffbe..eb305327 100644 --- a/inventory/override.py +++ b/inventory/override.py @@ -642,3 +642,6 @@ class BaseBillActionView(LoginRequiredMixin,PermissionRequiredMixin, RedirectVie level=messages.ERROR, extra_tags='is-danger') return response + + + diff --git a/inventory/utils.py b/inventory/utils.py index 08cb62ce..938e0d33 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -226,8 +226,8 @@ def reserve_car(car, request): car.save() # --- Logging for Success --- logger.info( - f"Car {car.id} ('{car.make} {car.model}') reserved successfully " - f"by user {request.user.id} ('{request.user.username}'). " + f"Car {car.pk} ('{car.id_car_make} {car.id_car_model}') reserved successfully " + f"by user {request.user}. " f"Reserved until: {reserved_until}." ) @@ -235,8 +235,8 @@ def reserve_car(car, request): except Exception as e: # --- Logging for Error --- logger.error( - f"Error reserving car {car.id} ('{car.make} {car.model}') " - f"for user {request.user.id} ('{request.user.username}'). " + f"Error reserving car {car.pk} ('{car.id_car_make} {car.id_car_model}') " + f"for user {request.user} . " f"Error: {e}", exc_info=True ) @@ -473,7 +473,7 @@ def set_invoice_payment(dealer, entity, invoice, amount, payment_method): calculator = CarFinanceCalculator(invoice) finance_data = calculator.get_finance_data() - handle_account_process(invoice, amount, finance_data) + # handle_account_process(invoice, amount, finance_data) invoice.make_payment(amount) invoice.save() diff --git a/inventory/views.py b/inventory/views.py index d15e4db2..f697bdb6 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -4210,13 +4210,12 @@ def sales_list_view(request, dealer_slug): staff = getattr(request.user.staffmember, "staff", None) qs = [] try: - if dealer: + if request.is_dealer: qs = models.ExtraInfo.get_sale_orders(staff=staff,is_dealer=True) - else: + elif request.is_staff: qs = models.ExtraInfo.get_sale_orders(staff=staff) except Exception as e: print(e) - print(qs) # sale_orders = models.SaleOrder.objects.filter( # dealer=dealer, # ) @@ -4289,19 +4288,19 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) staff = getattr(self.request.user.staffmember, "staff", None) - dealer = getattr(self.request.user, "dealer", None) - if dealer: + if self.request.is_dealer: qs = models.ExtraInfo.objects.filter( content_type=ContentType.objects.get_for_model(EstimateModel), related_content_type=ContentType.objects.get_for_model(models.Staff), ) - else: + elif self.request.is_staff: qs = models.ExtraInfo.objects.filter( content_type=ContentType.objects.get_for_model(EstimateModel), related_content_type=ContentType.objects.get_for_model(models.Staff), - related_object_id=staff.pk if staff else self.request.user.pk, + related_object_id=staff.pk, ) context["staff_estimates"] = qs return context @@ -4450,17 +4449,17 @@ def create_estimate(request, dealer_slug, slug=None): } for item in items_txs } - else: - item = entity.get_items_all().filter(pk=items).first() - instance = models.Car.objects.get(vin=item.name) - estimate_itemtxs = { - item.item_number: { - "unit_cost": instance.finances.cost_price, - "unit_revenue": instance.finances.selling_price, - "quantity": Decimal(quantities), - "total_amount": instance.finances.total_vat * int(quantities), - } - } + # else: + # item = entity.get_items_all().filter(pk=items).first() + # instance = models.Car.objects.get(vin=item.name) + # estimate_itemtxs = { + # item.item_number: { + # "unit_cost": instance.finances.cost_price, + # "unit_revenue": instance.finances.selling_price, + # "quantity": Decimal(quantities), + # "total_amount": instance.finances.total_vat * int(quantities), + # } + # } try: estimate.migrate_itemtxs( @@ -4478,16 +4477,14 @@ def create_estimate(request, dealer_slug, slug=None): ) if isinstance(items, list): for item in estimate_itemtxs.keys(): - item_instance = ItemModel.objects.filter(item_number=item).first() - instance = models.Car.objects.get(vin=item_instance.name) - # reserve_car(instance, request) #TODO + item_instance = entity.get_items_all().filter(item_number=item).first() - else: - item_instance = ItemModel.objects.filter( - additioinal_info__car_info__hash=items - ).first() - instance = models.Car.objects.get(hash=item) - # reserve_car(instance, request) #TODO + # else: + # item_instance = ItemModel.objects.filter( + # additioinal_info__car_info__hash=items + # ).first() + # instance = models.Car.objects.get(hash=item) + # reserve_car(instance, request) #TODO opportunity_id = data.get("opportunity_id") if opportunity_id != "None": @@ -4518,7 +4515,8 @@ def create_estimate(request, dealer_slug, slug=None): "url": f"{url}", } ) - + ####################################### + ##GET form = forms.EstimateModelCreateForm() form.fields["customer"].queryset = models.Customer.objects.filter( dealer=dealer, active=True @@ -4860,6 +4858,9 @@ def estimate_mark_as(request, dealer_slug, pk): ) estimate.mark_as_approved() estimate.save() + #Reserve The Car + car = estimate.get_itemtxs_data()[0].first().item_model.car + reserve_car(car, request) messages.success(request, _("Quotation approved successfully")) return redirect( "estimate_list", dealer_slug=dealer.slug @@ -4934,8 +4935,20 @@ class InvoiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_queryset(self): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) + entity = dealer.entity + staff = getattr(self.request.user.staffmember, "staff", None) + qs = [] + try: + if self.request.is_dealer: + qs = models.ExtraInfo.get_invoices(staff=staff,is_dealer=True) + elif self.request.is_staff: + qs = models.ExtraInfo.get_invoices(staff=staff) + except Exception as e: + print(e) + query = self.request.GET.get("q") - invoices = dealer.entity.get_invoices() + invoices = qs + # invoices = dealer.entity.get_invoices() return apply_search_filters(invoices, query) @@ -5624,7 +5637,8 @@ class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): dealer=dealer, content_type__model="lead", object_id=self.object.id, scheduled_by=self.request.user - ) + ).order_by("-created_at") + context["status_history"] = models.LeadStatusHistory.objects.filter( lead=self.object ) @@ -6193,6 +6207,14 @@ def schedule_event(request, dealer_slug,content_type,slug): ) instance.save() + models.Activity.objects.create( + dealer=dealer, + content_object=obj, + notes=instance.notes, + created_by=request.user, + activity_type=instance.scheduled_type, + ) + # --- Logging for successful AppointmentRequest and Appointment creation --- logger.info( f"User {user_username} successfully scheduled {content_type} ID: {obj.pk} ('{obj.slug}'). " @@ -6551,6 +6573,7 @@ class OpportunityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV permission_required = ["inventory.view_opportunity"] def get_context_data(self, **kwargs): + dealer = get_object_or_404(models.Dealer,slug=self.kwargs.get("dealer_slug")) context = super().get_context_data(**kwargs) form = forms.OpportunityStatusForm() url = reverse("opportunity_update_status", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "slug": self.object.slug}) @@ -6596,11 +6619,24 @@ class OpportunityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV context["tasks"] = models.Tasks.objects.filter( content_type__model="opportunity", object_id=self.object.id ) + qs = models.Schedule.objects.filter( + dealer=dealer, + content_type__model="lead", object_id=self.object.lead.id, + scheduled_by=self.request.user + ) + + context["schedules"] = qs | models.Schedule.objects.filter( + dealer=dealer, + content_type__model="opportunity", object_id=self.object.id, + scheduled_by=self.request.user + ) + context["schedules"] = context["schedules"].order_by("-created_at") context["upcoming_events"] = { - "schedules": self.object.lead.get_all_schedules().filter( + "schedules": qs.filter( scheduled_at__gt=timezone.now() - ), + )[:5], } + context["schedule_form"] = forms.ScheduleForm() return context @@ -7504,6 +7540,7 @@ class OrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_queryset(self): dealer = get_user_type(self.request) qs = super().get_queryset() + print(qs) return qs.filter(estimate__entity=dealer.entity) @@ -8678,7 +8715,7 @@ class LedgerModelCreateView(LedgerModelCreateViewBase): ) def form_valid(self, form): - dealer = get_user_type(self.request) + dealer = get_user_type(self.request) form.field["entity"] = dealer.entity return super().form_valid(form) diff --git a/templates/crm/opportunities/opportunity_detail.html b/templates/crm/opportunities/opportunity_detail.html index 8792e2ac..6f9f7bd0 100644 --- a/templates/crm/opportunities/opportunity_detail.html +++ b/templates/crm/opportunities/opportunity_detail.html @@ -86,7 +86,7 @@