add qotation-02
This commit is contained in:
commit
9422426762
@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-gc9bh4*3=b6hihdnaom0edjsbxh$5t)aap@e8p&340r7)*)qb8
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['10.10.1.109', 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
|
||||
ALLOWED_HOSTS = ['10.10.1.109',"10.10.1.120", 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
|
||||
|
||||
# Application definition
|
||||
|
||||
@ -110,9 +110,9 @@ WSGI_APPLICATION = 'car_inventory.wsgi.application'
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django_prometheus.db.backends.postgresql",
|
||||
"NAME": "haikal_app",
|
||||
"USER": "f95166",
|
||||
"PASSWORD": "Kfsh&rc9788",
|
||||
"NAME": "haikal",
|
||||
"USER": "haikal",
|
||||
"PASSWORD": "haikal",
|
||||
"HOST": "localhost",
|
||||
"PORT": 5432,
|
||||
}
|
||||
|
||||
38
inventory/management/commands/generate_vin.py
Normal file
38
inventory/management/commands/generate_vin.py
Normal file
@ -0,0 +1,38 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from inventory.services import get_model,decodevin
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
import requests
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Seed the Customer model with 20 records'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
vin,description = self.generate_vin()
|
||||
result = decodevin(vin)
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Generated VIN: {vin}'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Description: {description}'))
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Decoded VIN: {result}'))
|
||||
make,model,year_model = result.values()
|
||||
self.stdout.write(self.style.SUCCESS(f'VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}'))
|
||||
m = get_model(model)
|
||||
self.stdout.write(self.style.SUCCESS(f'Make: {m.id_car_make} - Model: {m}'))
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
self.stdout.write(self.style.SUCCESS(f'####################################################################################################'))
|
||||
|
||||
|
||||
|
||||
def generate_vin(self):
|
||||
# url = "https://www.vindecoder.org/vin-decoder"
|
||||
url = "https://vingenerator.org/"
|
||||
response = requests.get(url)
|
||||
soup = BeautifulSoup(response.content, "html.parser")
|
||||
vin = soup.find("input", {"name": "vin"})["value"]
|
||||
description = soup.find("div", {"class": "description"}).text
|
||||
|
||||
return vin,description
|
||||
@ -0,0 +1,21 @@
|
||||
# Generated by Django 4.2.17 on 2024-12-10 11:57
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0004_remove_carfinance_administration_vat_amount_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='carfinance',
|
||||
options={'verbose_name': 'Car Financial Details'},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='carfinance',
|
||||
name='total',
|
||||
),
|
||||
]
|
||||
@ -1,52 +1,87 @@
|
||||
"""
|
||||
Services module
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
from .utils import get_jwt_token
|
||||
from pyvin import VIN
|
||||
from django.conf import settings
|
||||
from openai import OpenAI
|
||||
from .models import Car
|
||||
from .models import Car,CarMake,CarModel
|
||||
|
||||
|
||||
def get_make(item):
|
||||
data = CarMake.objects.filter(name__iexact=item).first()
|
||||
return data
|
||||
def get_model(item,make):
|
||||
data = make.carmodel_set.filter(name__iexact=item).first()
|
||||
if not data:
|
||||
r = item.split(" ")
|
||||
for i in r:
|
||||
if data:=make.carmodel_set.filter(name__iexact=i).first():
|
||||
break
|
||||
return data
|
||||
|
||||
def normalize_name(name):
|
||||
return name.replace(' ', '').replace('-', '').lower()
|
||||
return name.replace(" ", "").replace("-", "").lower()
|
||||
|
||||
|
||||
def decode_vin_pyvin(vin):
|
||||
vehicle = VIN(vin)
|
||||
def decodevin(vin):
|
||||
|
||||
if result:=decode_vin(vin):
|
||||
return result
|
||||
elif result:=elm(vin):
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
data = {
|
||||
'Make': vehicle.Make,
|
||||
'Model': vehicle.Model,
|
||||
'ModelYear': vehicle.ModelYear,
|
||||
}
|
||||
print(data)
|
||||
return data
|
||||
|
||||
|
||||
def decode_vin(vin):
|
||||
v = VIN(vin)
|
||||
data = {}
|
||||
if v:
|
||||
data = {
|
||||
"maker": v.Make,
|
||||
"model": v.Model,
|
||||
"modelYear": v.ModelYear,
|
||||
}
|
||||
|
||||
return data if all([x for x in data.values()]) else None
|
||||
|
||||
|
||||
# vehicle-info
|
||||
# c2729afb
|
||||
# 6d397471920412d672af1b8a02ca52ea
|
||||
|
||||
|
||||
# option-info
|
||||
# 367974ed
|
||||
# 046b0412c1b4d3f8c39ec6375d6f3030
|
||||
def elm(vin):
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
'app-id': 'c2729afb',
|
||||
'app-key': '6d397471920412d672af1b8a02ca52ea',
|
||||
'client-id': '94142c27-2536-47e9-8e28-9ca7728b9442',
|
||||
"app-id": "c2729afb",
|
||||
"app-key": "6d397471920412d672af1b8a02ca52ea",
|
||||
"client-id": "94142c27-2536-47e9-8e28-9ca7728b9442",
|
||||
}
|
||||
url = 'https://vehicle-maintenance.api.elm.sa/api/v1/vehicles/vehicle-info?vin='+vin
|
||||
url = (
|
||||
"https://vehicle-maintenance.api.elm.sa/api/v1/vehicles/vehicle-info?vin=" + vin
|
||||
)
|
||||
|
||||
payload = {}
|
||||
response = requests.request("GET", url, headers=headers, data=payload)
|
||||
car_info = json.loads(response.text)
|
||||
print(car_info)
|
||||
return car_info
|
||||
response = json.loads(response.text)
|
||||
data = {}
|
||||
if response.get("data"):
|
||||
data = {
|
||||
"maker": response["data"]["maker"],
|
||||
"model": response["data"]["model"],
|
||||
"modelYear": response["data"]["modelYear"],
|
||||
}
|
||||
|
||||
return data if all([x for x in data.values()]) else None
|
||||
|
||||
|
||||
def translate(content, *args, **kwargs):
|
||||
@ -54,8 +89,11 @@ def translate(content, *args, **kwargs):
|
||||
completion = client.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a translation assistant that translates English to Arabic."},
|
||||
{"role": "user", "content": content}
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a translation assistant that translates English to Arabic.",
|
||||
},
|
||||
{"role": "user", "content": content},
|
||||
],
|
||||
temperature=0.3,
|
||||
)
|
||||
@ -67,12 +105,3 @@ def calculate_stock_value():
|
||||
cars = Car.objects.all()
|
||||
total_value = sum(car.selling_price for car in cars)
|
||||
return total_value
|
||||
|
||||
|
||||
# from django_ledger.models import EntityModel
|
||||
#
|
||||
# def get_purchase_orders():
|
||||
# entity = EntityModel.objects.get(name='Marwan2')
|
||||
# items = entity.
|
||||
# print(items.values())
|
||||
# return items
|
||||
|
||||
@ -24,7 +24,7 @@ from django.forms import ChoiceField, ModelForm, RadioSelect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.contrib import messages
|
||||
from django.db.models import Sum, F, Count
|
||||
from .services import elm, decode_vin_pyvin
|
||||
from .services import elm, decodevin,get_make,get_model,normalize_name
|
||||
from . import models, forms
|
||||
from django_tables2.export.views import ExportMixin
|
||||
|
||||
@ -133,90 +133,41 @@ class AjaxHandlerView(LoginRequiredMixin, View):
|
||||
vin_no = request.GET.get('vin_no')
|
||||
if not vin_no or len(vin_no.strip()) != 17:
|
||||
return JsonResponse({'success': False, 'error': 'Invalid VIN number provided.'}, status=400)
|
||||
|
||||
vin_no = vin_no.strip()
|
||||
vin_data = {}
|
||||
decoding_method = ''
|
||||
|
||||
decoding_methods = [
|
||||
('PYVIN', decode_vin_pyvin),
|
||||
('VIN', VIN),
|
||||
('ELM', elm)
|
||||
]
|
||||
|
||||
manufacturer_name = model_name = year_model = None
|
||||
|
||||
for method_name, decode_function in decoding_methods:
|
||||
try:
|
||||
vin_info = decode_function(vin_no)
|
||||
if vin_info:
|
||||
if method_name == 'PYVIN':
|
||||
manufacturer_name = vin_info.Make.strip()
|
||||
model_name = vin_info.Model.strip()
|
||||
year_model = vin_info.ModelYear
|
||||
if not manufacturer_name or not model_name or not year_model:
|
||||
raise ValueError('PYVIN returned incomplete data.')
|
||||
elif method_name == 'VIN':
|
||||
manufacturer_name = vin_info.make.strip()
|
||||
model_name = vin_info.model.strip()
|
||||
year_model = vin_info.model_year
|
||||
if not manufacturer_name or not model_name or not year_model:
|
||||
raise ValueError('VIN returned incomplete data.')
|
||||
elif method_name == 'ELM':
|
||||
elm_data = vin_info.get('data', {})
|
||||
manufacturer_name = elm_data.get('maker', '').strip()
|
||||
model_name = elm_data.get('model', '').strip()
|
||||
year_model = elm_data.get('modelYear', '').strip()
|
||||
if not manufacturer_name or not model_name or not year_model:
|
||||
raise ValueError('ELM returned incomplete data.')
|
||||
|
||||
decoding_method = method_name
|
||||
print(f"decoded by {method_name}")
|
||||
break
|
||||
else:
|
||||
logger.warning(f"{method_name} returned no data for {vin_no}.")
|
||||
except Exception as e:
|
||||
logger.warning(f"VIN decoding with {method_name} failed for {vin_no}: {e}")
|
||||
|
||||
if not manufacturer_name or not model_name or not year_model:
|
||||
return JsonResponse({'success': False, 'error': 'VIN not found in all sources.'}, status=404)
|
||||
|
||||
if not (result :=decodevin(vin_no)):
|
||||
return JsonResponse({'success': False, 'error': 'VIN not found in all sources.'}, status=404)
|
||||
|
||||
manufacturer_name,model_name,year_model = result.values()
|
||||
make = get_make(manufacturer_name)
|
||||
model = get_model(model_name,make)
|
||||
|
||||
logger.info(
|
||||
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
|
||||
)
|
||||
regex_make= manufacturer_name.replace(" ", "[- ]?")
|
||||
car_make = (models.CarMake.objects
|
||||
.filter(name__iregex=regex_make, is_sa_import=True)
|
||||
.first())
|
||||
)
|
||||
car_model = model
|
||||
car_make = make
|
||||
|
||||
if not car_make:
|
||||
return JsonResponse({'success': False, 'error': 'Manufacturer not found in the database.'}, status=404)
|
||||
|
||||
vin_data['make_id'] = car_make.id_car_make
|
||||
vin_data['name'] = car_make.name
|
||||
vin_data['arabic_name'] = car_make.arabic_name
|
||||
|
||||
regex_pattern = model_name.replace(" ", "[- ]?")
|
||||
car_model = (models.CarModel.objects
|
||||
.filter(id_car_make=car_make.id_car_make,
|
||||
name__iregex=regex_pattern)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
||||
if not car_model:
|
||||
return JsonResponse(
|
||||
{'success': False,
|
||||
'error': 'Model not found for the given manufacturer.'}, status=404)
|
||||
|
||||
vin_data['model_id'] = car_model.id_car_model
|
||||
vin_data['model_id'] = ""
|
||||
else:
|
||||
vin_data['model_id'] = car_model.id_car_model
|
||||
vin_data['year'] = year_model
|
||||
return JsonResponse({'success': True, 'data': vin_data})
|
||||
|
||||
def get_models(self, request):
|
||||
make_id = request.GET.get('make_id')
|
||||
car_models = (models.CarModel.objects
|
||||
.filter(id_car_make=make_id,
|
||||
id_car_make__is_sa_import=True)
|
||||
.values('id_car_model', 'name', 'arabic_name')
|
||||
)
|
||||
car_models = models.CarModel.objects.filter(id_car_make=make_id).values('id_car_model', 'name', 'arabic_name')
|
||||
return JsonResponse(list(car_models), safe=False)
|
||||
|
||||
def get_series(self, request):
|
||||
@ -693,7 +644,6 @@ class QuotationCreateView(LoginRequiredMixin, CreateView):
|
||||
template_name = 'sales/quotation_form.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.dealer = self.request.user.dealer
|
||||
quotation = form.save()
|
||||
selected_cars = form.cleaned_data.get("cars")
|
||||
for car in selected_cars:
|
||||
|
||||
BIN
static/images/logos/vendors/MainAfter.jpg
vendored
Normal file
BIN
static/images/logos/vendors/MainAfter.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
@ -55,7 +55,7 @@ small, .small {
|
||||
<script type="text/javascript" src="{% static 'js/main.js' %}"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
/* $('.form-select').select2({
|
||||
/*$('.form-select').select2({
|
||||
theme: 'bootstrap4',
|
||||
});*/
|
||||
'use strict';
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
<div class="modal-content rounded-top-3">
|
||||
<div class="modal-header bg-primary text-white rounded-top-3 shadow">
|
||||
<h5 class="modal-title" id="scannerModalLabel">{{ _("scanner") }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ _("Close") }}"></button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ _('Close') }}"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<video id="video" autoplay playsinline></video>
|
||||
@ -396,8 +396,8 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
function showLoading() {
|
||||
Swal.fire({
|
||||
title: '{% trans 'Please Wait' %}',
|
||||
text: '{% trans 'Loading' %}...',
|
||||
title: "{% trans 'Please Wait' %}",
|
||||
text: "{% trans 'Loading' %}...",
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
@ -428,7 +428,8 @@ function closeModal(){
|
||||
async function decodeVin() {
|
||||
const vinNumber = vinInput.value.trim();
|
||||
if (vinNumber.length !== 17) {
|
||||
alert("{% trans 'Please enter a valid VIN.' %}");
|
||||
notify("error","{% trans 'Please enter a valid VIN.' %}");
|
||||
/*alert("{% trans 'Please enter a valid VIN.' %}");*/
|
||||
return;
|
||||
}
|
||||
showLoading();
|
||||
@ -444,12 +445,15 @@ async function decodeVin() {
|
||||
hideLoading();
|
||||
await updateFields(data.data);
|
||||
} else {
|
||||
alert(data.error || "{% trans 'Failed to decode VIN.' %}");
|
||||
hideLoading();
|
||||
notify("error",data.error)
|
||||
/* alert(data.error || "{% trans 'Failed to decode VIN.' %}");*/
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error decoding VIN:", error);
|
||||
hideLoading();
|
||||
alert("{% trans 'An error occurred while decoding the VIN.' %}");
|
||||
notify("error","{% trans 'An error occurred while decoding the VIN.' %}")
|
||||
/*alert("{% trans 'An error occurred while decoding the VIN.' %}");*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,8 +477,9 @@ async function updateFields(vinData) {
|
||||
}
|
||||
|
||||
// Start the scanner
|
||||
function startScanner() {
|
||||
codeReader.decodeFromVideoDevice(null, videoElement, (result, err) => {
|
||||
async function startScanner() {
|
||||
codeReader.decodeFromVideoDevice(null, videoElement, async(result, err) => {
|
||||
let res = await result
|
||||
if (result) {
|
||||
vinInput.value = result.text;
|
||||
closeModal();
|
||||
@ -533,6 +538,8 @@ async function loadModels(makeId) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function loadSeries(modelId){
|
||||
resetDropdown(serieSelect, '{% trans "Select" %}');
|
||||
resetDropdown(trimSelect, '{% trans "Select" %}');
|
||||
@ -617,8 +624,27 @@ async function loadSpecifications(trimId){
|
||||
/*stockTypeSelect.addEventListener('change', checkFormCompletion);
|
||||
mileageInput.addEventListener('input', checkFormCompletion);
|
||||
remarksInput.addEventListener('input', checkFormCompletion);*/
|
||||
makeSelect.addEventListener("change", (e) => {loadModels(e.target.value)})
|
||||
modelSelect.addEventListener("change", (e) => {loadSeries(e.target.value)})
|
||||
decodeVinBtn.addEventListener('click', decodeVin);
|
||||
});
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: "top-end",
|
||||
showConfirmButton: false,
|
||||
timer: 3000,
|
||||
timerProgressBar: true,
|
||||
didOpen: (toast) => {
|
||||
toast.onmouseenter = Swal.stopTimer;
|
||||
toast.onmouseleave = Swal.resumeTimer;
|
||||
}
|
||||
});
|
||||
function notify(tag,msg){
|
||||
Toast.fire({
|
||||
icon: tag,
|
||||
titleText: msg
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user