add qotation
# Conflicts: # car_inventory/settings.py # inventory/models.py # inventory/services.py # inventory/urls.py # inventory/views.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!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['10.10.1.109','10.10.1.120', 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
|
ALLOWED_HOSTS = ['10.10.1.109', '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",
|
"NAME": "haikal_app",
|
||||||
"USER": "haikal",
|
"USER": "f95166",
|
||||||
"PASSWORD": "haikal",
|
"PASSWORD": "Kfsh&rc9788",
|
||||||
"HOST": "localhost",
|
"HOST": "localhost",
|
||||||
"PORT": 5432,
|
"PORT": 5432,
|
||||||
}
|
}
|
||||||
|
|||||||
69
carapi.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import requests
|
||||||
|
import csv
|
||||||
|
|
||||||
|
# Replace with your actual API token and secret key
|
||||||
|
API_TOKEN = 'f5204a00-6f31-4de2-96d8-ed998e0d230c'
|
||||||
|
SECRET_KEY = 'ae430502a5c66e818d9722919c8b5584'
|
||||||
|
BASE_URL = 'https://carapi.app/api/v1'
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_and_save_car_makes_models(api_url, headers, output_csv):
|
||||||
|
TRANSLATION = []
|
||||||
|
page = 1
|
||||||
|
pages_per_batch = 1
|
||||||
|
|
||||||
|
while True:
|
||||||
|
responses = []
|
||||||
|
# Fetch 100 pages in one batch
|
||||||
|
for i in range(pages_per_batch):
|
||||||
|
current_page = page + i
|
||||||
|
response = requests.get(f"{api_url}&page={current_page}", headers=headers)
|
||||||
|
if response.status_code == 200 and page < 100:
|
||||||
|
responses.append(response.json())
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Process the batch of responses
|
||||||
|
for data in responses:
|
||||||
|
if 'data' not in data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for item in data['data']:
|
||||||
|
make_name = item['make_model']['make']['name']
|
||||||
|
model_name = item['make_model']['name']
|
||||||
|
|
||||||
|
# Create dictionary for each make and model combination
|
||||||
|
translation_entry = {
|
||||||
|
'make': f"{make_name} ",
|
||||||
|
'model': f"{model_name} " # Replace with actual Arabic translation if available
|
||||||
|
}
|
||||||
|
TRANSLATION.append(translation_entry)
|
||||||
|
|
||||||
|
# Increment the page number for the next batch
|
||||||
|
page += pages_per_batch
|
||||||
|
|
||||||
|
# Check if there are more pages to fetch
|
||||||
|
if not responses or ('next' in responses[-1]['collection'] and not responses[-1]['collection']['next']):
|
||||||
|
break
|
||||||
|
|
||||||
|
# Save the TRANSLATION data to a CSV file
|
||||||
|
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
|
||||||
|
fieldnames = ['make', 'model']
|
||||||
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||||
|
|
||||||
|
writer.writeheader()
|
||||||
|
for entry in TRANSLATION:
|
||||||
|
writer.writerow(entry)
|
||||||
|
|
||||||
|
print(f"Data saved to {output_csv}")
|
||||||
|
|
||||||
|
|
||||||
|
# Example usage:
|
||||||
|
api_url = "https://carapi.app/api/trims?sort=make_model_id&direction=asc&verbose=yes"
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJjYXJhcGkuYXBwIiwic3ViIjoiYjU1OGYzMDMtODI0Ni00NjgzLTkwYTQtZmYwMGQxYWNmNGU3IiwiYXVkIjoiYjU1OGYzMDMtODI0Ni00NjgzLTkwYTQtZmYwMGQxYWNmNGU3IiwiZXhwIjoxNzIzNzMxODMyLCJpYXQiOjE3MjMxMjcwMzIsImp0aSI6IjNkMGJhMzA4LWUzZTAtNGJhZC1iZmMxLTBiMDA3YzNmMmE2NSIsInVzZXIiOnsic3Vic2NyaWJlZCI6dHJ1ZSwic3Vic2NyaXB0aW9uIjoic3RhcnRlciIsInJhdGVfbGltaXRfdHlwZSI6ImhhcmQiLCJhZGRvbnMiOnsiYW50aXF1ZV92ZWhpY2xlcyI6ZmFsc2UsImRhdGFfZmVlZCI6ZmFsc2V9fX0.t__L53yN0OndnOP3_YxaAbrwgQXSYwVUgEqE1IwH8Nk', # Replace with actual token
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
output_csv = 'car_makes_models.csv'
|
||||||
|
|
||||||
|
fetch_and_save_car_makes_models(api_url, headers, output_csv)
|
||||||
79
haikalna.py
@ -6,23 +6,24 @@ from typing import List
|
|||||||
|
|
||||||
def vin_years(vin_char: str) -> List[int]:
|
def vin_years(vin_char: str) -> List[int]:
|
||||||
letters = 'ABCDEFGHJKLMNPRSTVWXY123456789'
|
letters = 'ABCDEFGHJKLMNPRSTVWXY123456789'
|
||||||
year_char = vin_char.upper()
|
year_letter = vin_char
|
||||||
|
|
||||||
if year_char not in letters:
|
|
||||||
raise ValueError("Invalid VIN character. Must be A-Z (excluding I, O, Q) or 1-9.")
|
|
||||||
|
|
||||||
year = 1979
|
year = 1979
|
||||||
current_year = datetime.now().year
|
year_current = datetime.now().year
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for letter in cycle(letters):
|
for letter in cycle(letters):
|
||||||
year += 1
|
year += 1
|
||||||
if letter == year_char:
|
|
||||||
|
if letter == year_letter:
|
||||||
result.append(year)
|
result.append(year)
|
||||||
if year >= current_year:
|
|
||||||
|
if year == year_current:
|
||||||
break
|
break
|
||||||
|
|
||||||
result.sort(reverse=True)
|
result.sort(reverse=True)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -150,7 +151,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"J8T": "GMC",
|
"J8T": "GMC",
|
||||||
"J8Z": "Chevrolet",
|
"J8Z": "Chevrolet",
|
||||||
"KF3": "Merkavim",
|
"KF3": "Merkavim",
|
||||||
"KF6": "Automotive Industries,",
|
|
||||||
"KL": "Daewoo",
|
"KL": "Daewoo",
|
||||||
"KLA": "Daewoo",
|
"KLA": "Daewoo",
|
||||||
"KLP": "CT&T United",
|
"KLP": "CT&T United",
|
||||||
@ -190,9 +190,9 @@ wmi_manufacturer_mapping = {
|
|||||||
"KPT": "SsangYong",
|
"KPT": "SsangYong",
|
||||||
"LA6": "King Long",
|
"LA6": "King Long",
|
||||||
"LC0": "BYD",
|
"LC0": "BYD",
|
||||||
"LBE": "Beijing-Hyundai Shouwang",
|
"LBE": "Hyundai Shouwang",
|
||||||
"LBM": "Zongshen Piaggio",
|
"LBM": "Zongshen Piaggio",
|
||||||
"LBV": "BMW Brilliance",
|
"LBV": "BMW",
|
||||||
"LB1": "Fujian Benz",
|
"LB1": "Fujian Benz",
|
||||||
"LB3": "Geely",
|
"LB3": "Geely",
|
||||||
"LCR": "Gonow",
|
"LCR": "Gonow",
|
||||||
@ -222,17 +222,15 @@ wmi_manufacturer_mapping = {
|
|||||||
"LGL": "Guilin Daewoo",
|
"LGL": "Guilin Daewoo",
|
||||||
"LGW": "Great Wall",
|
"LGW": "Great Wall",
|
||||||
"LGX": "BYD",
|
"LGX": "BYD",
|
||||||
"LGZ": "Guangzhou Denway Bus",
|
|
||||||
"LHA": "Shuanghuan",
|
"LHA": "Shuanghuan",
|
||||||
"LHB": "BAIC",
|
"LHB": "BAIC",
|
||||||
"LHG": "Guangzhou Honda",
|
"LHG": "Guangzhou Honda",
|
||||||
"LH1": "FAW",
|
"LH1": "FAW",
|
||||||
"LJC": "Jincheng",
|
"LJC": "Jincheng",
|
||||||
"LJD": "Human Horizons - HiPhi",
|
"LJD": "Yueda Kia",
|
||||||
"LJN": "Zhengzhou Nissan",
|
"LJN": "Zhengzhou Nissan",
|
||||||
"LJS": "Yaxing Coach",
|
"LJS": "Yaxing Coach",
|
||||||
"LJU": "Lotus Geely",
|
"LJU": "Lotus Geely",
|
||||||
"LJV": "Chengdu Wangpai",
|
|
||||||
"LJX": "JMC Ford",
|
"LJX": "JMC Ford",
|
||||||
"LJ1": "Nio",
|
"LJ1": "Nio",
|
||||||
"LJ8": "Zotye",
|
"LJ8": "Zotye",
|
||||||
@ -260,7 +258,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"LPE": "BYD",
|
"LPE": "BYD",
|
||||||
"LPS": "Polestar",
|
"LPS": "Polestar",
|
||||||
"LRB": "SAIC Buick",
|
"LRB": "SAIC Buick",
|
||||||
"LRD": "Foton Daimler",
|
"LRD": "Foton",
|
||||||
"LRE": "SAIC Cadillac",
|
"LRE": "SAIC Cadillac",
|
||||||
"LRW": "Tesla",
|
"LRW": "Tesla",
|
||||||
"LSC": "Changan",
|
"LSC": "Changan",
|
||||||
@ -270,15 +268,14 @@ wmi_manufacturer_mapping = {
|
|||||||
"LSJ": "SAIC MG",
|
"LSJ": "SAIC MG",
|
||||||
"LSK": "SAIC Maxus",
|
"LSK": "SAIC Maxus",
|
||||||
"LSV": "SAIC Volkswagen",
|
"LSV": "SAIC Volkswagen",
|
||||||
"LSY": "Brilliance Jinbei GM",
|
"LSY": "Brilliance",
|
||||||
"LS4": "Changan",
|
"LS4": "Changan",
|
||||||
"LS5": "Changan",
|
"LS5": "Changan",
|
||||||
"LS6": "Changan",
|
"LS6": "Changan",
|
||||||
"LS7": "JMC",
|
"LS7": "JMC",
|
||||||
"LTA": "ZX Auto",
|
"LTA": "ZX Auto",
|
||||||
"LTN": "Soueast",
|
"LTN": "Soueast",
|
||||||
"LTP": "National Electric Vehicle Sweden AB",
|
"LTV": "FAW Toyota",
|
||||||
"LTV": "FAW Toyota (Tianjin)",
|
|
||||||
"LUC": "Honda",
|
"LUC": "Honda",
|
||||||
"LUD": "Dongfeng Nissan",
|
"LUD": "Dongfeng Nissan",
|
||||||
"LUX": "Dongfeng Yulon",
|
"LUX": "Dongfeng Yulon",
|
||||||
@ -322,18 +319,15 @@ wmi_manufacturer_mapping = {
|
|||||||
"L4F": "Suzhou Eagle",
|
"L4F": "Suzhou Eagle",
|
||||||
"L5C": "KangDi",
|
"L5C": "KangDi",
|
||||||
"L5K": "Yongkang",
|
"L5K": "Yongkang",
|
||||||
"L6T": "Geely, Lynk & Co, Zeekr",
|
"L6T": "Lynk & Co",
|
||||||
"L82": "Baotian",
|
"L82": "Baotian",
|
||||||
"L85": "Yongkang Huabao",
|
"L85": "Yongkang Huabao",
|
||||||
"L9N": "Taotao",
|
"L9N": "Taotao",
|
||||||
"MAB": "Mahindra & Mahindra",
|
|
||||||
"MAC": "Mahindra & Mahindra",
|
|
||||||
"MAH": "Fiat",
|
"MAH": "Fiat",
|
||||||
"MAJ": "Ford",
|
"MAJ": "Ford",
|
||||||
"MAK": "Honda",
|
"MAK": "Honda",
|
||||||
"MAL": "Hyundai",
|
"MAL": "Hyundai",
|
||||||
"MAT": "Tatar",
|
"MAT": "Tatar",
|
||||||
"MA1": "Mahindra & Mahindra",
|
|
||||||
"MA3": "Suzuki",
|
"MA3": "Suzuki",
|
||||||
"MA6": "GM",
|
"MA6": "GM",
|
||||||
"MA7": "Hindustan",
|
"MA7": "Hindustan",
|
||||||
@ -348,10 +342,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"MBX": "Piaggio",
|
"MBX": "Piaggio",
|
||||||
"MBY": "Asia Motors",
|
"MBY": "Asia Motors",
|
||||||
"MB1": "Ashok Leyland",
|
"MB1": "Ashok Leyland",
|
||||||
"MB7": "Reva Electric Company",
|
|
||||||
"MCA": "FCA Pvt. Ltd",
|
|
||||||
"MCB": "GM",
|
"MCB": "GM",
|
||||||
"MCD": "Mahindra Two Wheelers",
|
|
||||||
"MCG": "Atul",
|
"MCG": "Atul",
|
||||||
"MC1": "Force",
|
"MC1": "Force",
|
||||||
"MC2": "Eicher",
|
"MC2": "Eicher",
|
||||||
@ -361,7 +352,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"MD6": "TVS",
|
"MD6": "TVS",
|
||||||
"MD9": "Shuttles",
|
"MD9": "Shuttles",
|
||||||
"MEC": "Daimler",
|
"MEC": "Daimler",
|
||||||
"MEE": "Renault Private Limited",
|
"MEE": "Renault",
|
||||||
"MEG": "Harley-Davidson",
|
"MEG": "Harley-Davidson",
|
||||||
"MER": "Benelli",
|
"MER": "Benelli",
|
||||||
"MET": "Piaggio",
|
"MET": "Piaggio",
|
||||||
@ -502,7 +493,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"SAJ": "Jaguar",
|
"SAJ": "Jaguar",
|
||||||
"SAL": "Land Rover",
|
"SAL": "Land Rover",
|
||||||
"SAM": "Morris",
|
"SAM": "Morris",
|
||||||
"SAR": "Rover MG Rover",
|
"SAR": "Rover MG",
|
||||||
"SAT": "Triumph",
|
"SAT": "Triumph",
|
||||||
"SAX": "Austin-Rover",
|
"SAX": "Austin-Rover",
|
||||||
"SAZ": "Freight Rover",
|
"SAZ": "Freight Rover",
|
||||||
@ -513,7 +504,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"SBL": "Leyland",
|
"SBL": "Leyland",
|
||||||
"SBM": "McLaren",
|
"SBM": "McLaren",
|
||||||
"SBS": "Scammell",
|
"SBS": "Scammell",
|
||||||
"SBV": "Kenworth Peterbilt",
|
|
||||||
"SB1": "Toyota",
|
"SB1": "Toyota",
|
||||||
"SCA": "Rolls Royce",
|
"SCA": "Rolls Royce",
|
||||||
"SCB": "Bentley",
|
"SCB": "Bentley",
|
||||||
@ -568,13 +558,13 @@ wmi_manufacturer_mapping = {
|
|||||||
"TN9": "Karosa",
|
"TN9": "Karosa",
|
||||||
"TRA": "Ikarus Bus",
|
"TRA": "Ikarus Bus",
|
||||||
"TRC": "Csepel",
|
"TRC": "Csepel",
|
||||||
"TRU": "Audi Hungary",
|
"TRU": "Audi",
|
||||||
"TSB": "Ikarus Bus",
|
"TSB": "Ikarus Bus",
|
||||||
"TSE": "Ikarus,",
|
"TSE": "Ikarus,",
|
||||||
"TSF": "Alfabusz",
|
"TSF": "Alfabusz",
|
||||||
"TSM": "Suzuki Fiat",
|
"TSM": "Suzuki Fiat",
|
||||||
"TWG": "Ceatano Bus",
|
"TWG": "Ceatano Bus",
|
||||||
"TW1": "Toyota Caetano",
|
"TW1": "Toyota",
|
||||||
"TW2": "Ford",
|
"TW2": "Ford",
|
||||||
"TW6": "Citroën",
|
"TW6": "Citroën",
|
||||||
"TW7": "Mini",
|
"TW7": "Mini",
|
||||||
@ -670,7 +660,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"WBU": "Bürstner",
|
"WBU": "Bürstner",
|
||||||
"WBX": "BMW",
|
"WBX": "BMW",
|
||||||
"WBY": "BMW",
|
"WBY": "BMW",
|
||||||
"WB0": "Böckmann Fahrzeugwerke GmbH",
|
|
||||||
"WB1": "BMW",
|
"WB1": "BMW",
|
||||||
"WB5": "BMW",
|
"WB5": "BMW",
|
||||||
"WCD": "Freightliner",
|
"WCD": "Freightliner",
|
||||||
@ -691,14 +680,11 @@ wmi_manufacturer_mapping = {
|
|||||||
"WD6": "Freightliner",
|
"WD6": "Freightliner",
|
||||||
"WD8": "Dodge",
|
"WD8": "Dodge",
|
||||||
"WEB": "Evobus GmbH",
|
"WEB": "Evobus GmbH",
|
||||||
"WEL": "e.GO Mobile AG",
|
|
||||||
"WFC": "Fendt",
|
"WFC": "Fendt",
|
||||||
"WFD": "Fliegl Trailer",
|
"WFD": "Fliegl Trailer",
|
||||||
"WF0": "Ford",
|
"WF0": "Ford",
|
||||||
"WF1": "Merkur",
|
"WF1": "Merkur",
|
||||||
"WHB": "Hobby",
|
"WHB": "Hobby",
|
||||||
"WHD": "Humbaur GmbH",
|
|
||||||
"WHW": "Hako GmbH",
|
|
||||||
"WHY": "Hymer",
|
"WHY": "Hymer",
|
||||||
"WJM": "Iveco",
|
"WJM": "Iveco",
|
||||||
"WJR": "Irmscher",
|
"WJR": "Irmscher",
|
||||||
@ -760,12 +746,10 @@ wmi_manufacturer_mapping = {
|
|||||||
"XMC": "Mitsubishi",
|
"XMC": "Mitsubishi",
|
||||||
"XMD": "Mitsubishi",
|
"XMD": "Mitsubishi",
|
||||||
"XMG": "VDL Bus",
|
"XMG": "VDL Bus",
|
||||||
"XMR": "Nooteboom Trailers",
|
"XMR": "Nooteboom",
|
||||||
"XM4": "RAVO Holding",
|
"XM4": "RAVO Holding",
|
||||||
"XNB": "Mitsubishi",
|
"XNB": "Mitsubishi",
|
||||||
"XNC": "Mitsubishi",
|
"XNC": "Mitsubishi",
|
||||||
"XNL": "VDL Bus & Coach",
|
|
||||||
"XPN": "Knapen Trailers",
|
|
||||||
"XP7": "Tesla",
|
"XP7": "Tesla",
|
||||||
"XTA": "Lada",
|
"XTA": "Lada",
|
||||||
"XTB": "Moskvitch",
|
"XTB": "Moskvitch",
|
||||||
@ -803,7 +787,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"X9X": "Great Wall",
|
"X9X": "Great Wall",
|
||||||
"YAF": "Faymonville",
|
"YAF": "Faymonville",
|
||||||
"YAR": "Toyota",
|
"YAR": "Toyota",
|
||||||
"YA9": "Lambrecht Constructie NV",
|
|
||||||
"YBW": "Volkswagen",
|
"YBW": "Volkswagen",
|
||||||
"YB1": "Volvo",
|
"YB1": "Volvo",
|
||||||
"YB2": "Volvo",
|
"YB2": "Volvo",
|
||||||
@ -812,7 +795,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"YH1": "Solifer",
|
"YH1": "Solifer",
|
||||||
"YH2": "BRP",
|
"YH2": "BRP",
|
||||||
"YH4": "Fisker",
|
"YH4": "Fisker",
|
||||||
"YK1": "Saab-Valmet",
|
"YK1": "Saab",
|
||||||
"YSC": "Cadillac",
|
"YSC": "Cadillac",
|
||||||
"YSM": "Polestars",
|
"YSM": "Polestars",
|
||||||
"YSP": "Volta AB",
|
"YSP": "Volta AB",
|
||||||
@ -827,7 +810,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"YV3": "Volvos",
|
"YV3": "Volvos",
|
||||||
"YV4": "Volvo",
|
"YV4": "Volvo",
|
||||||
"YYC": "Think Nordic",
|
"YYC": "Think Nordic",
|
||||||
"Y3J": "Belkommunmash",
|
|
||||||
"Y3M": "MAZ",
|
"Y3M": "MAZ",
|
||||||
"Y4F": "Ford",
|
"Y4F": "Ford",
|
||||||
"Y4K": "Geely",
|
"Y4K": "Geely",
|
||||||
@ -841,19 +823,19 @@ wmi_manufacturer_mapping = {
|
|||||||
"Y8A": "LAZ",
|
"Y8A": "LAZ",
|
||||||
"Y9H": "LAZ",
|
"Y9H": "LAZ",
|
||||||
"ZAA": "Autobianchi",
|
"ZAA": "Autobianchi",
|
||||||
"ZAC": "Jeep Dodge Hornet",
|
"ZAC": "Jeep Dodge",
|
||||||
"ZAM": "Maserati",
|
"ZAM": "Maserati",
|
||||||
"ZAP": "Piaggio",
|
"ZAP": "Piaggio",
|
||||||
"ZAR": "Alfa Romeo",
|
"ZAR": "Alfa Romeo",
|
||||||
"ZAS": "Alfa Romeo",
|
"ZAS": "Alfa Romeo",
|
||||||
"ZBB": "Bertone",
|
"ZBB": "Bertone",
|
||||||
"ZBN": "Benelli",
|
"ZBN": "Benelli",
|
||||||
"ZBW": "Rayton-Fissore Magnum",
|
"ZBW": "Rayton-Fissore",
|
||||||
"ZCB": "Bartoletti",
|
"ZCB": "Bartoletti",
|
||||||
"ZCF": "Iveco",
|
"ZCF": "Iveco",
|
||||||
"ZCG": "Cagiva",
|
"ZCG": "Cagiva",
|
||||||
"ZCM": "Menarinibus",
|
"ZCM": "Menarinibus",
|
||||||
"ZC2": "Chrysler Maserati",
|
"ZC2": "Chrysler",
|
||||||
"ZDC": "Honda",
|
"ZDC": "Honda",
|
||||||
"ZDF": "Ferrari",
|
"ZDF": "Ferrari",
|
||||||
"ZDM": "Ducati",
|
"ZDM": "Ducati",
|
||||||
@ -895,8 +877,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"Z8T": "PCMA",
|
"Z8T": "PCMA",
|
||||||
"Z9M": "Mercedes-Benz",
|
"Z9M": "Mercedes-Benz",
|
||||||
"Z94": "Hyundai",
|
"Z94": "Hyundai",
|
||||||
"1AC": "American Corporation",
|
|
||||||
"1AF": "American LaFrance",
|
|
||||||
"1B3": "Dodge",
|
"1B3": "Dodge",
|
||||||
"1B4": "Dodge",
|
"1B4": "Dodge",
|
||||||
"1B7": "Dodge",
|
"1B7": "Dodge",
|
||||||
@ -946,7 +926,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"1GY": "Cadillac",
|
"1GY": "Cadillac",
|
||||||
"1HD": "Harley-Davidson",
|
"1HD": "Harley-Davidson",
|
||||||
"1HG": "Honda",
|
"1HG": "Honda",
|
||||||
"1HS": "International & Caterpillar",
|
"1HS": "Caterpillar",
|
||||||
"1JC": "Jeep",
|
"1JC": "Jeep",
|
||||||
"1JT": "Jeep",
|
"1JT": "Jeep",
|
||||||
"1JU": "Marmon",
|
"1JU": "Marmon",
|
||||||
@ -969,10 +949,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"1P3": "Plymouth",
|
"1P3": "Plymouth",
|
||||||
"1P4": "Plymouth",
|
"1P4": "Plymouth",
|
||||||
"1PY": "John Deere",
|
"1PY": "John Deere",
|
||||||
"1T7": "Thomas Built Buses",
|
|
||||||
"1T8": "Thomas Built Buses",
|
|
||||||
"1TC": "Coachmen",
|
"1TC": "Coachmen",
|
||||||
"1TU": "Transportation Manufacturing Corporation",
|
|
||||||
"1UJ": "Jayco",
|
"1UJ": "Jayco",
|
||||||
"1UT": "Jeep",
|
"1UT": "Jeep",
|
||||||
"1VH": "Orion Bus",
|
"1VH": "Orion Bus",
|
||||||
@ -993,8 +970,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"10T": "Oshkosh",
|
"10T": "Oshkosh",
|
||||||
"12A": "Avanti",
|
"12A": "Avanti",
|
||||||
"137": "Hummer",
|
"137": "Hummer",
|
||||||
"15G": "Gillig bus",
|
|
||||||
"16C": "Clenet Coachworks",
|
|
||||||
"16X": "Vixen",
|
"16X": "Vixen",
|
||||||
"19U": "Acura",
|
"19U": "Acura",
|
||||||
"19V": "Acura",
|
"19V": "Acura",
|
||||||
@ -1549,7 +1524,7 @@ def decode_vin(vin):
|
|||||||
return {
|
return {
|
||||||
'VIN': vin,
|
'VIN': vin,
|
||||||
'Manufacturer': manufacturer,
|
'Manufacturer': manufacturer,
|
||||||
'Year': year[0],
|
'Year': year,
|
||||||
'Model': model
|
'Model': model
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1558,7 +1533,7 @@ def decode_vin(vin):
|
|||||||
# VR3USHNLWRJ521303
|
# VR3USHNLWRJ521303
|
||||||
# KNARH81E8P5194005
|
# KNARH81E8P5194005
|
||||||
# Example usage
|
# Example usage
|
||||||
vin_number = 'LJD5AA1DXR0104257'
|
vin_number = 'LGWCBE196SB652802'
|
||||||
decoded_vin = decode_vin(vin_number)
|
decoded_vin = decode_vin(vin_number)
|
||||||
print(decoded_vin)
|
print(decoded_vin)
|
||||||
|
|
||||||
|
|||||||
@ -5,17 +5,22 @@ from . import models
|
|||||||
admin.site.register(models.Dealer)
|
admin.site.register(models.Dealer)
|
||||||
admin.site.register(models.Vendor)
|
admin.site.register(models.Vendor)
|
||||||
admin.site.register(models.Customer)
|
admin.site.register(models.Customer)
|
||||||
|
admin.site.register(models.SaleQuotation)
|
||||||
|
admin.site.register(models.SaleQuotationCar)
|
||||||
admin.site.register(models.Car)
|
admin.site.register(models.Car)
|
||||||
admin.site.register(models.CarFinance)
|
admin.site.register(models.CarFinance)
|
||||||
admin.site.register(models.CarColors)
|
admin.site.register(models.CarColors)
|
||||||
admin.site.register(models.CarRegistration)
|
admin.site.register(models.CarRegistration)
|
||||||
admin.site.register(models.CustomCard)
|
admin.site.register(models.CustomCard)
|
||||||
admin.site.register(models.CarSpecificationValue)
|
admin.site.register(models.CarSpecificationValue)
|
||||||
|
admin.site.register(models.ExteriorColors)
|
||||||
|
admin.site.register(models.InteriorColors)
|
||||||
|
|
||||||
@admin.register(models.CarMake)
|
@admin.register(models.CarMake)
|
||||||
class CarMakeAdmin(admin.ModelAdmin):
|
class CarMakeAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'arabic_name', 'is_sa_import')
|
list_display = ('name', 'arabic_name', 'is_sa_import')
|
||||||
search_fields = ('name', 'arabic_name')
|
search_fields = ('name', 'arabic_name')
|
||||||
|
list_filter = ('is_sa_import', 'name',)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Car Make"
|
verbose_name = "Car Make"
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from .mixins import AddClassMixin
|
from .mixins import AddClassMixin
|
||||||
|
from django.forms.models import inlineformset_factory
|
||||||
from .models import (
|
from .models import (
|
||||||
Dealer,
|
Dealer,
|
||||||
# Branch,
|
# Branch,
|
||||||
@ -9,9 +10,12 @@ from .models import (
|
|||||||
CarFinance,
|
CarFinance,
|
||||||
CustomCard,
|
CustomCard,
|
||||||
CarRegistration,
|
CarRegistration,
|
||||||
CarColors
|
CarColors,
|
||||||
|
ExteriorColors,
|
||||||
|
InteriorColors,
|
||||||
|
SaleQuotation
|
||||||
)
|
)
|
||||||
from django.contrib.contenttypes.forms import generic_inlineformset_factory
|
from django.forms import ModelMultipleChoiceField
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
@ -19,7 +23,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
class DealerForm(forms.ModelForm):
|
class DealerForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Dealer
|
model = Dealer
|
||||||
fields = ['crn', 'vrn', 'arabic_name', 'name', 'phone_number', 'address', 'logo']
|
fields = ['name', 'arabic_name', 'crn', 'vrn', 'phone_number', 'address', 'logo']
|
||||||
|
|
||||||
|
|
||||||
# Customer Form
|
# Customer Form
|
||||||
@ -87,57 +91,10 @@ class CarUpdateForm(forms.ModelForm, AddClassMixin):
|
|||||||
|
|
||||||
|
|
||||||
class CarFinanceForm(AddClassMixin, forms.ModelForm):
|
class CarFinanceForm(AddClassMixin, forms.ModelForm):
|
||||||
profit_margin_percentage = forms.DecimalField(
|
|
||||||
max_digits=10,
|
|
||||||
decimal_places=2,
|
|
||||||
min_value=0,
|
|
||||||
max_value=100,
|
|
||||||
label="Profit Margin",
|
|
||||||
required=True,
|
|
||||||
widget=forms.NumberInput(attrs={'min': '0', 'max': '100', 'step': '0.01'})
|
|
||||||
)
|
|
||||||
vat_rate_percentage = forms.DecimalField(
|
|
||||||
max_digits=10,
|
|
||||||
decimal_places=2,
|
|
||||||
min_value=0,
|
|
||||||
max_value=100,
|
|
||||||
label="Vat Rate",
|
|
||||||
required=True,
|
|
||||||
widget=forms.NumberInput(attrs={'min': '0', 'max': '100', 'step': '0.01'})
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CarFinance
|
model = CarFinance
|
||||||
fields = ['cost_price']
|
exclude = ['car', 'profit_margin', 'vat_amount', 'total', 'vat_rate']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(CarFinanceForm, self).__init__(*args, **kwargs)
|
|
||||||
if self.instance and self.instance.pk:
|
|
||||||
# Convert profit_margin from decimal to percentage for initial display
|
|
||||||
self.fields['profit_margin_percentage'].initial = self.instance.profit_margin * 100
|
|
||||||
self.fields['vat_rate_percentage'].initial = self.instance.vat_rate * 100
|
|
||||||
|
|
||||||
def clean_profit_margin_percentage(self):
|
|
||||||
profit_margin_percentage = self.cleaned_data['profit_margin_percentage']
|
|
||||||
if not (0 <= profit_margin_percentage <= 100):
|
|
||||||
raise forms.ValidationError('Profit margin must be between 0 and 100.')
|
|
||||||
return profit_margin_percentage
|
|
||||||
|
|
||||||
def clean_vat_rate_percentage(self):
|
|
||||||
vat_rate_percentage = self.cleaned_data['vat_rate_percentage']
|
|
||||||
if not (0 <= vat_rate_percentage <= 100):
|
|
||||||
raise forms.ValidationError('vat rate must be between 0 and 100.')
|
|
||||||
return vat_rate_percentage
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
instance = super(CarFinanceForm, self).save(commit=False)
|
|
||||||
profit_margin_percentage = self.cleaned_data['profit_margin_percentage']
|
|
||||||
vat_rate_percentage = self.cleaned_data['vat_rate_percentage']
|
|
||||||
instance.profit_margin = profit_margin_percentage / 100
|
|
||||||
instance.vat_rate = vat_rate_percentage / 100
|
|
||||||
if commit:
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
# Custom Card Form
|
# Custom Card Form
|
||||||
@ -165,3 +122,52 @@ class VendorForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Vendor
|
model = Vendor
|
||||||
exclude = ['dealer']
|
exclude = ['dealer']
|
||||||
|
|
||||||
|
|
||||||
|
class CarColorsForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = CarColors
|
||||||
|
fields = ['exterior', 'interior']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.fields['exterior'].queryset = ExteriorColors.objects.all()
|
||||||
|
self.fields['exterior'].widget = forms.RadioSelect(attrs={'class': 'form-check-input'})
|
||||||
|
self.fields['exterior'].choices = [
|
||||||
|
(color.id, f"{color.get_local_name}") for color in ExteriorColors.objects.all().order_by('-name')
|
||||||
|
]
|
||||||
|
|
||||||
|
self.fields['interior'].queryset = InteriorColors.objects.all()
|
||||||
|
self.fields['interior'].widget = forms.RadioSelect(attrs={'class': 'form-check-input'})
|
||||||
|
self.fields['interior'].choices = [
|
||||||
|
(color.id, f"{color.get_local_name}") for color in InteriorColors.objects.all().order_by('-name')
|
||||||
|
]
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
exterior = cleaned_data.get("exterior")
|
||||||
|
interior = cleaned_data.get("interior")
|
||||||
|
|
||||||
|
if not exterior or not interior:
|
||||||
|
raise forms.ValidationError(_("Both exterior and interior colors must be selected."))
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class QuotationForm(forms.ModelForm):
|
||||||
|
cars = ModelMultipleChoiceField(
|
||||||
|
queryset=Car.objects.none(), # Default empty queryset
|
||||||
|
widget=forms.CheckboxSelectMultiple,
|
||||||
|
label="Select Cars"
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = SaleQuotation
|
||||||
|
fields = ['customer', 'cars', 'remarks']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['cars'].queryset = Car.objects.filter(
|
||||||
|
finances__isnull=False
|
||||||
|
).distinct()
|
||||||
|
|||||||
100
inventory/management/commands/populate_colors.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from inventory.models import ExteriorColors, InteriorColors
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Populates the ExteriorColors and InteriorColors models with predefined data"
|
||||||
|
|
||||||
|
exterior_colors = [
|
||||||
|
{"rgb": "192, 192, 192", "name": "Silver Metallic", "arabic_name": "فضي معدني"},
|
||||||
|
{"rgb": "0, 0, 0", "name": "Jet Black", "arabic_name": "أسود نفاث"},
|
||||||
|
{"rgb": "255, 255, 255", "name": "Bright White", "arabic_name": "أبيض ناصع"},
|
||||||
|
{"rgb": "128, 128, 128", "name": "Graphite Gray", "arabic_name": "رمادي غرافيتي"},
|
||||||
|
{"rgb": "80, 80, 80", "name": "Gunmetal Gray", "arabic_name": "رمادي معدني"},
|
||||||
|
{"rgb": "255, 0, 0", "name": "Racing Red", "arabic_name": "أحمر سباق"},
|
||||||
|
{"rgb": "255, 69, 0", "name": "Inferno Orange", "arabic_name": "برتقالي جهنمي"},
|
||||||
|
{"rgb": "0, 0, 255", "name": "Deep Blue Pearl", "arabic_name": "أزرق لؤلؤي عميق"},
|
||||||
|
{"rgb": "75, 0, 130", "name": "Indigo Night", "arabic_name": "ليلة نيلي"},
|
||||||
|
{"rgb": "255, 215, 0", "name": "Solar Gold", "arabic_name": "ذهبي شمسي"},
|
||||||
|
{"rgb": "34, 139, 34", "name": "Emerald Green", "arabic_name": "أخضر زمردي"},
|
||||||
|
{"rgb": "60, 179, 113", "name": "Forest Mist Green", "arabic_name": "أخضر ضباب الغابة"},
|
||||||
|
{"rgb": "255, 140, 0", "name": "Burnt Amber", "arabic_name": "كهرماني محروق"},
|
||||||
|
{"rgb": "160, 82, 45", "name": "Copper Brown", "arabic_name": "بني نحاسي"},
|
||||||
|
{"rgb": "128, 0, 0", "name": "Crimson Maroon", "arabic_name": "ماروني قرمزي"},
|
||||||
|
{"rgb": "245, 245, 220", "name": "Beige Champagne", "arabic_name": "بيج شامبين"},
|
||||||
|
{"rgb": "169, 169, 169", "name": "Shadow Gray", "arabic_name": "رمادي ظل"},
|
||||||
|
{"rgb": "255, 250, 205", "name": "Lemon Pearl", "arabic_name": "لؤلؤي ليموني"},
|
||||||
|
{"rgb": "220, 220, 220", "name": "Platinum Silver", "arabic_name": "فضي بلاتيني"},
|
||||||
|
{"rgb": "105, 105, 105", "name": "Charcoal Metallic", "arabic_name": "رمادي فحمي معدني"},
|
||||||
|
{"rgb": "128, 0, 128", "name": "Royal Purple", "arabic_name": "أرجواني ملكي"},
|
||||||
|
{"rgb": "210, 105, 30", "name": "Sunset Bronze", "arabic_name": "برونزي الغروب"},
|
||||||
|
{"rgb": "0, 128, 128", "name": "Teal Lagoon", "arabic_name": "أزرق مخضر بحري"},
|
||||||
|
{"rgb": "72, 61, 139", "name": "Midnight Blue", "arabic_name": "أزرق منتصف الليل"},
|
||||||
|
{"rgb": "255, 20, 147", "name": "Blazing Pink", "arabic_name": "وردي لامع"},
|
||||||
|
{"rgb": "192, 57, 43", "name": "Crimson Flame", "arabic_name": "لهب قرمزي"},
|
||||||
|
{"rgb": "255, 228, 196", "name": "Cream Sand", "arabic_name": "كريم رملي"},
|
||||||
|
{"rgb": "112, 128, 144", "name": "Steel Gray", "arabic_name": "رمادي فولاذي"},
|
||||||
|
{"rgb": "0, 100, 0", "name": "Hunter Green", "arabic_name": "أخضر صياد"},
|
||||||
|
{"rgb": "255, 223, 0", "name": "Bright Yellow", "arabic_name": "أصفر ساطع"},
|
||||||
|
{"rgb": "85, 107, 47", "name": "Olive Metallic", "arabic_name": "زيتوني معدني"},
|
||||||
|
{"rgb": "128, 128, 0", "name": "Mustard Gold", "arabic_name": "ذهبي خردلي"},
|
||||||
|
{"rgb": "139, 69, 19", "name": "Cocoa Brown", "arabic_name": "بني كاكاو"},
|
||||||
|
{"rgb": "255, 165, 0", "name": "Tangerine Flame", "arabic_name": "لهب المندرين"},
|
||||||
|
{"rgb": "0, 0, 139", "name": "Navy Sapphire", "arabic_name": "كحلي ياقوتي"},
|
||||||
|
{"rgb": "70, 130, 180", "name": "Skyline Blue", "arabic_name": "أزرق أفق"},
|
||||||
|
{"rgb": "220, 20, 60", "name": "Crimson Passion", "arabic_name": "شغف قرمزي"},
|
||||||
|
{"rgb": "189, 183, 107", "name": "Khaki Dune", "arabic_name": "كاكي كثيب"},
|
||||||
|
{"rgb": "50, 205, 50", "name": "Lime Essence", "arabic_name": "ليموني نقي"},
|
||||||
|
{"rgb": "139, 0, 139", "name": "Amethyst Glow", "arabic_name": "توهج جمشت"},
|
||||||
|
{"rgb": "255, 215, 180", "name": "Rosé Gold", "arabic_name": "ذهبي وردي"},
|
||||||
|
{"rgb": "46, 139, 87", "name": "Moss Green", "arabic_name": "أخضر طحلبي"},
|
||||||
|
{"rgb": "72, 209, 204", "name": "Caribbean Aqua", "arabic_name": "أكوا كاريبي"},
|
||||||
|
{"rgb": "255, 240, 245", "name": "Pearl Blush", "arabic_name": "تورد لؤلؤي"},
|
||||||
|
{"rgb": "244, 164, 96", "name": "Sierra Sunset", "arabic_name": "غروب سييرا"},
|
||||||
|
{"rgb": "139, 0, 0", "name": "Crimson Ruby", "arabic_name": "روبي قرمزي"},
|
||||||
|
{"rgb": "192, 192, 192", "name": "Chrome", "arabic_name": "كروم"},
|
||||||
|
{"rgb": "255, 105, 180", "name": "Hot Magenta", "arabic_name": "ماجنتا ساخن"},
|
||||||
|
{"rgb": "0, 255, 255", "name": "Ice Blue", "arabic_name": "أزرق جليدي"},
|
||||||
|
{"rgb": "184, 134, 11", "name": "Golden Bronze", "arabic_name": "برونزي ذهبي"},
|
||||||
|
{"rgb": "128, 128, 64", "name": "Bronze Olive", "arabic_name": "زيتوني برونزي"},
|
||||||
|
]
|
||||||
|
|
||||||
|
interior_colors = [
|
||||||
|
{"rgb": "0, 0, 0", "name": "Jet Black", "arabic_name": "أسود نفاث"},
|
||||||
|
{"rgb": "54, 69, 79", "name": "Charcoal Black", "arabic_name": "أسود فحمي"},
|
||||||
|
{"rgb": "255, 255, 255", "name": "Bright White", "arabic_name": "أبيض ناصع"},
|
||||||
|
{"rgb": "245, 245, 220", "name": "Off-White", "arabic_name": "أبيض مصفر"},
|
||||||
|
{"rgb": "210, 180, 140", "name": "Beige", "arabic_name": "بيج"},
|
||||||
|
{"rgb": "203, 194, 190", "name": "Sandstone", "arabic_name": "حجر رملي"},
|
||||||
|
{"rgb": "80, 80, 80", "name": "Graphite Gray", "arabic_name": "رمادي غرافيتي"},
|
||||||
|
{"rgb": "127, 128, 133", "name": "Ebony/Medium Slate", "arabic_name": "إيبوني/لائحة متوسطة"},
|
||||||
|
{"rgb": "124, 79, 58", "name": "Mocha", "arabic_name": "موكا"},
|
||||||
|
{"rgb": "193, 154, 107", "name": "Camel Tan", "arabic_name": "بيج الجمل"},
|
||||||
|
{"rgb": "128, 0, 0", "name": "Maroon", "arabic_name": "مارون"},
|
||||||
|
{"rgb": "0, 0, 128", "name": "Navy Blue", "arabic_name": "أزرق بحري"},
|
||||||
|
{"rgb": "25, 25, 112", "name": "Midnight Blue", "arabic_name": "أزرق منتصف الليل"},
|
||||||
|
{"rgb": "72, 60, 50", "name": "Taupe", "arabic_name": "توب"},
|
||||||
|
]
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
self.stdout.write("Populating Exterior Colors...")
|
||||||
|
for color in self.exterior_colors:
|
||||||
|
obj, created = ExteriorColors.objects.get_or_create(
|
||||||
|
name=color["name"], arabic_name=color["arabic_name"], rgb=color["rgb"]
|
||||||
|
)
|
||||||
|
if created:
|
||||||
|
self.stdout.write(f"Added Exterior Color: {obj.name} ({obj.rgb})")
|
||||||
|
else:
|
||||||
|
self.stdout.write(f"Exterior Color already exists: {obj.name} ({obj.rgb})")
|
||||||
|
|
||||||
|
self.stdout.write("Populating Interior Colors...")
|
||||||
|
for color in self.interior_colors:
|
||||||
|
obj, created = InteriorColors.objects.get_or_create(
|
||||||
|
name=color["name"], arabic_name=color["arabic_name"], rgb=color["rgb"]
|
||||||
|
)
|
||||||
|
if created:
|
||||||
|
self.stdout.write(f"Added Interior Color: {obj.name} ({obj.rgb})")
|
||||||
|
else:
|
||||||
|
self.stdout.write(f"Interior Color already exists: {obj.name} ({obj.rgb})")
|
||||||
|
|
||||||
|
self.stdout.write("Finished populating colors.")
|
||||||
@ -1,8 +1,9 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-04 23:43
|
# Generated by Django 5.1.4 on 2024-12-09 13:58
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import inventory.mixins
|
import inventory.mixins
|
||||||
import phonenumber_field.modelfields
|
import phonenumber_field.modelfields
|
||||||
|
from decimal import Decimal
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@ -47,21 +48,56 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ExteriorColors',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Name')),
|
||||||
|
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||||
|
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Exterior Colors',
|
||||||
|
'verbose_name_plural': 'Exterior Colors',
|
||||||
|
},
|
||||||
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InteriorColors',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='Name')),
|
||||||
|
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||||
|
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Interior Colors',
|
||||||
|
'verbose_name_plural': 'Interior Colors',
|
||||||
|
},
|
||||||
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CarFinance',
|
name='CarFinance',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')),
|
('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')),
|
||||||
('profit_margin', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Profit Margin')),
|
('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')),
|
||||||
('selling_price', models.DecimalField(decimal_places=2, editable=False, max_digits=14, verbose_name='Selling Price')),
|
('profit_margin', models.DecimalField(decimal_places=2, editable=False, max_digits=14, verbose_name='Profit Margin')),
|
||||||
('vat_rate', models.DecimalField(decimal_places=2, default=0.15, max_digits=10, verbose_name='VAT Rate')),
|
('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')),
|
||||||
('vat_amount', models.DecimalField(decimal_places=2, editable=False, max_digits=12, verbose_name='VAT Amount')),
|
('registration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Registration Fee')),
|
||||||
('total', models.DecimalField(decimal_places=2, editable=False, max_digits=14, verbose_name='Total Amount')),
|
('administration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Administration Fee')),
|
||||||
|
('transportation_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Transportation Fee')),
|
||||||
|
('custom_card_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Custom Card Fee')),
|
||||||
|
('vat_rate', models.DecimalField(decimal_places=2, default=Decimal('0.15'), max_digits=14, verbose_name='VAT Rate')),
|
||||||
|
('administration_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Administration VAT')),
|
||||||
|
('transportation_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Transportation VAT')),
|
||||||
|
('custom_card_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Custom Card VAT')),
|
||||||
|
('selling_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Selling VAT')),
|
||||||
|
('total_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Total VAT')),
|
||||||
|
('total_before_vat', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Before VAT')),
|
||||||
|
('total', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Amount')),
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')),
|
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')),
|
||||||
],
|
],
|
||||||
options={
|
|
||||||
'verbose_name': 'Car Financial Details',
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='car',
|
model_name='car',
|
||||||
@ -171,7 +207,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')),
|
('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')),
|
||||||
('custom_date', models.DateTimeField(verbose_name='Custom Date')),
|
('custom_date', models.DateField(verbose_name='Custom Date')),
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')),
|
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -223,34 +259,22 @@ class Migration(migrations.Migration):
|
|||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ExteriorColors',
|
name='SaleQuotation',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=255, verbose_name='Name')),
|
('remarks', models.TextField(blank=True, null=True)),
|
||||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.customer')),
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exteriorcolor', to='inventory.car')),
|
|
||||||
],
|
],
|
||||||
options={
|
|
||||||
'verbose_name': 'Exterior Color',
|
|
||||||
'verbose_name_plural': 'Exterior Colors',
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='InteriorColors',
|
name='SaleQuotationCar',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=255, verbose_name='Name')),
|
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car')),
|
||||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
('financial_details', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_finances', to='inventory.carfinance')),
|
||||||
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation')),
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interiorcolor', to='inventory.car', verbose_name='Car')),
|
|
||||||
],
|
],
|
||||||
options={
|
|
||||||
'verbose_name': 'Interior Color',
|
|
||||||
'verbose_name_plural': 'Interior Colors',
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Vendor',
|
name='Vendor',
|
||||||
@ -263,6 +287,7 @@ class Migration(migrations.Migration):
|
|||||||
('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')),
|
('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')),
|
||||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
||||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
||||||
|
('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')),
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')),
|
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -290,4 +315,18 @@ class Migration(migrations.Migration):
|
|||||||
'unique_together': {('car', 'reserved_until')},
|
'unique_together': {('car', 'reserved_until')},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CarColors',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.car')),
|
||||||
|
('exterior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.exteriorcolors')),
|
||||||
|
('interior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.interiorcolors')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Color',
|
||||||
|
'verbose_name_plural': 'Colors',
|
||||||
|
'unique_together': {('car', 'exterior', 'interior')},
|
||||||
|
},
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-06 14:30
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='interiorcolors',
|
|
||||||
name='car',
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='CarColors',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=255, verbose_name='Name')),
|
|
||||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
|
||||||
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
|
||||||
('color_type', models.CharField(choices=[('exterior', 'Exterior'), ('interior', 'Interior')], default='exterior', max_length=10, verbose_name='Color Type')),
|
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.car')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Color',
|
|
||||||
'verbose_name_plural': 'Colors',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='ExteriorColors',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='InteriorColors',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 20:42
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='financial_details',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotation',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('DRAFT', 'Draft'), ('CONFIRMED', 'Confirmed'), ('CANCELED', 'Canceled')], default='DRAFT', max_length=10, verbose_name='Status'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotation',
|
||||||
|
name='updated_at',
|
||||||
|
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='administration_fee',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=150, max_digits=14, verbose_name='Administration Fee'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='custom_card_fee',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=70, max_digits=14, verbose_name='Custom Card Fee'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='selling_price',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=120000, max_digits=14, verbose_name='Selling Price'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='total_amount',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=135000, max_digits=14, verbose_name='Total Amount'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='transportation_fee',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=500, max_digits=14, verbose_name='Transportation Fee'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='vat_amount',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=4352, max_digits=14, verbose_name='VAT Amount'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salequotation',
|
||||||
|
name='created_at',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, verbose_name='Created At'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salequotation',
|
||||||
|
name='customer',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salequotation',
|
||||||
|
name='remarks',
|
||||||
|
field=models.TextField(blank=True, null=True, verbose_name='Remarks'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='car',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='quotation',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SalesOrder',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
||||||
|
('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')),
|
||||||
|
('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-08 08:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0002_remove_interiorcolors_car_carcolors_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='customcard',
|
|
||||||
name='custom_date',
|
|
||||||
field=models.DateField(verbose_name='Custom Date'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 21:06
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0002_remove_salequotationcar_financial_details_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='administration_fee',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='custom_card_fee',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='selling_price',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='total_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='transportation_fee',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='salequotationcar',
|
||||||
|
name='vat_amount',
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-09 21:59
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0003_remove_salequotationcar_administration_fee_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='administration_vat_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='custom_card_vat_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='selling_vat_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='total_before_vat',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='total_vat_amount',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='transportation_vat_amount',
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -14,10 +14,12 @@ from django_ledger.models import (
|
|||||||
UnitOfMeasureModel,
|
UnitOfMeasureModel,
|
||||||
CustomerModel,
|
CustomerModel,
|
||||||
ItemModelQuerySet,
|
ItemModelQuerySet,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from decimal import Decimal
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from .mixins import LocalizedNameMixin
|
from .mixins import LocalizedNameMixin
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ class CarMake(models.Model, LocalizedNameMixin):
|
|||||||
id_car_make = models.AutoField(primary_key=True)
|
id_car_make = models.AutoField(primary_key=True)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
arabic_name = models.CharField(max_length=255)
|
arabic_name = models.CharField(max_length=255)
|
||||||
logo = models.ImageField(_("logo"), upload_to="car_make", blank=True, null=True)
|
logo = models.ImageField(_('logo'), upload_to='car_make', blank=True, null=True)
|
||||||
is_sa_import = models.BooleanField(default=False)
|
is_sa_import = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -38,7 +40,7 @@ class CarMake(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
class CarModel(models.Model, LocalizedNameMixin):
|
class CarModel(models.Model, LocalizedNameMixin):
|
||||||
id_car_model = models.AutoField(primary_key=True)
|
id_car_model = models.AutoField(primary_key=True)
|
||||||
id_car_make = models.ForeignKey(CarMake, models.DO_NOTHING, db_column="id_car_make")
|
id_car_make = models.ForeignKey(CarMake, models.DO_NOTHING, db_column='id_car_make')
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
arabic_name = models.CharField(max_length=255)
|
arabic_name = models.CharField(max_length=255)
|
||||||
|
|
||||||
@ -51,9 +53,7 @@ class CarModel(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
class CarSerie(models.Model, LocalizedNameMixin):
|
class CarSerie(models.Model, LocalizedNameMixin):
|
||||||
id_car_serie = models.AutoField(primary_key=True)
|
id_car_serie = models.AutoField(primary_key=True)
|
||||||
id_car_model = models.ForeignKey(
|
id_car_model = models.ForeignKey(CarModel, models.DO_NOTHING, db_column='id_car_model')
|
||||||
CarModel, models.DO_NOTHING, db_column="id_car_model"
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
arabic_name = models.CharField(max_length=255)
|
arabic_name = models.CharField(max_length=255)
|
||||||
|
|
||||||
@ -66,9 +66,7 @@ class CarSerie(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
class CarTrim(models.Model, LocalizedNameMixin):
|
class CarTrim(models.Model, LocalizedNameMixin):
|
||||||
id_car_trim = models.AutoField(primary_key=True)
|
id_car_trim = models.AutoField(primary_key=True)
|
||||||
id_car_serie = models.ForeignKey(
|
id_car_serie = models.ForeignKey(CarSerie, models.DO_NOTHING, db_column='id_car_serie')
|
||||||
CarSerie, models.DO_NOTHING, db_column="id_car_serie"
|
|
||||||
)
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
arabic_name = models.CharField(max_length=255)
|
arabic_name = models.CharField(max_length=255)
|
||||||
start_production_year = models.IntegerField(blank=True, null=True)
|
start_production_year = models.IntegerField(blank=True, null=True)
|
||||||
@ -85,9 +83,7 @@ class CarSpecification(models.Model, LocalizedNameMixin):
|
|||||||
id_car_specification = models.AutoField(primary_key=True)
|
id_car_specification = models.AutoField(primary_key=True)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
arabic_name = models.CharField(max_length=255)
|
arabic_name = models.CharField(max_length=255)
|
||||||
id_parent = models.ForeignKey(
|
id_parent = models.ForeignKey('self', models.DO_NOTHING, db_column='id_parent', blank=True, null=True)
|
||||||
"self", models.DO_NOTHING, db_column="id_parent", blank=True, null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -98,10 +94,8 @@ class CarSpecification(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
class CarSpecificationValue(models.Model):
|
class CarSpecificationValue(models.Model):
|
||||||
id_car_specification_value = models.AutoField(primary_key=True)
|
id_car_specification_value = models.AutoField(primary_key=True)
|
||||||
id_car_trim = models.ForeignKey(CarTrim, models.DO_NOTHING, db_column="id_car_trim")
|
id_car_trim = models.ForeignKey(CarTrim, models.DO_NOTHING, db_column='id_car_trim')
|
||||||
id_car_specification = models.ForeignKey(
|
id_car_specification = models.ForeignKey(CarSpecification, models.DO_NOTHING, db_column='id_car_specification')
|
||||||
CarSpecification, models.DO_NOTHING, db_column="id_car_specification"
|
|
||||||
)
|
|
||||||
value = models.CharField(max_length=500)
|
value = models.CharField(max_length=500)
|
||||||
unit = models.CharField(max_length=255, blank=True, null=True)
|
unit = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
@ -114,21 +108,24 @@ class CarSpecificationValue(models.Model):
|
|||||||
|
|
||||||
# Car Model
|
# Car Model
|
||||||
class CarStatusChoices(models.TextChoices):
|
class CarStatusChoices(models.TextChoices):
|
||||||
AVAILABLE = "available", _("Available")
|
AVAILABLE = 'available', _('Available')
|
||||||
SOLD = "sold", _("Sold")
|
SOLD = 'sold', _('Sold')
|
||||||
HOLD = "hold", _("Hold")
|
HOLD = 'hold', _('Hold')
|
||||||
DAMAGED = "damaged", _("Damaged")
|
DAMAGED = 'damaged', _('Damaged')
|
||||||
|
|
||||||
|
|
||||||
class CarStockTypeChoices(models.TextChoices):
|
class CarStockTypeChoices(models.TextChoices):
|
||||||
NEW = "new", _("New")
|
NEW = 'new', _('New')
|
||||||
USED = "used", _("Used")
|
USED = 'used', _('Used')
|
||||||
|
|
||||||
|
|
||||||
class Car(models.Model):
|
class Car(models.Model):
|
||||||
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
||||||
dealer = models.ForeignKey(
|
dealer = models.ForeignKey(
|
||||||
"Dealer", models.DO_NOTHING, related_name="cars", verbose_name=_("Dealer")
|
"Dealer",
|
||||||
|
models.DO_NOTHING,
|
||||||
|
related_name='cars',
|
||||||
|
verbose_name=_("Dealer")
|
||||||
)
|
)
|
||||||
|
|
||||||
vendor = models.ForeignKey(
|
vendor = models.ForeignKey(
|
||||||
@ -136,53 +133,53 @@ class Car(models.Model):
|
|||||||
models.DO_NOTHING,
|
models.DO_NOTHING,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name="cars",
|
related_name='cars',
|
||||||
verbose_name=_("Vendor"),
|
verbose_name=_("Vendor")
|
||||||
)
|
)
|
||||||
id_car_make = models.ForeignKey(
|
id_car_make = models.ForeignKey(
|
||||||
CarMake,
|
CarMake,
|
||||||
models.DO_NOTHING,
|
models.DO_NOTHING,
|
||||||
db_column="id_car_make",
|
db_column='id_car_make',
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_("Make"),
|
verbose_name=_("Make")
|
||||||
)
|
)
|
||||||
id_car_model = models.ForeignKey(
|
id_car_model = models.ForeignKey(
|
||||||
CarModel,
|
CarModel,
|
||||||
models.DO_NOTHING,
|
models.DO_NOTHING,
|
||||||
db_column="id_car_model",
|
db_column='id_car_model',
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_("Model"),
|
verbose_name=_("Model")
|
||||||
)
|
)
|
||||||
year = models.IntegerField(verbose_name=_("Year"))
|
year = models.IntegerField(verbose_name=_("Year"))
|
||||||
id_car_serie = models.ForeignKey(
|
id_car_serie = models.ForeignKey(
|
||||||
CarSerie,
|
CarSerie,
|
||||||
models.DO_NOTHING,
|
models.DO_NOTHING,
|
||||||
db_column="id_car_serie",
|
db_column='id_car_serie',
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_("Series"),
|
verbose_name=_("Series")
|
||||||
)
|
)
|
||||||
id_car_trim = models.ForeignKey(
|
id_car_trim = models.ForeignKey(
|
||||||
CarTrim,
|
CarTrim,
|
||||||
models.DO_NOTHING,
|
models.DO_NOTHING,
|
||||||
db_column="id_car_trim",
|
db_column='id_car_trim',
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name=_("Trim"),
|
verbose_name=_("Trim")
|
||||||
)
|
)
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
choices=CarStatusChoices.choices,
|
choices=CarStatusChoices.choices,
|
||||||
default=CarStatusChoices.AVAILABLE,
|
default=CarStatusChoices.AVAILABLE,
|
||||||
verbose_name=_("Status"),
|
verbose_name=_("Status")
|
||||||
)
|
)
|
||||||
stock_type = models.CharField(
|
stock_type = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
choices=CarStockTypeChoices.choices,
|
choices=CarStockTypeChoices.choices,
|
||||||
default=CarStockTypeChoices.NEW,
|
default=CarStockTypeChoices.NEW,
|
||||||
verbose_name=_("Stock Type"),
|
verbose_name=_("Stock Type")
|
||||||
)
|
)
|
||||||
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
|
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
|
||||||
mileage = models.IntegerField(blank=True, null=True, verbose_name=_("Mileage"))
|
mileage = models.IntegerField(blank=True, null=True, verbose_name=_("Mileage"))
|
||||||
@ -205,23 +202,21 @@ class Car(models.Model):
|
|||||||
@property
|
@property
|
||||||
def selling_price(self):
|
def selling_price(self):
|
||||||
finance = self.finances.first()
|
finance = self.finances.first()
|
||||||
return finance.selling_price if finance else Decimal("0.00")
|
return finance.selling_price if finance else Decimal('0.00')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vat_amount(self):
|
def vat_amount(self):
|
||||||
finance = self.finances.first()
|
finance = self.finances.first()
|
||||||
return finance.vat_amount if finance else Decimal("0.00")
|
return finance.vat_amount if finance else Decimal('0.00')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total(self):
|
def total(self):
|
||||||
finance = self.finances.first()
|
finance = self.finances.first()
|
||||||
return finance.total if finance else Decimal("0.00")
|
return finance.total if finance else Decimal('0.00')
|
||||||
|
|
||||||
|
|
||||||
class CarReservation(models.Model):
|
class CarReservation(models.Model):
|
||||||
car = models.ForeignKey(
|
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations')
|
||||||
"Car", on_delete=models.CASCADE, related_name="reservations"
|
|
||||||
)
|
|
||||||
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
reserved_at = models.DateTimeField(auto_now_add=True)
|
reserved_at = models.DateTimeField(auto_now_add=True)
|
||||||
reserved_until = models.DateTimeField()
|
reserved_until = models.DateTimeField()
|
||||||
@ -230,81 +225,98 @@ class CarReservation(models.Model):
|
|||||||
return self.reserved_until > now()
|
return self.reserved_until > now()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("car", "reserved_until")
|
unique_together = ('car', 'reserved_until')
|
||||||
ordering = ["-reserved_at"]
|
ordering = ['-reserved_at']
|
||||||
|
|
||||||
|
|
||||||
# Car Finance Model
|
# Car Finance Model
|
||||||
class CarFinance(models.Model):
|
class CarFinance(models.Model):
|
||||||
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name="finances")
|
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='finances')
|
||||||
cost_price = models.DecimalField(
|
cost_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Cost Price"))
|
||||||
max_digits=14, decimal_places=2, verbose_name=_("Cost Price")
|
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
|
||||||
)
|
profit_margin = models.DecimalField(max_digits=14,
|
||||||
profit_margin = models.DecimalField(
|
decimal_places=2,
|
||||||
max_digits=10, decimal_places=2, verbose_name=_("Profit Margin")
|
verbose_name=_("Profit Margin"),
|
||||||
)
|
editable=False)
|
||||||
selling_price = models.DecimalField(
|
discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"),
|
||||||
max_digits=14, decimal_places=2, verbose_name=_("Selling Price"), editable=False
|
default=Decimal('0.00'))
|
||||||
)
|
registration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Registration Fee"),
|
||||||
vat_rate = models.DecimalField(
|
default=Decimal('0.00'))
|
||||||
max_digits=10, decimal_places=2, default=0.15, verbose_name=_("VAT Rate")
|
administration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Administration Fee"),
|
||||||
)
|
default=Decimal('0.00'))
|
||||||
vat_amount = models.DecimalField(
|
transportation_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Transportation Fee"),
|
||||||
max_digits=12, decimal_places=2, verbose_name=_("VAT Amount"), editable=False
|
default=Decimal('0.00'))
|
||||||
)
|
custom_card_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Custom Card Fee"),
|
||||||
total = models.DecimalField(
|
default=Decimal('0.00'))
|
||||||
max_digits=14, decimal_places=2, verbose_name=_("Total Amount"), editable=False
|
vat_rate = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.15'), verbose_name=_("VAT Rate"),)
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Car Financial Details")
|
verbose_name = _("Car Financial Details")
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
self.selling_price = self.cost_price * (1 + self.profit_margin)
|
try:
|
||||||
self.vat_amount = self.selling_price * self.vat_rate
|
self.profit_margin = self.selling_price - self.cost_price - self.discount_amount
|
||||||
self.total = self.selling_price + self.vat_amount
|
services = self.administration_fee + self.transportation_fee + self.custom_card_fee
|
||||||
|
price_after_discount = self.selling_price - self.discount_amount
|
||||||
|
total_vat_amount = (price_after_discount + services) * self.vat_rate
|
||||||
|
self.total = price_after_discount + services + total_vat_amount + self.registration_fee
|
||||||
|
|
||||||
|
except InvalidOperation as e:
|
||||||
|
raise ValidationError(_("Invalid decimal operation: %s") % str(e))
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_vat_amount(self):
|
||||||
|
return self.total if self.total else Decimal('0.00')
|
||||||
|
|
||||||
|
|
||||||
|
class ExteriorColors(models.Model, LocalizedNameMixin):
|
||||||
|
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||||
|
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||||
|
rgb = models.CharField(max_length=24, blank=True, null=True, verbose_name=_("RGB"))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Exterior Colors")
|
||||||
|
verbose_name_plural = _("Exterior Colors")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return f"{self.name} ({self.rgb})"
|
||||||
f"Car Financial Details for {self.car}: Selling Price {self.selling_price}"
|
|
||||||
)
|
|
||||||
|
class InteriorColors(models.Model, LocalizedNameMixin):
|
||||||
|
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||||
|
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||||
|
rgb = models.CharField(max_length=24, blank=True, null=True, verbose_name=_("RGB"))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Interior Colors")
|
||||||
|
verbose_name_plural = _("Interior Colors")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.rgb})"
|
||||||
|
|
||||||
|
|
||||||
# Colors Model
|
# Colors Model
|
||||||
class CarColors(models.Model):
|
class CarColors(models.Model):
|
||||||
class ColorType(models.TextChoices):
|
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='colors')
|
||||||
EXTERIOR = "exterior", _("Exterior")
|
exterior = models.ForeignKey('ExteriorColors', on_delete=models.CASCADE, related_name='colors')
|
||||||
INTERIOR = "interior", _("Interior")
|
interior = models.ForeignKey('InteriorColors', on_delete=models.CASCADE, related_name='colors')
|
||||||
|
|
||||||
car = models.ForeignKey("Car", on_delete=models.CASCADE, related_name="colors")
|
|
||||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
|
||||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
|
||||||
rgb = models.CharField(max_length=24, blank=True, null=True, verbose_name=_("RGB"))
|
|
||||||
color_type = models.CharField(
|
|
||||||
max_length=10,
|
|
||||||
choices=ColorType.choices,
|
|
||||||
default=ColorType.EXTERIOR,
|
|
||||||
verbose_name=_("Color Type"),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Color")
|
verbose_name = _("Color")
|
||||||
verbose_name_plural = _("Colors")
|
verbose_name_plural = _("Colors")
|
||||||
|
unique_together = ('car', 'exterior', 'interior')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.get_color_type_display()} - {self.name} ({self.rgb})"
|
return f"{self.car} ({self.exterior.name}) ({self.interior.name})"
|
||||||
|
|
||||||
|
|
||||||
# Custom Card Model
|
# Custom Card Model
|
||||||
class CustomCard(models.Model):
|
class CustomCard(models.Model):
|
||||||
car = models.ForeignKey(
|
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car"))
|
||||||
Car,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="custom_cards",
|
|
||||||
verbose_name=_("Car"),
|
|
||||||
)
|
|
||||||
custom_number = models.CharField(max_length=255, verbose_name=_("Custom Number"))
|
custom_number = models.CharField(max_length=255, verbose_name=_("Custom Number"))
|
||||||
custom_date = models.DateField(verbose_name=_("Custom Date"))
|
custom_date = models.DateField(verbose_name=_("Custom Date"))
|
||||||
|
|
||||||
@ -318,12 +330,7 @@ class CustomCard(models.Model):
|
|||||||
|
|
||||||
# Car Registration Model
|
# Car Registration Model
|
||||||
class CarRegistration(models.Model):
|
class CarRegistration(models.Model):
|
||||||
car = models.ForeignKey(
|
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='registrations', verbose_name=_("Car"))
|
||||||
Car,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name="registrations",
|
|
||||||
verbose_name=_("Car"),
|
|
||||||
)
|
|
||||||
plate_number = models.IntegerField(verbose_name=_("Plate Number"))
|
plate_number = models.IntegerField(verbose_name=_("Plate Number"))
|
||||||
text1 = models.CharField(max_length=1, verbose_name=_("Text 1"))
|
text1 = models.CharField(max_length=1, verbose_name=_("Text 1"))
|
||||||
text2 = models.CharField(max_length=1, verbose_name=_("Text 2"))
|
text2 = models.CharField(max_length=1, verbose_name=_("Text 2"))
|
||||||
@ -349,20 +356,14 @@ class TimestampedModel(models.Model):
|
|||||||
|
|
||||||
# Dealer Model
|
# Dealer Model
|
||||||
class Dealer(models.Model, LocalizedNameMixin):
|
class Dealer(models.Model, LocalizedNameMixin):
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='dealer')
|
||||||
crn = models.CharField(
|
crn = models.CharField(max_length=10, verbose_name=_("Commercial Registration Number"))
|
||||||
max_length=10, verbose_name=_("Commercial Registration Number")
|
|
||||||
)
|
|
||||||
vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"))
|
vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"))
|
||||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||||
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
||||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
phone_number = PhoneNumberField(region='SA', verbose_name=_("Phone Number"))
|
||||||
address = models.CharField(
|
address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address"))
|
||||||
max_length=200, blank=True, null=True, verbose_name=_("Address")
|
logo = models.ImageField(upload_to="logos/users", blank=True, null=True, verbose_name=_("Logo"))
|
||||||
)
|
|
||||||
logo = models.ImageField(
|
|
||||||
upload_to="logos/users", blank=True, null=True, verbose_name=_("Logo")
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Dealer")
|
verbose_name = _("Dealer")
|
||||||
@ -374,20 +375,15 @@ class Dealer(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
# Vendor Model
|
# Vendor Model
|
||||||
class Vendor(models.Model, LocalizedNameMixin):
|
class Vendor(models.Model, LocalizedNameMixin):
|
||||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="vendors")
|
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='vendors')
|
||||||
crn = models.CharField(
|
crn = models.CharField(max_length=10, unique=True, verbose_name=_("Commercial Registration Number"))
|
||||||
max_length=10, unique=True, verbose_name=_("Commercial Registration Number")
|
vrn = models.CharField(max_length=15, unique=True, verbose_name=_("VAT Registration Number"))
|
||||||
)
|
|
||||||
vrn = models.CharField(
|
|
||||||
max_length=15, unique=True, verbose_name=_("VAT Registration Number")
|
|
||||||
)
|
|
||||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||||
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
||||||
contact_person = models.CharField(max_length=100, verbose_name=_("Contact Person"))
|
contact_person = models.CharField(max_length=100, verbose_name=_("Contact Person"))
|
||||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
phone_number = PhoneNumberField(region='SA', verbose_name=_("Phone Number"))
|
||||||
address = models.CharField(
|
address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address"))
|
||||||
max_length=200, blank=True, null=True, verbose_name=_("Address")
|
logo = models.ImageField(upload_to="logos/vendors", blank=True, null=True, verbose_name=_("Logo"))
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Vendor")
|
verbose_name = _("Vendor")
|
||||||
@ -399,24 +395,14 @@ class Vendor(models.Model, LocalizedNameMixin):
|
|||||||
|
|
||||||
# Customer Model
|
# Customer Model
|
||||||
class Customer(models.Model):
|
class Customer(models.Model):
|
||||||
dealer = models.ForeignKey(
|
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='customers')
|
||||||
Dealer, on_delete=models.CASCADE, related_name="customers"
|
|
||||||
)
|
|
||||||
first_name = models.CharField(max_length=50, verbose_name=_("First Name"))
|
first_name = models.CharField(max_length=50, verbose_name=_("First Name"))
|
||||||
middle_name = models.CharField(
|
middle_name = models.CharField(max_length=50, blank=True, null=True, verbose_name=_("Middle Name"))
|
||||||
max_length=50, blank=True, null=True, verbose_name=_("Middle Name")
|
|
||||||
)
|
|
||||||
last_name = models.CharField(max_length=50, verbose_name=_("Last Name"))
|
last_name = models.CharField(max_length=50, verbose_name=_("Last Name"))
|
||||||
email = models.EmailField(unique=True, verbose_name=_("Email"))
|
email = models.EmailField(unique=True, verbose_name=_("Email"))
|
||||||
national_id = models.CharField(
|
national_id = models.CharField(max_length=10, unique=True, verbose_name=_("National ID"))
|
||||||
max_length=10, unique=True, verbose_name=_("National ID")
|
phone_number = PhoneNumberField(region='SA', unique=True, verbose_name=_("Phone Number"))
|
||||||
)
|
address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address"))
|
||||||
phone_number = PhoneNumberField(
|
|
||||||
region="SA", unique=True, verbose_name=_("Phone Number")
|
|
||||||
)
|
|
||||||
address = models.CharField(
|
|
||||||
max_length=200, blank=True, null=True, verbose_name=_("Address")
|
|
||||||
)
|
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -424,9 +410,84 @@ class Customer(models.Model):
|
|||||||
verbose_name_plural = _("Customers")
|
verbose_name_plural = _("Customers")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
middle = f" {self.middle_name}" if self.middle_name else ""
|
middle = f" {self.middle_name}" if self.middle_name else ''
|
||||||
return f"{self.first_name}{middle} {self.last_name}"
|
return f"{self.first_name}{middle} {self.last_name}"
|
||||||
|
|
||||||
|
|
||||||
|
class SaleQuotation(models.Model):
|
||||||
|
STATUS_CHOICES = [
|
||||||
|
("DRAFT", _("Draft")),
|
||||||
|
("CONFIRMED", _("Confirmed")),
|
||||||
|
("CANCELED", _("Canceled")),
|
||||||
|
]
|
||||||
|
|
||||||
|
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="quotations", verbose_name=_("Customer"))
|
||||||
|
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
|
||||||
|
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="DRAFT", verbose_name=_("Status"))
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
||||||
|
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))
|
||||||
|
|
||||||
|
def confirm(self):
|
||||||
|
"""Confirm the quotation and lock financial details."""
|
||||||
|
if self.status != "DRAFT":
|
||||||
|
raise ValueError(_("Only draft quotations can be confirmed."))
|
||||||
|
self.status = "CONFIRMED"
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
"""Cancel the quotation."""
|
||||||
|
if self.status == "CONFIRMED":
|
||||||
|
raise ValueError(_("Cannot cancel a confirmed quotation."))
|
||||||
|
self.status = "CANCELED"
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Quotation #{self.id} for {self.customer}"
|
||||||
|
|
||||||
|
|
||||||
|
class SaleQuotationCar(models.Model):
|
||||||
|
quotation = models.ForeignKey(
|
||||||
|
SaleQuotation,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="quotation_cars",
|
||||||
|
verbose_name=_("Quotation")
|
||||||
|
)
|
||||||
|
car = models.ForeignKey(
|
||||||
|
Car,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_("Car")
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_financial_details(self):
|
||||||
|
"""Retrieve financial details dynamically from CarFinance."""
|
||||||
|
car_finance = self.car.finances.first()
|
||||||
|
if not car_finance:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"selling_price": car_finance.selling_price,
|
||||||
|
"administration_fee": car_finance.administration_fee,
|
||||||
|
"transportation_fee": car_finance.transportation_fee,
|
||||||
|
"custom_card_fee": car_finance.custom_card_fee,
|
||||||
|
"registration_fee": car_finance.registration_fee,
|
||||||
|
"vat_rate": car_finance.vat_rate,
|
||||||
|
"discount_amount": car_finance.discount_amount,
|
||||||
|
"total_amount": car_finance.total,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.car} - Quotation #{self.quotation.id}"
|
||||||
|
|
||||||
|
|
||||||
|
class SalesOrder(models.Model):
|
||||||
|
quotation = models.OneToOneField(SaleQuotation, on_delete=models.CASCADE, related_name="sales_order", verbose_name=_("Quotation"))
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
||||||
|
total_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Total Amount"))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Sales Order #{self.id} from Quotation #{self.quotation.id}"
|
||||||
|
|
||||||
|
|
||||||
# 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):
|
||||||
|
|||||||
@ -25,6 +25,7 @@ def decode_vin_pyvin(vin):
|
|||||||
print(data)
|
print(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
# vehicle-info
|
# vehicle-info
|
||||||
# c2729afb
|
# c2729afb
|
||||||
# 6d397471920412d672af1b8a02ca52ea
|
# 6d397471920412d672af1b8a02ca52ea
|
||||||
@ -44,197 +45,10 @@ def elm(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)
|
car_info = json.loads(response.text)
|
||||||
|
print(car_info)
|
||||||
return car_info
|
return car_info
|
||||||
|
|
||||||
|
|
||||||
def get_unique_colors(api_response):
|
|
||||||
print(api_response)
|
|
||||||
colors = api_response.get("data", [])
|
|
||||||
print(colors)
|
|
||||||
|
|
||||||
unique_colors = {}
|
|
||||||
for color in colors:
|
|
||||||
color_name = color.get("name")
|
|
||||||
rgb = color.get("rgb")
|
|
||||||
if color_name not in unique_colors:
|
|
||||||
unique_colors[color_name] = rgb
|
|
||||||
|
|
||||||
return [{"name": name, "rgb": rgb} for name, rgb in unique_colors.items()]
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_colors(car_data):
|
|
||||||
|
|
||||||
car_colors = {
|
|
||||||
"data": [
|
|
||||||
{"rgb": "192, 192, 192", "name": "Silver Metallic"},
|
|
||||||
{"rgb": "0, 0, 0", "name": "Jet Black"},
|
|
||||||
{"rgb": "255, 255, 255", "name": "Bright White"},
|
|
||||||
{"rgb": "128, 128, 128", "name": "Graphite Gray"},
|
|
||||||
{"rgb": "80, 80, 80", "name": "Gunmetal Gray"},
|
|
||||||
{"rgb": "255, 0, 0", "name": "Racing Red"},
|
|
||||||
{"rgb": "255, 69, 0", "name": "Inferno Orange"},
|
|
||||||
{"rgb": "0, 0, 255", "name": "Deep Blue Pearl"},
|
|
||||||
{"rgb": "75, 0, 130", "name": "Indigo Night"},
|
|
||||||
{"rgb": "255, 215, 0", "name": "Solar Gold"},
|
|
||||||
{"rgb": "34, 139, 34", "name": "Emerald Green"},
|
|
||||||
{"rgb": "60, 179, 113", "name": "Forest Mist Green"},
|
|
||||||
{"rgb": "255, 140, 0", "name": "Burnt Amber"},
|
|
||||||
{"rgb": "160, 82, 45", "name": "Copper Brown"},
|
|
||||||
{"rgb": "128, 0, 0", "name": "Crimson Maroon"},
|
|
||||||
{"rgb": "245, 245, 220", "name": "Beige Champagne"},
|
|
||||||
{"rgb": "169, 169, 169", "name": "Shadow Gray"},
|
|
||||||
{"rgb": "255, 250, 205", "name": "Lemon Pearl"},
|
|
||||||
{"rgb": "220, 220, 220", "name": "Platinum Silver"},
|
|
||||||
{"rgb": "105, 105, 105", "name": "Charcoal Metallic"},
|
|
||||||
{"rgb": "128, 0, 128", "name": "Royal Purple"},
|
|
||||||
{"rgb": "210, 105, 30", "name": "Sunset Bronze"},
|
|
||||||
{"rgb": "0, 128, 128", "name": "Teal Lagoon"},
|
|
||||||
{"rgb": "72, 61, 139", "name": "Midnight Blue"},
|
|
||||||
{"rgb": "255, 20, 147", "name": "Blazing Pink"},
|
|
||||||
{"rgb": "192, 57, 43", "name": "Crimson Flame"},
|
|
||||||
{"rgb": "255, 228, 196", "name": "Cream Sand"},
|
|
||||||
{"rgb": "112, 128, 144", "name": "Steel Gray"},
|
|
||||||
{"rgb": "0, 100, 0", "name": "Hunter Green"},
|
|
||||||
{"rgb": "255, 223, 0", "name": "Bright Yellow"},
|
|
||||||
{"rgb": "85, 107, 47", "name": "Olive Metallic"},
|
|
||||||
{"rgb": "128, 128, 0", "name": "Mustard Gold"},
|
|
||||||
{"rgb": "139, 69, 19", "name": "Cocoa Brown"},
|
|
||||||
{"rgb": "255, 165, 0", "name": "Tangerine Flame"},
|
|
||||||
{"rgb": "0, 0, 139", "name": "Navy Sapphire"},
|
|
||||||
{"rgb": "70, 130, 180", "name": "Skyline Blue"},
|
|
||||||
{"rgb": "220, 20, 60", "name": "Crimson Passion"},
|
|
||||||
{"rgb": "189, 183, 107", "name": "Khaki Dune"},
|
|
||||||
{"rgb": "50, 205, 50", "name": "Lime Essence"},
|
|
||||||
{"rgb": "139, 0, 139", "name": "Amethyst Glow"},
|
|
||||||
{"rgb": "255, 215, 180", "name": "Rosé Gold"},
|
|
||||||
{"rgb": "46, 139, 87", "name": "Moss Green"},
|
|
||||||
{"rgb": "72, 209, 204", "name": "Caribbean Aqua"},
|
|
||||||
{"rgb": "255, 240, 245", "name": "Pearl Blush"},
|
|
||||||
{"rgb": "244, 164, 96", "name": "Sierra Sunset"},
|
|
||||||
{"rgb": "139, 0, 0", "name": "Crimson Ruby"},
|
|
||||||
{"rgb": "192, 192, 192", "name": "Chrome"},
|
|
||||||
{"rgb": "255, 105, 180", "name": "Hot Magenta"},
|
|
||||||
{"rgb": "0, 255, 255", "name": "Ice Blue"},
|
|
||||||
{"rgb": "184, 134, 11", "name": "Golden Bronze"},
|
|
||||||
{"rgb": "128, 128, 64", "name": "Bronze Olive"},
|
|
||||||
{"rgb": "245, 222, 179", "name": "Wheat Cream"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
jwt_token = get_jwt_token()
|
|
||||||
if not jwt_token:
|
|
||||||
print("Failed to retrieve JWT token.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
year = car_data['year']
|
|
||||||
make = car_data['make']
|
|
||||||
model = car_data['model']
|
|
||||||
|
|
||||||
url = "https://carapi.app/api/exterior-colors?year={}&make={}&model={}".format(year, make, model)
|
|
||||||
params = {
|
|
||||||
'limit': '1000',
|
|
||||||
'sort': 'name',
|
|
||||||
'direction': 'asc',
|
|
||||||
'verbose': 'no',
|
|
||||||
'all_trims': 'no',
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': f'Bearer {jwt_token}',
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = requests.get(url, headers=headers, params=params)
|
|
||||||
color_info = response.json()
|
|
||||||
|
|
||||||
if not color_info["data"] == []:
|
|
||||||
return get_unique_colors(color_info)
|
|
||||||
else:
|
|
||||||
return car_colors["data"]
|
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
print(f"Error fetching color information: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_interior_colors(car_data):
|
|
||||||
|
|
||||||
car_colors = {
|
|
||||||
"data": [
|
|
||||||
{"rgb": "0, 0, 0", "name": "Jet Black"},
|
|
||||||
{"rgb": "54, 69, 79", "name": "Charcoal Black"},
|
|
||||||
{"rgb": "255, 255, 255", "name": "Bright White"},
|
|
||||||
{"rgb": "245, 245, 220", "name": "Off-White"},
|
|
||||||
{"rgb": "210, 180, 140", "name": "Beige"},
|
|
||||||
{"rgb": "205, 133, 63", "name": "Tan"},
|
|
||||||
{"rgb": "128, 128, 128", "name": "Gray"},
|
|
||||||
{"rgb": "80, 80, 80", "name": "Graphite Gray"},
|
|
||||||
{"rgb": "112, 128, 144", "name": "Gunmetal Gray"},
|
|
||||||
{"rgb": "192, 192, 192", "name": "Silver Metallic"},
|
|
||||||
{"rgb": "139, 69, 19", "name": "Cognac Brown"},
|
|
||||||
{"rgb": "149, 94, 55", "name": "Chestnut Brown"},
|
|
||||||
{"rgb": "97, 63, 43", "name": "Espresso Brown"},
|
|
||||||
{"rgb": "72, 40, 34", "name": "Dark Chocolate"},
|
|
||||||
{"rgb": "139, 69, 19", "name": "Saddle Brown"},
|
|
||||||
{"rgb": "124, 79, 58", "name": "Mocha"},
|
|
||||||
{"rgb": "193, 154, 107", "name": "Camel Tan"},
|
|
||||||
{"rgb": "128, 0, 32", "name": "Burgundy"},
|
|
||||||
{"rgb": "128, 0, 0", "name": "Maroon"},
|
|
||||||
{"rgb": "139, 0, 0", "name": "Deep Red"},
|
|
||||||
{"rgb": "0, 0, 128", "name": "Navy Blue"},
|
|
||||||
{"rgb": "65, 105, 225", "name": "Royal Blue"},
|
|
||||||
{"rgb": "34, 139, 34", "name": "Forest Green"},
|
|
||||||
{"rgb": "80, 200, 120", "name": "Emerald Green"},
|
|
||||||
{"rgb": "255, 255, 240", "name": "Ivory"},
|
|
||||||
{"rgb": "242, 242, 242", "name": "Pearl White"},
|
|
||||||
{"rgb": "169, 169, 169", "name": "Stone Gray"},
|
|
||||||
{"rgb": "112, 128, 144", "name": "Slate Gray"},
|
|
||||||
{"rgb": "150, 111, 51", "name": "Ash Brown"},
|
|
||||||
{"rgb": "128, 128, 0", "name": "Olive Green"},
|
|
||||||
{"rgb": "25, 25, 112", "name": "Midnight Blue"},
|
|
||||||
{"rgb": "72, 60, 50", "name": "Taupe"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
jwt_token = get_jwt_token()
|
|
||||||
if not jwt_token:
|
|
||||||
print("Failed to retrieve JWT token.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
year = car_data['year']
|
|
||||||
make = car_data['make']
|
|
||||||
model = car_data['model']
|
|
||||||
|
|
||||||
url = "https://carapi.app/api/interior-colors?year={}&make={}&model={}".format(year, make, model)
|
|
||||||
params = {
|
|
||||||
'limit': '100',
|
|
||||||
'sort': 'name',
|
|
||||||
'direction': 'asc',
|
|
||||||
'verbose': 'no',
|
|
||||||
'all_trims': 'no',
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': f'Bearer {jwt_token}',
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = requests.get(url, headers=headers, params=params)
|
|
||||||
color_info = response.json()
|
|
||||||
|
|
||||||
if not color_info["data"] == []:
|
|
||||||
return get_unique_colors(color_info)
|
|
||||||
else:
|
|
||||||
return car_colors["data"]
|
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
print(f"Error fetching color information: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def translate(content, *args, **kwargs):
|
def translate(content, *args, **kwargs):
|
||||||
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
completion = client.chat.completions.create(
|
completion = client.chat.completions.create(
|
||||||
|
|||||||
@ -55,11 +55,20 @@ urlpatterns = [
|
|||||||
path('cars/finance/update/<int:pk>/', views.CarFinanceUpdateView.as_view(), name='car_finance_update'),
|
path('cars/finance/update/<int:pk>/', views.CarFinanceUpdateView.as_view(), name='car_finance_update'),
|
||||||
path('cars/add/', views.CarCreateView.as_view(), name='car_add'),
|
path('cars/add/', views.CarCreateView.as_view(), name='car_add'),
|
||||||
path('ajax/', views.AjaxHandlerView.as_view(), name='ajax_handler'),
|
path('ajax/', views.AjaxHandlerView.as_view(), name='ajax_handler'),
|
||||||
path('cars/<int:car_pk>/add-color/', views.CarColorCreateView.as_view(), name='add_color'),
|
path('cars/<int:car_pk>/add-color/', views.CarColorCreate.as_view(), name='add_color'),
|
||||||
path('cars/<int:car_pk>/colors/<int:pk>/update/',
|
# path('cars/<int:car_pk>/colors/<int:pk>/update/',views.CarColorUpdateView.as_view(),name='color_update'),
|
||||||
views.CarColorUpdateView.as_view(),
|
|
||||||
name='color_update'),
|
|
||||||
path('cars/reserve/<int:car_id>/', views.reserve_car_view, name='reserve_car'),
|
path('cars/reserve/<int:car_id>/', views.reserve_car_view, name='reserve_car'),
|
||||||
path('reservations/<int:reservation_id>/', views.manage_reservation, name='reservations'),
|
path('reservations/<int:reservation_id>/', views.manage_reservation, name='reservations'),
|
||||||
path('cars/<int:car_pk>/add-custom-card/', views.CustomCardCreateView.as_view(), name='add_custom_card'),
|
path('cars/<int:car_pk>/add-custom-card/', views.CustomCardCreateView.as_view(), name='add_custom_card'),
|
||||||
|
|
||||||
|
# Sales URLs
|
||||||
|
path('sales/quotations/create/', views.QuotationCreateView.as_view(), name='quotation_create'),
|
||||||
|
path('sales/quotations/<int:pk>/', views.QuotationDetailView.as_view(), name='quotation_detail'),
|
||||||
|
path('sales/quotations/', views.QuotationListView.as_view(), name='quotation_list'),
|
||||||
|
path('sales/quotations/<int:pk>/confirm/', views.confirm_quotation, name='confirm_quotation'),
|
||||||
|
path('sales/orders/detail/<int:order_id>/', views.SalesOrderDetailView.as_view(), name='order_detail'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-12-08 16:18+0300\n"
|
"POT-Creation-Date: 2024-12-09 09:40+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -19,9 +19,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||||
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||||
|
|
||||||
#: api/models.py:6 inventory/models.py:122
|
#: api/models.py:6 inventory/models.py:123
|
||||||
#: templates/inventory/car_detail.html:61 templates/inventory/car_form.html:83
|
#: templates/inventory/car_detail.html:61 templates/inventory/car_form.html:83
|
||||||
#: templates/inventory/car_inventory.html:40
|
#: templates/inventory/car_inventory.html:53
|
||||||
#: templates/inventory/car_list.html:67 templates/inventory/car_list.html:69
|
#: templates/inventory/car_list.html:67 templates/inventory/car_list.html:69
|
||||||
msgid "VIN"
|
msgid "VIN"
|
||||||
msgstr "رقم الهيكل"
|
msgstr "رقم الهيكل"
|
||||||
@ -34,47 +34,51 @@ msgstr "الإنجليزية"
|
|||||||
msgid "Arabic"
|
msgid "Arabic"
|
||||||
msgstr "العربية"
|
msgstr "العربية"
|
||||||
|
|
||||||
#: inventory/forms.py:147 inventory/models.py:284
|
#: inventory/forms.py:102 inventory/models.py:357
|
||||||
#: templates/inventory/car_detail.html:135
|
#: templates/inventory/car_detail.html:135
|
||||||
msgid "Custom Date"
|
msgid "Custom Date"
|
||||||
msgstr "تاريخ البطاقة الجمركية"
|
msgstr "تاريخ البطاقة الجمركية"
|
||||||
|
|
||||||
#: inventory/models.py:30 templates/vendors/vendors_list.html:44
|
#: inventory/forms.py:151
|
||||||
|
msgid "Both exterior and interior colors must be selected."
|
||||||
|
msgstr "يجب اختيار اللونين الخارجي والداخلي."
|
||||||
|
|
||||||
|
#: inventory/models.py:31 templates/vendors/vendors_list.html:44
|
||||||
msgid "logo"
|
msgid "logo"
|
||||||
msgstr "الشعار"
|
msgstr "الشعار"
|
||||||
|
|
||||||
#: inventory/models.py:110
|
#: inventory/models.py:111
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:21
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:21
|
||||||
msgid "Available"
|
msgid "Available"
|
||||||
msgstr "متاح"
|
msgstr "متاح"
|
||||||
|
|
||||||
#: inventory/models.py:111
|
#: inventory/models.py:112
|
||||||
msgid "Sold"
|
msgid "Sold"
|
||||||
msgstr "تم البيع"
|
msgstr "تم البيع"
|
||||||
|
|
||||||
#: inventory/models.py:112
|
#: inventory/models.py:113
|
||||||
msgid "Hold"
|
msgid "Hold"
|
||||||
msgstr "في الانتظار"
|
msgstr "في الانتظار"
|
||||||
|
|
||||||
#: inventory/models.py:113
|
#: inventory/models.py:114
|
||||||
msgid "Damaged"
|
msgid "Damaged"
|
||||||
msgstr "تالف"
|
msgstr "تالف"
|
||||||
|
|
||||||
#: inventory/models.py:117
|
#: inventory/models.py:118
|
||||||
msgid "New"
|
msgid "New"
|
||||||
msgstr "جديد"
|
msgstr "جديد"
|
||||||
|
|
||||||
#: inventory/models.py:118
|
#: inventory/models.py:119
|
||||||
msgid "Used"
|
msgid "Used"
|
||||||
msgstr "مستعمل"
|
msgstr "مستعمل"
|
||||||
|
|
||||||
#: inventory/models.py:127 inventory/models.py:332
|
#: inventory/models.py:128 inventory/models.py:405
|
||||||
msgid "Dealer"
|
msgid "Dealer"
|
||||||
msgstr "المعرض"
|
msgstr "المعرض"
|
||||||
|
|
||||||
#: inventory/models.py:136 inventory/models.py:351
|
#: inventory/models.py:137 inventory/models.py:424
|
||||||
#: templates/inventory/car_detail.html:108
|
#: templates/inventory/car_detail.html:108
|
||||||
#: templates/inventory/car_form.html:225
|
#: templates/inventory/car_form.html:230
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:359
|
#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:359
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/vendor.py:191
|
#: venv/lib/python3.11/site-packages/django_ledger/models/vendor.py:191
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:12
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:12
|
||||||
@ -82,28 +86,28 @@ msgstr "المعرض"
|
|||||||
msgid "Vendor"
|
msgid "Vendor"
|
||||||
msgstr "المورد"
|
msgstr "المورد"
|
||||||
|
|
||||||
#: inventory/models.py:144 templates/inventory/car_inventory.html:42
|
#: inventory/models.py:145 templates/inventory/car_inventory.html:55
|
||||||
msgid "Make"
|
msgid "Make"
|
||||||
msgstr "الصانع"
|
msgstr "الصانع"
|
||||||
|
|
||||||
#: inventory/models.py:152 templates/inventory/car_inventory.html:43
|
#: inventory/models.py:153 templates/inventory/car_inventory.html:56
|
||||||
msgid "Model"
|
msgid "Model"
|
||||||
msgstr "الموديل"
|
msgstr "الموديل"
|
||||||
|
|
||||||
#: inventory/models.py:154 templates/inventory/car_form.html:117
|
#: inventory/models.py:155 templates/inventory/car_form.html:118
|
||||||
#: templates/inventory/car_inventory.html:41
|
#: templates/inventory/car_inventory.html:54
|
||||||
msgid "Year"
|
msgid "Year"
|
||||||
msgstr "السنة"
|
msgstr "السنة"
|
||||||
|
|
||||||
#: inventory/models.py:161 templates/inventory/car_form.html:177
|
#: inventory/models.py:162 templates/inventory/car_form.html:182
|
||||||
msgid "Series"
|
msgid "Series"
|
||||||
msgstr "السلسلة"
|
msgstr "السلسلة"
|
||||||
|
|
||||||
#: inventory/models.py:169
|
#: inventory/models.py:170
|
||||||
msgid "Trim"
|
msgid "Trim"
|
||||||
msgstr "الفئة"
|
msgstr "الفئة"
|
||||||
|
|
||||||
#: inventory/models.py:175 templates/inventory/car_detail.html:86
|
#: inventory/models.py:176 templates/inventory/car_detail.html:86
|
||||||
#: templates/inventory/car_list.html:163
|
#: templates/inventory/car_list.html:163
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:10
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:10
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:12
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:12
|
||||||
@ -114,171 +118,201 @@ msgstr "الفئة"
|
|||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "الحالة"
|
msgstr "الحالة"
|
||||||
|
|
||||||
#: inventory/models.py:181 templates/inventory/car_detail.html:90
|
#: inventory/models.py:182 templates/inventory/car_detail.html:90
|
||||||
#: templates/inventory/car_form.html:243 templates/inventory/car_list.html:177
|
#: templates/inventory/car_form.html:248 templates/inventory/car_list.html:177
|
||||||
msgid "Stock Type"
|
msgid "Stock Type"
|
||||||
msgstr "نوع المخزون"
|
msgstr "نوع المخزون"
|
||||||
|
|
||||||
#: inventory/models.py:183 templates/inventory/car_detail.html:113
|
#: inventory/models.py:184 templates/inventory/car_detail.html:113
|
||||||
#: templates/inventory/car_form.html:296 templates/inventory/car_list.html:200
|
#: templates/inventory/car_form.html:301 templates/inventory/car_list.html:200
|
||||||
msgid "Remarks"
|
msgid "Remarks"
|
||||||
msgstr "ملاحظات"
|
msgstr "ملاحظات"
|
||||||
|
|
||||||
#: inventory/models.py:184 templates/inventory/car_detail.html:94
|
#: inventory/models.py:185 templates/inventory/car_detail.html:94
|
||||||
#: templates/inventory/car_form.html:260 templates/inventory/car_list.html:191
|
#: templates/inventory/car_form.html:265 templates/inventory/car_list.html:191
|
||||||
#: templates/inventory/car_list.html:192
|
#: templates/inventory/car_list.html:192
|
||||||
msgid "Mileage"
|
msgid "Mileage"
|
||||||
msgstr "عدد الكيلومترات"
|
msgstr "عدد الكيلومترات"
|
||||||
|
|
||||||
#: inventory/models.py:185 templates/inventory/car_detail.html:98
|
#: inventory/models.py:186 templates/inventory/car_detail.html:98
|
||||||
#: templates/inventory/car_form.html:278
|
#: templates/inventory/car_form.html:283
|
||||||
msgid "Receiving Date"
|
msgid "Receiving Date"
|
||||||
msgstr "تاريخ الاستلام"
|
msgstr "تاريخ الاستلام"
|
||||||
|
|
||||||
#: inventory/models.py:188 inventory/models.py:282 inventory/models.py:296
|
#: inventory/models.py:189 inventory/models.py:355 inventory/models.py:369
|
||||||
msgid "Car"
|
msgid "Car"
|
||||||
msgstr "السيارة"
|
msgstr "السيارة"
|
||||||
|
|
||||||
#: inventory/models.py:189
|
#: inventory/models.py:190
|
||||||
msgid "Cars"
|
msgid "Cars"
|
||||||
msgstr "السيارات"
|
msgstr "السيارات"
|
||||||
|
|
||||||
#: inventory/models.py:234 templates/inventory/car_detail.html:160
|
#: inventory/models.py:237 templates/inventory/car_detail.html:160
|
||||||
#: templates/inventory/car_finance_form.html:33
|
|
||||||
msgid "Cost Price"
|
msgid "Cost Price"
|
||||||
msgstr "سعر التكلفة"
|
msgstr "سعر التكلفة"
|
||||||
|
|
||||||
#: inventory/models.py:235 templates/inventory/car_detail.html:164
|
#: inventory/models.py:240
|
||||||
#: templates/inventory/car_finance_form.html:40
|
|
||||||
msgid "Profit Margin"
|
msgid "Profit Margin"
|
||||||
msgstr "هامش الربح"
|
msgstr "هامش الربح"
|
||||||
|
|
||||||
#: inventory/models.py:236 templates/inventory/car_detail.html:168
|
#: inventory/models.py:244 templates/inventory/car_detail.html:165
|
||||||
#: templates/inventory/car_finance_form.html:54
|
|
||||||
msgid "Selling Price"
|
msgid "Selling Price"
|
||||||
msgstr "سعر البيع"
|
msgstr "سعر البيع"
|
||||||
|
|
||||||
#: inventory/models.py:237 templates/inventory/car_detail.html:172
|
#: inventory/models.py:247 templates/inventory/car_detail.html:189
|
||||||
#: templates/inventory/car_finance_form.html:47
|
|
||||||
msgid "VAT Rate"
|
|
||||||
msgstr "نسبة ضريبة القيمة المضافة"
|
|
||||||
|
|
||||||
#: inventory/models.py:238 templates/inventory/car_detail.html:176
|
|
||||||
#: templates/inventory/car_finance_form.html:58
|
|
||||||
msgid "VAT Amount"
|
msgid "VAT Amount"
|
||||||
msgstr "مبلغ ضريبة القيمة المضافة"
|
msgstr "مبلغ ضريبة القيمة المضافة"
|
||||||
|
|
||||||
#: inventory/models.py:239 templates/inventory/car_finance_form.html:62
|
#: inventory/models.py:251 templates/inventory/car_detail.html:173
|
||||||
|
msgid "Registration Fee"
|
||||||
|
msgstr "رسوم التسجيل"
|
||||||
|
|
||||||
|
#: inventory/models.py:255 templates/inventory/car_detail.html:169
|
||||||
|
msgid "Administration Fee"
|
||||||
|
msgstr "الرسوم الادارية"
|
||||||
|
|
||||||
|
#: inventory/models.py:259 templates/inventory/car_detail.html:177
|
||||||
|
msgid "Transportation Fee"
|
||||||
|
msgstr "رسوم النقل"
|
||||||
|
|
||||||
|
#: inventory/models.py:263 templates/inventory/car_detail.html:181
|
||||||
|
msgid "Custom Card Fee"
|
||||||
|
msgstr "رسوم البطاقة الجمركية"
|
||||||
|
|
||||||
|
#: inventory/models.py:267 templates/inventory/car_detail.html:185
|
||||||
|
msgid "Discount Amount"
|
||||||
|
msgstr "مبلغ الخصم"
|
||||||
|
|
||||||
|
#: inventory/models.py:271
|
||||||
msgid "Total Amount"
|
msgid "Total Amount"
|
||||||
msgstr "المبلغ الإجمالي"
|
msgstr "المبلغ الإجمالي"
|
||||||
|
|
||||||
#: inventory/models.py:242
|
#: inventory/models.py:275
|
||||||
msgid "Car Financial Details"
|
msgid "Car Financial Details"
|
||||||
msgstr "التفاصيل المالية السيارة"
|
msgstr "تفاصيل المالية للسيارة"
|
||||||
|
|
||||||
#: inventory/models.py:258
|
#: inventory/models.py:280
|
||||||
msgid "Exterior"
|
msgid "Selling price cannot be negative."
|
||||||
msgstr "الخارجي"
|
msgstr "لا يمكن أن يكون سعر البيع سالبًا."
|
||||||
|
|
||||||
#: inventory/models.py:259
|
#: inventory/models.py:282
|
||||||
msgid "Interior"
|
msgid "Discount amount cannot be negative."
|
||||||
msgstr "الداخلي"
|
msgstr "لا يمكن أن يكون مبلغ الخصم سالبًا."
|
||||||
|
|
||||||
#: inventory/models.py:262 templates/dealers/dealer_detail.html:26
|
#: inventory/models.py:284
|
||||||
|
msgid "Discount amount cannot exceed selling price."
|
||||||
|
msgstr "لا يمكن أن يتجاوز مبلغ الخصم سعر البيع."
|
||||||
|
|
||||||
|
#: inventory/models.py:289
|
||||||
|
msgid "Fees cannot be negative."
|
||||||
|
msgstr "لا يمكن أن تكون الرسوم سلبية."
|
||||||
|
|
||||||
|
#: inventory/models.py:304
|
||||||
|
#, python-format
|
||||||
|
msgid "Invalid decimal operation: %s"
|
||||||
|
msgstr "عملية عشرية غير صالحة: %s"
|
||||||
|
|
||||||
|
#: inventory/models.py:313 inventory/models.py:326
|
||||||
|
#: templates/dealers/dealer_detail.html:26
|
||||||
#: templates/vendors/view_vendor.html:39
|
#: templates/vendors/view_vendor.html:39
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/forms/coa.py:16
|
#: venv/lib/python3.11/site-packages/django_ledger/forms/coa.py:16
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/forms/coa.py:37
|
#: venv/lib/python3.11/site-packages/django_ledger/forms/coa.py:37
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "الاسم"
|
msgstr "الاسم"
|
||||||
|
|
||||||
#: inventory/models.py:263 inventory/models.py:325 inventory/models.py:344
|
#: inventory/models.py:314 inventory/models.py:327 inventory/models.py:398
|
||||||
|
#: inventory/models.py:417
|
||||||
msgid "Arabic Name"
|
msgid "Arabic Name"
|
||||||
msgstr "الاسم بالعربية"
|
msgstr "الاسم بالعربية"
|
||||||
|
|
||||||
#: inventory/models.py:264
|
#: inventory/models.py:315 inventory/models.py:328
|
||||||
msgid "RGB"
|
msgid "RGB"
|
||||||
msgstr "آر جي بي"
|
msgstr "آر جي بي"
|
||||||
|
|
||||||
#: inventory/models.py:269 templates/inventory/color_palette.html:83
|
#: inventory/models.py:318 inventory/models.py:319
|
||||||
msgid "Color Type"
|
msgid "Exterior Colors"
|
||||||
msgstr "نوع اللون"
|
msgstr "الألوان الخارجية"
|
||||||
|
|
||||||
#: inventory/models.py:273
|
#: inventory/models.py:331 inventory/models.py:332
|
||||||
|
msgid "Interior Colors"
|
||||||
|
msgstr "الألوان الداخلية"
|
||||||
|
|
||||||
|
#: inventory/models.py:345
|
||||||
msgid "Color"
|
msgid "Color"
|
||||||
msgstr "اللون"
|
msgstr "اللون"
|
||||||
|
|
||||||
#: inventory/models.py:274
|
#: inventory/models.py:346
|
||||||
msgid "Colors"
|
msgid "Colors"
|
||||||
msgstr "الألوان"
|
msgstr "الألوان"
|
||||||
|
|
||||||
#: inventory/models.py:283 templates/inventory/car_detail.html:131
|
#: inventory/models.py:356 templates/inventory/car_detail.html:131
|
||||||
msgid "Custom Number"
|
msgid "Custom Number"
|
||||||
msgstr "رقم البطاقة الجمركية"
|
msgstr "رقم البطاقة الجمركية"
|
||||||
|
|
||||||
#: inventory/models.py:287 templates/inventory/car_detail.html:16
|
#: inventory/models.py:360 templates/inventory/car_detail.html:16
|
||||||
#: templates/inventory/car_detail.html:141
|
#: templates/inventory/car_detail.html:141
|
||||||
msgid "Custom Card"
|
msgid "Custom Card"
|
||||||
msgstr "البطاقة الجمركية"
|
msgstr "البطاقة الجمركية"
|
||||||
|
|
||||||
#: inventory/models.py:288
|
#: inventory/models.py:361
|
||||||
msgid "Custom Cards"
|
msgid "Custom Cards"
|
||||||
msgstr "البطاقات الجمركية"
|
msgstr "البطاقات الجمركية"
|
||||||
|
|
||||||
#: inventory/models.py:297
|
#: inventory/models.py:370
|
||||||
msgid "Plate Number"
|
msgid "Plate Number"
|
||||||
msgstr "رقم اللوحة"
|
msgstr "رقم اللوحة"
|
||||||
|
|
||||||
#: inventory/models.py:298
|
#: inventory/models.py:371
|
||||||
msgid "Text 1"
|
msgid "Text 1"
|
||||||
msgstr "النص 1"
|
msgstr "النص 1"
|
||||||
|
|
||||||
#: inventory/models.py:299
|
#: inventory/models.py:372
|
||||||
msgid "Text 2"
|
msgid "Text 2"
|
||||||
msgstr "النص 2"
|
msgstr "النص 2"
|
||||||
|
|
||||||
#: inventory/models.py:300
|
#: inventory/models.py:373
|
||||||
msgid "Text 3"
|
msgid "Text 3"
|
||||||
msgstr "النص 3"
|
msgstr "النص 3"
|
||||||
|
|
||||||
#: inventory/models.py:301
|
#: inventory/models.py:374
|
||||||
msgid "Registration Date"
|
msgid "Registration Date"
|
||||||
msgstr "تاريخ التسجيل"
|
msgstr "تاريخ التسجيل"
|
||||||
|
|
||||||
#: inventory/models.py:304
|
#: inventory/models.py:377
|
||||||
msgid "Registration"
|
msgid "Registration"
|
||||||
msgstr "التسجيل"
|
msgstr "التسجيل"
|
||||||
|
|
||||||
#: inventory/models.py:305
|
#: inventory/models.py:378
|
||||||
msgid "Registrations"
|
msgid "Registrations"
|
||||||
msgstr "تسجيل السيارات"
|
msgstr "تسجيل السيارات"
|
||||||
|
|
||||||
#: inventory/models.py:313 inventory/models.py:368
|
#: inventory/models.py:386 inventory/models.py:441
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:38
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:38
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/tags/closing_entry_table.html:12
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/tags/closing_entry_table.html:12
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:17
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:17
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "تاريخ الإنشاء"
|
msgstr "تاريخ الإنشاء"
|
||||||
|
|
||||||
#: inventory/models.py:314
|
#: inventory/models.py:387
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:41
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:41
|
||||||
msgid "Updated"
|
msgid "Updated"
|
||||||
msgstr "تم التحديث"
|
msgstr "تم التحديث"
|
||||||
|
|
||||||
#: inventory/models.py:323 inventory/models.py:342
|
#: inventory/models.py:396 inventory/models.py:415
|
||||||
#: templates/dealers/dealer_detail.html:30
|
#: templates/dealers/dealer_detail.html:30
|
||||||
msgid "Commercial Registration Number"
|
msgid "Commercial Registration Number"
|
||||||
msgstr "رقم السجل التجاري"
|
msgstr "رقم السجل التجاري"
|
||||||
|
|
||||||
#: inventory/models.py:324 inventory/models.py:343
|
#: inventory/models.py:397 inventory/models.py:416
|
||||||
#: templates/dealers/dealer_detail.html:34
|
#: templates/dealers/dealer_detail.html:34
|
||||||
msgid "VAT Registration Number"
|
msgid "VAT Registration Number"
|
||||||
msgstr "رقم التسجيل في ضريبة القيمة المضافة"
|
msgstr "رقم التسجيل في ضريبة القيمة المضافة"
|
||||||
|
|
||||||
#: inventory/models.py:326 inventory/models.py:345
|
#: inventory/models.py:399 inventory/models.py:418
|
||||||
msgid "English Name"
|
msgid "English Name"
|
||||||
msgstr "الاسم بالإنجليزية"
|
msgstr "الاسم بالإنجليزية"
|
||||||
|
|
||||||
#: inventory/models.py:327 inventory/models.py:347 inventory/models.py:366
|
#: inventory/models.py:400 inventory/models.py:420 inventory/models.py:439
|
||||||
#: templates/customers/view_customer.html:53
|
#: templates/customers/view_customer.html:53
|
||||||
#: templates/dealers/dealer_detail.html:38
|
#: templates/dealers/dealer_detail.html:38
|
||||||
#: templates/vendors/view_vendor.html:44
|
#: templates/vendors/view_vendor.html:44
|
||||||
@ -286,7 +320,7 @@ msgstr "الاسم بالإنجليزية"
|
|||||||
msgid "Phone Number"
|
msgid "Phone Number"
|
||||||
msgstr "رقم الهاتف"
|
msgstr "رقم الهاتف"
|
||||||
|
|
||||||
#: inventory/models.py:328 inventory/models.py:348 inventory/models.py:367
|
#: inventory/models.py:401 inventory/models.py:421 inventory/models.py:440
|
||||||
#: templates/customers/view_customer.html:54
|
#: templates/customers/view_customer.html:54
|
||||||
#: templates/dealers/dealer_detail.html:42
|
#: templates/dealers/dealer_detail.html:42
|
||||||
#: templates/vendors/view_vendor.html:46
|
#: templates/vendors/view_vendor.html:46
|
||||||
@ -295,47 +329,47 @@ msgstr "رقم الهاتف"
|
|||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "العنوان"
|
msgstr "العنوان"
|
||||||
|
|
||||||
#: inventory/models.py:329
|
#: inventory/models.py:402
|
||||||
msgid "Logo"
|
msgid "Logo"
|
||||||
msgstr "الشعار"
|
msgstr "الشعار"
|
||||||
|
|
||||||
#: inventory/models.py:333
|
#: inventory/models.py:406
|
||||||
msgid "Dealers"
|
msgid "Dealers"
|
||||||
msgstr "المعارض"
|
msgstr "المعارض"
|
||||||
|
|
||||||
#: inventory/models.py:346 templates/vendors/view_vendor.html:43
|
#: inventory/models.py:419 templates/vendors/view_vendor.html:43
|
||||||
msgid "Contact Person"
|
msgid "Contact Person"
|
||||||
msgstr "الشخص المسؤول"
|
msgstr "الشخص المسؤول"
|
||||||
|
|
||||||
#: inventory/models.py:352 templates/header.html:85 templates/header.html:100
|
#: inventory/models.py:425 templates/header.html:85 templates/header.html:100
|
||||||
#: templates/vendors/vendor_form.html:4 templates/vendors/vendors_list.html:4
|
#: templates/vendors/vendor_form.html:4 templates/vendors/vendors_list.html:4
|
||||||
#: templates/vendors/vendors_list.html:5
|
#: templates/vendors/vendors_list.html:5
|
||||||
msgid "Vendors"
|
msgid "Vendors"
|
||||||
msgstr "الموردين"
|
msgstr "الموردين"
|
||||||
|
|
||||||
#: inventory/models.py:361 templates/customers/view_customer.html:46
|
#: inventory/models.py:434 templates/customers/view_customer.html:46
|
||||||
msgid "First Name"
|
msgid "First Name"
|
||||||
msgstr "الاسم الأول"
|
msgstr "الاسم الأول"
|
||||||
|
|
||||||
#: inventory/models.py:362 templates/customers/view_customer.html:47
|
#: inventory/models.py:435 templates/customers/view_customer.html:47
|
||||||
msgid "Middle Name"
|
msgid "Middle Name"
|
||||||
msgstr "اسم الأب"
|
msgstr "اسم الأب"
|
||||||
|
|
||||||
#: inventory/models.py:363 templates/customers/view_customer.html:48
|
#: inventory/models.py:436 templates/customers/view_customer.html:48
|
||||||
msgid "Last Name"
|
msgid "Last Name"
|
||||||
msgstr "اسم العائلة"
|
msgstr "اسم العائلة"
|
||||||
|
|
||||||
#: inventory/models.py:364 templates/customers/view_customer.html:51
|
#: inventory/models.py:437 templates/customers/view_customer.html:51
|
||||||
#: templates/vendors/view_vendor.html:45
|
#: templates/vendors/view_vendor.html:45
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:111
|
#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:111
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "البريد الإلكتروني"
|
msgstr "البريد الإلكتروني"
|
||||||
|
|
||||||
#: inventory/models.py:365 templates/customers/view_customer.html:52
|
#: inventory/models.py:438 templates/customers/view_customer.html:52
|
||||||
msgid "National ID"
|
msgid "National ID"
|
||||||
msgstr "رقم الهوية الوطنية"
|
msgstr "رقم الهوية الوطنية"
|
||||||
|
|
||||||
#: inventory/models.py:371
|
#: inventory/models.py:444
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/customer.py:199
|
#: venv/lib/python3.11/site-packages/django_ledger/models/customer.py:199
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/estimate.py:252
|
#: venv/lib/python3.11/site-packages/django_ledger/models/estimate.py:252
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:318
|
#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:318
|
||||||
@ -344,11 +378,11 @@ msgstr "رقم الهوية الوطنية"
|
|||||||
msgid "Customer"
|
msgid "Customer"
|
||||||
msgstr "العميل"
|
msgstr "العميل"
|
||||||
|
|
||||||
#: inventory/models.py:372
|
#: inventory/models.py:445
|
||||||
msgid "Customers"
|
msgid "Customers"
|
||||||
msgstr "العملاء"
|
msgstr "العملاء"
|
||||||
|
|
||||||
#: inventory/models.py:394
|
#: inventory/models.py:467
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:436
|
#: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:436
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/models/coa.py:152
|
#: venv/lib/python3.11/site-packages/django_ledger/models/coa.py:152
|
||||||
msgid "Chart of Accounts"
|
msgid "Chart of Accounts"
|
||||||
@ -370,116 +404,96 @@ msgstr "نسيت كلمة المرور؟"
|
|||||||
msgid "You are not associated with any dealer."
|
msgid "You are not associated with any dealer."
|
||||||
msgstr "أنت غير مرتبط بأي معرض."
|
msgstr "أنت غير مرتبط بأي معرض."
|
||||||
|
|
||||||
#: inventory/views.py:248 templates/header.html:33 templates/index.html:20
|
#: inventory/views.py:260 templates/header.html:33 templates/index.html:20
|
||||||
#: templates/inventory/car_inventory.html:5
|
#: templates/inventory/car_inventory.html:5
|
||||||
#: templates/inventory/car_inventory.html:7
|
#: templates/inventory/car_inventory.html:7
|
||||||
msgid "inventory"
|
msgid "inventory"
|
||||||
msgstr "المخزون"
|
msgstr "المخزون"
|
||||||
|
|
||||||
#: inventory/views.py:370
|
#: inventory/views.py:401
|
||||||
msgid "Car finance details saved successfully."
|
msgid "Car finance details saved successfully."
|
||||||
msgstr "تم حفظ تفاصيل المالية للسيارة بنجاح."
|
msgstr "تم حفظ تفاصيل المالية للسيارة بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:388
|
#: inventory/views.py:419
|
||||||
msgid "Car finance updated successfully."
|
msgid "Car finance updated successfully."
|
||||||
msgstr "تم تحديث التفاصيل المالية للسيارة بنجاح."
|
msgstr "تم تحديث التفاصيل المالية للسيارة بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:401
|
#: inventory/views.py:432
|
||||||
msgid "Car updated successfully."
|
msgid "Car updated successfully."
|
||||||
msgstr "تم تحديث السيارة بنجاح"
|
msgstr "تم تحديث السيارة بنجاح"
|
||||||
|
|
||||||
#: inventory/views.py:414
|
#: inventory/views.py:445
|
||||||
msgid "Car deleted successfully."
|
msgid "Car deleted successfully."
|
||||||
msgstr "تم حذف السيارة بنجاح."
|
msgstr "تم حذف السيارة بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:434
|
#: inventory/views.py:465
|
||||||
msgid "Custom Card added successfully."
|
msgid "Custom Card added successfully."
|
||||||
msgstr "تم إضافة البطاقة الجمركية بنجاح."
|
msgstr "تم إضافة البطاقة الجمركية بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:452 inventory/views.py:521
|
#: inventory/views.py:474
|
||||||
msgid "Select a Color"
|
|
||||||
msgstr "اختر اللون"
|
|
||||||
|
|
||||||
#: inventory/views.py:457
|
|
||||||
msgid "Select Color Type"
|
|
||||||
msgstr "حدد نوع اللون"
|
|
||||||
|
|
||||||
#: inventory/views.py:485 inventory/views.py:548
|
|
||||||
msgid "Invalid color selection."
|
|
||||||
msgstr "تحديد اللون غير صالح."
|
|
||||||
|
|
||||||
#: inventory/views.py:495
|
|
||||||
msgid "Color added successfully."
|
|
||||||
msgstr "تمت إضافة اللون بنجاح."
|
|
||||||
|
|
||||||
#: inventory/views.py:555
|
|
||||||
msgid "Exterior color updated successfully."
|
|
||||||
msgstr "تم تحديث اللون الخارجي بنجاح."
|
|
||||||
|
|
||||||
#: inventory/views.py:572
|
|
||||||
msgid "This car is already reserved."
|
msgid "This car is already reserved."
|
||||||
msgstr "هذه السيارة محجوزة بالفعل."
|
msgstr "هذه السيارة محجوزة بالفعل."
|
||||||
|
|
||||||
#: inventory/views.py:582
|
#: inventory/views.py:484
|
||||||
msgid "Car reserved successfully."
|
msgid "Car reserved successfully."
|
||||||
msgstr "تم حجز السيارة بنجاح."
|
msgstr "تم حجز السيارة بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:599
|
#: inventory/views.py:501
|
||||||
msgid "Reservation renewed successfully."
|
msgid "Reservation renewed successfully."
|
||||||
msgstr "تم تجديد الحجز بنجاح"
|
msgstr "تم تجديد الحجز بنجاح"
|
||||||
|
|
||||||
#: inventory/views.py:604
|
#: inventory/views.py:506
|
||||||
msgid "Reservation canceled successfully."
|
msgid "Reservation canceled successfully."
|
||||||
msgstr "تم إلغاء الحجز بنجاح."
|
msgstr "تم إلغاء الحجز بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:608
|
#: inventory/views.py:510
|
||||||
msgid "Invalid action."
|
msgid "Invalid action."
|
||||||
msgstr "إجراء غير صالح."
|
msgstr "إجراء غير صالح."
|
||||||
|
|
||||||
#: inventory/views.py:610
|
#: inventory/views.py:512
|
||||||
msgid "Invalid request method."
|
msgid "Invalid request method."
|
||||||
msgstr "طريقة الطلب غير صالحة"
|
msgstr "طريقة الطلب غير صالحة"
|
||||||
|
|
||||||
#: inventory/views.py:632
|
#: inventory/views.py:534
|
||||||
msgid "Dealer created successfully."
|
msgid "Dealer created successfully."
|
||||||
msgstr "تم إنشاء المعرض بنجاح."
|
msgstr "تم إنشاء المعرض بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:643
|
#: inventory/views.py:545
|
||||||
msgid "Dealer updated successfully."
|
msgid "Dealer updated successfully."
|
||||||
msgstr "تم تحديث المعرض بنجاح."
|
msgstr "تم تحديث المعرض بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:653
|
#: inventory/views.py:555
|
||||||
msgid "Dealer deleted successfully."
|
msgid "Dealer deleted successfully."
|
||||||
msgstr "تم حذف المعرض بنجاح."
|
msgstr "تم حذف المعرض بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:659 templates/customers/customer_form.html:4
|
#: inventory/views.py:561 templates/customers/customer_form.html:4
|
||||||
#: templates/customers/customer_list.html:5
|
#: templates/customers/customer_list.html:5
|
||||||
#: templates/customers/customer_list.html:6 templates/header.html:59
|
#: templates/customers/customer_list.html:6 templates/header.html:59
|
||||||
#: templates/header.html:74
|
#: templates/header.html:74
|
||||||
msgid "customers"
|
msgid "customers"
|
||||||
msgstr "العملاء"
|
msgstr "العملاء"
|
||||||
|
|
||||||
#: inventory/views.py:698
|
#: inventory/views.py:600
|
||||||
msgid "Customer created successfully."
|
msgid "Customer created successfully."
|
||||||
msgstr "تم إنشاء العميل بنجاح."
|
msgstr "تم إنشاء العميل بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:714
|
#: inventory/views.py:616
|
||||||
msgid "Customer updated successfully."
|
msgid "Customer updated successfully."
|
||||||
msgstr "تم تحديث العميل بنجاح."
|
msgstr "تم تحديث العميل بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:724
|
#: inventory/views.py:626
|
||||||
msgid "Customer deleted successfully."
|
msgid "Customer deleted successfully."
|
||||||
msgstr "تم حذف العميل بنجاح."
|
msgstr "تم حذف العميل بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:750
|
#: inventory/views.py:652
|
||||||
msgid "Vendor created successfully."
|
msgid "Vendor created successfully."
|
||||||
msgstr "تم إنشاء المورد بنجاح."
|
msgstr "تم إنشاء المورد بنجاح."
|
||||||
|
|
||||||
#: inventory/views.py:766
|
#: inventory/views.py:668
|
||||||
msgid "Vendor updated successfully."
|
msgid "Vendor updated successfully."
|
||||||
msgstr "تم تحديث المورد بنجاح"
|
msgstr "تم تحديث المورد بنجاح"
|
||||||
|
|
||||||
#: inventory/views.py:776
|
#: inventory/views.py:678
|
||||||
msgid "Vendor deleted successfully."
|
msgid "Vendor deleted successfully."
|
||||||
msgstr "تم حذف المورد بنجاح."
|
msgstr "تم حذف المورد بنجاح."
|
||||||
|
|
||||||
@ -583,8 +597,10 @@ msgid "Add Customer"
|
|||||||
msgstr "إضافة عميل"
|
msgstr "إضافة عميل"
|
||||||
|
|
||||||
#: templates/customers/customer_form.html:31
|
#: templates/customers/customer_form.html:31
|
||||||
|
#: templates/inventory/add_colors.html:54
|
||||||
#: templates/inventory/add_custom_card.html:7
|
#: templates/inventory/add_custom_card.html:7
|
||||||
#: templates/inventory/car_edit.html:41 templates/inventory/car_form.html:320
|
#: templates/inventory/car_edit.html:41
|
||||||
|
#: templates/inventory/car_finance_form.html:40
|
||||||
#: templates/inventory/color_palette.html:106
|
#: templates/inventory/color_palette.html:106
|
||||||
#: templates/vendors/vendor_form.html:31
|
#: templates/vendors/vendor_form.html:31
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:81
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:81
|
||||||
@ -598,10 +614,11 @@ msgid "Save"
|
|||||||
msgstr "حفظ"
|
msgstr "حفظ"
|
||||||
|
|
||||||
#: templates/customers/customer_form.html:33
|
#: templates/customers/customer_form.html:33
|
||||||
|
#: templates/inventory/add_colors.html:55
|
||||||
#: templates/inventory/add_custom_card.html:8
|
#: templates/inventory/add_custom_card.html:8
|
||||||
#: templates/inventory/car_confirm_delete.html:14
|
#: templates/inventory/car_confirm_delete.html:14
|
||||||
#: templates/inventory/car_detail.html:266
|
#: templates/inventory/car_detail.html:282
|
||||||
#: templates/inventory/car_finance_form.html:68
|
#: templates/inventory/car_finance_form.html:41
|
||||||
#: templates/inventory/color_palette.html:107
|
#: templates/inventory/color_palette.html:107
|
||||||
#: templates/inventory/reserve_car.html:30
|
#: templates/inventory/reserve_car.html:30
|
||||||
#: templates/vendors/vendor_form.html:33
|
#: templates/vendors/vendor_form.html:33
|
||||||
@ -616,7 +633,7 @@ msgid "Cancel"
|
|||||||
msgstr "إلغاء"
|
msgstr "إلغاء"
|
||||||
|
|
||||||
#: templates/customers/customer_list.html:20
|
#: templates/customers/customer_list.html:20
|
||||||
#: templates/inventory/car_inventory.html:29
|
#: templates/inventory/car_inventory.html:31
|
||||||
#: templates/inventory/car_list.html:70 templates/vendors/vendors_list.html:21
|
#: templates/inventory/car_list.html:70 templates/vendors/vendors_list.html:21
|
||||||
msgid "search"
|
msgid "search"
|
||||||
msgstr "بحث"
|
msgstr "بحث"
|
||||||
@ -644,7 +661,7 @@ msgstr "الإجراءات"
|
|||||||
|
|
||||||
#: templates/customers/customer_list.html:59
|
#: templates/customers/customer_list.html:59
|
||||||
#: templates/inventory/car_detail.html:124
|
#: templates/inventory/car_detail.html:124
|
||||||
#: templates/inventory/car_inventory.html:62
|
#: templates/inventory/car_inventory.html:75
|
||||||
#: templates/vendors/vendors_list.html:65
|
#: templates/vendors/vendors_list.html:65
|
||||||
msgid "view"
|
msgid "view"
|
||||||
msgstr "عرض"
|
msgstr "عرض"
|
||||||
@ -674,8 +691,7 @@ msgid "Customer Details"
|
|||||||
msgstr "تفاصيل العميل"
|
msgstr "تفاصيل العميل"
|
||||||
|
|
||||||
#: templates/customers/view_customer.html:61
|
#: templates/customers/view_customer.html:61
|
||||||
#: templates/inventory/car_detail.html:217
|
#: templates/inventory/car_detail.html:307
|
||||||
#: templates/inventory/car_detail.html:291
|
|
||||||
#: templates/vendors/view_vendor.html:48
|
#: templates/vendors/view_vendor.html:48
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/customer/includes/card_customer.html:28
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/customer/includes/card_customer.html:28
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:83
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:83
|
||||||
@ -717,7 +733,7 @@ msgid "Delete"
|
|||||||
msgstr "حذف"
|
msgstr "حذف"
|
||||||
|
|
||||||
#: templates/customers/view_customer.html:72
|
#: templates/customers/view_customer.html:72
|
||||||
#: templates/inventory/car_detail.html:293
|
#: templates/inventory/car_detail.html:309
|
||||||
msgid "Back to List"
|
msgid "Back to List"
|
||||||
msgstr "العودة إلى القائمة"
|
msgstr "العودة إلى القائمة"
|
||||||
|
|
||||||
@ -941,7 +957,7 @@ msgid "View your best-selling cars."
|
|||||||
msgstr "عرض السيارات الأكثر مبيعاً."
|
msgstr "عرض السيارات الأكثر مبيعاً."
|
||||||
|
|
||||||
#: templates/index.html:151 templates/inventory/car_detail.html:74
|
#: templates/index.html:151 templates/inventory/car_detail.html:74
|
||||||
#: templates/inventory/car_form.html:155 templates/inventory/car_list.html:97
|
#: templates/inventory/car_form.html:159 templates/inventory/car_list.html:97
|
||||||
msgid "model"
|
msgid "model"
|
||||||
msgstr "الموديل"
|
msgstr "الموديل"
|
||||||
|
|
||||||
@ -1000,13 +1016,31 @@ msgstr "الجمعة"
|
|||||||
msgid "Sat"
|
msgid "Sat"
|
||||||
msgstr "السبت"
|
msgstr "السبت"
|
||||||
|
|
||||||
|
#: templates/inventory/add_colors.html:5
|
||||||
|
msgid "Add Colors"
|
||||||
|
msgstr "إضافة لون"
|
||||||
|
|
||||||
|
#: templates/inventory/add_colors.html:6
|
||||||
|
msgid "Select exterior and interior colors for"
|
||||||
|
msgstr "اختر الألوان الخارجية والداخلية لـ"
|
||||||
|
|
||||||
|
#: templates/inventory/add_colors.html:13
|
||||||
|
#: templates/inventory/car_detail.html:219
|
||||||
|
msgid "Exterior"
|
||||||
|
msgstr "الخارجي"
|
||||||
|
|
||||||
|
#: templates/inventory/add_colors.html:32
|
||||||
|
#: templates/inventory/car_detail.html:228
|
||||||
|
msgid "Interior"
|
||||||
|
msgstr "الداخلي"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:6 templates/inventory/car_detail.html:58
|
#: templates/inventory/car_detail.html:6 templates/inventory/car_detail.html:58
|
||||||
msgid "Car Details"
|
msgid "Car Details"
|
||||||
msgstr "تفاصيل السيارة"
|
msgstr "تفاصيل السيارة"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:37
|
#: templates/inventory/car_detail.html:37
|
||||||
#: templates/inventory/car_detail.html:117 templates/inventory/car_form.html:37
|
#: templates/inventory/car_detail.html:117 templates/inventory/car_form.html:37
|
||||||
#: templates/inventory/car_form.html:316 templates/inventory/car_list.html:47
|
#: templates/inventory/car_form.html:322 templates/inventory/car_list.html:47
|
||||||
#: templates/inventory/car_list.html:221
|
#: templates/inventory/car_list.html:221
|
||||||
msgid "specifications"
|
msgid "specifications"
|
||||||
msgstr "المواصفات"
|
msgstr "المواصفات"
|
||||||
@ -1015,7 +1049,7 @@ msgstr "المواصفات"
|
|||||||
msgid "year"
|
msgid "year"
|
||||||
msgstr "السنة"
|
msgstr "السنة"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:69 templates/inventory/car_form.html:137
|
#: templates/inventory/car_detail.html:69 templates/inventory/car_form.html:140
|
||||||
#: templates/inventory/car_list.html:79
|
#: templates/inventory/car_list.html:79
|
||||||
msgid "make"
|
msgid "make"
|
||||||
msgstr "الصانع"
|
msgstr "الصانع"
|
||||||
@ -1024,7 +1058,7 @@ msgstr "الصانع"
|
|||||||
msgid "series"
|
msgid "series"
|
||||||
msgstr "السلسلة"
|
msgstr "السلسلة"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:82 templates/inventory/car_form.html:199
|
#: templates/inventory/car_detail.html:82 templates/inventory/car_form.html:204
|
||||||
#: templates/inventory/car_list.html:141
|
#: templates/inventory/car_list.html:141
|
||||||
msgid "trim"
|
msgid "trim"
|
||||||
msgstr "الفئة"
|
msgstr "الفئة"
|
||||||
@ -1041,7 +1075,7 @@ msgstr "إضافة"
|
|||||||
msgid "Financial Details"
|
msgid "Financial Details"
|
||||||
msgstr "التفاصيل المالية"
|
msgstr "التفاصيل المالية"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:180
|
#: templates/inventory/car_detail.html:193
|
||||||
#: templates/inventory/inventory_stats.html:61
|
#: templates/inventory/inventory_stats.html:61
|
||||||
#: 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:98
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:127
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:127
|
||||||
@ -1060,44 +1094,44 @@ msgstr "التفاصيل المالية"
|
|||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "الإجمالي"
|
msgstr "الإجمالي"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:187
|
#: templates/inventory/car_detail.html:200
|
||||||
msgid "Edit Finance Details"
|
msgid "Edit Finance Details"
|
||||||
msgstr "تعديل التفاصيل المالية"
|
msgstr "تعديل التفاصيل المالية"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:191
|
#: templates/inventory/car_detail.html:204
|
||||||
msgid "No finance details available."
|
msgid "No finance details available."
|
||||||
msgstr "لا توجد تفاصيل مالية متاحة."
|
msgstr "لا توجد تفاصيل مالية متاحة."
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:194
|
#: templates/inventory/car_detail.html:207
|
||||||
msgid "Add Finance Details"
|
msgid "Add Finance Details"
|
||||||
msgstr "إضافة التفاصيل المالية"
|
msgstr "إضافة التفاصيل المالية"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:200
|
#: templates/inventory/car_detail.html:213
|
||||||
msgid "Colors Details"
|
msgid "Colors Details"
|
||||||
msgstr "تفاصيل الألوان"
|
msgstr "تفاصيل الألوان"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:224
|
#: templates/inventory/car_detail.html:240
|
||||||
msgid "No colors available for this car."
|
msgid "No colors available for this car."
|
||||||
msgstr "لا تتوفر ألوان لهذه السيارة."
|
msgstr "لا تتوفر ألوان لهذه السيارة."
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:231
|
#: templates/inventory/car_detail.html:247
|
||||||
msgid "Get Colors"
|
msgid "Get Colors"
|
||||||
msgstr "الحصول على الألوان"
|
msgstr "الحصول على الألوان"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:238
|
#: templates/inventory/car_detail.html:254
|
||||||
msgid "Reservations Details"
|
msgid "Reservations Details"
|
||||||
msgstr "تفاصيل الحجز"
|
msgstr "تفاصيل الحجز"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:243
|
#: templates/inventory/car_detail.html:259
|
||||||
msgid "Reserved By"
|
msgid "Reserved By"
|
||||||
msgstr "محجوز بواسطة"
|
msgstr "محجوز بواسطة"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:244
|
#: templates/inventory/car_detail.html:260
|
||||||
msgid "Expires At"
|
msgid "Expires At"
|
||||||
msgstr "ينتهي في"
|
msgstr "ينتهي في"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:245
|
#: templates/inventory/car_detail.html:261
|
||||||
#: templates/inventory/car_inventory.html:44
|
#: templates/inventory/car_inventory.html:57
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/account_txs_table.html:29
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/account_txs_table.html:29
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:29
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:29
|
||||||
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:92
|
#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:92
|
||||||
@ -1124,27 +1158,27 @@ msgstr "ينتهي في"
|
|||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "الإجراءات"
|
msgstr "الإجراءات"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:260
|
#: templates/inventory/car_detail.html:276
|
||||||
msgid "renew"
|
msgid "renew"
|
||||||
msgstr "تجديد"
|
msgstr "تجديد"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:277
|
#: templates/inventory/car_detail.html:293
|
||||||
#: templates/inventory/reserve_car.html:29
|
#: templates/inventory/reserve_car.html:29
|
||||||
msgid "Reserve"
|
msgid "Reserve"
|
||||||
msgstr "حجز"
|
msgstr "حجز"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:289
|
#: templates/inventory/car_detail.html:305
|
||||||
#: templates/inventory/transfer_car.html:23
|
#: templates/inventory/transfer_car.html:23
|
||||||
msgid "transfer"
|
msgid "transfer"
|
||||||
msgstr "نقل"
|
msgstr "نقل"
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:378
|
#: templates/inventory/car_detail.html:394
|
||||||
#: templates/inventory/car_list.html:542
|
#: templates/inventory/car_list.html:542
|
||||||
#: templates/partials/specifications_modal.html:11
|
#: templates/partials/specifications_modal.html:11
|
||||||
msgid "No specifications available."
|
msgid "No specifications available."
|
||||||
msgstr "لا توجد مواصفات متاحة."
|
msgstr "لا توجد مواصفات متاحة."
|
||||||
|
|
||||||
#: templates/inventory/car_detail.html:382
|
#: templates/inventory/car_detail.html:398
|
||||||
#: templates/inventory/car_list.html:546
|
#: templates/inventory/car_list.html:546
|
||||||
msgid "Error loading specifications."
|
msgid "Error loading specifications."
|
||||||
msgstr "حدث خطأ أثناء تحميل المواصفات."
|
msgstr "حدث خطأ أثناء تحميل المواصفات."
|
||||||
@ -1153,30 +1187,14 @@ msgstr "حدث خطأ أثناء تحميل المواصفات."
|
|||||||
msgid "Edit Car"
|
msgid "Edit Car"
|
||||||
msgstr "تعديل السيارة"
|
msgstr "تعديل السيارة"
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:5
|
#: templates/inventory/car_finance_form.html:6
|
||||||
msgid "Car Finance Details"
|
msgid "Car Finance Details"
|
||||||
msgstr "التفاصيل المالية السيارة"
|
msgstr "التفاصيل المالية السيارة"
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:9
|
#: templates/inventory/car_finance_form.html:10
|
||||||
msgid "Finance Details for"
|
msgid "Finance Details for"
|
||||||
msgstr "التفاصيل المالية لـ"
|
msgstr "التفاصيل المالية لـ"
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:36
|
|
||||||
msgid "Please provide a valid cost price."
|
|
||||||
msgstr "يرجى تقديم سعر تكلفة صالح."
|
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:43
|
|
||||||
msgid "Please provide a profit margin between 0 and 100."
|
|
||||||
msgstr "يجب أن يكون هامش الربح بين 0 و 100"
|
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:50
|
|
||||||
msgid "Please provide a valid VAT rate."
|
|
||||||
msgstr "يرجى تقديم معدل صالح لضريبة القيمة المضافة."
|
|
||||||
|
|
||||||
#: templates/inventory/car_finance_form.html:67
|
|
||||||
msgid "Save Finance Details"
|
|
||||||
msgstr "حفظ التفاصيل المالية"
|
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:42 templates/inventory/car_form.html:58
|
#: templates/inventory/car_form.html:42 templates/inventory/car_form.html:58
|
||||||
#: templates/partials/scanner_modal.html:6
|
#: templates/partials/scanner_modal.html:6
|
||||||
#: templates/partials/specifications_modal.html:8
|
#: templates/partials/specifications_modal.html:8
|
||||||
@ -1190,7 +1208,7 @@ msgstr "الماسح الضوئي"
|
|||||||
#: templates/inventory/car_form.html:62
|
#: templates/inventory/car_form.html:62
|
||||||
#: templates/partials/scanner_modal.html:10
|
#: templates/partials/scanner_modal.html:10
|
||||||
msgid "VIN will appear here."
|
msgid "VIN will appear here."
|
||||||
msgstr ""
|
msgstr "رقم الهيكل سيظهر هنا."
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:63
|
#: templates/inventory/car_form.html:63
|
||||||
#: templates/partials/scanner_modal.html:11
|
#: templates/partials/scanner_modal.html:11
|
||||||
@ -1201,34 +1219,42 @@ msgstr "التعرف الآلي على الحروف"
|
|||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "بحث"
|
msgstr "بحث"
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:160 templates/inventory/car_form.html:182
|
#: templates/inventory/car_form.html:165 templates/inventory/car_form.html:187
|
||||||
#: templates/inventory/car_form.html:204 templates/inventory/car_form.html:498
|
#: templates/inventory/car_form.html:209 templates/inventory/car_form.html:519
|
||||||
#: templates/inventory/car_form.html:515 templates/inventory/car_form.html:516
|
#: templates/inventory/car_form.html:536 templates/inventory/car_form.html:537
|
||||||
#: templates/inventory/car_form.html:534
|
#: templates/inventory/car_form.html:555
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr "اختيار"
|
msgstr "اختيار"
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:381
|
#: templates/inventory/car_form.html:329
|
||||||
|
msgid "Save and Add Another"
|
||||||
|
msgstr "حفظ وإضافة آخر"
|
||||||
|
|
||||||
|
#: templates/inventory/car_form.html:335
|
||||||
|
msgid "Save and Go to Inventory"
|
||||||
|
msgstr "حفظ والانتقال إلى المخزون"
|
||||||
|
|
||||||
|
#: templates/inventory/car_form.html:399
|
||||||
msgid "Please Wait"
|
msgid "Please Wait"
|
||||||
msgstr "الرجاء الإنتظار"
|
msgstr "الرجاء الإنتظار"
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:382
|
#: templates/inventory/car_form.html:400
|
||||||
msgid "Loading"
|
msgid "Loading"
|
||||||
msgstr "تحميل"
|
msgstr "تحميل"
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:413
|
#: templates/inventory/car_form.html:431
|
||||||
msgid "Please enter a valid VIN."
|
msgid "Please enter a valid VIN."
|
||||||
msgstr "الرجاء إدخال رقم هيكل صالح مكون من 17 حرفًا."
|
msgstr "الرجاء إدخال رقم هيكل صالح مكون من 17 حرفًا."
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:429
|
#: templates/inventory/car_form.html:447
|
||||||
msgid "Failed to decode VIN."
|
msgid "Failed to decode VIN."
|
||||||
msgstr "فشل في فك تشفير رقم الهيكل"
|
msgstr "فشل في فك تشفير رقم الهيكل"
|
||||||
|
|
||||||
#: templates/inventory/car_form.html:434
|
#: templates/inventory/car_form.html:452
|
||||||
msgid "An error occurred while decoding the VIN."
|
msgid "An error occurred while decoding the VIN."
|
||||||
msgstr "حدث خطأ أثناء فك تشفير الهيكل"
|
msgstr "حدث خطأ أثناء فك تشفير الهيكل"
|
||||||
|
|
||||||
#: templates/inventory/car_inventory.html:67
|
#: templates/inventory/car_inventory.html:80
|
||||||
msgid "No cars available."
|
msgid "No cars available."
|
||||||
msgstr "لا توجد سيارات متاحة."
|
msgstr "لا توجد سيارات متاحة."
|
||||||
|
|
||||||
@ -1294,6 +1320,10 @@ msgstr "تحديث اللون"
|
|||||||
msgid "Add Color for"
|
msgid "Add Color for"
|
||||||
msgstr "إضافة لون الى"
|
msgstr "إضافة لون الى"
|
||||||
|
|
||||||
|
#: templates/inventory/color_palette.html:83
|
||||||
|
msgid "Color Type"
|
||||||
|
msgstr "نوع اللون"
|
||||||
|
|
||||||
#: templates/inventory/inventory_stats.html:5
|
#: templates/inventory/inventory_stats.html:5
|
||||||
msgid "Inventory Statistics"
|
msgid "Inventory Statistics"
|
||||||
msgstr "إحصائيات المخزون"
|
msgstr "إحصائيات المخزون"
|
||||||
|
|||||||
BIN
static/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
BIN
static/images/logos/.DS_Store
vendored
BIN
static/images/logos/Alamjdouie-Hyundai-Auto.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
static/images/logos/suppliers/.DS_Store
vendored
Normal file
BIN
static/images/logos/suppliers/Alamjdouie-Hyundai-01.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
static/images/logos/suppliers/Alamjdouie-Hyundai-Auto_١.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/logos/suppliers/Aljomaih-Automotive-Company-2.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
static/images/logos/suppliers/Aljomaih-Automotive-Company-3.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/logos/users/marwan-company_b9ATueB.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
static/images/logos/vendors/Alamjdouie-Hyundai-01.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
static/images/logos/vendors/Alamjdouie-Hyundai-Auto.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
static/images/logos/vendors/Alamjdouie-Hyundai-Auto_3Z7TlPQ.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
static/images/logos/vendors/Alamjdouie-Hyundai-Auto_IybmIRQ.png
vendored
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/logos/vendors/Aljomaih-Automotive-Company-2.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
static/images/logos/vendors/Aljomaih-Automotive-Company-3.png
vendored
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/logos/vendors/Aljomaih-Automotive-Company.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/logos/vendors/Aljomaih-Automotive-Company_PrrrHZs.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
templates/.DS_Store
vendored
@ -30,7 +30,10 @@
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
small, .small {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
.btn {
|
.btn {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
@ -45,7 +48,7 @@
|
|||||||
<!-- Main content goes here -->
|
<!-- Main content goes here -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
|
||||||
|
|
||||||
<!-- JavaScript Files -->
|
<!-- JavaScript Files -->
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
<footer class="mt-3 mb-0 fixed-bottom">
|
|
||||||
<div class="container text-center">
|
|
||||||
<div class="text-body-secondary fw-light">
|
|
||||||
<span>© 2024</span> <span>{% trans 'All right reserved' %}:</span> <a class="text-muted" href="https://tenhal.sa">{% trans 'Tenhal' %}</a><span> </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
61
templates/inventory/add_colors.html
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h5 class="text-center">{% trans "Add Colors" %}</h5>
|
||||||
|
<p class="text-center">{% trans "Select exterior and interior colors for" %} {{ car.id_car_make.get_local_name }} {{ car.id_car_model.get_local_name }}</p>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<!-- Exterior Colors -->
|
||||||
|
<div class="row g-4">
|
||||||
|
<p class="fs-5 mb-0">{% trans 'Exterior Colors' %}</p>
|
||||||
|
{% for color in form.fields.exterior.queryset %}
|
||||||
|
<div class="col-lg-4 col-xl-2">
|
||||||
|
<div class="card rounded shadow">
|
||||||
|
<div class="card-body" style="background-color: rgb({{ color.rgb }});">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
name="exterior"
|
||||||
|
id="id_exterior" value="{{ color.id }}" >
|
||||||
|
<label class="form-check-label" for="id_exterior">
|
||||||
|
<small>{{ color.get_local_name }}</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<!-- Interior Colors -->
|
||||||
|
<p class="fs-5 mt-3 mb-0">{% trans 'Interior Colors' %}</p>
|
||||||
|
{% for color in form.fields.interior.queryset %}
|
||||||
|
<div class="col-lg-4 col-xl-2">
|
||||||
|
<div class="card rounded shadow">
|
||||||
|
<div class="card-body" style="background-color: rgb({{ color.rgb }});">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
name="interior"
|
||||||
|
id="id_interior" value="{{ color.id }}" >
|
||||||
|
<label class="form-check-label" for="id_interior">
|
||||||
|
<small>{{ color.get_local_name }}</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Save and Cancel Buttons -->
|
||||||
|
<div class="row g-1 mt-4">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="submit" class="btn btn-success btn-sm me-1">{% trans "Save" %}</button>
|
||||||
|
<a href="{% url 'car_detail' car.pk %}" class="btn btn-secondary btn-sm">{% trans "Cancel" %}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -31,7 +31,7 @@
|
|||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||||
<div class="modal-content glossy-modal">
|
<div class="modal-content glossy-modal">
|
||||||
<div class="modal-header bg-success">
|
<div class="modal-header bg-primary text-light">
|
||||||
<h5 class="modal-title"
|
<h5 class="modal-title"
|
||||||
id="specificationsModalLabel">
|
id="specificationsModalLabel">
|
||||||
{% trans 'specifications'|upper %}
|
{% trans 'specifications'|upper %}
|
||||||
@ -152,7 +152,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-xl-6">
|
<div class="col-lg-6 col-xl-6">
|
||||||
|
|
||||||
<p class="fs-5">{% trans 'Financial Details' %}</p>
|
<p class="fs-5">{% trans 'Financial Details' %}</p>
|
||||||
{% if car.finances.exists %} {% for finance in car.finances.all %}
|
{% if car.finances.exists %} {% for finance in car.finances.all %}
|
||||||
<table class="table table-sm table-responsive mb-3 align-middle">
|
<table class="table table-sm table-responsive mb-3 align-middle">
|
||||||
@ -160,17 +159,29 @@
|
|||||||
<th>{% trans "Cost Price" %}</th>
|
<th>{% trans "Cost Price" %}</th>
|
||||||
<td>{{ finance.cost_price }}</td>
|
<td>{{ finance.cost_price }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>{% trans "Profit Margin" %}</th>
|
|
||||||
<td>{{ finance.profit_margin|percentage }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Selling Price" %}</th>
|
<th>{% trans "Selling Price" %}</th>
|
||||||
<td>{{ finance.selling_price }}</td>
|
<td>{{ finance.selling_price }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VAT Rate" %}</th>
|
<td><small class="ms-5">{% trans "Administration Fee" %}</small></td>
|
||||||
<td>{{ finance.vat_rate|percentage }}</td>
|
<td><small>{{ finance.administration_fee }}</small></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><small class="ms-5">{% trans "Registration Fee" %}</small></td>
|
||||||
|
<td><small>{{ finance.registration_fee }}</small></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><small class="ms-5">{% trans "Transportation Fee" %}</small></td>
|
||||||
|
<td><small>{{ finance.transportation_fee }}</small></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><small class="ms-5">{% trans "Custom Card Fee" %}</small></td>
|
||||||
|
<td><small>{{ finance.custom_card_fee }}</small></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Discount Amount" %}</th>
|
||||||
|
<td>{{ finance.discount_amount }} - </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VAT Amount" %}</th>
|
<th>{% trans "VAT Amount" %}</th>
|
||||||
@ -200,25 +211,28 @@
|
|||||||
<p class="fs-5 mt-2">{% trans 'Colors Details' %}</p>
|
<p class="fs-5 mt-2">{% trans 'Colors Details' %}</p>
|
||||||
<table class="table table-sm table-responsive align-middle">
|
<table class="table table-sm table-responsive align-middle">
|
||||||
<tbody class=" align-middle">
|
<tbody class=" align-middle">
|
||||||
{% for color in car.colors.all %}
|
{% if car.colors.exists %}
|
||||||
|
{% for color in car.colors.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<th>{% trans 'Exterior' %}</th>
|
||||||
{{ color.get_color_type_display }}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span>{{ color.name.get_local_name }}</span>
|
<span>{{ color.exterior.get_local_name }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
<div class="text-end" style="width: 150px; height: 32px; background-color: rgb({{ color.rgb }}); border-radius: 5px; border-style: solid; border-color: #000;"></div>
|
<div class="text-end" style="width: 32px; height: 32px; background-color: rgb({{ color.exterior.rgb }}); border-radius: 50px; border-style: solid; border-color: #000;"></div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">
|
|
||||||
<a class="btn btn-warning btn-sm"
|
|
||||||
href="{% url 'color_update' car.pk color.pk %}">
|
|
||||||
{% trans 'Edit' %}
|
|
||||||
<i class="bi bi-arrow-repeat"></i></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
<tr>
|
||||||
|
<th>{% trans 'Interior' %}</th>
|
||||||
|
<td>
|
||||||
|
<span>{{ color.interior.get_local_name }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
<div class="text-end" style="width: 32px; height: 32px; background-color: rgb({{ color.interior.rgb }}); border-radius: 50px; border-style: solid; border-color: #000;"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
{% trans "No colors available for this car." %}
|
{% trans "No colors available for this car." %}
|
||||||
@ -232,7 +246,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="fs-5 mt-2">{% trans 'Reservations Details' %}</p>
|
<p class="fs-5 mt-2">{% trans 'Reservations Details' %}</p>
|
||||||
@ -250,22 +264,26 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ reservation.reserved_by.username }}</td>
|
<td>{{ reservation.reserved_by.username }}</td>
|
||||||
<td>{{ reservation.reserved_until }}</td>
|
<td>{{ reservation.reserved_until }}</td>
|
||||||
<td colspan="2">
|
<td>
|
||||||
|
{% if reservation.is_active %}
|
||||||
<form method="post" action="{% url 'reservations' reservation.id %}">
|
<form method="post" action="{% url 'reservations' reservation.id %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
name="action"
|
name="action"
|
||||||
value="renew"
|
value="renew"
|
||||||
class="btn btn-sm btn-primary">
|
class="btn btn-sm btn-success">
|
||||||
<small>{% trans "renew" %}</small>
|
<small>{% trans "Renew" %}</small>
|
||||||
</button>
|
</button>
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
name="action"
|
name="action"
|
||||||
value="cancel"
|
value="cancel"
|
||||||
class="btn btn-sm btn-danger">
|
class="btn btn-sm btn-secondary">
|
||||||
<small>{% trans "Cancel" %}</small>
|
<small>{% trans "Cancel" %}</small>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-danger" style="width: 120px;">{% trans "Expired" %}</span>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load crispy_forms_filters %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
@ -25,87 +26,25 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<form method="post" class="needs-validation" novalidate>
|
||||||
|
<div class="row g-1">
|
||||||
|
<div class="col-lg-4 col-xl-12">
|
||||||
|
|
||||||
<form method="post" class="needs-validation" novalidate>
|
{% csrf_token %}
|
||||||
{% csrf_token %}
|
|
||||||
<div class="row g-1">
|
{{ form|crispy }}
|
||||||
<div class="col-lg-4 col-xl-2">
|
|
||||||
<label for="id_cost_price" class="form-label">{% trans 'Cost Price' %}</label>
|
|
||||||
{{ form.cost_price|add_class:"form-control form-control-sm" }}
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{% trans 'Please provide a valid cost price.' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-4 col-xl-2">
|
|
||||||
<label for="id_profit_margin_percentage" class="form-label">{% trans 'Profit Margin' %} (%)</label>
|
|
||||||
<input type="number" name="profit_margin_percentage" id="id_profit_margin_percentage" class="form-control form-control-sm" min="0" max="100" step="1" required>
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{% trans 'Please provide a profit margin between 0 and 100.' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-4 col-xl-2">
|
|
||||||
<label for="id_vat_rate_percentage" class="form-label">{% trans 'VAT Rate' %} (%)</label>
|
|
||||||
<input type="number" name="vat_rate_percentage" id="id_vat_rate_percentage" class="form-control form-control-sm" min="0" max="100" step="1" required>
|
|
||||||
<div class="invalid-feedback">
|
|
||||||
{% trans 'Please provide a valid VAT rate.' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-2 col-xl-12">
|
|
||||||
<label class="form-label">{% trans 'Selling Price' %}</label>
|
|
||||||
<input type="text" class="form-control" id="selling_price_display" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-2 col-xl-12">
|
|
||||||
<label class="form-label">{% trans 'VAT Amount' %}</label>
|
|
||||||
<input type="text" class="form-control" id="vat_amount_display" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-2 col-xl-12">
|
|
||||||
<label class="form-label">{% trans 'Total Amount' %}</label>
|
|
||||||
<input type="text" class="form-control" id="total_display" readonly>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-end mt-4">
|
</div>
|
||||||
<button type="submit" class="btn btn-sm btn-primary me-1">{% trans "Save Finance Details" %}</button>
|
<div class="row g-1">
|
||||||
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger">{% trans "Cancel" %}</a>
|
<div class="btn-group">
|
||||||
|
<button type="submit" class="btn btn-sm btn-success me-1">{% trans "Save" %}</button>
|
||||||
|
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger">{% trans "Cancel" %}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- JavaScript Section -->
|
<!-- JavaScript Section -->
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
const costPriceInput = document.getElementById('id_cost_price');
|
|
||||||
const profitMarginInput = document.getElementById('id_profit_margin_percentage');
|
|
||||||
const vatRateInput = document.getElementById('id_vat_rate_percentage');
|
|
||||||
|
|
||||||
const sellingPriceDisplay = document.getElementById('selling_price_display');
|
|
||||||
const vatAmountDisplay = document.getElementById('vat_amount_display');
|
|
||||||
const totalDisplay = document.getElementById('total_display');
|
|
||||||
|
|
||||||
function calculateFinanceDetails() {
|
|
||||||
const costPrice = parseFloat(costPriceInput.value) || 0;
|
|
||||||
const profitMarginPercentage = parseFloat(profitMarginInput.value) || 0;
|
|
||||||
const vatRatePercentage = parseFloat(vatRateInput.value) || 0;
|
|
||||||
|
|
||||||
const profitMarginDecimal = profitMarginPercentage / 100;
|
|
||||||
const vatRateDecimal = vatRatePercentage / 100;
|
|
||||||
|
|
||||||
const sellingPrice = costPrice * (1 + profitMarginDecimal);
|
|
||||||
const vatAmount = sellingPrice * vatRateDecimal;
|
|
||||||
const totalAmount = sellingPrice + vatAmount;
|
|
||||||
|
|
||||||
sellingPriceDisplay.value = sellingPrice.toFixed(2);
|
|
||||||
vatAmountDisplay.value = vatAmount.toFixed(2);
|
|
||||||
totalDisplay.value = totalAmount.toFixed(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial calculation
|
|
||||||
calculateFinanceDetails();
|
|
||||||
|
|
||||||
// Event listeners
|
|
||||||
costPriceInput.addEventListener('input', calculateFinanceDetails);
|
|
||||||
profitMarginInput.addEventListener('input', calculateFinanceDetails);
|
|
||||||
vatRateInput.addEventListener('input', calculateFinanceDetails);
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -112,10 +112,12 @@
|
|||||||
<div class="col-lg-4 col-xl-3">
|
<div class="col-lg-4 col-xl-3">
|
||||||
<div class="card h-100 border-1 rounded shadow">
|
<div class="card h-100 border-1 rounded shadow">
|
||||||
<div class="card-body" id="year-container">
|
<div class="card-body" id="year-container">
|
||||||
|
|
||||||
<label class="form-label"
|
<label class="form-label"
|
||||||
for="{{ form.year.id_for_label }}">
|
for="{{ form.year.id_for_label }}">
|
||||||
{% trans 'Year' %}:
|
{% trans 'Year' %}:
|
||||||
</label>
|
</label>
|
||||||
|
<span class="text-success fw-bold" id="year-check"></span>
|
||||||
<input type="number"
|
<input type="number"
|
||||||
class="form-control form-control-sm"
|
class="form-control form-control-sm"
|
||||||
id="{{ form.year.id_for_label }}"
|
id="{{ form.year.id_for_label }}"
|
||||||
@ -132,10 +134,12 @@
|
|||||||
<div class="col-lg-4 col-xl-3">
|
<div class="col-lg-4 col-xl-3">
|
||||||
<div class="card h-100 border-1 rounded shadow">
|
<div class="card h-100 border-1 rounded shadow">
|
||||||
<div id="make-container" class="card-body">
|
<div id="make-container" class="card-body">
|
||||||
|
<div class="status"></div>
|
||||||
<label class="form-label"
|
<label class="form-label"
|
||||||
for="{{ form.id_car_make.id_for_label }}">
|
for="{{ form.id_car_make.id_for_label }}">
|
||||||
{% trans 'make'|capfirst %}:
|
{% trans 'make'|capfirst %}:
|
||||||
</label>
|
</label>
|
||||||
|
<span class="text-success fw-bold" id="make-check"></span>
|
||||||
{{ form.id_car_make|add_class:"form-select form-select-sm" }}
|
{{ form.id_car_make|add_class:"form-select form-select-sm" }}
|
||||||
{% if form.id_car_make.errors %}
|
{% if form.id_car_make.errors %}
|
||||||
<div class="text-danger small">
|
<div class="text-danger small">
|
||||||
@ -154,6 +158,7 @@
|
|||||||
for="{{ form.id_car_model.id_for_label }}">
|
for="{{ form.id_car_model.id_for_label }}">
|
||||||
{% trans 'model'|capfirst %}:
|
{% trans 'model'|capfirst %}:
|
||||||
</label>
|
</label>
|
||||||
|
<span class="text-success fw-bold" id="model-check"></span>
|
||||||
<select class="form-select form-select-sm"
|
<select class="form-select form-select-sm"
|
||||||
id="{{ form.id_car_model.id_for_label }}"
|
id="{{ form.id_car_model.id_for_label }}"
|
||||||
name="{{ form.id_car_model.html_name }}">
|
name="{{ form.id_car_model.html_name }}">
|
||||||
@ -307,18 +312,30 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Specifications Buttons -->
|
<!-- Specifications Buttons -->
|
||||||
<div class="col-lg-4 col-xl-6 justify-content-between">
|
<div class="row g-1">
|
||||||
<button type="button"
|
<div class="btn-group">
|
||||||
class="btn btn-danger mt-1"
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-danger me-1"
|
||||||
id="specification-btn"
|
id="specification-btn"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
data-bs-target="#specificationsModal"
|
data-bs-target="#specificationsModal"
|
||||||
disabled>{% trans 'specifications'|capfirst %}
|
disabled>{% trans 'specifications'|capfirst %}
|
||||||
</button>
|
</button>
|
||||||
<button type="submit"
|
<!--<div class="form-group">-->
|
||||||
class="btn btn-primary mt-1"
|
<button type="submit"
|
||||||
id="saveCarBtn" disabled>{% trans 'Save' %}
|
name="add_another"
|
||||||
</button>
|
value="true"
|
||||||
|
class="btn btn-sm btn-success me-1">
|
||||||
|
{% trans "Save and Add Another" %}
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
name="go_to_stats"
|
||||||
|
value="true"
|
||||||
|
class="btn btn-sm btn-primary">
|
||||||
|
{% trans "Save and Go to Inventory" %}
|
||||||
|
</button>
|
||||||
|
<!--</div>-->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@ -364,7 +381,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
const yearBg = document.getElementById('year-container');
|
const yearBg = document.getElementById('year-container');
|
||||||
const serieBg = document.getElementById('serie-container');
|
const serieBg = document.getElementById('serie-container');
|
||||||
const trimBg = document.getElementById('trim-container');
|
const trimBg = document.getElementById('trim-container');
|
||||||
const saveCarBtn = document.getElementById('saveCarBtn');
|
/*const saveCarBtn = document.getElementById('saveCarBtn');*/
|
||||||
|
|
||||||
const ajaxUrl = "{% url 'ajax_handler' %}";
|
const ajaxUrl = "{% url 'ajax_handler' %}";
|
||||||
|
|
||||||
@ -373,7 +390,8 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
const videoElement = document.getElementById('video');
|
const videoElement = document.getElementById('video');
|
||||||
const resultDisplay = document.getElementById('result');
|
const resultDisplay = document.getElementById('result');
|
||||||
const fallbackButton = document.getElementById('ocr-fallback-btn');
|
const fallbackButton = document.getElementById('ocr-fallback-btn');
|
||||||
const codeReader = new ZXing.BrowserMultiFormatReader();
|
let codeReader;
|
||||||
|
codeReader = new ZXing.BrowserMultiFormatReader();
|
||||||
let currentStream = null;
|
let currentStream = null;
|
||||||
|
|
||||||
function showLoading() {
|
function showLoading() {
|
||||||
@ -439,16 +457,19 @@ async function updateFields(vinData) {
|
|||||||
console.log(vinData)
|
console.log(vinData)
|
||||||
if (vinData.make_id) {
|
if (vinData.make_id) {
|
||||||
makeSelect.value = vinData.make_id;
|
makeSelect.value = vinData.make_id;
|
||||||
|
document.getElementById("make-check").innerHTML = '✓';
|
||||||
await loadModels(vinData.make_id);
|
await loadModels(vinData.make_id);
|
||||||
}
|
}
|
||||||
if (vinData.model_id) {
|
if (vinData.model_id) {
|
||||||
modelSelect.value = vinData.model_id;
|
modelSelect.value = vinData.model_id;
|
||||||
|
document.getElementById("model-check").innerHTML = '✓';
|
||||||
await loadSeries(vinData.model_id);
|
await loadSeries(vinData.model_id);
|
||||||
}
|
}
|
||||||
if (vinData.year) {
|
if (vinData.year) {
|
||||||
yearSelect.value = vinData.year;
|
yearSelect.value = vinData.year;
|
||||||
|
document.getElementById("year-check").innerHTML = '✓';
|
||||||
}
|
}
|
||||||
checkFormCompletion();
|
/*checkFormCompletion();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the scanner
|
// Start the scanner
|
||||||
@ -489,12 +510,12 @@ function stopScanner() {
|
|||||||
function resetDropdown(dropdown, placeholder) {
|
function resetDropdown(dropdown, placeholder) {
|
||||||
dropdown.innerHTML = `<option value="">${placeholder}</option>`;
|
dropdown.innerHTML = `<option value="">${placeholder}</option>`;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
function checkFormCompletion() {
|
function checkFormCompletion() {
|
||||||
const isFormComplete = vinInput.value.length === 17 && stockTypeSelect.value;
|
const isFormComplete = vinInput.value.length === 17 && stockTypeSelect.value;
|
||||||
saveCarBtn.disabled = !isFormComplete;
|
saveCarBtn.disabled = !isFormComplete;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
async function loadModels(makeId) {
|
async function loadModels(makeId) {
|
||||||
resetDropdown(modelSelect, '{% trans "Select" %}');
|
resetDropdown(modelSelect, '{% trans "Select" %}');
|
||||||
const response = await fetch(`${ajaxUrl}?action=get_models&make_id=${makeId}`, {
|
const response = await fetch(`${ajaxUrl}?action=get_models&make_id=${makeId}`, {
|
||||||
@ -551,6 +572,7 @@ async function loadTrims(serie_id, model_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadSpecifications(trimId){
|
async function loadSpecifications(trimId){
|
||||||
|
specificationsContent.innerHTML = '';
|
||||||
const response = await fetch(`${ajaxUrl}?action=get_specifications&trim_id=${trimId}`, {
|
const response = await fetch(`${ajaxUrl}?action=get_specifications&trim_id=${trimId}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
@ -592,9 +614,9 @@ async function loadSpecifications(trimId){
|
|||||||
});
|
});
|
||||||
|
|
||||||
closeButton.addEventListener('click', closeModal);
|
closeButton.addEventListener('click', closeModal);
|
||||||
stockTypeSelect.addEventListener('change', checkFormCompletion);
|
/*stockTypeSelect.addEventListener('change', checkFormCompletion);
|
||||||
mileageInput.addEventListener('input', checkFormCompletion);
|
mileageInput.addEventListener('input', checkFormCompletion);
|
||||||
remarksInput.addEventListener('input', checkFormCompletion);
|
remarksInput.addEventListener('input', checkFormCompletion);*/
|
||||||
decodeVinBtn.addEventListener('click', decodeVin);
|
decodeVinBtn.addEventListener('click', decodeVin);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
82
templates/sales/quotation_detail.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4>{% trans "Quotation Details" %} - {{ quotation.id }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h5>{% trans "Customer Details" %}</h5>
|
||||||
|
<p>
|
||||||
|
<strong>{% trans "Name" %}:</strong>
|
||||||
|
{{ quotation.customer.first_name }} {{ quotation.customer.last_name_name }}</p>
|
||||||
|
<p><strong>{% trans "Address" %}:</strong> {{ quotation.customer.address }}</p>
|
||||||
|
<p><strong>{% trans "VAT No" %}:</strong> {{ quotation.customer.vat_number }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h5>{% trans "Quotation Information" %}</h5>
|
||||||
|
<p><strong>{% trans "Quotation No" %}:</strong> {{ quotation.id }}</p>
|
||||||
|
<p><strong>{% trans "Date" %}:</strong> {{ quotation.created_at|date }}</p>
|
||||||
|
<p><strong>{% trans "Remarks" %}:</strong> {{ quotation.remarks }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">{% trans "Car Details" %}</h5>
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>VIN</th>
|
||||||
|
<th>Model</th>
|
||||||
|
<th>Selling Price</th>
|
||||||
|
<th>VAT</th>
|
||||||
|
<th>Total Before VAT</th>
|
||||||
|
<th>Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in quotation.quotation_cars.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.car.vin }}</td>
|
||||||
|
<td>{{ item.car.id_car_model.get_local_name }}</td>
|
||||||
|
<td>{{ item.car.selling_price }}</td>
|
||||||
|
<td>{{ item.car.total_vat_amount }}</td>
|
||||||
|
<td>{{ item.car.total_before_vat }}</td>
|
||||||
|
<td>{{ item.car.total }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3">Totals</th>
|
||||||
|
<th>{{ item.car.total_vat_amount }}</th>
|
||||||
|
<th>{{ item.car.total_before_vat }}</th>
|
||||||
|
<th>{{ item.car.total }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5 class="mt-4">{% trans "Summary" %}</h5>
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Total Sales Before VAT" %}</th>
|
||||||
|
<td>{{ quotations.total_sales_before_vat }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "VAT Amount" %}</th>
|
||||||
|
<td>{{ quotations.vat_amount }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Total Sales After VAT" %}</th>
|
||||||
|
<td>{{ quotations.total_sales_after_vat }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-end">
|
||||||
|
<a href="{% url 'quotation_list' %}" class="btn btn-secondary">{% trans "Back to Quotations" %}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
23
templates/sales/quotation_form.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load crispy_forms_filters %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block title %}{{ _("Create Quotation") }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h3 class="text-center">{% trans "Create Quotation" %}</h3>
|
||||||
|
<form method="post" class="needs-validation" novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="row g-3">
|
||||||
|
{{ form|crispy }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<button type="submit" class="btn btn-success me-2">{% trans "Save" %}</button>
|
||||||
|
<a href="{% url 'quotation_list' %}" class="btn btn-secondary">{% trans "Cancel" %}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
48
templates/sales/quotation_list.html
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block title %}{{ _("Quotations") }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h3 class="text-center">{% trans "Quotations" %}</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>{% trans "Customer" %}</th>
|
||||||
|
<th>{% trans "Total Cars" %}</th>
|
||||||
|
<th>{% trans "Total Amount" %}</th>
|
||||||
|
<th>{% trans "Created At" %}</th>
|
||||||
|
<th>{% trans "Actions" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for quotation in quotations %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ forloop.counter }}</td>
|
||||||
|
<td>{{ quotation.customer.get_full_name }}</td>
|
||||||
|
<td>{{ quotation.quotation_cars.count }}</td>
|
||||||
|
<td>{{ quotation.total }}</td>
|
||||||
|
<td>{{ quotation.created_at|date:"d/m/Y H:i" }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'quotation_detail' quotation.id %}" class="btn btn-sm btn-info">
|
||||||
|
{% trans "View" %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center">{% trans "No Quotations Found" %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
39
templates/sales/sales_order_detail.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}{{ _("Sales Order Details") }}{% endblock title %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h2>{{ _("Sales Order Details") }}</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _("Quotation ID") }}</th>
|
||||||
|
<td>{{ sales_order.quotation.id }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _("Customer") }}</th>
|
||||||
|
<td>{{ sales_order.quotation.customer }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _("Total Amount") }}</th>
|
||||||
|
<td>{{ sales_order.total_amount }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>{{ _("Cars in Sales Order") }}</h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{{ _("Car") }}</th>
|
||||||
|
<th>{{ _("Selling Price") }}</th>
|
||||||
|
<th>{{ _("VAT Amount") }}</th>
|
||||||
|
<th>{{ _("Total Amount") }}</th>
|
||||||
|
</tr>
|
||||||
|
{% for car in sales_order.quotation.quotation_cars.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ car.car }}</td>
|
||||||
|
<td>{{ car.selling_price }}</td>
|
||||||
|
<td>{{ car.vat_amount }}</td>
|
||||||
|
<td>{{ car.total_amount }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
206
templates/vendors/vendors_list.html
vendored
@ -1,134 +1,110 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% block title %}{% trans 'Vendors'|capfirst %}{% endblock title %}
|
{% block title %}{{ _('Vendors')|capfirst }}{% endblock title %}
|
||||||
{% block vendors %}<a class="nav-link active">{% trans "Vendors"|capfirst %}</a>{% endblock %}
|
{% block vendors %}<a class="nav-link active">{{ _("Vendors")|capfirst }}</a>{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="container-fluid p-3">
|
||||||
<div class="container-fluid">
|
<div class="card shadow-sm">
|
||||||
<div class="card mb-3">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<div class="card-header fw-light mb-0">
|
<h6 class="mb-0">{{ _("Vendors")|capfirst }}</h6>
|
||||||
{% include 'breadcrumbs.html' %}
|
<form method="get" class="d-inline-block">
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="container-fluid p-2">
|
|
||||||
<form method="get">
|
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<button id="inputGroup-sizing-sm"
|
<button class="btn btn-secondary" type="submit">
|
||||||
class="btn btn-sm btn-secondary rounded-start" type="submit">
|
{{ _("Search")|capfirst }}
|
||||||
{% trans 'search'|capfirst %}
|
|
||||||
</button>
|
</button>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="q"
|
name="q"
|
||||||
class="form-control form-control-sm rounded-end"
|
class="form-control"
|
||||||
value="{{ request.GET.q }}"
|
placeholder="{{ _('Enter vendor name') }}"
|
||||||
aria-describedby="inputGroup-sizing-sm"/>
|
value="{{ request.GET.q }}">
|
||||||
<!-- Clear Button -->
|
{% if request.GET.q %}
|
||||||
{% if request.GET.q %}
|
<a href="{% url request.resolver_match.view_name %}" class="btn btn-outline-danger ms-1">
|
||||||
<a href="{% url request.resolver_match.view_name %}"
|
<i class="bi bi-x-lg"></i>
|
||||||
class="btn btn-sm btn-outline-danger ms-1 rounded">
|
</a>
|
||||||
<i class="bi bi-x-lg"></i>
|
{% endif %}
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover table-responsive-sm">
|
<div class="card-body p-0">
|
||||||
<thead>
|
<table class="table table-hover table-striped mb-0">
|
||||||
<tr>
|
<thead class="table-light">
|
||||||
<th>{% trans 'name'|capfirst %}</th>
|
<tr>
|
||||||
|
<th>{{ _("Name")|capfirst }}</th>
|
||||||
|
<th>{{ _("Logo")|capfirst }}</th>
|
||||||
|
<th>{{ _("Address")|capfirst }}</th>
|
||||||
|
<th>{{ _("Actions")|capfirst }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% if page_obj.object_list %}
|
||||||
|
{% for vendor in vendors %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ vendor.get_local_name }}</td>
|
||||||
|
<td>
|
||||||
|
<img src="{{ vendor.logo.url }}"
|
||||||
|
alt="{{ vendor.get_local_name }}"
|
||||||
|
class="img-thumbnail"
|
||||||
|
style="max-width: 100px;">
|
||||||
|
|
||||||
<th>{% trans 'logo'|capfirst %}</th>
|
</td>
|
||||||
<th>{% trans 'address'|capfirst %}</th>
|
<td>{{ vendor.address }}</td>
|
||||||
<th>{% trans 'actions'|capfirst %}</th>
|
<td>
|
||||||
</tr>
|
<a href="{% url 'vendor_detail' vendor.id %}" class="btn btn-warning btn-sm">
|
||||||
</thead>
|
{{ _("View")|capfirst }}
|
||||||
<tbody>
|
</a>
|
||||||
{% if page_obj.object_list %}
|
</td>
|
||||||
{% for vendor in page_obj.object_list %}
|
</tr>
|
||||||
<tr>
|
{% endfor %}
|
||||||
<td>
|
|
||||||
{{ vendor.get_local_name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if vendor.logo %}
|
|
||||||
<img src="{% static 'images/' %}{{ vendor.logo }}" width="100" height="30">
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{% static 'images/logos/default_no_logo.png' %}" width="100" height="30">
|
<tr>
|
||||||
|
<td colspan="4" class="text-center">{{ _("No vendors found")|capfirst }}</td>
|
||||||
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</tbody>
|
||||||
<td>{{ vendor.address }}</td>
|
</table>
|
||||||
<td>
|
|
||||||
<a class="btn btn-sm btn-warning" href="{% url 'vendor_detail' vendor.id %}">{% trans 'view'|capfirst %}</a>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td class="border-0" colspan="6">{% trans 'no vendors found'|capfirst %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<nav aria-label="Page navigation">
|
|
||||||
<ul class="pagination pagination-sm justify-content-center">
|
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}page=1" aria-label={% trans 'first'|capfirst %}>
|
|
||||||
<span aria-hidden="true">««</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}page={{ page_obj.previous_page_number }}" aria-label={% trans 'previous'|capfirst %}>
|
|
||||||
<span aria-hidden="true">«</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-hidden="true">««</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-hidden="true">«</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% for num in page_obj.paginator.page_range %}
|
|
||||||
{% if page_obj.number == num %}
|
|
||||||
<li class="page-item active">
|
|
||||||
<span class="page-link">{{ num }}</span>
|
|
||||||
</li>
|
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}page={{ num }}">{{ num }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}page={{ page_obj.next_page_number }}" aria-label={% trans 'next'|capfirst %}>
|
|
||||||
<span aria-hidden="true">»</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% if request.GET.q %}q={{ request.GET.q }}&{% endif %}page={{ page_obj.paginator.num_pages }}" aria-label={% trans 'last'|capfirst %}>
|
|
||||||
<span aria-hidden="true">»»</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-hidden="true">»</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-hidden="true">»»</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Optional: Pagination -->
|
||||||
|
{% if is_paginated %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm justify-content-center">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item py-0">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link" href="#" aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% for num in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == num %}
|
||||||
|
<li class="page-item active"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %} {% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link" href="#" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
42
testapi.py
@ -1,23 +1,23 @@
|
|||||||
|
|
||||||
from vin import VIN
|
# from vin import VIN
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
|
#
|
||||||
vin_no = 'VR7ED9HP6SJ522156'
|
# vin_no = 'VR7ED9HP6SJ522156'
|
||||||
|
#
|
||||||
details = {
|
# details = {
|
||||||
# 'Description': VIN(vin_no).description,
|
# # 'Description': VIN(vin_no).description,
|
||||||
'make': VIN(vin_no).make,
|
# 'make': VIN(vin_no).make,
|
||||||
'year': VIN(vin_no).model_year,
|
# 'year': VIN(vin_no).model_year,
|
||||||
'model': VIN(vin_no).model,
|
# 'model': VIN(vin_no).model,
|
||||||
'trim': VIN(vin_no).trim,
|
# 'trim': VIN(vin_no).trim,
|
||||||
'Series': VIN(vin_no).series,
|
# 'Series': VIN(vin_no).series,
|
||||||
'body_class': VIN(vin_no).body_class,
|
# 'body_class': VIN(vin_no).body_class,
|
||||||
'Type': VIN(vin_no).vehicle_type,
|
# 'Type': VIN(vin_no).vehicle_type,
|
||||||
'Electrification level': VIN(vin_no).electrification_level,
|
# 'Electrification level': VIN(vin_no).electrification_level,
|
||||||
}
|
# }
|
||||||
|
#
|
||||||
print(details)
|
# print(details)
|
||||||
|
|
||||||
# from vininfo import Vin
|
# from vininfo import Vin
|
||||||
#
|
#
|
||||||
@ -120,3 +120,11 @@ print(details)
|
|||||||
#
|
#
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# print(e)
|
# print(e)
|
||||||
|
vin_no = "LS5A3DKR0SA966230"
|
||||||
|
|
||||||
|
|
||||||
|
url = "https://vin17.com/Search/query?vin=+"+vin_no
|
||||||
|
|
||||||
|
response = requests.request("GET", url)
|
||||||
|
car_info = json.loads(response.text)
|
||||||
|
print(car_info)
|
||||||
|
|||||||