fix car cratea functionality

This commit is contained in:
gitea 2024-12-11 12:52:58 +00:00
parent 88e81fadf1
commit 05486e3d62
9 changed files with 226 additions and 145 deletions

View File

@ -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! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True 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 # Application definition
@ -110,9 +110,9 @@ WSGI_APPLICATION = 'car_inventory.wsgi.application'
DATABASES = { DATABASES = {
"default": { "default": {
"ENGINE": "django_prometheus.db.backends.postgresql", "ENGINE": "django_prometheus.db.backends.postgresql",
"NAME": "haikal_app", "NAME": "haikal",
"USER": "f95166", "USER": "haikal",
"PASSWORD": "Kfsh&rc9788", "PASSWORD": "haikal",
"HOST": "localhost", "HOST": "localhost",
"PORT": 5432, "PORT": 5432,
} }

View 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

View File

@ -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',
),
]

View File

@ -489,69 +489,69 @@ class SalesOrder(models.Model):
# Create Entity # Create Entity
@receiver(post_save, sender=Dealer) # @receiver(post_save, sender=Dealer)
def create_ledger_entity(sender, instance, created, **kwargs): # def create_ledger_entity(sender, instance, created, **kwargs):
if created: # if created:
entity = EntityModel.objects.create( # entity = EntityModel.objects.create(
name=instance.name, # name=instance.name,
admin=instance.user, # admin=instance.user,
address_1=instance.address, # address_1=instance.address,
fy_start_month=1, # fy_start_month=1,
accrual_method=True, # accrual_method=True,
depth=0, # depth=0,
) # )
default_coa = entity.create_chart_of_accounts(assign_as_default=True, # default_coa = entity.create_chart_of_accounts(assign_as_default=True,
commit=True, # commit=True,
coa_name=_("Chart of Accounts")) # coa_name=_("Chart of Accounts"))
if default_coa: # if default_coa:
entity.populate_default_coa(activate_accounts=True, coa_model=default_coa) # entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
print(f"Ledger entity created for Dealer: {instance.name}") # print(f"Ledger entity created for Dealer: {instance.name}")
# # Create Vendor # # # Create Vendor
@receiver(post_save, sender=Vendor) # @receiver(post_save, sender=Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs): # def create_ledger_vendor(sender, instance, created, **kwargs):
if created: # if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first() # entity = EntityModel.objects.filter(name=instance.dealer.name).first()
vendor = VendorModel.objects.update_or_create( # vendor = VendorModel.objects.update_or_create(
entity_model=entity, # entity_model=entity,
vendor_name=instance.name, # vendor_name=instance.name,
vendor_number=instance.crn, # vendor_number=instance.crn,
address_1=instance.address, # address_1=instance.address,
phone=instance.phone_number, # phone=instance.phone_number,
tax_id_number=instance.vrn, # tax_id_number=instance.vrn,
active=True, # active=True,
hidden=False, # hidden=False,
additional_info={ # additional_info={
"arabic_name": instance.arabic_name, # "arabic_name": instance.arabic_name,
"contact_person": instance.contact_person, # "contact_person": instance.contact_person,
}, # },
) # )
print(f"VendorModel created for Vendor: {instance.name}") # print(f"VendorModel created for Vendor: {instance.name}")
@receiver(post_save, sender=Customer) # @receiver(post_save, sender=Customer)
def create_customer(sender, instance, created, **kwargs): # def create_customer(sender, instance, created, **kwargs):
if created: # if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first() # entity = EntityModel.objects.filter(name=instance.dealer.name).first()
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}" # name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
customer = CustomerModel.objects.create( # customer = CustomerModel.objects.create(
entity_model=entity, # entity_model=entity,
customer_name=name, # customer_name=name,
customer_number=instance.national_id, # customer_number=instance.national_id,
address_1=instance.address, # address_1=instance.address,
phone=instance.phone_number, # phone=instance.phone_number,
email=instance.email, # email=instance.email,
sales_tax_rate=0.15, # sales_tax_rate=0.15,
) # )
print(f"Customer created: {name}") # print(f"Customer created: {name}")
# # Create Item # # Create Item

View File

