diff --git a/haikalbot/migrations/0001_initial.py b/haikalbot/migrations/0001_initial.py index 944b6da5..6a1928ce 100644 --- a/haikalbot/migrations/0001_initial.py +++ b/haikalbot/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.1 on 2025-06-12 16:25 +# Generated by Django 5.2.1 on 2025-06-12 14:22 import django.db.models.deletion import django.utils.timezone diff --git a/inventory/forms.py b/inventory/forms.py index 84934642..7ace0c01 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -20,6 +20,9 @@ from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormB from django_ledger.forms.journal_entry import ( JournalEntryModelCreateForm as JournalEntryModelCreateFormBase, ) +import csv +from io import TextIOWrapper +from django.utils.translation import gettext_lazy as _ from .models import ( Dealer, @@ -1928,3 +1931,66 @@ class ItemInventoryForm(forms.Form): label=_("Trim"), ) + + + +##################################################################### + +class CSVUploadForm(forms.Form): + dealer = forms.ModelChoiceField( + queryset=Dealer.objects.all(), + label=_('Dealer'), + widget=forms.HiddenInput() + ) + vendor = forms.ModelChoiceField( + queryset=Vendor.objects.all(), + label=_('Vendor'), + widget=forms.Select(attrs={'class': 'form-select'}), + required=True + ) + year = forms.IntegerField( + label=_('Year'), + widget=forms.NumberInput(attrs={'class': 'form-control'}), + required=True + ) + exterior = forms.ModelChoiceField( + queryset=ExteriorColors.objects.all(), + label=_('Exterior Color'), + widget=forms.RadioSelect(attrs={'class': 'form-select'}), + required=True + ) + interior = forms.ModelChoiceField( + queryset=InteriorColors.objects.all(), + label=_('Interior Color'), + widget=forms.RadioSelect(attrs={'class': 'form-select'}), + required=True + ) + receiving_date = forms.DateField( + label=_('Receiving Date'), + widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), + required=True + ) + + def clean_csv_file(self): + csv_file = self.cleaned_data['csv_file'] + if not csv_file.name.endswith('.csv'): + raise forms.ValidationError(_('File is not a CSV file')) + + # Read and validate CSV structure + try: + csv_data = TextIOWrapper(csv_file.file, encoding='utf-8') + reader = csv.DictReader(csv_data) + + required_fields = ['vin', 'make', 'model', 'year'] + if not all(field in reader.fieldnames for field in required_fields): + missing = set(required_fields) - set(reader.fieldnames) + raise forms.ValidationError( + _('CSV is missing required columns: %(missing)s'), + params={'missing': ', '.join(missing)} + ) + except Exception as e: + raise forms.ValidationError(_('Error reading CSV file: %(error)s') % {'error': str(e)}) + + # Reset file pointer for later processing + csv_file.file.seek(0) + return csv_file \ No newline at end of file diff --git a/inventory/models.py b/inventory/models.py index 3154f4b8..8fab2192 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -712,7 +712,9 @@ class Car(Base): .filter(name=f"Cogs:{self.id_car_make.name}") .first() ) - + def add_colors(self,exterior,interior): + self.colors = CarColors.objects.create(car=self,exterior=exterior,interior=interior) + self.save() class CarTransfer(models.Model): car = models.ForeignKey( diff --git a/inventory/urls.py b/inventory/urls.py index 729b763a..197cbcfc 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -234,7 +234,7 @@ urlpatterns = [ name="fetch_notifications", ), path( - "crm/notifications//mark_as_read/", + "crm/notifications//mark_as_read/", views.mark_notification_as_read, name="mark_notification_as_read", ), @@ -254,6 +254,8 @@ urlpatterns = [ name="vendor_delete", ), # Car URLs + path('cars/upload_cars/', views.upload_cars, name='upload_cars'), + path('cars//upload_cars/', views.upload_cars, name='upload_cars'), path("cars/add/", views.CarCreateView.as_view(), name="car_add"), path("cars/inventory/", views.CarInventory.as_view(), name="car_inventory_all"), path( @@ -696,13 +698,13 @@ path( path("items/bills/", views.BillListView.as_view(), name="bill_list"), # path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"), path('items/bills//create/', - views.BillModelCreateViewView.as_view(), + views.BillModelCreateView.as_view(), name='bill-create'), path('items/bills//create/purchase-order//', - views.BillModelCreateViewView.as_view(for_purchase_order=True), + views.BillModelCreateView.as_view(for_purchase_order=True), name='bill-create-po'), path('items/bills//create/estimate//', - views.BillModelCreateViewView.as_view(for_estimate=True), + views.BillModelCreateView.as_view(for_estimate=True), name='bill-create-estimate'), path('items/bills//detail//', views.BillModelDetailViewView.as_view(), @@ -769,7 +771,6 @@ path( name="bill_mark_as_paid", ), - # orders path("orders/", views.OrderListView.as_view(), name="order_list_view"), @@ -858,7 +859,7 @@ path( path('management///permenant_delete_account/', views.permenant_delete_account, name='permenant_delete_account'), path('management/audit_log_dashboard/', views.AuditLogDashboardView, name='audit_log_dashboard'), - + ######### # Purchase Order path('purchase_orders/', views.PurchaseOrderListView.as_view(), name='purchase_order_list'), diff --git a/inventory/views.py b/inventory/views.py index ef34571a..4320ae97 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,14 +1,19 @@ # Standard +import os +import io +import csv import cv2 import json import logging -from datetime import datetime -from time import sleep +import tempfile import numpy as np +from time import sleep # from rich import print from random import randint from decimal import Decimal +from io import TextIOWrapper from django.apps import apps +from datetime import datetime from calendar import month_name from pyzbar.pyzbar import decode from urllib.parse import urlparse, urlunparse @@ -17,6 +22,7 @@ from urllib.parse import urlparse, urlunparse from inventory.models import Status as LeadStatus from django.db import IntegrityError from background_task.models import Task +from django.views.generic import FormView from django.db.models.deletion import RestrictedError from django.http.response import StreamingHttpResponse from django.core.exceptions import ImproperlyConfigured, ValidationError @@ -26,7 +32,7 @@ from django.db.models import Q from django.conf import settings from django.db.models import Func from django.contrib import messages -from django.http import Http404, HttpResponseNotFound, HttpResponseRedirect, JsonResponse, HttpResponseForbidden +from django.http import Http404, HttpResponseBadRequest, HttpResponseNotFound, HttpResponseRedirect, JsonResponse, HttpResponseForbidden from django.forms import HiddenInput, ValidationError from django.shortcuts import HttpResponse @@ -85,15 +91,17 @@ from django_ledger.forms.bank_account import ( BankAccountUpdateForm, ) from django_ledger.views.bill import ( - BillModelCreateView, + # BillModelCreateView, BillModelDetailView, BillModelUpdateView, BaseBillActionView as BaseBillActionViewBase, + BillModelModelBaseView ) from django_ledger.forms.bill import ( ApprovedBillModelUpdateForm, InReviewBillModelUpdateForm, get_bill_itemtxs_formset_class, + BillModelCreateForm ) from django_ledger.forms.invoice import ( @@ -980,23 +988,23 @@ class CarColorsUpdateView( LoginRequiredMixin, PermissionRequiredMixin, SuccessM template_name = "inventory/add_colors.html" success_message = _("Car Colors details updated successfully") permission_required = ["inventory.change_car"] - + def get_object(self, queryset=None): """ Retrieves the CarColors instance associated with the Car slug from the URL. This ensures we are updating the colors for the correct car. """ - + # Get the car_slug from the URL keywords arguments slug = self.kwargs.get('slug') - + # If no car_slug is provided, it's an invalid request if not slug: # You might want to raise Http404 or a more specific error here raise ValueError("Car slug is required to identify the colors to update.") - + return get_object_or_404(models.CarColors, car__slug=slug) def get_success_url(self): @@ -1008,7 +1016,7 @@ class CarColorsUpdateView( LoginRequiredMixin, PermissionRequiredMixin, SuccessM return reverse("car_detail", kwargs={"slug": self.object.car.slug}) def get_context_data(self, **kwargs): - """ + """ Adds the related Car object to the template context. """ context = super().get_context_data(**kwargs) @@ -6118,6 +6126,7 @@ class BillDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): permission_required = ["django_ledger.view_billmodel"] def get_context_data(self, **kwargs): + dealer = get_user_type(self.request) bill = kwargs.get("object") if bill.get_itemtxs_data(): txs = bill.get_itemtxs_data()[0] @@ -6133,6 +6142,7 @@ class BillDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): kwargs["transactions"] = transactions kwargs["grand_total"] = grand_total + kwargs["entity"] = dealer.entity return super().get_context_data(**kwargs) @@ -6307,13 +6317,299 @@ def bill_mark_as_paid(request, pk): return redirect("bill_detail", pk=bill.pk) +# class BillModelCreateViewView(Create): +# template_name = 'bill/bill_create.html' -class BillModelCreateViewView(BillModelCreateView): +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context["entity"] = get_user_type(self.request).entity +# return context + + +# def post(self, request, *args, **kwargs): +# """ +# Completely override the post method to ensure our form handling is called +# """ +# print("Custom post method called") # Debugging +# form = self.get_form() +# if form.is_valid(): +# return self.custom_form_valid(form) +# else: +# return self.form_invalid(form) + +# def custom_form_valid(self, form): +# """ +# Our own form_valid implementation that will definitely be called +# """ +# print("Custom form_valid called") # Debugging + +# # Handle PO case +# if self.for_purchase_order: +# print("Handling PO case") # Debugging +# return self.handle_po_case(form) + +# # Handle Estimate case +# if self.for_estimate: +# print("Handling Estimate case") # Debugging +# return self.handle_estimate_case(form) + +# # Default case +# print("Handling default case") # Debugging +# return self.handle_default_case(form) + +# def handle_po_case(self, form): +# """Special handling for purchase orders""" +# po_pk = self.kwargs['po_pk'] +# item_uuids = self.request.GET.get('item_uuids', '').split(',') + +# if not item_uuids or not all(item_uuids): +# return HttpResponseBadRequest() + +# # Create bill +# bill_model = form.save(commit=False) +# ledger_model, bill_model = bill_model.configure( +# entity_slug=self.AUTHORIZED_ENTITY_MODEL, +# commit_ledger=True +# ) + +# # Get PO +# po_qs = PurchaseOrderModel.objects.for_entity( +# entity_slug=self.kwargs['entity_slug'], +# user_model=self.request.user +# ) +# po_model = get_object_or_404(po_qs, uuid__exact=po_pk) + +# # Validate +# try: +# bill_model.can_bind_po(po_model, raise_exception=True) +# except ValidationError as e: +# messages.error(self.request, e.message) +# return self.render_to_response(self.get_context_data(form=form)) + +# # Update models +# po_model_items_qs = po_model.itemtransactionmodel_set.filter(uuid__in=item_uuids) +# if po_model.is_contract_bound(): +# bill_model.ce_model_id = po_model.ce_model_id + +# bill_model.update_amount_due() +# bill_model.get_state(commit=True) +# bill_model.clean() +# bill_model.save() +# po_model_items_qs.update(bill_model=bill_model) + +# # Redirect to our custom URL +# return HttpResponseRedirect( +# reverse('purchase_order_update', +# kwargs={ +# 'entity_slug': self.kwargs['entity_slug'], +# 'po_pk': po_pk +# }) +# ) + +# def handle_estimate_case(self, form): +# """Special handling for estimates""" +# bill_model = form.save(commit=False) +# ledger_model, bill_model = bill_model.configure( +# entity_slug=self.AUTHORIZED_ENTITY_MODEL, +# commit_ledger=True +# ) + +# ce_pk = self.kwargs['ce_pk'] +# estimate_model_qs = EstimateModel.objects.for_entity( +# entity_slug=self.kwargs['entity_slug'], +# user_model=self.request.user +# ) +# estimate_model = get_object_or_404(estimate_model_qs, uuid__exact=ce_pk) +# bill_model.bind_estimate(estimate_model=estimate_model, commit=True) + +# # Redirect to our custom URL +# return HttpResponseRedirect( +# reverse('estimate_detail', +# kwargs={ +# 'pk': ce_pk +# }) +# ) + +# def handle_default_case(self, form): +# """Default form handling""" +# bill_model = form.save(commit=False) +# ledger_model, bill_model = bill_model.configure( +# entity_slug=self.AUTHORIZED_ENTITY_MODEL, +# commit_ledger=True +# ) +# bill_model.save() + +# # Redirect to our custom URL +# return HttpResponseRedirect( +# reverse('bill-detail', +# kwargs={ +# 'entity_slug': self.kwargs['entity_slug'], +# 'bill_pk': bill_model.uuid +# }) +# ) +class BillModelCreateView(CreateView): template_name = 'bill/bill_create.html' + PAGE_TITLE = _('Create Bill') + extra_context = { + 'page_title': PAGE_TITLE, + 'header_title': PAGE_TITLE, + 'header_subtitle_icon': 'uil:bill' + } + for_purchase_order = False + for_estimate = False + + def get(self, request, **kwargs): + if not request.user.is_authenticated: + return HttpResponseForbidden() + + if self.for_estimate and 'ce_pk' in self.kwargs: + estimate_qs = EstimateModel.objects.for_entity( + entity_slug=self.kwargs['entity_slug'], + user_model=self.request.user + ) + estimate_model: EstimateModel = get_object_or_404(estimate_qs, uuid__exact=self.kwargs['ce_pk']) + if not estimate_model.can_bind(): + return HttpResponseNotFound('404 Not Found') + return super(BillModelCreateView, self).get(request, **kwargs) + def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["entity"] = get_user_type(self.request).entity + context = super(BillModelCreateView, self).get_context_data(**kwargs) + + if self.for_purchase_order: + po_pk = self.kwargs['po_pk'] + po_item_uuids_qry_param = self.request.GET.get('item_uuids') + if po_item_uuids_qry_param: + try: + po_item_uuids = po_item_uuids_qry_param.split(',') + except: + return HttpResponseBadRequest() + else: + return HttpResponseBadRequest() + + po_qs = PurchaseOrderModel.objects.for_entity( + entity_slug=self.kwargs['entity_slug'], + user_model=self.request.user + ).prefetch_related('itemtransactionmodel_set') + po_model: PurchaseOrderModel = get_object_or_404(po_qs, uuid__exact=po_pk) + po_itemtxs_qs = po_model.itemtransactionmodel_set.filter( + bill_model__isnull=True, + uuid__in=po_item_uuids + ) + context['po_model'] = po_model + context['po_itemtxs_qs'] = po_itemtxs_qs + form_action = reverse('bill-create-po', + kwargs={ + 'entity_slug': self.kwargs['entity_slug'], + 'po_pk': po_model.uuid + }) + f'?item_uuids={po_item_uuids_qry_param}' + elif self.for_estimate: + estimate_qs = EstimateModel.objects.for_entity( + entity_slug=self.kwargs['entity_slug'], + user_model=self.request.user + ) + estimate_uuid = self.kwargs['ce_pk'] + estimate_model: EstimateModel = get_object_or_404(estimate_qs, uuid__exact=estimate_uuid) + form_action = reverse('bill-create-estimate', + kwargs={ + 'entity_slug': self.kwargs['entity_slug'], + 'ce_pk': estimate_model.uuid + }) + else: + form_action = reverse('bill-create', + kwargs={ + 'entity_slug': self.kwargs['entity_slug'], + }) + context['form_action_url'] = form_action return context + + def get_initial(self): + return { + 'date_draft': get_localdate() + } + + def get_form(self, form_class=None): + dealer = get_user_type(self.request) + return BillModelCreateForm( + entity_model=dealer.entity, + **self.get_form_kwargs() + ) + + def form_valid(self, form): + dealer = get_user_type(self.request) + bill_model: BillModel = form.save(commit=False) + ledger_model, bill_model = bill_model.configure( + entity_slug=dealer.entity.slug, + user_model=self.request.user, + commit_ledger=True + ) + + if self.for_estimate: + ce_pk = self.kwargs['ce_pk'] + estimate_model_qs = EstimateModel.objects.for_entity( + entity_slug=self.kwargs['entity_slug'], + user_model=self.request.user) + + estimate_model = get_object_or_404(estimate_model_qs, uuid__exact=ce_pk) + bill_model.bind_estimate(estimate_model=estimate_model, commit=False) + + elif self.for_purchase_order: + po_pk = self.kwargs['po_pk'] + item_uuids = self.request.GET.get('item_uuids') + if not item_uuids: + return HttpResponseBadRequest() + item_uuids = item_uuids.split(',') + po_qs = PurchaseOrderModel.objects.for_entity( + entity_slug=self.kwargs['entity_slug'], + user_model=self.request.user + ) + po_model: PurchaseOrderModel = get_object_or_404(po_qs, uuid__exact=po_pk) + + try: + bill_model.can_bind_po(po_model, raise_exception=True) + except ValidationError as e: + messages.add_message(self.request, + message=e.message, + level=messages.ERROR, + extra_tags='is-danger') + return self.render_to_response(self.get_context_data(form=form)) + + po_model_items_qs = po_model.itemtransactionmodel_set.filter(uuid__in=item_uuids) + + if po_model.is_contract_bound(): + bill_model.ce_model_id = po_model.ce_model_id + + bill_model.update_amount_due() + bill_model.get_state(commit=True) + bill_model.clean() + bill_model.save() + po_model_items_qs.update(bill_model=bill_model) + return HttpResponseRedirect(self.get_success_url()) + + return super(BillModelCreateView, self).form_valid(form) + + def get_success_url(self): + entity_slug = self.kwargs['entity_slug'] + if self.for_purchase_order: + po_pk = self.kwargs['po_pk'] + return reverse('purchase_order_update', + kwargs={ + 'entity_slug': entity_slug, + 'po_pk': po_pk + }) + elif self.for_estimate: + return reverse('customer-estimate-detail', + kwargs={ + 'entity_slug': entity_slug, + 'ce_pk': self.kwargs['ce_pk'] + }) + bill_model: BillModel = self.object + return reverse('bill-detail', + kwargs={ + 'entity_slug': entity_slug, + 'bill_pk': bill_model.uuid + }) + + class BillModelDetailViewView(BillModelDetailView): template_name = 'bill/bill_detail.html' class BillModelUpdateViewView(BillModelUpdateView): @@ -8385,7 +8681,7 @@ def AuditLogDashboardView(request): page_obj = paginator.page(1) except EmptyPage: page_obj = paginator.page(paginator.num_pages) - + elif q == 'loginEvents': template_name = 'admin_management/auth_logs.html' @@ -8408,7 +8704,7 @@ def AuditLogDashboardView(request): # 1. Paginate the raw QuerySet FIRST paginator = Paginator(model_events_queryset, logs_per_page) - + try: # Get the page object, which contains only the raw QuerySet objects for the current page page_obj_raw = paginator.page(current_pagination_page) @@ -8462,18 +8758,18 @@ def AuditLogDashboardView(request): 'new': 'Invalid JSON in changed_fields' }) processed_model_events_for_page.append(event_data) - + # 3. Replace the object_list of the original page_obj with the processed data # This keeps all pagination properties (has_next, number, etc.) intact. page_obj_raw.object_list = processed_model_events_for_page page_obj = page_obj_raw # This will be passed to the context - + # Pass the final page object to the context context['page_obj'] = page_obj return render(request, template_name, context) - + def activate_account(request, content_type, slug): @@ -8533,6 +8829,7 @@ def PurchaseOrderCreateView(request): return render(request, "purchase_orders/po_form.html", {"form": form}) def InventoryItemCreateView(request): + for_po = request.GET.get('for_po') dealer = get_user_type(request) entity = dealer.entity coa = entity.get_default_coa() @@ -8552,13 +8849,16 @@ def InventoryItemCreateView(request): model = request.POST.get("model") serie = request.POST.get("serie") trim = request.POST.get("trim") + year = request.POST.get("year") + exterior = models.ExteriorColors.objects.get(pk=request.POST.get("exterior")) + interior = models.InteriorColors.objects.get(pk=request.POST.get("interior")) make_name = models.CarMake.objects.get(pk=make) model_name = models.CarModel.objects.get(pk=model) serie_name = models.CarSerie.objects.get(pk=serie) trim_name = models.CarTrim.objects.get(pk=trim) - inventory_name = f"{make_name.name} - {model_name.name} - {serie_name.name} - {trim_name.name}" + inventory_name = f"{make_name.name} - {model_name.name} - {serie_name.name} - {trim_name.name} - {year} - {exterior.name} - {interior.name}" uom = entity.get_uom_all().get(name='Unit') entity.create_item_inventory( name=inventory_name, @@ -8569,6 +8869,10 @@ def InventoryItemCreateView(request): ) messages.success(request, _("Inventory item created successfully")) return redirect('purchase_order_list') + if for_po: + form = forms.CSVUploadForm() + context = {"make_data":models.CarMake.objects.all(),"inventory_accounts":inventory_accounts,"cogs_accounts":cogs_accounts,"form":form} + return render(request,'purchase_orders/car_inventory_item_form.html',context) return render(request,'purchase_orders/inventory_item_form.html',{"make_data":models.CarMake.objects.all(),"inventory_accounts":inventory_accounts,"cogs_accounts":cogs_accounts}) @@ -8878,4 +9182,64 @@ class BillModelActionUnlockLedgerView(BaseBillActionView): class BillModelActionForceMigrateView(BaseBillActionView): - action_name = 'migrate_state' \ No newline at end of file + action_name = 'migrate_state' + +############################################################### +############################################################### + +def upload_cars(request,po_pk=None): + dealer = get_user_type(request) + + if request.method == 'POST': + csv_file = request.FILES.get('csv_file') + year = request.POST.get("year") + receiving_date = datetime.strptime(request.POST.get("receiving_date"), "%Y-%m-%d") + receiving_date = timezone.make_aware(receiving_date) + + try: + make = models.CarMake.objects.get(pk=request.POST.get("make")) + model = models.CarModel.objects.get(pk=request.POST.get("model")) + serie = models.CarSerie.objects.get(pk=request.POST.get("serie")) + trim = models.CarTrim.objects.get(pk=request.POST.get("trim")) + vendor = models.Vendor.objects.get(pk=request.POST.get("vendor")) + exterior = models.ExteriorColors.objects.get(pk=request.POST.get("exterior")) + interior = models.InteriorColors.objects.get(pk=request.POST.get("interior")) + except Exception as e: + messages.error(request, f"Error processing CSV: {str(e)}") + if po_pk: + return redirect('upload_cars',po_pk=po_pk) + else: + return redirect('upload_cars') + if not csv_file.name.endswith('.csv'): + messages.error(request, "Please upload a CSV file") + return redirect('upload_cars') + try: + # Read the file content + file_content = csv_file.read().decode('utf-8') + csv_data = io.StringIO(file_content) + reader = csv.DictReader(csv_data) + cars_created = 0 + for row in reader: + car = models.Car.objects.create( + dealer=dealer, + vin=row['vin'], + id_car_make=make, + id_car_model=model, + id_car_serie=serie, + id_car_trim=trim, + year=year, + vendor=vendor, + receiving_date=receiving_date, + ) + car.add_colors(exterior=exterior, interior=interior) + cars_created += 1 + + messages.success(request, f"Successfully imported {cars_created} cars") + return redirect('car_list') # redirect to your car list view + + except Exception as e: + messages.error(request, f"Error processing CSV: {str(e)}") + form = forms.CSVUploadForm() + return render(request, 'csv_upload.html',{"make_data":models.CarMake.objects.all(),"form":form}) +############################################################### +############################################################### \ No newline at end of file diff --git a/locale/ar/LC_MESSAGES/django.mo b/locale/ar/LC_MESSAGES/django.mo index 57675332..42dbe36c 100644 Binary files a/locale/ar/LC_MESSAGES/django.mo and b/locale/ar/LC_MESSAGES/django.mo differ diff --git a/locale/ar/LC_MESSAGES/django.po b/locale/ar/LC_MESSAGES/django.po index f69e8c22..13697872 100644 --- a/locale/ar/LC_MESSAGES/django.po +++ b/locale/ar/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-06-13 02:11+0300\n" +"POT-Creation-Date: 2025-06-15 19:29+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -32,32 +32,34 @@ msgstr "" #: templates/sales/estimates/sale_order_form.html:122 #: templates/sales/estimates/sale_order_preview.html:178 #: templates/sales/invoices/invoice_detail.html:241 +#: templates/sales/orders/order_details.html:201 +#: templates/sales/orders/order_details.html:486 #: templates/sales/sales_list.html:115 msgid "VIN" msgstr "رقم الهيكل" -#: api/views.py:146 inventory/views.py:681 +#: api/views.py:147 inventory/views.py:681 msgid "Invalid VIN number provided" msgstr "تم تقديم رقم تعريف مركبة (VIN) غير صالح" -#: api/views.py:154 +#: api/views.py:155 msgid "VIN not found in any source" msgstr "لم يتم العثور على رقم الهيكل (VIN) في أي مصدر" -#: car_inventory/settings.py:174 +#: car_inventory/settings.py:173 msgid "SAR" msgstr "ريال" -#: car_inventory/settings.py:270 +#: car_inventory/settings.py:269 #: venv/lib/python3.11/site-packages/appointments/settings.py:136 msgid "English" msgstr "الإنجليزية" -#: car_inventory/settings.py:271 +#: car_inventory/settings.py:270 msgid "Arabic" msgstr "العربية" -#: car_inventory/settings.py:360 templates/header.html:358 +#: car_inventory/settings.py:359 templates/header.html:358 #: templates/welcome-temp.html:57 templates/welcome_header.html:7 msgid "Haikal" msgstr "هيكل" @@ -358,6 +360,7 @@ msgstr "الكمية" #: templates/plans/create_order.html:29 templates/plans/invoices/layout.html:11 #: templates/sales/invoices/invoice_create.html:5 #: templates/sales/invoices/invoice_detail.html:69 +#: templates/sales/orders/order_details.html:439 #: templates/sales/orders/order_list.html:17 #: templates/sales/payments/payment_list.html:21 #: templates/sales/sales_list.html:119 @@ -413,6 +416,7 @@ msgid "SADAD" msgstr "سداد" #: inventory/forms.py:1009 templates/sales/estimates/sale_order_form.html:177 +#: templates/sales/orders/order_details.html:128 msgid "Payment Method" msgstr "طريقة الدفع" @@ -446,6 +450,7 @@ msgstr "إلى" #: templates/sales/estimates/sale_order_form.html:124 #: templates/sales/estimates/sale_order_preview.html:179 #: templates/sales/invoices/invoice_detail.html:238 +#: templates/sales/orders/order_details.html:189 #: templates/sales/sales_list.html:113 msgid "Make" msgstr "الصانع" @@ -460,6 +465,7 @@ msgstr "الصانع" #: templates/sales/estimates/sale_order_form.html:126 #: templates/sales/estimates/sale_order_preview.html:180 #: templates/sales/invoices/invoice_detail.html:239 +#: templates/sales/orders/order_details.html:193 #: templates/sales/sales_list.html:114 msgid "Model" msgstr "الموديل" @@ -908,6 +914,7 @@ msgstr "المورد" #: templates/sales/estimates/sale_order_form.html:128 #: templates/sales/estimates/sale_order_preview.html:181 #: templates/sales/invoices/invoice_detail.html:240 +#: templates/sales/orders/order_details.html:197 msgid "Year" msgstr "السنة" @@ -932,6 +939,7 @@ msgstr "ملاحظات" #: templates/inventory/car_form.html:177 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:157 #: templates/inventory/car_list.html:197 templates/inventory/car_list.html:203 +#: templates/sales/orders/order_details.html:205 msgid "Mileage" msgstr "عدد الكيلومترات" @@ -1065,6 +1073,7 @@ msgstr "وصف اختياري حول وضع السيارة في صالة الع #: inventory/models.py:965 #: templates/crm/opportunities/opportunity_detail.html:139 +#: templates/sales/orders/order_details.html:148 msgid "Last Updated" msgstr "آخر تحديث" @@ -1384,11 +1393,13 @@ msgstr "إلغاء العرض" msgid "Create Order" msgstr "إنشاء طلب" -#: inventory/models.py:1276 +#: inventory/models.py:1276 templates/sales/orders/order_details.html:389 +#: templates/sales/orders/order_details.html:528 msgid "Cancel Order" msgstr "إلغاء الطلب" #: inventory/models.py:1277 templates/sales/estimates/estimate_detail.html:108 +#: templates/sales/orders/order_details.html:377 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_create.html:24 #: venv/lib/python3.11/site-packages/django_ledger/views/invoice.py:68 msgid "Create Invoice" @@ -1402,6 +1413,7 @@ msgstr "إلغاء الفاتورة" msgid "Qualification" msgstr "التأهيل" +#: inventory/models.py:1283 msgid "Test Drive" msgstr "تجربة القيادة" @@ -1409,6 +1421,7 @@ msgstr "تجربة القيادة" #: templates/sales/estimates/estimate_detail.html:79 #: templates/sales/estimates/estimate_send.html:5 #: templates/sales/estimates/sale_order_form.html:171 +#: templates/sales/orders/order_details.html:431 #: templates/sales/sales_list.html:118 msgid "Quotation" msgstr "عرض سعر" @@ -1478,6 +1491,8 @@ msgstr "الصورة" #: templates/sales/estimates/sale_order_preview.html:167 #: templates/sales/invoices/invoice_list.html:16 #: templates/sales/journals/journal_list.html:16 +#: templates/sales/orders/order_details.html:124 +#: templates/sales/orders/order_details.html:461 #: templates/sales/orders/order_list.html:15 #: venv/lib/python3.11/site-packages/django_ledger/models/customer.py:189 #: venv/lib/python3.11/site-packages/django_ledger/models/estimate.py:252 @@ -1653,6 +1668,7 @@ msgstr "المُعرّف الفريد للفرصة (slug)." #: inventory/models.py:2008 templates/crm/leads/lead_detail.html:110 #: templates/crm/leads/lead_list.html:75 templates/header.html:148 +#: templates/sales/orders/order_details.html:453 msgid "Opportunity" msgstr "فرصة" @@ -1680,6 +1696,7 @@ msgstr "ملاحظة" #: templates/crm/opportunities/opportunity_detail.html:329 #: templates/customers/view_customer.html:192 #: templates/plans/invoices/layout.html:175 +#: templates/sales/orders/order_details.html:568 #: venv/lib/python3.11/site-packages/django_ledger/forms/bill.py:154 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/card_markdown.html:9 msgid "Notes" @@ -2194,6 +2211,8 @@ msgstr "المخزون" msgid "Car Colors details updated successfully" msgstr "تم تحديث تفاصيل ألوان السيارة بنجاح" +#: inventory/views.py:1017 +#, python-format msgid "Update Colors for %(car_name)s" msgstr "تحديث الألوان لـ %(car_name)s" @@ -2334,7 +2353,8 @@ msgstr "لقد وصلت إلى الحد الأقصى لعدد أعضاء الف #: inventory/views.py:2743 msgid "A user with this email already exists. Please use a different email." -msgstr "يوجد مستخدم بهذا البريد الإلكتروني بالفعل. يرجى استخدام بريد إلكتروني مختلف." +msgstr "" +"يوجد مستخدم بهذا البريد الإلكتروني بالفعل. يرجى استخدام بريد إلكتروني مختلف." #: inventory/views.py:2790 msgid "User updated successfully" @@ -2624,9 +2644,11 @@ msgstr "تم حذف الحساب بنجاح" msgid "You cannot delete this account,it is related to another account" msgstr "لا يمكنك حذف هذا الحساب، لأنه مرتبط بحساب آخر" +#: inventory/views.py:8529 msgid "Purchase order created successfully" msgstr "تم إنشاء أمر الشراء بنجاح" +#: inventory/views.py:8570 msgid "Inventory item created successfully" msgstr "تم إنشاء عنصر المخزون بنجاح" @@ -3499,12 +3521,16 @@ msgstr "الطابع الزمني" msgid "User" msgstr "المستخدم" +#: templates/admin_management/auth_logs.html:32 msgid "Event Type" msgstr "نوع الحدث" +#: templates/admin_management/auth_logs.html:33 msgid "username" msgstr "اسم المستخدم" +#: templates/admin_management/auth_logs.html:34 +#: templates/admin_management/request_logs.html:33 msgid "IP Address" msgstr "عنوان IP" @@ -3544,39 +3570,51 @@ msgstr "لوحة سجل التدقيق" msgid "Action" msgstr "الإجراء" +#: templates/admin_management/model_logs.html:34 msgid "Object ID" msgstr "معرّف الكائن" +#: templates/admin_management/model_logs.html:35 msgid "Object Representation" msgstr "تمثيل الكائن" +#: templates/admin_management/model_logs.html:36 msgid "Field" msgstr "الحقل" +#: templates/admin_management/model_logs.html:37 msgid "Old Value" msgstr "القيمة القديمة" +#: templates/admin_management/model_logs.html:38 msgid "New Value" msgstr "القيمة الجديدة" +#: templates/admin_management/model_logs.html:99 msgid "Object created." msgstr "تم إنشاء الكائن." +#: templates/admin_management/model_logs.html:101 msgid "Object deleted." msgstr "تم حذف الكائن." +#: templates/admin_management/model_logs.html:103 msgid "No specific field changes recorded." msgstr "لم يتم تسجيل تغييرات محددة في الحقول." +#: templates/admin_management/model_logs.html:116 msgid "No model change audit events found." msgstr "لم يتم العثور على أحداث تدقيق لتغييرات النماذج." +#: templates/admin_management/nav.html:6 msgid "User Actions" msgstr "إجراءات المستخدم" +#: templates/admin_management/nav.html:11 msgid "User Login Events" msgstr "أحداث تسجيل دخول المستخدم" +#: templates/admin_management/nav.html:16 msgid "User Page Requests" msgstr "طلبات صفحات المستخدم" @@ -3925,6 +3963,7 @@ msgstr "المدة" #: templates/administration/manage_service.html:66 #: templates/appointment/appointment_client_information.html:108 +#: templates/sales/orders/order_details.html:234 #: venv/lib/python3.11/site-packages/appointment/templates/appointment/appointment_client_information.html:115 msgid "Down Payment" msgstr "دفعة مقدمة" @@ -4440,6 +4479,7 @@ msgstr "تفاصيل الدفع" #: templates/sales/estimates/estimate_detail.html:197 #: templates/sales/estimates/sale_order_preview.html:184 #: templates/sales/invoices/invoice_detail.html:244 +#: templates/sales/orders/order_details.html:269 #: venv/lib/python3.11/site-packages/appointment/templates/appointment/appointment_client_information.html:103 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:98 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:127 @@ -5146,6 +5186,7 @@ msgstr "السيارة المطلوبة" msgid "Related Records" msgstr "السجلات المرتبطة" +#: templates/crm/leads/lead_detail.html:114 msgid "No Opportunity" msgstr "لا توجد فرصة" @@ -5194,6 +5235,7 @@ msgid "Add Note" msgstr "إضافة ملاحظة" #: templates/crm/leads/lead_detail.html:296 +#: templates/sales/orders/order_details.html:132 msgid "Created By" msgstr "تم الإنشاء بواسطة" @@ -5269,6 +5311,10 @@ msgstr "نعم" msgid "In Progress" msgstr "قيد التنفيذ" +#: templates/crm/leads/lead_list.html:138 +msgid "View Schedules" +msgstr "عرض الجداول" + #: templates/crm/leads/lead_list.html:214 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:27 #: templates/dealers/dealer_detail.html:22 @@ -5320,9 +5366,11 @@ msgstr "متابعات" msgid "Negotiation Ups" msgstr "مفاوضات إضافية" +#: templates/crm/leads/partials/update_action.html:5 msgid "Update Lead Actions" msgstr "تحديث إجراءات العميل المحتمل" +#: templates/crm/leads/partials/update_action.html:16 msgid "Select Stage" msgstr "اختر المرحلة" @@ -5347,6 +5395,8 @@ msgstr "لا يوجد إجراء" #: templates/modal/event_details_modal.html:21 #: templates/partials/scanner_modal.html:6 #: templates/partials/specifications_modal.html:8 +#: templates/sales/orders/order_details.html:542 +#: templates/sales/orders/order_details.html:573 #: venv/lib/python3.11/site-packages/appointment/templates/modal/confirm_modal.html:18 #: venv/lib/python3.11/site-packages/appointment/templates/modal/error_modal.html:17 #: venv/lib/python3.11/site-packages/appointment/templates/modal/event_details_modal.html:19 @@ -5376,24 +5426,34 @@ msgstr "تفاصيل الفرصة" msgid "View Quotation" msgstr "مشاهدة عرض السعر" +#: templates/crm/opportunities/opportunity_detail.html:77 msgid "Upcoming Events" msgstr "الأحداث القادمة" +#: templates/crm/opportunities/opportunity_detail.html:90 msgid "No upcoming events" msgstr "لا توجد أحداث قادمة" +#: templates/crm/opportunities/opportunity_detail.html:109 msgid "No Estimate" msgstr "لا يوجد تقدير" +#: templates/crm/opportunities/opportunity_detail.html:117 +#: templates/payment_success.html:29 +#: templates/sales/estimates/estimate_detail.html:97 +#: templates/sales/invoices/invoice_detail.html:5 msgid "View Invoice" msgstr "عرض الفاتورة" +#: templates/crm/opportunities/opportunity_detail.html:119 msgid "No Invoice" msgstr "لا توجد فاتورة" +#: templates/crm/opportunities/opportunity_detail.html:128 msgid "System Information" msgstr "معلومات النظام" +#: templates/crm/opportunities/opportunity_detail.html:133 msgid "Created " msgstr "تم الإنشاء" @@ -5418,6 +5478,7 @@ msgstr "تاريخ الإنشاء" msgid "Meetings" msgstr "الاجتماعات" +#: templates/crm/opportunities/opportunity_detail.html:333 msgid "Calls" msgstr "المكالمات" @@ -5606,6 +5667,7 @@ msgstr "حالة الدفع" #: templates/sales/invoices/invoice_detail.html:80 #: templates/sales/invoices/invoice_detail.html:224 #: templates/sales/invoices/invoice_list.html:40 +#: templates/sales/orders/order_details.html:268 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:346 #: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:303 msgid "Paid" @@ -6471,6 +6533,7 @@ msgid "Cannot Edit, Car in Transfer." msgstr "لا يمكن التعديل، السيارة قيد النقل." #: templates/inventory/car_detail.html:233 +#: templates/sales/orders/order_details.html:224 msgid "Financial Details" msgstr "التفاصيل المالية" @@ -6597,9 +6660,11 @@ msgstr "يرجى إضافة مورد قبل إضافة السيارة." msgid "Add Vendor" msgstr "إضافة مورد" +#: templates/inventory/car_form.html:58 msgid "Scan VIN" msgstr "مسح رقم الهيكل" +#: templates/inventory/car_form.html:64 msgid "Decode VIN" msgstr "تحليل رقم الهيكل" @@ -7333,9 +7398,13 @@ msgstr "الأصول" msgid "COGS" msgstr "تكلفة البضائع المباعة" +#: templates/ledger/coa_accounts/account_list.html:32 +#: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:483 +#: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:569 msgid "Capital" msgstr "رأس المال" +#: templates/ledger/coa_accounts/account_list.html:37 msgid "Income" msgstr "الإيرادات" @@ -8080,9 +8149,11 @@ msgstr "تم الدفع بنجاح" msgid "Thank You" msgstr "شكرًا لك" +#: templates/payment_success.html:26 msgid "Your payment was successful" msgstr "تمت عملية الدفع بنجاح" +#: templates/payment_success.html:26 msgid "Your order is being processed" msgstr "يتم الآن معالجة طلبك" @@ -8341,6 +8412,7 @@ msgid "Issued" msgstr "تاريخ الإصدار" #: templates/plans/invoices/layout.html:27 +#: templates/sales/orders/order_details.html:120 msgid "Order Date" msgstr "تاريخ الطلب" @@ -8613,6 +8685,7 @@ msgid "Confirm Your Information" msgstr "تأكيد معلوماتك" #: templates/pricing_page.html:178 +#: templates/sales/orders/order_details.html:106 msgid "Order Summary" msgstr "ملخص الطلب" @@ -8749,9 +8822,11 @@ msgstr "مورد جديد" msgid "Edit Purchase Order" msgstr "تعديل أمر الشراء" +#: templates/purchase_orders/po_form.html:24 msgid "Add New Purchase Order" msgstr "إضافة أمر شراء جديد" +#: templates/purchase_orders/po_list.html:22 msgid "Create New PO" msgstr "إنشاء أمر شراء جديد" @@ -8874,6 +8949,7 @@ msgstr "إرسال" #: templates/sales/estimates/sale_order_form.html:5 #: templates/sales/estimates/sale_order_form1.html:5 #: templates/sales/estimates/sale_order_preview.html:159 +#: templates/sales/orders/order_details.html:84 msgid "Sale Order" msgstr "أمر بيع" @@ -8922,7 +8998,7 @@ msgstr "قبول" #: templates/sales/invoices/invoice_detail.html:109 msgid "Owned" -msgstr "مملوك" +msgstr "متبقي" #: templates/sales/invoices/invoice_detail.html:179 #: templates/sales/invoices/invoice_list.html:15 @@ -8953,6 +9029,145 @@ msgstr "لم يتم العثور على فاتورة" msgid "Create Payment" msgstr "إجراء الدفع" +#: templates/sales/orders/order_details.html:88 +#: templates/sales/orders/purchase_order.html:37 +msgid "Print" +msgstr "طباعة" + +#: templates/sales/orders/order_details.html:91 +msgid "Share" +msgstr "مشاركة" + +#: templates/sales/orders/order_details.html:138 +#: templates/sales/orders/order_list.html:19 +#, fuzzy +#| msgid "Expected Revenue" +msgid "Expected Delivery" +msgstr "الإيرادات المتوقعة" + +#: templates/sales/orders/order_details.html:143 +msgid "Not scheduled" +msgstr "لم يتم الجدولة" + +#: templates/sales/orders/order_details.html:156 +msgid "Cancellation Reason" +msgstr "سبب الإلغاء" + +#: templates/sales/orders/order_details.html:164 +msgid "Order Comments" +msgstr "ملاحظات الطلب" + +#: templates/sales/orders/order_details.html:176 +msgid "Vehicle Details" +msgstr "تفاصيل المركبة" + +#: templates/sales/orders/order_details.html:206 +#: templates/sales/orders/order_details.html:493 +msgid "km" +msgstr "كم" + +#: templates/sales/orders/order_details.html:214 +msgid "No vehicle assigned to this order" +msgstr "لم يتم تخصيص مركبة لهذا الطلب" + +#: templates/sales/orders/order_details.html:230 +msgid "Agreed Price" +msgstr "السعر المتفق عليه" + +#: templates/sales/orders/order_details.html:238 +msgid "Trade-In Value" +msgstr "قيمة الاستبدال" + +#: templates/sales/orders/order_details.html:244 +msgid "Loan Amount" +msgstr "قيمة القرض" + +#: templates/sales/orders/order_details.html:248 +msgid "Total Paid" +msgstr "المبلغ المدفوع" + +#: templates/sales/orders/order_details.html:252 +msgid "Remaining Balance" +msgstr "المبلغ المتبقي" + +#: templates/sales/orders/order_details.html:277 +msgid "Documents" +msgstr "المستندات" + +#: templates/sales/orders/order_details.html:279 +msgid "Add Document" +msgstr "إضافة مستند" + +#: templates/sales/orders/order_details.html:285 +msgid "Drag & drop files here or click to browse" +msgstr "اسحب وأفلت الملفات هنا أو انقر للتصفح" + +#: templates/sales/orders/order_details.html:305 +msgid "No documents uploaded yet" +msgstr "لم يتم تحميل أي مستندات بعد" + +#: templates/sales/orders/order_details.html:315 +msgid "Comments & Notes" +msgstr "التعليقات والملاحظات" + +#: templates/sales/orders/order_details.html:325 +msgid "Post Comment" +msgstr "نشر تعليق" + +#: templates/sales/orders/order_details.html:344 +msgid "No comments yet" +msgstr "لا توجد تعليقات بعد" + +#: templates/sales/orders/order_details.html:357 +msgid "Order Actions" +msgstr "إجراءات الطلب" + +#: templates/sales/orders/order_details.html:370 +msgid "Edit Order" +msgstr "تعديل الطلب" + +#: templates/sales/orders/order_details.html:383 +#: templates/sales/orders/order_details.html:555 +#: templates/sales/orders/order_details.html:574 +msgid "Schedule Delivery" +msgstr "جدولة التسليم" + +#: templates/sales/orders/order_details.html:399 +msgid "Order Status Timeline" +msgstr "الجدول الزمني لحالة الطلب" + +#: templates/sales/orders/order_details.html:412 +msgid "Changed by" +msgstr "تم التغيير بواسطة" + +#: templates/sales/orders/order_details.html:417 +msgid "No status history available" +msgstr "لا يوجد سجل للحالة" + +#: templates/sales/orders/order_details.html:427 +msgid "Related Items" +msgstr "العناصر ذات الصلة" + +#: templates/sales/orders/order_details.html:448 +msgid "Not created yet" +msgstr "لم يتم الإنشاء بعد" + +#: templates/sales/orders/order_details.html:475 +msgid "Trade-In Vehicle" +msgstr "مركبة الاستبدال" + +#: templates/sales/orders/order_details.html:537 +msgid "Reason for Cancellation" +msgstr "سبب الإلغاء" + +#: templates/sales/orders/order_details.html:543 +msgid "Confirm Cancellation" +msgstr "تأكيد الإلغاء" + +#: templates/sales/orders/order_details.html:564 +msgid "Delivery Date" +msgstr "تاريخ التسليم" + #: templates/sales/orders/order_list.html:14 msgid "Order Number" msgstr "رقم الطلب" @@ -8961,14 +9176,6 @@ msgstr "رقم الطلب" msgid "For Quotation" msgstr "لعرض سعر" -#: templates/sales/orders/order_list.html:19 -msgid "Expected Delivery" -msgstr "موعد التسليم المتوقع" - -#: templates/sales/orders/purchase_order.html:37 -msgid "Print" -msgstr "طباعة" - #: templates/sales/orders/purchase_order.html:45 #: venv/lib/python3.11/site-packages/django_ledger/models/entity.py:3170 msgid "Purchase Order" @@ -10385,9 +10592,13 @@ msgstr "الفرنسية" msgid "not allowed with argument %s" msgstr "غير مسموح به مع الوسيط %s" +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:201 +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:215 +#, python-format msgid "ignored explicit argument %r" msgstr "تم تجاهل الوسيط المحدد %r" +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:317 msgid "too few arguments" msgstr "عدد غير كافٍ من الوسائط" diff --git a/templates/bill/bill_detail.html b/templates/bill/bill_detail.html index 33d19e37..66055386 100644 --- a/templates/bill/bill_detail.html +++ b/templates/bill/bill_detail.html @@ -277,5 +277,5 @@ - +{% include "bill/includes/mark_as.html" %} {% endblock %} \ No newline at end of file diff --git a/templates/crm/leads/lead_list.html b/templates/crm/leads/lead_list.html index 65fe6a1c..5f87ca8d 100644 --- a/templates/crm/leads/lead_list.html +++ b/templates/crm/leads/lead_list.html @@ -135,7 +135,7 @@

