new
This commit is contained in:
commit
f6d59da008
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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(
|
||||
|
||||
@ -234,7 +234,7 @@ urlpatterns = [
|
||||
name="fetch_notifications",
|
||||
),
|
||||
path(
|
||||
"crm/notifications/<int:pk>/mark_as_read/",
|
||||
"crm/notifications/<int:notification_id>/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/<uuid:po_pk>/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/<slug:entity_slug>/create/',
|
||||
views.BillModelCreateViewView.as_view(),
|
||||
views.BillModelCreateView.as_view(),
|
||||
name='bill-create'),
|
||||
path('items/bills/<slug:entity_slug>/create/purchase-order/<uuid:po_pk>/',
|
||||
views.BillModelCreateViewView.as_view(for_purchase_order=True),
|
||||
views.BillModelCreateView.as_view(for_purchase_order=True),
|
||||
name='bill-create-po'),
|
||||
path('items/bills/<slug:entity_slug>/create/estimate/<uuid:ce_pk>/',
|
||||
views.BillModelCreateViewView.as_view(for_estimate=True),
|
||||
views.BillModelCreateView.as_view(for_estimate=True),
|
||||
name='bill-create-estimate'),
|
||||
path('items/bills/<slug:entity_slug>/detail/<uuid:bill_pk>/',
|
||||
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/<str:content_type>/<slug:slug>/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'),
|
||||
|
||||
@ -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'
|
||||
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})
|
||||
###############################################################
|
||||
###############################################################
|
||||
Binary file not shown.
@ -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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 "عدد غير كافٍ من الوسائط"
|
||||
|
||||
|
||||
@ -277,5 +277,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "bill/includes/mark_as.html" %}
|
||||
{% endblock %}
|
||||
@ -135,7 +135,7 @@
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{lead.slug}}" aria-expanded="false" aria-controls="collapseTwo">
|
||||
View Schedules ({{lead.get_latest_schedules.count}})
|
||||
{{ _("View Schedules")}} ({{lead.get_latest_schedules.count}})
|
||||
</button>
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" id="collapse{{lead.slug}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn fs-10 btn-sm dropdown-toggle dropdown-caret-none transition-none notification-dropdown-toggle" 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 text-body"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="{% url 'mark_notification_as_read' notification.pk %}">{{ _("Mark as Read")}}</a></div>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="{% url 'mark_notification_as_read' notification.id %}">{{ _("Mark as Read")}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
186
templates/csv_upload.html
Normal file
186
templates/csv_upload.html
Normal file
@ -0,0 +1,186 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
.color-card {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
width: 80px; /* Increased from 3rem for better visibility */
|
||||
height: 80px; /* Increased from 3rem for better visibility */
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.color-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.color-option {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.color-radio {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.color-radio:checked + .color-display {
|
||||
border: 2px solid #0d6efd;
|
||||
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.color-radio:focus + .color-display {
|
||||
border-color: #86b7fe;
|
||||
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.color-display {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
border-radius: 0.25rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.color-name {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Added for better layout of color options */
|
||||
.color-options-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
{% endblock customCSS %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<h2>Upload Cars CSV</h2>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="mt-4">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="col">
|
||||
{{form.vendor.label}}
|
||||
{{form.vendor}}
|
||||
</div>
|
||||
<div class="col">
|
||||
{{form.year.label}}
|
||||
{{form.year}}
|
||||
</div>
|
||||
<div class="col">
|
||||
{{form.receiving_date.label}}
|
||||
{{form.receiving_date}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="row g-4">
|
||||
<p class="fs-5 mb-2">{% trans 'Exterior Colors' %}</p>
|
||||
<div class="color-options-container">
|
||||
{% for color in form.fields.exterior.queryset %}
|
||||
<div class="color-card">
|
||||
<label class="color-option">
|
||||
<input class="color-radio" type="radio" name="exterior" value="{{ color.id }}" {% if color.id == form.instance.exterior.id %}checked{% endif %}>
|
||||
<div class="color-display" style="background-color: rgb({{ color.rgb }})">
|
||||
<span class="color-name">{{ color.get_local_name }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<p class="fs-5 mb-2">{% trans 'Interior Colors' %}</p>
|
||||
<div class="color-options-container">
|
||||
{% for color in form.fields.interior.queryset %}
|
||||
<div class="color-card">
|
||||
<label class="color-option">
|
||||
<input class="color-radio" type="radio" name="interior" value="{{ color.id }}" {% if color.id == form.instance.interior.id %}checked{% endif %}>
|
||||
<div class="color-display" style="background-color: rgb({{ color.rgb }})">
|
||||
<span class="color-name">{{ color.get_local_name }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="csv_file" class="form-label">CSV File</label>
|
||||
<input type="file" class="form-control" id="csv_file" name="csv_file" accept=".csv" required>
|
||||
<div class="form-text">
|
||||
CSV should include columns: vin, make, model, year (required)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Upload</button>
|
||||
<a href="{% url 'car_list' %}" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
|
||||
<div class="mt-4">
|
||||
<h4>CSV Format Example</h4>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>vin</th>
|
||||
<th>make</th>
|
||||
<th>model</th>
|
||||
<th>year</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1HGCM82633A123456</td>
|
||||
<td>Honda</td>
|
||||
<td>Accord</td>
|
||||
<td>2023</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{% static 'sample/cars_sample.csv' %}" class="btn btn-outline-primary">
|
||||
Download Sample CSV
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -28,6 +28,20 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'inventory_item_create' %}">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add invenotry item"|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'purchase_order_list' %}">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
|
||||
@ -416,7 +430,7 @@
|
||||
<div class="overflow-auto scrollbar" style="height: 10rem;">
|
||||
<ul class="nav d-flex flex-column mb-2 pb-1">
|
||||
{% if request.is_dealer %}
|
||||
<li class="nav-item">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 d-block" href="{% url 'dealer_detail' request.user.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
|
||||
</li>
|
||||
{% else %}
|
||||
|
||||
@ -67,7 +67,9 @@
|
||||
{% elif bill.is_approved %}
|
||||
<span class="badge badge-phoenix badge-phoenix-success">
|
||||
{% elif bill.is_paid %}
|
||||
<span class="badge badge-phoenix badge-phoenix-success">
|
||||
<span class="badge badge-phoenix badge-phoenix-success">
|
||||
{% elif bill.is_canceled %}
|
||||
<span class="badge badge-phoenix badge-phoenix-danger">
|
||||
{% endif %}
|
||||
{{ bill.bill_status }}
|
||||
</span>
|
||||
@ -79,10 +81,10 @@
|
||||
<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>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2">
|
||||
<a href="{% url 'bill_detail' bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
|
||||
<a href="{% url 'bill-detail' entity_slug=entity.slug bill_pk=bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
|
||||
@ -1,13 +1,103 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static i18n crispy_forms_tags %}
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
.color-card {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
width: 80px; /* Increased from 3rem for better visibility */
|
||||
height: 80px; /* Increased from 3rem for better visibility */
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.color-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.color-option {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.color-radio {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.color-radio:checked + .color-display {
|
||||
border: 2px solid #0d6efd;
|
||||
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.color-radio:focus + .color-display {
|
||||
border-color: #86b7fe;
|
||||
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.color-display {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
border-radius: 0.25rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.color-name {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Added for better layout of color options */
|
||||
.color-options-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<form action="" method="post">
|
||||
{% 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 %}
|
||||
<div class="row g-4">
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %}
|
||||
</div>
|
||||
<div class="col">
|
||||
{% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="col">
|
||||
{{form.vendor.label}}
|
||||
{{form.vendor}}
|
||||
</div>
|
||||
<div class="col">
|
||||
{{form.year.label}}
|
||||
{{form.year}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="account">Account</label>
|
||||
<select class="form-control" name="account" id="account">
|
||||
@ -16,6 +106,43 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<<<<<<< HEAD
|
||||
<button type="submit" class="btn btn-phoenix-primary">Add New Item To Inventory</button>
|
||||
=======
|
||||
<div class="row g-4 mt-4">
|
||||
<div class="col">
|
||||
<p class="fs-5 mb-2">{% trans 'Exterior Colors' %}</p>
|
||||
<div class="color-options-container">
|
||||
{% for color in form.fields.exterior.queryset %}
|
||||
<div class="color-card">
|
||||
<label class="color-option">
|
||||
<input class="color-radio" type="radio" name="exterior" value="{{ color.id }}" {% if color.id == form.instance.exterior.id %}checked{% endif %}>
|
||||
<div class="color-display" style="background-color: rgb({{ color.rgb }})">
|
||||
<span class="color-name">{{ color.get_local_name }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<p class="fs-5 mb-2">{% trans 'Interior Colors' %}</p>
|
||||
<div class="color-options-container">
|
||||
{% for color in form.fields.interior.queryset %}
|
||||
<div class="color-card">
|
||||
<label class="color-option">
|
||||
<input class="color-radio" type="radio" name="interior" value="{{ color.id }}" {% if color.id == form.instance.interior.id %}checked{% endif %}>
|
||||
<div class="color-display" style="background-color: rgb({{ color.rgb }})">
|
||||
<span class="color-name">{{ color.get_local_name }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-5">Add New Item To Inventory</button>
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</form>
|
||||
{% endblock content %}
|
||||
@ -58,8 +58,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<h4 class="h6 mb-1">{% trans 'Contract' %}</h4>
|
||||
<p class="mb-0">{{ po_model.ce_model.estimate_number }}</p>
|
||||
</div>
|
||||
<<<<<<< HEAD
|
||||
<a href="{% url 'django_ledger:customer-estimate-detail' entity_slug=view.kwargs.entity_slug ce_pk=po_model.ce_model_id %}"
|
||||
class="btn btn-sm btn-phoenix-info ms-auto">
|
||||
=======
|
||||
<a href="{% url 'estimate_detail' po_model.ce_model_id %}"
|
||||
class="btn btn-sm btn-outline-info ms-auto">
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
{% trans 'View Contract' %}
|
||||
</a>
|
||||
</div>
|
||||
@ -192,6 +197,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
onclick="showPOModal('Fulfill PO', '{% url 'po-action-mark-as-fulfilled' entity_slug po_model.pk %}', 'Mark As Fulfilled')">
|
||||
<i class="fas fa-truck me-2"></i>{% trans 'Mark as Fulfilled' %}
|
||||
</button>
|
||||
<<<<<<< HEAD
|
||||
<button class="btn btn-phoenix-danger"
|
||||
onclick="showPOModal('Cancel PO', '{% url 'po-action-mark-as-canceled' entity_slug po_model.pk %}', 'Mark As Cancelled')">
|
||||
<i class="fas fa-ban me-2"></i>{% trans 'Cancel' %}
|
||||
@ -219,6 +225,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<i class="fas fa-window-close me-2"></i>{% trans 'Cancel' %}
|
||||
</button>
|
||||
{% modal_action_v2 bill po_model.get_mark_as_canceled_url po_model.get_mark_as_canceled_message po_model.get_mark_as_canceled_html_id %}
|
||||
=======
|
||||
{% endif %}
|
||||
|
||||
{# Danger Action Buttons #}
|
||||
{% if po_model.can_delete %}
|
||||
<button class="btn btn-outline-danger"
|
||||
onclick="showPOModal('Cancel PO', '{% url 'po-delete' entity_slug po_model.pk %}', 'Mark As Cancelled')">
|
||||
<i class="fas fa-ban me-2"></i>{% trans 'Delete' %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if po_model.can_void %}
|
||||
<button class="btn btn-outline-danger"
|
||||
onclick="showPOModal('Void PO', '{% url 'po-action-mark-as-void' entity_slug po_model.pk %}', 'Mark As Void')">
|
||||
<i class="fas fa-times-circle me-2"></i>{% trans 'Void' %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if po_model.can_cancel %}
|
||||
<button class="btn btn-outline-danger"
|
||||
onclick="showPOModal('Cancel PO', '{% url 'po-action-mark-as-canceled' entity_slug po_model.pk %}', 'Mark As Cancelled')">
|
||||
<i class="fas fa-ban me-2"></i>{% trans 'Cancel' %}
|
||||
</button>
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@ -228,7 +258,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
{% else %}
|
||||
<div class="card border-0 shadow-sm text-center py-5">
|
||||
<div class="card-body">
|
||||
<a href="{% url 'django_ledger:po-create' entity_slug=entity_slug %}" class="text-decoration-none">
|
||||
<a href="{% url 'purchase_order_create' %}" class="text-decoration-none">
|
||||
<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>
|
||||
</a>
|
||||
|
||||
@ -34,9 +34,9 @@
|
||||
</div>
|
||||
<div class="dropdown-menu" id="dropdown-menu-{{ po.uuid }}" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a href="{% url 'django_ledger:po-detail' entity_slug=entity_slug po_pk=po.uuid %}"
|
||||
<a href="{% url 'purchase_order_detail' po_pk=po.uuid %}"
|
||||
class="dropdown-item has-text-success">Details</a>
|
||||
<a href="{% url 'django_ledger:po-delete' entity_slug=entity_slug po_pk=po.uuid %}"
|
||||
<a href="{% url 'po-delete' entity_slug=entity_slug po_pk=po.uuid %}"
|
||||
class="dropdown-item has-text-weight-bold has-text-danger">{% trans ' Delete' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
Purchase Order {{ po_model.po_number }}?</h2>
|
||||
|
||||
<p class="card-text text-muted mb-4">All transactions associated with this Purchase Order will be deleted.
|
||||
If you want to void the PO instead, <a href="{% url 'django_ledger:po-detail' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" class="text-decoration-none">click here</a></p>
|
||||
If you want to void the PO instead, <a href="{% url 'purchase_order_detail' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" class="text-decoration-none">click here</a></p>
|
||||
|
||||
<div class="d-flex justify-content-center gap-3 mt-4">
|
||||
<a href="{% url 'purchase_order_update' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}"
|
||||
|
||||
@ -18,11 +18,15 @@
|
||||
<h3 class="">
|
||||
{{ _("Purchase Orders") |capfirst }}
|
||||
</h2>
|
||||
<a href="{% url 'purchase_order_create' %}"
|
||||
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
|
||||
<div>
|
||||
<a href="{% url 'purchase_order_create' %}"
|
||||
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
|
||||
<a href="{% url 'inventory_item_create' %}?for_po=1"
|
||||
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create Inventory Item for PO") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% include "partials/search_box.html" %}
|
||||
|
||||
|
||||
<div class="table-responsive px-1 scrollbar mt-3">
|
||||
<table class= "table align-items-center table-flush table-hover">
|
||||
<thead>
|
||||
@ -31,13 +35,13 @@
|
||||
<th class="sort white-space-nowrap align-middle" scope="col" style="width:40%">Description</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col" style="width:15%">Status</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col" style="width:15%">Created At</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col" style="width:15%">Actions</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col" style="width:15%">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
{% if purchase_orders %}
|
||||
{% for po in purchase_orders %}
|
||||
|
||||
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
<td class="align-middle product white-space-nowrap">{{ po.po_number }}</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ po.po_title }}</td>
|
||||
@ -48,11 +52,13 @@
|
||||
</td>
|
||||
<td class="align-middle product white-space-nowrap">{{ po.created|date:"M d, Y" }}</td>
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
<a href="{% url 'purchase_order_detail' po.pk %}"
|
||||
class="btn btn-sm btn-phoenix-success">
|
||||
<i class="fa-regular fa-eye me-1"></i>
|
||||
{% trans "view"|capfirst %}
|
||||
</a>
|
||||
<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>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2">
|
||||
<a href="{% url 'purchase_order_detail' po.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
|
||||
<a href="{% url 'upload_cars' po.pk %}" class="dropdown-item text-success-dark">{% trans 'Upload Data' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
</td>
|
||||
<td class="has-text-centered">{% if item.bill_model_id %}
|
||||
<a class="is-small is-info button"
|
||||
href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=item.bill_model_id %}">View
|
||||
href="{% url 'bill-detail' entity_slug=entity_slug bill_pk=item.bill_model_id %}">View
|
||||
Bill</a>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -76,19 +76,27 @@
|
||||
{% block content %}
|
||||
<div class="container-fluid px-0">
|
||||
<!-- Header -->
|
||||
<header class="bg-primary text-white py-3">
|
||||
<header class="bg-primary py-3">
|
||||
<div class="container">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h1 class="h4 mb-0">
|
||||
<i class="fas fa-file-invoice me-2"></i>
|
||||
Sale Order #{{ saleorder.formatted_order_id }}
|
||||
{{ _("Sale Order")}} #{{ saleorder.formatted_order_id }}
|
||||
</h1>
|
||||
<div>
|
||||
<<<<<<< HEAD
|
||||
<button class="btn btn-sm btn-phoenix-light me-2">
|
||||
<i class="fas fa-print me-1"></i> Print
|
||||
</button>
|
||||
<button class="btn btn-sm btn-phoenix-light">
|
||||
<i class="fas fa-share-alt me-1"></i> Share
|
||||
=======
|
||||
<button class="btn btn-sm btn-outline-light me-2">
|
||||
<i class="fas fa-print me-1"></i> {{ _("Print") }}
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-light">
|
||||
<i class="fas fa-share-alt me-1"></i> {{ _("Share") }}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -103,7 +111,7 @@
|
||||
<!-- Order Summary Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-light">
|
||||
<h5 class="mb-0 text-primary">Order Summary</h5>
|
||||
<h5 class="mb-0 text-primary">{{ _("Order Summary")}}</h5>
|
||||
<span class="status-badge
|
||||
{% if saleorder.status == 'approved' %}bg-success text-white
|
||||
{% elif saleorder.status == 'cancelled' %}bg-danger text-white
|
||||
@ -117,35 +125,35 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Order Date</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Order Date")}}</label>
|
||||
<p class="mb-0 fw-bold">{{ saleorder.order_date|date }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Customer</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Customer") }}</label>
|
||||
<p class="mb-0 fw-bold">{{ saleorder.customer.full_name|capfirst }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Payment Method</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Payment Method")}}</label>
|
||||
<p class="mb-0 fw-bold">{{ saleorder.get_payment_method_display }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Created By</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Created By")}}</label>
|
||||
<p class="mb-0 fw-bold">{{ saleorder.created_by }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Expected Delivery</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Expected Delivery")}}</label>
|
||||
<p class="mb-0 fw-bold">
|
||||
{% if saleorder.expected_delivery_date %}
|
||||
{{ saleorder.expected_delivery_date|date }}
|
||||
{% else %}
|
||||
<span class="text-warning">Not scheduled</span>
|
||||
<span class="text-warning">{{ _("Not scheduled")}}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Last Updated</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Last Updated")}}</label>
|
||||
<p class="mb-0 fw-bold">
|
||||
{{ saleorder.updated_at|naturaltime|capfirst }} by
|
||||
{{ saleorder.last_modified_by }}
|
||||
@ -153,7 +161,7 @@
|
||||
</div>
|
||||
{% if saleorder.status == 'cancelled' %}
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Cancellation Reason</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Cancellation Reason")}}</label>
|
||||
<p class="mb-0 fw-bold text-danger">{{ saleorder.cancellation_reason|default:"Not specified" }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -161,7 +169,7 @@
|
||||
</div>
|
||||
{% if saleorder.comments %}
|
||||
<div class="mt-3">
|
||||
<label class="form-label text-muted small mb-1">Order Comments</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Order Comments")}}</label>
|
||||
<blockquote class="blockquote mb-0">
|
||||
<p class="mb-0">{{ saleorder.comments }}</p>
|
||||
</blockquote>
|
||||
@ -173,7 +181,7 @@
|
||||
<!-- Vehicle Details Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Vehicle Details</h5>
|
||||
<h5 class="mb-0">{{ _("Vehicle Details")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
@ -186,24 +194,24 @@
|
||||
<div class="col-md-8">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label text-muted small mb-1">Make</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Make") }}</label>
|
||||
<p class="mb-0">{{ car.make }}</p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label text-muted small mb-1">Model</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Model") }}</label>
|
||||
<p class="mb-0">{{ car.model }}</p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label text-muted small mb-1">Year</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Year") }}</label>
|
||||
<p class="mb-0">{{ car.year }}</p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label text-muted small mb-1">VIN</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("VIN") }}</label>
|
||||
<p class="mb-0">{{ car.vin }}</p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label text-muted small mb-1">Mileage</label>
|
||||
<p class="mb-0">{{ car.mileage|intcomma }} km</p>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Mileage") }}</label>
|
||||
<p class="mb-0">{{ car.mileage|intcomma }} {{ _("km") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -211,7 +219,7 @@
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12 text-center py-4">
|
||||
<p class="text-muted">No vehicle assigned to this order</p>
|
||||
<p class="text-muted">{{ _("No vehicle assigned to this order")}}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -221,35 +229,35 @@
|
||||
<!-- Financial Details Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Financial Details</h5>
|
||||
<h5 class="mb-0">{{ _("Financial Details")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Agreed Price</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Agreed Price")}}</label>
|
||||
<p class="mb-0 fw-bold">SAR {{ saleorder.agreed_price|intcomma }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Down Payment</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Down Payment")}}</label>
|
||||
<p class="mb-0">SAR {{ saleorder.down_payment_amount|intcomma }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Trade-In Value</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Trade-In Value")}}</label>
|
||||
<p class="mb-0">SAR {{ saleorder.trade_in_value|intcomma }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Loan Amount</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Loan Amount")}}</label>
|
||||
<p class="mb-0">SAR {{ saleorder.loan_amount|intcomma }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Total Paid</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Total Paid")}}</label>
|
||||
<p class="mb-0">SAR {{ saleorder.total_paid_amount|intcomma }}</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Remaining Balance</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Remaining Balance")}}</label>
|
||||
<p class="mb-0 fw-bold {% if saleorder.remaining_balance > 0 %}text-danger{% else %}text-success{% endif %}">
|
||||
SAR {{ saleorder.remaining_balance|intcomma }}
|
||||
</p>
|
||||
@ -265,8 +273,8 @@
|
||||
aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-1 small text-muted">
|
||||
<span>{{ payment_percentage }}% Paid</span>
|
||||
<span>SAR {{ saleorder.agreed_price|intcomma }} Total</span>
|
||||
<span>{{ payment_percentage }}% {{ _("Paid") }}</span>
|
||||
<span>SAR {{ saleorder.agreed_price|intcomma }} {{ _("Total") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -274,15 +282,21 @@
|
||||
<!-- Documents Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<<<<<<< HEAD
|
||||
<h5 class="mb-0">Documents</h5>
|
||||
<button class="btn btn-sm btn-phoenix-primary">
|
||||
<i class="fas fa-plus me-1"></i> Add Document
|
||||
=======
|
||||
<h5 class="mb-0">{{ _("Documents") }}</h5>
|
||||
<button class="btn btn-sm btn-primary">
|
||||
<i class="fas fa-plus me-1"></i> {{ _("Add Document")}}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="file-upload mb-3">
|
||||
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-2"></i>
|
||||
<p class="mb-1">Drag & drop files here or click to browse</p>
|
||||
<p class="mb-1">{{ _("Drag & drop files here or click to browse")}}</p>
|
||||
<p class="small text-muted mb-0">PDF, JPG, PNG up to 10MB</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
@ -290,7 +304,7 @@
|
||||
<div class="col-md-3 mb-3">
|
||||
<div class="card">
|
||||
{% if document.file.url|lower|slice:'-3:' == 'pdf' %}
|
||||
<img src="{% static 'images/pdf-icon.png' %}" class="document-thumbnail card-img-top" alt="PDF Document">
|
||||
<img src="{% static 'images/icons/file.png' %}" class="document-thumbnail card-img-top" alt="PDF Document">
|
||||
{% else %}
|
||||
<img src="{{ document.file.url }}" class="document-thumbnail card-img-top" alt="Document">
|
||||
{% endif %}
|
||||
@ -302,7 +316,7 @@
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-12 text-center py-3">
|
||||
<p class="text-muted">No documents uploaded yet</p>
|
||||
<p class="text-muted">{{ _("No documents uploaded yet")}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@ -312,7 +326,7 @@
|
||||
<!-- Comments Card -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Comments & Notes</h5>
|
||||
<h5 class="mb-0">{{ _("Comments & Notes")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% comment %} <form method="post" action="{% url 'add_sale_order_comment' saleorder.pk %}"> {% endcomment %}
|
||||
@ -321,7 +335,11 @@
|
||||
<div class="mb-3">
|
||||
<textarea class="form-control" name="comment" rows="3" placeholder="Add a comment or note..." required></textarea>
|
||||
<div class="d-flex justify-content-end mt-2">
|
||||
<<<<<<< HEAD
|
||||
<button type="submit" class="btn btn-phoenix-primary btn-sm">Post Comment</button>
|
||||
=======
|
||||
<button type="submit" class="btn btn-primary btn-sm">{{ _("Post Comment")}}</button>
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -340,7 +358,7 @@
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="text-center py-3">
|
||||
<p class="text-muted">No comments yet</p>
|
||||
<p class="text-muted">{{ _("No comments yet")}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@ -353,7 +371,7 @@
|
||||
<!-- Actions Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Order Actions</h5>
|
||||
<h5 class="mb-0">{{ _("Order Actions")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
@ -364,26 +382,46 @@
|
||||
{% endif %}
|
||||
|
||||
{% comment %} <a href="{% url 'edit_sale_order' saleorder.pk %}" class="btn btn-primary"> {% endcomment %}
|
||||
<<<<<<< HEAD
|
||||
<a href="" class="btn btn-phoenix-primary">
|
||||
<i class="fas fa-edit me-2"></i> Edit Order
|
||||
=======
|
||||
<a href="" class="btn btn-primary">
|
||||
<i class="fas fa-edit me-2"></i> {{ _("Edit Order")}}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</a>
|
||||
|
||||
{% if not saleorder.invoice %}
|
||||
{% comment %} <a href="{% url 'create_invoice_from_order' saleorder.pk %}" class="btn btn-info"> {% endcomment %}
|
||||
<<<<<<< HEAD
|
||||
<a href="" class="btn btn-phoenix-info">
|
||||
<i class="fas fa-file-invoice-dollar me-2"></i> Create Invoice
|
||||
=======
|
||||
<a href="" class="btn btn-info">
|
||||
<i class="fas fa-file-invoice-dollar me-2"></i> {{ _("Create Invoice")}}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if saleorder.status == 'approved' and not saleorder.actual_delivery_date %}
|
||||
<<<<<<< HEAD
|
||||
<button class="btn btn-phoenix-warning" data-bs-toggle="modal" data-bs-target="#deliveryModal">
|
||||
<i class="fas fa-truck me-2"></i> Schedule Delivery
|
||||
=======
|
||||
<button class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#deliveryModal">
|
||||
<i class="fas fa-truck me-2"></i> {{ _("Schedule Delivery")}}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if saleorder.status != 'cancelled' %}
|
||||
<<<<<<< HEAD
|
||||
<button class="btn btn-phoenix-danger" data-bs-toggle="modal" data-bs-target="#cancelModal">
|
||||
<i class="fas fa-times-circle me-2"></i> Cancel Order
|
||||
=======
|
||||
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#cancelModal">
|
||||
<i class="fas fa-times-circle me-2"></i> {{ _("Cancel Order")}}
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -393,7 +431,7 @@
|
||||
<!-- Status Timeline Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Order Status Timeline</h5>
|
||||
<h5 class="mb-0">{{ _("Order Status Timeline")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="timeline">
|
||||
@ -406,12 +444,12 @@
|
||||
<p class="small mb-0">
|
||||
{% if log.note %}{{ log.note }}{% endif %}
|
||||
<br>
|
||||
<small class="text-muted">Changed by: {{ log.changed_by.get_full_name|default:log.changed_by.username }}</small>
|
||||
<small class="text-muted">{{ _("Changed by")}}: {{ log.changed_by.get_full_name|default:log.changed_by.username }}</small>
|
||||
</p>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="text-center py-3">
|
||||
<p class="text-muted">No status history available</p>
|
||||
<p class="text-muted">{{ _("No status history available")}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@ -421,11 +459,11 @@
|
||||
<!-- Related Items Card -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Related Items</h5>
|
||||
<h5 class="mb-0">{{ _("Related Items")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Estimate</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Quotation") }}</label>
|
||||
<a href="{% url 'estimate_detail' saleorder.estimate.pk %}" target="_blank" rel="noopener noreferrer">
|
||||
<p class="mb-0">
|
||||
<span class="badge bg-success ms-1">{{ saleorder.estimate.estimate_number }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
|
||||
@ -433,7 +471,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Invoice</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Invoice") }}</label>
|
||||
<p class="mb-0">
|
||||
{% if saleorder.invoice %}
|
||||
<a href="{% url 'invoice_detail' saleorder.invoice.pk %}" target="_blank" rel="noopener noreferrer">
|
||||
@ -442,12 +480,12 @@
|
||||
</p>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="text-muted">Not created yet</span>
|
||||
<span class="text-muted">{{ _("Not created yet")}}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Opportunity</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Opportunity") }}</label>
|
||||
<a href="{% url 'opportunity_detail' saleorder.opportunity.slug %}" target="_blank" rel="noopener noreferrer">
|
||||
<p class="mb-0">
|
||||
<span class="badge bg-success ms-1">{{ saleorder.opportunity }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
|
||||
@ -455,7 +493,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small mb-1">Customer</label>
|
||||
<label class="form-label text-muted small mb-1">{{ _("Customer") }}</label>
|
||||
<a href="{% url 'customer_detail' saleorder.customer.slug %}" target="_blank" rel="noopener noreferrer">
|
||||
<p class="mb-0">
|
||||
<span class="badge bg-success ms-1">{{ saleorder.customer.full_name|capfirst }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
|
||||
@ -469,7 +507,7 @@
|
||||
{% if saleorder.trade_in_vehicle %}
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Trade-In Vehicle</h5>
|
||||
<h5 class="mb-0">{{ _("Trade-In Vehicle")}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center mb-3">
|
||||
@ -480,14 +518,14 @@
|
||||
{{ saleorder.trade_in_vehicle.make }}
|
||||
{{ saleorder.trade_in_vehicle.model }}
|
||||
</h6>
|
||||
<p class="small text-muted mb-2">VIN: {{ saleorder.trade_in_vehicle.vin }}</p>
|
||||
<p class="small text-muted mb-2">{{ _("VIN") }}: {{ saleorder.trade_in_vehicle.vin }}</p>
|
||||
<p class="fw-bold">SAR {{ saleorder.trade_in_value|intcomma }}</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<p class="small mb-1">
|
||||
<i class="fas fa-tachometer-alt me-1 text-muted"></i>
|
||||
{{ saleorder.trade_in_vehicle.mileage|intcomma }} km
|
||||
{{ saleorder.trade_in_vehicle.mileage|intcomma }} {{ _("km") }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
@ -522,7 +560,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="cancelModalLabel">Cancel Order</h5>
|
||||
<h5 class="modal-title" id="cancelModalLabel">{{ _("Cancel Order")}}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
{% comment %} <form method="post" action="{% url 'cancel_sale_order' saleorder.pk %}"> {% endcomment %}
|
||||
@ -530,13 +568,18 @@
|
||||
{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="cancellationReason" class="form-label">Reason for Cancellation</label>
|
||||
<label for="cancellationReason" class="form-label">{{ _("Reason for Cancellation")}}</label>
|
||||
<textarea class="form-control" id="cancellationReason" name="cancellation_reason" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<<<<<<< HEAD
|
||||
<button type="button" class="btn btn-phoenix-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-phoenix-danger">Confirm Cancellation</button>
|
||||
=======
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
||||
<button type="submit" class="btn btn-danger">{{ _("Confirm Cancellation")}}</button>
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -548,7 +591,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deliveryModalLabel">Schedule Delivery</h5>
|
||||
<h5 class="modal-title" id="deliveryModalLabel">{{ _("Schedule Delivery")}}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
{% comment %} <form method="post" action="{% url 'schedule_delivery' saleorder.pk %}"> {% endcomment %}
|
||||
@ -556,17 +599,22 @@
|
||||
{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="deliveryDate" class="form-label">Delivery Date</label>
|
||||
<label for="deliveryDate" class="form-label">{{ _("Delivery Date")}}</label>
|
||||
<input type="date" class="form-control" id="deliveryDate" name="delivery_date" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="deliveryNotes" class="form-label">Notes</label>
|
||||
<label for="deliveryNotes" class="form-label">{{ _("Notes") }}</label>
|
||||
<textarea class="form-control" id="deliveryNotes" name="notes" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<<<<<<< HEAD
|
||||
<button type="button" class="btn btn-phoenix-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-phoenix-primary">Schedule Delivery</button>
|
||||
=======
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
|
||||
<button type="submit" class="btn btn-primary">{{ _("Schedule Delivery")}}</button>
|
||||
>>>>>>> 90fea4d25623ba4dd0f6fd2390e23b40857b6dff
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user