@ -1,52 +1,87 @@
""" """
Services module Services module
""" """
import requests import requests
import json import json
from .utils import get_jwt_token from .utils import get_jwt_token
from pyvin import VIN from pyvin import VIN
from django.conf import settings from django.conf import settings
from openai import OpenAI 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): def normalize_name(name):
return name.replace(' ', '').replace('-', '').lower() return name.replace(" ", "").replace("-", "").lower()
def decode_vin_pyvin(vin): def decodevin(vin):
vehicle = VIN(vin)
if result:=decode_vin(vin):
return result
elif result:=elm(vin):
return result
else:
return None
data = {
'Make': vehicle.Make,
'Model': vehicle.Model, def decode_vin(vin):
'ModelYear': vehicle.ModelYear, v = VIN(vin)
} data = {}
print(data) if v:
return data data = {
"maker": v.Make,
"model": v.Model,
"modelYear": v.ModelYear,
}
return data if all([x for x in data.values()]) else None
# vehicle-info # vehicle-info
# c2729afb # c2729afb
# 6d397471920412d672af1b8a02ca52ea # 6d397471920412d672af1b8a02ca52ea
# option-info # option-info
# 367974ed # 367974ed
# 046b0412c1b4d3f8c39ec6375d6f3030 # 046b0412c1b4d3f8c39ec6375d6f3030
def elm(vin): def elm(vin):
headers = { headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
'app-id': 'c2729afb', "app-id": "c2729afb",
'app-key': '6d397471920412d672af1b8a02ca52ea', "app-key": "6d397471920412d672af1b8a02ca52ea",
'client-id': '94142c27-2536-47e9-8e28-9ca7728b9442', "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 = {} payload = {}
response = requests.request("GET", url, headers=headers, data=payload) response = requests.request("GET", url, headers=headers, data=payload)
car_info = json.loads(response.text) response = json.loads(response.text)
print(car_info) data = {}
return car_info 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): def translate(content, *args, **kwargs):
@ -54,8 +89,11 @@ def translate(content, *args, **kwargs):
completion = client.chat.completions.create( completion = client.chat.completions.create(
model="gpt-4", model="gpt-4",
messages=[ 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, temperature=0.3,
) )
@ -67,4 +105,3 @@ def calculate_stock_value():
cars = Car.objects.all() cars = Car.objects.all()
total_value = sum(car.selling_price for car in cars) total_value = sum(car.selling_price for car in cars)
return total_value return total_value

View File

@ -24,7 +24,7 @@ from django.forms import ChoiceField, ModelForm, RadioSelect
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.contrib import messages from django.contrib import messages
from django.db.models import Sum, F, Count 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 . import models, forms
from django_tables2.export.views import ExportMixin from django_tables2.export.views import ExportMixin
@ -133,76 +133,35 @@ class AjaxHandlerView(LoginRequiredMixin, View):
vin_no = request.GET.get('vin_no') vin_no = request.GET.get('vin_no')
if not vin_no or len(vin_no.strip()) != 17: if not vin_no or len(vin_no.strip()) != 17:
return JsonResponse({'success': False, 'error': 'Invalid VIN number provided.'}, status=400) return JsonResponse({'success': False, 'error': 'Invalid VIN number provided.'}, status=400)
vin_no = vin_no.strip() vin_no = vin_no.strip()
vin_data = {} vin_data = {}
decoding_method = '' decoding_method = ''
decoding_methods = [
('PYVIN', decode_vin_pyvin),
('VIN', VIN),
('ELM', elm)
]
manufacturer_name = model_name = year_model = None manufacturer_name = model_name = year_model = None
if not (result :=decodevin(vin_no)):
for method_name, decode_function in decoding_methods: return JsonResponse({'success': False, 'error': 'VIN not found in all sources.'}, status=404)
try:
vin_info = decode_function(vin_no) manufacturer_name,model_name,year_model = result.values()
if vin_info: make = get_make(manufacturer_name)
if method_name == 'PYVIN': model = get_model(model_name,make)
manufacturer_name = vin_info.Make.strip()
model_name = vin_info.Model.strip()
year_model = vin_info.ModelYear
if not manufacturer_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()
print(manufacturer_name)
model_name = elm_data.get('model', '').strip()
print(model_name)
year_model = elm_data.get('modelYear', '').strip()
print(year_model)
if not manufacturer_name or not model_name or not year_model:
raise ValueError('ELM returned incomplete data.')
# model_name = normalize_name(model_name_before)
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)
logger.info( logger.info(
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}" f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
) )
regex_make= manufacturer_name.replace(" ", "[- ]?") car_model = model
car_make = models.CarMake.objects.filter(name__iregex=regex_make).first() car_make = make
if not car_make: if not car_make:
return JsonResponse({'success': False, 'error': 'Manufacturer not found in the database.'}, status=404) return JsonResponse({'success': False, 'error': 'Manufacturer not found in the database.'}, status=404)
vin_data['make_id'] = car_make.id_car_make vin_data['make_id'] = car_make.id_car_make
vin_data['name'] = car_make.name vin_data['name'] = car_make.name
vin_data['arabic_name'] = car_make.arabic_name vin_data['arabic_name'] = car_make.arabic_name
# car_model = models.CarModel.objects.filter(id_car_make=car_make.id_car_make, name__contains=model_name).first()
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: if not car_model:
return JsonResponse({'success': False, 'error': 'Model not found for the given manufacturer.'}, status=404) vin_data['model_id'] = ""
else:
vin_data['model_id'] = car_model.id_car_model vin_data['model_id'] = car_model.id_car_model
vin_data['year'] = year_model vin_data['year'] = year_model
return JsonResponse({'success': True, 'data': vin_data}) return JsonResponse({'success': True, 'data': vin_data})

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -55,9 +55,9 @@ small, .small {
<script type="text/javascript" src="{% static 'js/main.js' %}"></script> <script type="text/javascript" src="{% static 'js/main.js' %}"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
$('.form-select').select2({ /*$('.form-select').select2({
theme: 'bootstrap4', theme: 'bootstrap4',
}); });*/
'use strict'; 'use strict';
// Fetch all the forms with the "needs-validation" class // Fetch all the forms with the "needs-validation" class

View File

@ -55,7 +55,7 @@
<div class="modal-content rounded-top-3"> <div class="modal-content rounded-top-3">
<div class="modal-header bg-primary text-white rounded-top-3 shadow"> <div class="modal-header bg-primary text-white rounded-top-3 shadow">
<h5 class="modal-title" id="scannerModalLabel">{{ _("scanner") }}</h5> <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>
<div class="modal-body text-center"> <div class="modal-body text-center">
<video id="video" autoplay playsinline></video> <video id="video" autoplay playsinline></video>
@ -396,8 +396,8 @@ document.addEventListener("DOMContentLoaded", function() {
function showLoading() { function showLoading() {
Swal.fire({ Swal.fire({
title: '{% trans 'Please Wait' %}', title: "{% trans 'Please Wait' %}",
text: '{% trans 'Loading' %}...', text: "{% trans 'Loading' %}...",
allowOutsideClick: false, allowOutsideClick: false,
didOpen: () => { didOpen: () => {
Swal.showLoading(); Swal.showLoading();
@ -428,7 +428,8 @@ function closeModal(){
async function decodeVin() { async function decodeVin() {
const vinNumber = vinInput.value.trim(); const vinNumber = vinInput.value.trim();
if (vinNumber.length !== 17) { 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; return;
} }
showLoading(); showLoading();
@ -444,12 +445,15 @@ async function decodeVin() {
hideLoading(); hideLoading();
await updateFields(data.data); await updateFields(data.data);
} else { } else {
alert(data.error || "{% trans 'Failed to decode VIN.' %}"); hideLoading();
notify("error",data.error)
/* alert(data.error || "{% trans 'Failed to decode VIN.' %}");*/
} }
} catch (error) { } catch (error) {
console.error("Error decoding VIN:", error); console.error("Error decoding VIN:", error);
hideLoading(); 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 // Start the scanner
function startScanner() { async function startScanner() {
codeReader.decodeFromVideoDevice(null, videoElement, (result, err) => { codeReader.decodeFromVideoDevice(null, videoElement, async(result, err) => {
let res = await result
if (result) { if (result) {
vinInput.value = result.text; vinInput.value = result.text;
closeModal(); closeModal();
@ -533,6 +538,8 @@ async function loadModels(makeId) {
}); });
} }
async function loadSeries(modelId){ async function loadSeries(modelId){
resetDropdown(serieSelect, '{% trans "Select" %}'); resetDropdown(serieSelect, '{% trans "Select" %}');
resetDropdown(trimSelect, '{% trans "Select" %}'); resetDropdown(trimSelect, '{% trans "Select" %}');
@ -617,8 +624,27 @@ async function loadSpecifications(trimId){
/*stockTypeSelect.addEventListener('change', checkFormCompletion); /*stockTypeSelect.addEventListener('change', checkFormCompletion);
mileageInput.addEventListener('input', checkFormCompletion); mileageInput.addEventListener('input', checkFormCompletion);
remarksInput.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); 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> </script>
{% endblock %} {% endblock %}