diff --git a/templates/crm/notifications_history.html b/templates/crm/notifications_history.html index 7d00619d..804d010b 100644 --- a/templates/crm/notifications_history.html +++ b/templates/crm/notifications_history.html @@ -22,7 +22,7 @@
{% endfor %} diff --git a/templates/csv_upload.html b/templates/csv_upload.html new file mode 100644 index 00000000..89d6206f --- /dev/null +++ b/templates/csv_upload.html @@ -0,0 +1,186 @@ +{% extends "base.html" %} +{% load static i18n %} + +{% block customCSS %} + +{% endblock customCSS %} + +{% block content %} +
+

Upload Cars CSV

+ + {% if messages %} + {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} + {% endif %} + +
+ {% csrf_token %} + +
+
+ {% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %} +
+
+ {% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %} +
+
+ {% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %} +
+
+ {% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %} +
+
+
+
+ {{form.vendor.label}} + {{form.vendor}} +
+
+ {{form.year.label}} + {{form.year}} +
+
+ {{form.receiving_date.label}} + {{form.receiving_date}} +
+
+ +
+
+

{% trans 'Exterior Colors' %}

+
+ {% for color in form.fields.exterior.queryset %} +
+ +
+ {% endfor %} +
+ +

{% trans 'Interior Colors' %}

+
+ {% for color in form.fields.interior.queryset %} +
+ +
+ {% endfor %} +
+
+
+
+ + +
+ CSV should include columns: vin, make, model, year (required) +
+
+ + + Cancel +
+ +
+

CSV Format Example

+ + + + + + + + + + + + + + + + + +
vinmakemodelyear
1HGCM82633A123456HondaAccord2023
+ + Download Sample CSV + +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/header.html b/templates/header.html index bbbac993..c66156b1 100644 --- a/templates/header.html +++ b/templates/header.html @@ -28,6 +28,20 @@ + + {% endif %}