diff --git a/car_inventory/settings.py b/car_inventory/settings.py index b12b3c77..06a4d1df 100644 --- a/car_inventory/settings.py +++ b/car_inventory/settings.py @@ -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, } diff --git a/inventory/management/commands/generate_vin.py b/inventory/management/commands/generate_vin.py new file mode 100644 index 00000000..b7d6ba44 --- /dev/null +++ b/inventory/management/commands/generate_vin.py @@ -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 diff --git a/inventory/migrations/0005_alter_carfinance_options_remove_carfinance_total.py b/inventory/migrations/0005_alter_carfinance_options_remove_carfinance_total.py new file mode 100644 index 00000000..aa7921b2 --- /dev/null +++ b/inventory/migrations/0005_alter_carfinance_options_remove_carfinance_total.py @@ -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', + ), + ] diff --git a/inventory/models.py b/inventory/models.py index 6188a371..c53cc4f1 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -489,69 +489,69 @@ class SalesOrder(models.Model): # Create Entity -@receiver(post_save, sender=Dealer) -def create_ledger_entity(sender, instance, created, **kwargs): - if created: - entity = EntityModel.objects.create( - name=instance.name, - admin=instance.user, - address_1=instance.address, - fy_start_month=1, - accrual_method=True, - depth=0, - ) +# @receiver(post_save, sender=Dealer) +# def create_ledger_entity(sender, instance, created, **kwargs): +# if created: +# entity = EntityModel.objects.create( +# name=instance.name, +# admin=instance.user, +# address_1=instance.address, +# fy_start_month=1, +# accrual_method=True, +# depth=0, +# ) - default_coa = entity.create_chart_of_accounts(assign_as_default=True, - commit=True, - coa_name=_("Chart of Accounts")) - if default_coa: - entity.populate_default_coa(activate_accounts=True, coa_model=default_coa) - print(f"Ledger entity created for Dealer: {instance.name}") +# default_coa = entity.create_chart_of_accounts(assign_as_default=True, +# commit=True, +# coa_name=_("Chart of Accounts")) +# if default_coa: +# entity.populate_default_coa(activate_accounts=True, coa_model=default_coa) +# print(f"Ledger entity created for Dealer: {instance.name}") -# # Create Vendor -@receiver(post_save, sender=Vendor) -def create_ledger_vendor(sender, instance, created, **kwargs): +# # # Create Vendor +# @receiver(post_save, sender=Vendor) +# def create_ledger_vendor(sender, instance, created, **kwargs): - if created: - entity = EntityModel.objects.filter(name=instance.dealer.name).first() +# if created: +# entity = EntityModel.objects.filter(name=instance.dealer.name).first() - vendor = VendorModel.objects.update_or_create( - entity_model=entity, - vendor_name=instance.name, - vendor_number=instance.crn, - address_1=instance.address, - phone=instance.phone_number, - tax_id_number=instance.vrn, - active=True, - hidden=False, - additional_info={ - "arabic_name": instance.arabic_name, - "contact_person": instance.contact_person, - }, - ) +# vendor = VendorModel.objects.update_or_create( +# entity_model=entity, +# vendor_name=instance.name, +# vendor_number=instance.crn, +# address_1=instance.address, +# phone=instance.phone_number, +# tax_id_number=instance.vrn, +# active=True, +# hidden=False, +# additional_info={ +# "arabic_name": instance.arabic_name, +# "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) -def create_customer(sender, instance, created, **kwargs): +# @receiver(post_save, sender=Customer) +# def create_customer(sender, instance, created, **kwargs): - if created: - entity = EntityModel.objects.filter(name=instance.dealer.name).first() - name = f"{instance.first_name} {instance.middle_name} {instance.last_name}" +# if created: +# entity = EntityModel.objects.filter(name=instance.dealer.name).first() +# name = f"{instance.first_name} {instance.middle_name} {instance.last_name}" - customer = CustomerModel.objects.create( - entity_model=entity, - customer_name=name, - customer_number=instance.national_id, - address_1=instance.address, - phone=instance.phone_number, - email=instance.email, - sales_tax_rate=0.15, - ) +# customer = CustomerModel.objects.create( +# entity_model=entity, +# customer_name=name, +# customer_number=instance.national_id, +# address_1=instance.address, +# phone=instance.phone_number, +# email=instance.email, +# sales_tax_rate=0.15, +# ) - print(f"Customer created: {name}") +# print(f"Customer created: {name}") # # Create Item diff --git a/inventory/services.py b/inventory/services.py index 07e0eb30..c94f148c 100644 --- a/inventory/services.py +++ b/inventory/services.py @@ -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,4 +105,3 @@ def calculate_stock_value(): cars = Car.objects.all() total_value = sum(car.selling_price for car in cars) return total_value - diff --git a/inventory/views.py b/inventory/views.py index f84de195..23cc9c4b 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -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,76 +133,35 @@ 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 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) - + 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).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 - - # 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: - 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}) diff --git a/static/images/logos/vendors/MainAfter.jpg b/static/images/logos/vendors/MainAfter.jpg new file mode 100644 index 00000000..632e369f Binary files /dev/null and b/static/images/logos/vendors/MainAfter.jpg differ diff --git a/templates/base.html b/templates/base.html index 35106123..162254c8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -55,9 +55,9 @@ small, .small { {% endblock %} \ No newline at end of file