update
0
.idea/sqldialects.xml
generated
Normal file
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-06 23:09
|
# Generated by Django 5.1.4 on 2025-01-07 22:27
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|||||||
2881
car_make01.json
Normal file
4012
carmake_backup.json
Normal file
45641
carmodel_backup.json
Normal file
141095
carserie_backup.json
Normal file
0
carspecification_backup.json
Normal file
BIN
carspecificationvalue_backup.json
Normal file
0
cartrim_backup.json
Normal file
29
create_json.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import mysql.connector
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Connect to MySQL
|
||||||
|
mysql_conn = mysql.connector.connect(
|
||||||
|
host='localhost',
|
||||||
|
user='root',
|
||||||
|
password='Kfsh&rc9788',
|
||||||
|
database='trucks2db'
|
||||||
|
)
|
||||||
|
cursor = mysql_conn.cursor()
|
||||||
|
|
||||||
|
# Get list of tables
|
||||||
|
cursor.execute("SHOW TABLES")
|
||||||
|
tables = cursor.fetchall()
|
||||||
|
|
||||||
|
for table in tables:
|
||||||
|
table_name = table[0]
|
||||||
|
cursor.execute(f"SELECT * FROM {table_name}")
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
cursor.execute(f"DESCRIBE {table_name}")
|
||||||
|
columns = [column[0] for column in cursor.fetchall()]
|
||||||
|
|
||||||
|
# Convert rows to list of dictionaries
|
||||||
|
data = [dict(zip(columns, row)) for row in rows]
|
||||||
|
|
||||||
|
# Write to JSON file
|
||||||
|
with open(f'{table_name}.json', 'w') as f:
|
||||||
|
json.dump(data, f)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-06 23:09
|
# Generated by Django 5.1.4 on 2025-01-07 22:27
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-06 23:09
|
# Generated by Django 5.1.4 on 2025-01-07 22:27
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
267
import_data.py
@ -14,153 +14,154 @@ from inventory.models import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Set up Django environment
|
# Set up Django environment
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
||||||
# Load the cleaned JSON data
|
# Load the cleaned JSON data
|
||||||
with open("final_car_data.json", "r") as file:
|
with open("carmake_updated_backup.json", "r") as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
|
|
||||||
# Step 1: Insert CarMake
|
# Step 1: Insert CarMake
|
||||||
for item in tqdm(data["car_make"], desc="Inserting CarMake"):
|
for item in tqdm(data["inventory.car_make"], desc="Inserting CarMake"):
|
||||||
CarMake.objects.update_or_create(
|
CarMake.objects.update_or_create(
|
||||||
id_car_make=item["id_car_make"],
|
id_car_make=item[id_car_make],
|
||||||
defaults={
|
defaults={
|
||||||
"name": item["name"],
|
"name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
"arabic_name": item.get("arabic_name", ""),
|
||||||
"logo": item.get("Logo", ""),
|
"logo": item.get("Logo", ""),
|
||||||
"is_sa_import": item.get("is_sa_import", False),
|
"is_sa_import": item.get("is_sa_import", False),
|
||||||
|
"car_type": 1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Step 2: Insert CarModel
|
# # Step 2: Insert CarModel
|
||||||
for item in tqdm(data["car_model"], desc="Inserting CarModel"):
|
# for item in tqdm(data["car_model"], desc="Inserting CarModel"):
|
||||||
CarMake.objects.get(id_car_make=item["id_car_make"])
|
# CarMake.objects.get(id_car_make=item["id_car_make"])
|
||||||
CarModel.objects.update_or_create(
|
# CarModel.objects.update_or_create(
|
||||||
id_car_model=item["id_car_model"],
|
# id_car_model=item["id_car_model"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_make_id": item["id_car_make"],
|
# "id_car_make_id": item["id_car_make"],
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 3: Insert CarSerie
|
# # Step 3: Insert CarSerie
|
||||||
for item in tqdm(data["car_serie"], desc="Inserting CarSerie"):
|
# for item in tqdm(data["car_serie"], desc="Inserting CarSerie"):
|
||||||
CarModel.objects.get(id_car_model=item["id_car_model"])
|
# CarModel.objects.get(id_car_model=item["id_car_model"])
|
||||||
CarSerie.objects.update_or_create(
|
# CarSerie.objects.update_or_create(
|
||||||
id_car_serie=item["id_car_serie"],
|
# id_car_serie=item["id_car_serie"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_model_id": item["id_car_model"],
|
# "id_car_model_id": item["id_car_model"],
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"year_begin": item.get("year_begin"),
|
# "year_begin": item.get("year_begin"),
|
||||||
"year_end": item.get("year_end"),
|
# "year_end": item.get("year_end"),
|
||||||
"generation_name": item.get("generation_name", ""),
|
# "generation_name": item.get("generation_name", ""),
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 4: Insert CarTrim
|
# # Step 4: Insert CarTrim
|
||||||
for item in tqdm(data["car_trim"], desc="Inserting CarTrim"):
|
# for item in tqdm(data["car_trim"], desc="Inserting CarTrim"):
|
||||||
CarSerie.objects.get(id_car_serie=item["id_car_serie"])
|
# CarSerie.objects.get(id_car_serie=item["id_car_serie"])
|
||||||
CarTrim.objects.update_or_create(
|
# CarTrim.objects.update_or_create(
|
||||||
id_car_trim=item["id_car_trim"],
|
# id_car_trim=item["id_car_trim"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_serie_id": item["id_car_serie"],
|
# "id_car_serie_id": item["id_car_serie"],
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"start_production_year": item["start_production_year"],
|
# "start_production_year": item["start_production_year"],
|
||||||
"end_production_year": item["end_production_year"],
|
# "end_production_year": item["end_production_year"],
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 5: Insert CarEquipment
|
# # Step 5: Insert CarEquipment
|
||||||
for item in tqdm(data["car_equipment"], desc="Inserting CarEquipment"):
|
# for item in tqdm(data["car_equipment"], desc="Inserting CarEquipment"):
|
||||||
CarTrim.objects.get(id_car_trim=item["id_car_trim"])
|
# CarTrim.objects.get(id_car_trim=item["id_car_trim"])
|
||||||
CarEquipment.objects.update_or_create(
|
# CarEquipment.objects.update_or_create(
|
||||||
id_car_equipment=item["id_car_equipment"],
|
# id_car_equipment=item["id_car_equipment"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_trim_id": item["id_car_trim"],
|
# "id_car_trim_id": item["id_car_trim"],
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"year_begin": item.get("year"),
|
# "year_begin": item.get("year"),
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 6: Insert CarSpecification (Parent specifications first)
|
# # Step 6: Insert CarSpecification (Parent specifications first)
|
||||||
parent_specs = [item for item in data["car_specification"] if item["id_parent"] is None]
|
# parent_specs = [item for item in data["car_specification"] if item["id_parent"] is None]
|
||||||
child_specs = [item for item in data["car_specification"] if item["id_parent"] is not None]
|
# child_specs = [item for item in data["car_specification"] if item["id_parent"] is not None]
|
||||||
|
#
|
||||||
for item in tqdm(parent_specs, desc="Inserting Parent CarSpecifications"):
|
# for item in tqdm(parent_specs, desc="Inserting Parent CarSpecifications"):
|
||||||
CarSpecification.objects.update_or_create(
|
# CarSpecification.objects.update_or_create(
|
||||||
id_car_specification=item["id_car_specification"],
|
# id_car_specification=item["id_car_specification"],
|
||||||
defaults={
|
# defaults={
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"id_parent_id": None
|
# "id_parent_id": None
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
for item in tqdm(child_specs, desc="Inserting Child CarSpecifications"):
|
# for item in tqdm(child_specs, desc="Inserting Child CarSpecifications"):
|
||||||
CarSpecification.objects.get(id_car_specification=item["id_parent"])
|
# CarSpecification.objects.get(id_car_specification=item["id_parent"])
|
||||||
CarSpecification.objects.update_or_create(
|
# CarSpecification.objects.update_or_create(
|
||||||
id_car_specification=item["id_car_specification"],
|
# id_car_specification=item["id_car_specification"],
|
||||||
defaults={
|
# defaults={
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"id_parent_id": item["id_parent"]
|
# "id_parent_id": item["id_parent"]
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 7: Insert CarSpecificationValue
|
# # Step 7: Insert CarSpecificationValue
|
||||||
for item in tqdm(data["car_specification_value"], desc="Inserting CarSpecificationValue"):
|
# for item in tqdm(data["car_specification_value"], desc="Inserting CarSpecificationValue"):
|
||||||
CarTrim.objects.get(id_car_trim=item["id_car_trim"])
|
# CarTrim.objects.get(id_car_trim=item["id_car_trim"])
|
||||||
CarSpecification.objects.get(id_car_specification=item["id_car_specification"])
|
# CarSpecification.objects.get(id_car_specification=item["id_car_specification"])
|
||||||
CarSpecificationValue.objects.update_or_create(
|
# CarSpecificationValue.objects.update_or_create(
|
||||||
id_car_specification_value=item["id_car_specification_value"],
|
# id_car_specification_value=item["id_car_specification_value"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_trim_id": item["id_car_trim"],
|
# "id_car_trim_id": item["id_car_trim"],
|
||||||
"id_car_specification_id": item["id_car_specification"],
|
# "id_car_specification_id": item["id_car_specification"],
|
||||||
"value": item["value"],
|
# "value": item["value"],
|
||||||
"unit": item.get("unit", ""),
|
# "unit": item.get("unit", ""),
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 8: Insert CarOption (Parent options first)
|
# # Step 8: Insert CarOption (Parent options first)
|
||||||
parent_options = [item for item in data["car_option"] if item["id_parent"] is None]
|
# parent_options = [item for item in data["car_option"] if item["id_parent"] is None]
|
||||||
child_options = [item for item in data["car_option"] if item["id_parent"] is not None]
|
# child_options = [item for item in data["car_option"] if item["id_parent"] is not None]
|
||||||
|
#
|
||||||
for item in tqdm(parent_options, desc="Inserting Parent CarOptions"):
|
# for item in tqdm(parent_options, desc="Inserting Parent CarOptions"):
|
||||||
CarOption.objects.update_or_create(
|
# CarOption.objects.update_or_create(
|
||||||
id_car_option=item["id_car_option"],
|
# id_car_option=item["id_car_option"],
|
||||||
defaults={
|
# defaults={
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"id_parent_id": None
|
# "id_parent_id": None
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
for item in tqdm(child_options, desc="Inserting Child CarOptions"):
|
# for item in tqdm(child_options, desc="Inserting Child CarOptions"):
|
||||||
CarOption.objects.get(id_car_option=item["id_parent"])
|
# CarOption.objects.get(id_car_option=item["id_parent"])
|
||||||
CarOption.objects.update_or_create(
|
# CarOption.objects.update_or_create(
|
||||||
id_car_option=item["id_car_option"],
|
# id_car_option=item["id_car_option"],
|
||||||
defaults={
|
# defaults={
|
||||||
"name": item["name"],
|
# "name": item["name"],
|
||||||
"arabic_name": item.get("arabic_name", ""),
|
# "arabic_name": item.get("arabic_name", ""),
|
||||||
"id_parent_id": item["id_parent"]
|
# "id_parent_id": item["id_parent"]
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
# Step 9: Insert CarOptionValue
|
# # Step 9: Insert CarOptionValue
|
||||||
for item in tqdm(data["car_option_value"], desc="Inserting CarOptionValue"):
|
# for item in tqdm(data["car_option_value"], desc="Inserting CarOptionValue"):
|
||||||
CarEquipment.objects.get(id_car_equipment=item["id_car_equipment"])
|
# CarEquipment.objects.get(id_car_equipment=item["id_car_equipment"])
|
||||||
CarOption.objects.get(id_car_option=item["id_car_option"])
|
# CarOption.objects.get(id_car_option=item["id_car_option"])
|
||||||
CarOptionValue.objects.update_or_create(
|
# CarOptionValue.objects.update_or_create(
|
||||||
id_car_option_value=item["id_car_option_value"],
|
# id_car_option_value=item["id_car_option_value"],
|
||||||
defaults={
|
# defaults={
|
||||||
"id_car_option_id": item["id_car_option"],
|
# "id_car_option_id": item["id_car_option"],
|
||||||
"id_car_equipment_id": item["id_car_equipment"],
|
# "id_car_equipment_id": item["id_car_equipment"],
|
||||||
"is_base": item["is_base"],
|
# "is_base": item["is_base"],
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
|
|
||||||
print("Data population completed successfully.")
|
print("Data population completed successfully.")
|
||||||
BIN
inventory/.DS_Store
vendored
BIN
inventory/data/.DS_Store
vendored
Normal file
@ -9,7 +9,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
car_option = CarOption.objects.all()[8820:]
|
car_option = CarOption.objects.all()[10300:]
|
||||||
total = car_option.count()
|
total = car_option.count()
|
||||||
print(f'Translating {total} names...')
|
print(f'Translating {total} names...')
|
||||||
for index, car_option in enumerate(car_option, start=1):
|
for index, car_option in enumerate(car_option, start=1):
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-06 23:09
|
# Generated by Django 5.1.4 on 2025-01-07 22:27
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import inventory.mixins
|
import inventory.mixins
|
||||||
@ -57,6 +57,7 @@ class Migration(migrations.Migration):
|
|||||||
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
('logo', models.ImageField(blank=True, null=True, upload_to='car_make', verbose_name='logo')),
|
('logo', models.ImageField(blank=True, null=True, upload_to='car_make', verbose_name='logo')),
|
||||||
('is_sa_import', models.BooleanField(default=False)),
|
('is_sa_import', models.BooleanField(default=False)),
|
||||||
|
('car_type', models.SmallIntegerField(choices=[(1, 'Car'), (2, 'light commercial'), (3, 'truck trailer'), (4, 'trailer'), (5, 'truck'), (6, 'bus')])),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Make',
|
'verbose_name': 'Make',
|
||||||
@ -166,20 +167,6 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='CarGeneration',
|
|
||||||
fields=[
|
|
||||||
('id_car_generation', models.AutoField(primary_key=True, serialize=False)),
|
|
||||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
|
||||||
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
|
||||||
('year_begin', models.CharField(blank=True, max_length=255, null=True)),
|
|
||||||
('year_end', models.CharField(blank=True, max_length=255, null=True)),
|
|
||||||
('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Generation',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='car',
|
model_name='car',
|
||||||
name='id_car_model',
|
name='id_car_model',
|
||||||
@ -204,6 +191,7 @@ class Migration(migrations.Migration):
|
|||||||
('id_car_option_value', models.AutoField(primary_key=True, serialize=False)),
|
('id_car_option_value', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('value', models.CharField(max_length=500)),
|
('value', models.CharField(max_length=500)),
|
||||||
('unit', models.CharField(blank=True, max_length=255, null=True)),
|
('unit', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('is_base', models.IntegerField()),
|
||||||
('id_car_equipment', models.ForeignKey(db_column='id_car_equipment', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carequipment')),
|
('id_car_equipment', models.ForeignKey(db_column='id_car_equipment', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carequipment')),
|
||||||
('id_car_option', models.ForeignKey(db_column='id_car_option', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.caroption')),
|
('id_car_option', models.ForeignKey(db_column='id_car_option', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.caroption')),
|
||||||
],
|
],
|
||||||
@ -252,8 +240,8 @@ class Migration(migrations.Migration):
|
|||||||
name='CarSpecification',
|
name='CarSpecification',
|
||||||
fields=[
|
fields=[
|
||||||
('id_car_specification', models.AutoField(primary_key=True, serialize=False)),
|
('id_car_specification', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
('name', models.CharField(max_length=255)),
|
||||||
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
('arabic_name', models.CharField(max_length=255)),
|
||||||
('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
|
('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-07 01:32
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='caroptionvalue',
|
|
||||||
name='is_base',
|
|
||||||
field=models.IntegerField(default=1, max_length=1),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='carspecification',
|
|
||||||
name='arabic_name',
|
|
||||||
field=models.CharField(default='-', max_length=255),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='carspecification',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(default='-', max_length=255),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-07 01:32
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0002_caroptionvalue_is_base_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='caroptionvalue',
|
|
||||||
name='is_base',
|
|
||||||
field=models.IntegerField(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -54,6 +54,8 @@ class UnitOfMeasure(models.TextChoices):
|
|||||||
SQUARE_METER = 'SQ_M', 'Square Meter'
|
SQUARE_METER = 'SQ_M', 'Square Meter'
|
||||||
PIECE = 'PC', 'Piece'
|
PIECE = 'PC', 'Piece'
|
||||||
BUNDLE = 'BDL', 'Bundle'
|
BUNDLE = 'BDL', 'Bundle'
|
||||||
|
|
||||||
|
|
||||||
class VatRate(models.Model):
|
class VatRate(models.Model):
|
||||||
rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.15'))
|
rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.15'))
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
@ -65,12 +67,23 @@ class VatRate(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Rate: {self.rate}%"
|
return f"Rate: {self.rate}%"
|
||||||
|
|
||||||
|
|
||||||
|
class CarType(models.IntegerChoices):
|
||||||
|
CAR = 1, _('Car')
|
||||||
|
LIGHT_COMMERCIAL = 2, _('light commercial')
|
||||||
|
TRUCK_TRAILER = 3, _('truck trailer')
|
||||||
|
TRAILER = 4, _('trailer')
|
||||||
|
TRUCK = 5, _('truck')
|
||||||
|
BUS = 6, _('bus')
|
||||||
|
|
||||||
|
|
||||||
class CarMake(models.Model, LocalizedNameMixin):
|
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, blank=True, null=True)
|
name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
arabic_name = models.CharField(max_length=255, blank=True, null=True)
|
arabic_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
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)
|
||||||
|
car_type = models.SmallIntegerField(choices=CarType.choices)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -92,21 +105,6 @@ class CarModel(models.Model, LocalizedNameMixin):
|
|||||||
verbose_name = "Model"
|
verbose_name = "Model"
|
||||||
|
|
||||||
|
|
||||||
class CarGeneration(models.Model):
|
|
||||||
id_car_generation = models.AutoField(primary_key=True)
|
|
||||||
id_car_model = models.ForeignKey(CarModel, models.DO_NOTHING, db_column='id_car_model')
|
|
||||||
name = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
arabic_name = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
year_begin = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
year_end = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = "Generation"
|
|
||||||
|
|
||||||
|
|
||||||
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(CarModel, models.DO_NOTHING, db_column="id_car_model")
|
id_car_model = models.ForeignKey(CarModel, models.DO_NOTHING, db_column="id_car_model")
|
||||||
@ -369,34 +367,42 @@ class CarFinance(models.Model):
|
|||||||
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
|
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
|
||||||
discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"),
|
discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"),
|
||||||
default=Decimal('0.00'))
|
default=Decimal('0.00'))
|
||||||
|
# profit_margin = models.DecimalField(max_digits=14,
|
||||||
|
# decimal_places=2,
|
||||||
|
# verbose_name=_("Profit Margin"),
|
||||||
|
# editable=False)
|
||||||
|
# vat_amount = models.DecimalField(max_digits=14,
|
||||||
|
# decimal_places=2,
|
||||||
|
# verbose_name=_("Vat Amount"),
|
||||||
|
# editable=False,default=Decimal('0.00'))
|
||||||
|
# registration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Registration Fee"),
|
||||||
|
# default=Decimal('0.00'))
|
||||||
|
# administration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Administration Fee"),
|
||||||
|
# default=Decimal('0.00'))
|
||||||
|
# transportation_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Transportation Fee"),
|
||||||
|
# default=Decimal('0.00'))
|
||||||
|
# custom_card_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Custom Card Fee"),
|
||||||
|
# default=Decimal('0.00'))
|
||||||
@property
|
@property
|
||||||
def total(self):
|
def total(self):
|
||||||
total = self.selling_price
|
total = 0
|
||||||
|
|
||||||
if self.additional_services.count() != 0:
|
if self.additional_services.count() != 0:
|
||||||
total_additional_services = sum(x.default_amount for x in self.additional_services.all())
|
total_additional_services = sum(x.default_amount for x in self.additional_services.all())
|
||||||
total += total_additional_services
|
total = self.selling_price + total_additional_services
|
||||||
|
else:
|
||||||
return total
|
total = self.selling_price
|
||||||
@property
|
|
||||||
def total_discount(self):
|
|
||||||
if self.discount_amount != 0:
|
if self.discount_amount != 0:
|
||||||
total = self.total - self.discount_amount
|
total = total - self.discount_amount
|
||||||
return total
|
return total
|
||||||
return self.total
|
|
||||||
|
|
||||||
@property
|
|
||||||
def total_vat(self):
|
|
||||||
return self.total_discount + self.vat_amount
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vat_amount(self):
|
def vat_amount(self):
|
||||||
vat = VatRate.objects.filter(is_active=True).first()
|
vat = VatRate.objects.filter(is_active=True).first()
|
||||||
if vat:
|
return (self.total * vat.vat_rate).quantize(Decimal('0.01'))
|
||||||
return (self.total_discount * Decimal(vat.vat_rate)).quantize(Decimal('0.01'))
|
|
||||||
return Decimal('0.00')
|
@property
|
||||||
|
def total_vat(self):
|
||||||
|
return self.total + self.vat_amount
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
from decimal import Decimal
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@ -91,11 +90,4 @@ def reserve_car(car,request):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
messages.error(request, f"Error reserving car: {e}")
|
messages.error(request, f"Error reserving car: {e}")
|
||||||
|
|
||||||
return redirect("car_detail", pk=car.pk)
|
return redirect("car_detail", pk=car.pk)
|
||||||
|
|
||||||
|
|
||||||
def calculate_vat_amount(amount):
|
|
||||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
|
||||||
if vat:
|
|
||||||
return ((amount * Decimal(vat.vat_rate)).quantize(Decimal('0.01')),vat.vat_rate)
|
|
||||||
return amount
|
|
||||||
@ -59,13 +59,7 @@ from . import models, forms
|
|||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from .utils import (
|
from .utils import get_calculations, reserve_car, send_email, get_user_type
|
||||||
calculate_vat_amount,
|
|
||||||
get_calculations,
|
|
||||||
reserve_car,
|
|
||||||
send_email,
|
|
||||||
get_user_type,
|
|
||||||
)
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from allauth.account import views
|
from allauth.account import views
|
||||||
from django.db.models import Count, F, Value
|
from django.db.models import Count, F, Value
|
||||||
@ -635,8 +629,8 @@ class CustomCardCreateView(LoginRequiredMixin, CreateView):
|
|||||||
@login_required()
|
@login_required()
|
||||||
def reserve_car_view(request, car_id):
|
def reserve_car_view(request, car_id):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
car = get_object_or_404(models.Car, pk=car_id)
|
car = get_object_or_404(models.Car, pk=car_id)
|
||||||
if car.is_reserved():
|
if car.is_reserved():
|
||||||
messages.error(request, _("This car is already reserved."))
|
messages.error(request, _("This car is already reserved."))
|
||||||
return redirect("car_detail", pk=car.pk)
|
return redirect("car_detail", pk=car.pk)
|
||||||
response = reserve_car(car, request)
|
response = reserve_car(car, request)
|
||||||
@ -746,14 +740,6 @@ class CustomerDetailView(LoginRequiredMixin, DetailView):
|
|||||||
template_name = "customers/view_customer.html"
|
template_name = "customers/view_customer.html"
|
||||||
context_object_name = "customer"
|
context_object_name = "customer"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
name = f"{context['customer'].first_name} {context['customer'].middle_name} {context['customer'].last_name}"
|
|
||||||
context["estimates"] = self.request.entity.get_estimates().filter(
|
|
||||||
customer__customer_name=name
|
|
||||||
)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class CustomerCreateView(
|
class CustomerCreateView(
|
||||||
LoginRequiredMixin,
|
LoginRequiredMixin,
|
||||||
@ -1634,7 +1620,6 @@ def bank_account_delete(request, pk):
|
|||||||
# Accounts
|
# Accounts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AccountListView(LoginRequiredMixin, ListView):
|
class AccountListView(LoginRequiredMixin, ListView):
|
||||||
model = AccountModel
|
model = AccountModel
|
||||||
template_name = "ledger/coa_accounts/account_list.html"
|
template_name = "ledger/coa_accounts/account_list.html"
|
||||||
@ -1800,7 +1785,7 @@ def create_estimate(request):
|
|||||||
"quantity": float(item.get("quantity")),
|
"quantity": float(item.get("quantity")),
|
||||||
"unit_cost": car_instance.finances.cost_price,
|
"unit_cost": car_instance.finances.cost_price,
|
||||||
"unit_revenue": car_instance.finances.selling_price,
|
"unit_revenue": car_instance.finances.selling_price,
|
||||||
"total_amount": (car_instance.finances.total_vat)
|
"total_amount": car_instance.finances.cost_price
|
||||||
* int(item.get("quantity")),
|
* int(item.get("quantity")),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -1822,8 +1807,7 @@ def create_estimate(request):
|
|||||||
"unit_cost": instance.finances.cost_price,
|
"unit_cost": instance.finances.cost_price,
|
||||||
"unit_revenue": instance.finances.selling_price,
|
"unit_revenue": instance.finances.selling_price,
|
||||||
"quantity": float(quantities),
|
"quantity": float(quantities),
|
||||||
"total_amount": instance.finances.total_vat
|
"total_amount": instance.finances.total * int(quantities),
|
||||||
* int(quantities),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1836,9 +1820,9 @@ def create_estimate(request):
|
|||||||
if isinstance(items, list):
|
if isinstance(items, list):
|
||||||
for item in items:
|
for item in items:
|
||||||
item_instance = ItemModel.objects.get(pk=item)
|
item_instance = ItemModel.objects.get(pk=item)
|
||||||
instance = models.Car.objects.get(vin=item_instance.name)
|
instance = models.Car.objects.get(vin=item_instance.name)
|
||||||
reserve_car(instance, request)
|
response = reserve_car(instance, request)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
item_instance = ItemModel.objects.get(pk=items)
|
item_instance = ItemModel.objects.get(pk=items)
|
||||||
instance = models.Car.objects.get(vin=item_instance.name)
|
instance = models.Car.objects.get(vin=item_instance.name)
|
||||||
@ -1853,6 +1837,15 @@ def create_estimate(request):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# return JsonResponse(
|
||||||
|
# {
|
||||||
|
# "status": "error",
|
||||||
|
# "message": f"An error occurred while processing the request: {str(e)}",
|
||||||
|
# },
|
||||||
|
# status=400,
|
||||||
|
# )
|
||||||
|
|
||||||
form = EstimateModelCreateForm(entity_slug=entity.slug, user_model=entity.admin)
|
form = EstimateModelCreateForm(entity_slug=entity.slug, user_model=entity.admin)
|
||||||
car_list = models.Car.objects.filter(
|
car_list = models.Car.objects.filter(
|
||||||
dealer=dealer, finances__selling_price__gt=0
|
dealer=dealer, finances__selling_price__gt=0
|
||||||
@ -1881,27 +1874,25 @@ class EstimateDetailView(LoginRequiredMixin, DetailView):
|
|||||||
estimate = kwargs.get("object")
|
estimate = kwargs.get("object")
|
||||||
if estimate.get_itemtxs_data():
|
if estimate.get_itemtxs_data():
|
||||||
total = sum(
|
total = sum(
|
||||||
float(
|
(
|
||||||
models.Car.objects.get(
|
x.ce_revenue_estimate
|
||||||
|
- models.Car.objects.get(
|
||||||
vin=x.item_model.name
|
vin=x.item_model.name
|
||||||
).finances.total
|
).finances.discount_amount
|
||||||
)
|
)
|
||||||
* float(x.ce_quantity)
|
|
||||||
for x in estimate.get_itemtxs_data()[0].all()
|
for x in estimate.get_itemtxs_data()[0].all()
|
||||||
)
|
)
|
||||||
discount_amount = sum(
|
|
||||||
models.CarFinance.objects.get(
|
|
||||||
car__vin=i.item_model.name
|
|
||||||
).discount_amount
|
|
||||||
for i in estimate.get_itemtxs_data()[0].all()
|
|
||||||
)
|
|
||||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||||
grand_total = float(total) - float(discount_amount)
|
|
||||||
vat_amount = round(float(grand_total) * float(vat.vat_rate), 2)
|
# Calculate VAT and total with 2 decimal places
|
||||||
|
vat_amount = round(total * vat.vat_rate, 2) # Round to 2 decimal places
|
||||||
|
grand_total = round(
|
||||||
|
(total * vat.vat_rate) + total, 2
|
||||||
|
) # Round to 2 decimal places
|
||||||
|
|
||||||
|
# Add values to the context
|
||||||
kwargs["vat_amount"] = vat_amount
|
kwargs["vat_amount"] = vat_amount
|
||||||
kwargs["total"] = grand_total + vat_amount
|
kwargs["total"] = grand_total
|
||||||
kwargs["discount_amount"] = discount_amount
|
|
||||||
kwargs["vat"] = vat.rate
|
kwargs["vat"] = vat.rate
|
||||||
kwargs["invoice"] = (
|
kwargs["invoice"] = (
|
||||||
InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
||||||
@ -1950,25 +1941,52 @@ def estimate_mark_as(request, pk):
|
|||||||
if mark == "review":
|
if mark == "review":
|
||||||
if not estimate.can_review():
|
if not estimate.can_review():
|
||||||
messages.error(request, "Estimate is not ready for review")
|
messages.error(request, "Estimate is not ready for review")
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
estimate.mark_as_review()
|
estimate.mark_as_review()
|
||||||
|
|
||||||
elif mark == "approved":
|
elif mark == "approved":
|
||||||
if not estimate.can_approve():
|
if not estimate.can_approve():
|
||||||
messages.error(request, "Estimate is not ready for approval")
|
messages.error(request, "Estimate is not ready for approval")
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
estimate.mark_as_approved()
|
estimate.mark_as_approved()
|
||||||
messages.success(request, "Estimate approved successfully.")
|
|
||||||
|
messages.success(request, "Estimate approved successfully.")
|
||||||
elif mark == "rejected":
|
elif mark == "rejected":
|
||||||
if not estimate.can_cancel():
|
if not estimate.can_cancel():
|
||||||
messages.error(request, "Estimate is not ready for rejection")
|
messages.error(request, "Estimate is not ready for rejection")
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
estimate.mark_as_canceled()
|
estimate.mark_as_canceled()
|
||||||
messages.success(request, "Estimate canceled successfully.")
|
messages.success(request, "Estimate canceled successfully.")
|
||||||
|
|
||||||
elif mark == "completed":
|
elif mark == "completed":
|
||||||
if not estimate.can_complete():
|
if not estimate.can_complete():
|
||||||
messages.error(request, "Estimate is not ready for completion")
|
messages.error(request, "Estimate is not ready for completion")
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
|
|
||||||
|
# invoice = entity.create_invoice(customer_model=estimate.customer,
|
||||||
|
# terms=estimate.terms,
|
||||||
|
# cash_account=entity.get_default_coa_accounts().get(name="Cash"),
|
||||||
|
# prepaid_account=entity.get_default_coa_accounts().get(name="Accounts Receivable"),
|
||||||
|
# coa_model=entity.get_default_coa()
|
||||||
|
# )
|
||||||
|
|
||||||
|
# unit_items = estimate.get_itemtxs_data()[0]
|
||||||
|
# invoice_itemtxs = {
|
||||||
|
# i.item_model.item_number: {
|
||||||
|
# 'unit_cost': i.ce_unit_cost_estimate,
|
||||||
|
# 'quantity': i.ce_quantity,
|
||||||
|
# 'total_amount': i.ce_cost_estimate
|
||||||
|
# } for i in unit_items
|
||||||
|
# }
|
||||||
|
|
||||||
|
# invoice_itemtxs = invoice.migrate_itemtxs(itemtxs=invoice_itemtxs,
|
||||||
|
# commit=True,
|
||||||
|
# operation=InvoiceModel.ITEMIZE_APPEND)
|
||||||
|
# invoice.bind_estimate(estimate)
|
||||||
|
# invoice.mark_as_review()
|
||||||
|
# estimate.mark_as_completed()
|
||||||
|
# estimate.save()
|
||||||
|
# invoice.save()
|
||||||
estimate.save()
|
estimate.save()
|
||||||
messages.success(request, "Estimate marked as " + mark.upper())
|
messages.success(request, "Estimate marked as " + mark.upper())
|
||||||
|
|
||||||
@ -1994,27 +2012,15 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
invoice = kwargs.get("object")
|
invoice = kwargs.get("object")
|
||||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
|
||||||
|
|
||||||
if invoice.get_itemtxs_data():
|
if invoice.get_itemtxs_data():
|
||||||
total = sum(
|
total = sum(
|
||||||
float(x.ce_revenue_estimate) * float(x.ce_quantity)
|
x.unit_cost * x.quantity for x in invoice.get_itemtxs_data()[0].all()
|
||||||
for x in invoice.ce_model.get_itemtxs_data()[0].all()
|
|
||||||
)
|
)
|
||||||
discount_amount = sum(
|
total = int(total)
|
||||||
models.CarFinance.objects.get(
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||||
car__vin=i.item_model.name
|
kwargs["vat_amount"] = total * vat.vat_rate
|
||||||
).discount_amount
|
kwargs["total"] = (total * vat.vat_rate) + total
|
||||||
for i in invoice.get_itemtxs_data()[0].all()
|
|
||||||
)
|
|
||||||
|
|
||||||
grand_total = float(total) - float(discount_amount)
|
|
||||||
vat_amount = round(float(grand_total) * float(vat.vat_rate), 2)
|
|
||||||
|
|
||||||
|
|
||||||
kwargs["vat_amount"] = vat_amount
|
|
||||||
kwargs["total"] = grand_total + vat_amount
|
|
||||||
kwargs["discount_amount"] = discount_amount
|
|
||||||
kwargs["vat"] = vat.rate
|
kwargs["vat"] = vat.rate
|
||||||
kwargs["payments"] = JournalEntryModel.objects.filter(
|
kwargs["payments"] = JournalEntryModel.objects.filter(
|
||||||
ledger=invoice.ledger
|
ledger=invoice.ledger
|
||||||
@ -2074,27 +2080,13 @@ def invoice_create(request, pk):
|
|||||||
invoice_model.save()
|
invoice_model.save()
|
||||||
|
|
||||||
unit_items = estimate.get_itemtxs_data()[0]
|
unit_items = estimate.get_itemtxs_data()[0]
|
||||||
|
|
||||||
itemtxs = []
|
|
||||||
for item in unit_items:
|
|
||||||
car = models.Car.objects.get(vin=item.item_model.name)
|
|
||||||
itemtxs.append(
|
|
||||||
{
|
|
||||||
"item_number": item.item_model.item_number,
|
|
||||||
"unit_cost": car.finances.total_vat,
|
|
||||||
"unit_revenue": car.finances.total_vat,
|
|
||||||
"quantity": item.ce_quantity,
|
|
||||||
"total_amount": float(car.finances.total_vat)
|
|
||||||
* float(item.ce_quantity),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
invoice_itemtxs = {
|
invoice_itemtxs = {
|
||||||
i.get("item_number"): {
|
i.item_model.item_number: {
|
||||||
"unit_cost": i.get("unit_cost"),
|
"unit_cost": i.ce_unit_cost_estimate,
|
||||||
"quantity": i.get("quantity"),
|
"quantity": i.ce_quantity,
|
||||||
"total_amount": i.get("total_amount"),
|
"total_amount": i.ce_cost_estimate,
|
||||||
}
|
}
|
||||||
for i in itemtxs
|
for i in unit_items
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice_itemtxs = invoice_model.migrate_itemtxs(
|
invoice_itemtxs = invoice_model.migrate_itemtxs(
|
||||||
@ -2240,6 +2232,59 @@ class UserActivityLogListView(ListView):
|
|||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
# email
|
||||||
|
def send_email_view(request, pk):
|
||||||
|
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||||
|
if request.method == "POST":
|
||||||
|
# if not estimate.can_review():
|
||||||
|
# messages.error(request, "Estimate is not ready for review")
|
||||||
|
# return redirect("estimate_detail", pk=estimate.pk)
|
||||||
|
if not estimate.get_itemtxs_data()[0]:
|
||||||
|
messages.error(request, "Estimate has no items")
|
||||||
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
|
|
||||||
|
send_email(
|
||||||
|
"manager@tenhal.com",
|
||||||
|
request.POST.get("to"),
|
||||||
|
request.POST.get("subject"),
|
||||||
|
request.POST.get("message"),
|
||||||
|
)
|
||||||
|
# estimate.mark_as_review()
|
||||||
|
messages.success(request, "Email sent successfully!")
|
||||||
|
return redirect("estimate_detail", pk=estimate.pk)
|
||||||
|
link = reverse_lazy("estimate_preview", kwargs={"pk": estimate.pk})
|
||||||
|
msg = f"""
|
||||||
|
السلام عليكم
|
||||||
|
Dear {estimate.customer.customer_name},
|
||||||
|
|
||||||
|
أود أن أشارككم تقدير المشروع الذي ناقشناه. يرجى العثور على الوثيقة التفصيلية للمقترح المرفقة.
|
||||||
|
|
||||||
|
I hope this email finds you well. I wanted to share with you the estimate for the project we discussed. Please find the detailed estimate document attached.
|
||||||
|
|
||||||
|
يرجى مراجعة المقترح وإعلامي إذا كانت لديك أي أسئلة أو مخاوف. إذا كانت كل شيء يبدو جيدًا، يمكننا المضي قدمًا في المشروع.
|
||||||
|
|
||||||
|
Please review the estimate and let me know if you have any questions or concerns. If everything looks good, we can proceed with the project.
|
||||||
|
|
||||||
|
Estimate Link:
|
||||||
|
{link}
|
||||||
|
|
||||||
|
شكراً لاهتمامكم بهذا الأمر.
|
||||||
|
Thank you for your attention to this matter.
|
||||||
|
|
||||||
|
تحياتي,
|
||||||
|
Best regards,
|
||||||
|
[Your Name]
|
||||||
|
[Your Position]
|
||||||
|
[Your Company]
|
||||||
|
[Your Contact Information]
|
||||||
|
"""
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"sales/estimates/estimate_send.html",
|
||||||
|
{"estimate": estimate, "message": msg},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# CRM RELATED VIEWS
|
# CRM RELATED VIEWS
|
||||||
def create_lead(request, pk):
|
def create_lead(request, pk):
|
||||||
customer = get_object_or_404(models.Customer, pk=pk)
|
customer = get_object_or_404(models.Customer, pk=pk)
|
||||||
@ -2414,73 +2459,3 @@ class SubscriptionPlans(ListView):
|
|||||||
model = models.SubscriptionPlan
|
model = models.SubscriptionPlan
|
||||||
template_name = "subscriptions/subscription_plan.html"
|
template_name = "subscriptions/subscription_plan.html"
|
||||||
context_object_name = "plans"
|
context_object_name = "plans"
|
||||||
|
|
||||||
|
|
||||||
# email
|
|
||||||
def send_email_view(request, pk):
|
|
||||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
|
||||||
if request.method == "POST":
|
|
||||||
# if not estimate.can_review():
|
|
||||||
# messages.error(request, "Estimate is not ready for review")
|
|
||||||
# return redirect("estimate_detail", pk=estimate.pk)
|
|
||||||
if not estimate.get_itemtxs_data()[0]:
|
|
||||||
messages.error(request, "Estimate has no items")
|
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
|
||||||
|
|
||||||
send_email(
|
|
||||||
"manager@tenhal.com",
|
|
||||||
request.POST.get("to"),
|
|
||||||
request.POST.get("subject"),
|
|
||||||
request.POST.get("message"),
|
|
||||||
)
|
|
||||||
estimate.mark_as_review()
|
|
||||||
messages.success(request, "Email sent successfully!")
|
|
||||||
return redirect("estimate_detail", pk=estimate.pk)
|
|
||||||
link = reverse_lazy("estimate_preview", kwargs={"pk": estimate.pk})
|
|
||||||
msg = f"""
|
|
||||||
السلام عليكم
|
|
||||||
Dear {estimate.customer.customer_name},
|
|
||||||
|
|
||||||
أود أن أشارككم تقدير المشروع الذي ناقشناه. يرجى العثور على الوثيقة التفصيلية للمقترح المرفقة.
|
|
||||||
|
|
||||||
I hope this email finds you well. I wanted to share with you the estimate for the project we discussed. Please find the detailed estimate document attached.
|
|
||||||
|
|
||||||
يرجى مراجعة المقترح وإعلامي إذا كانت لديك أي أسئلة أو مخاوف. إذا كانت كل شيء يبدو جيدًا، يمكننا المضي قدمًا في المشروع.
|
|
||||||
|
|
||||||
Please review the estimate and let me know if you have any questions or concerns. If everything looks good, we can proceed with the project.
|
|
||||||
|
|
||||||
Estimate Link:
|
|
||||||
{link}
|
|
||||||
|
|
||||||
شكراً لاهتمامكم بهذا الأمر.
|
|
||||||
Thank you for your attention to this matter.
|
|
||||||
|
|
||||||
تحياتي,
|
|
||||||
Best regards,
|
|
||||||
[Your Name]
|
|
||||||
[Your Position]
|
|
||||||
[Your Company]
|
|
||||||
[Your Contact Information]
|
|
||||||
"""
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
"sales/estimates/estimate_send.html",
|
|
||||||
{"estimate": estimate, "message": msg},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# errors
|
|
||||||
def custom_page_not_found_view(request, exception):
|
|
||||||
return render(request, "errors/404.html", {})
|
|
||||||
|
|
||||||
|
|
||||||
def custom_error_view(request, exception=None):
|
|
||||||
return render(request, "errors/500.html", {})
|
|
||||||
|
|
||||||
|
|
||||||
def custom_permission_denied_view(request, exception=None):
|
|
||||||
return render(request, "errors/403.html", {})
|
|
||||||
|
|
||||||
|
|
||||||
def custom_bad_request_view(request, exception=None):
|
|
||||||
return render(request, "errors/400.html", {})
|
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import pymysql
|
import pymysql
|
||||||
|
import django
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
||||||
|
django.setup()
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
@ -11,10 +15,10 @@ from inventory.models import (
|
|||||||
# Step 1: Perform MySQL Dump
|
# Step 1: Perform MySQL Dump
|
||||||
def dump_mysql_database():
|
def dump_mysql_database():
|
||||||
print("Starting MySQL dump...")
|
print("Starting MySQL dump...")
|
||||||
db_user = "username"
|
db_user = "root"
|
||||||
db_password = "password"
|
db_password = "Kfsh&rc9788"
|
||||||
db_name = "haikaldb"
|
db_name = "trucks2db"
|
||||||
dump_file = f"haikaldb_{datetime.now().strftime('%Y%m%d')}.sql"
|
dump_file = f"trucks2db_{datetime.now().strftime('%Y%m%d')}.sql"
|
||||||
os.system(f"mysqldump -u {db_user} -p{db_password} {db_name} > {dump_file}")
|
os.system(f"mysqldump -u {db_user} -p{db_password} {db_name} > {dump_file}")
|
||||||
print(f"MySQL dump completed: {dump_file}")
|
print(f"MySQL dump completed: {dump_file}")
|
||||||
|
|
||||||
@ -23,9 +27,9 @@ def export_database_to_json():
|
|||||||
print("Starting export to JSON...")
|
print("Starting export to JSON...")
|
||||||
db_config = {
|
db_config = {
|
||||||
'host': 'localhost',
|
'host': 'localhost',
|
||||||
'user': 'username',
|
'user': 'root',
|
||||||
'password': 'password',
|
'password': 'Kfsh&rc9788',
|
||||||
'database': 'haikaldb'
|
'database': 'trucks2db',
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = pymysql.connect(**db_config)
|
connection = pymysql.connect(**db_config)
|
||||||
@ -41,9 +45,9 @@ def export_database_to_json():
|
|||||||
columns = [col[0] for col in cursor.description]
|
columns = [col[0] for col in cursor.description]
|
||||||
database_json[table_name] = [dict(zip(columns, row)) for row in rows]
|
database_json[table_name] = [dict(zip(columns, row)) for row in rows]
|
||||||
|
|
||||||
json_file_name = "database_export.json"
|
json_file_name = "trucks20250101.json"
|
||||||
with open(json_file_name, "w") as json_file:
|
with open(json_file_name, "w") as file:
|
||||||
json.dump(database_json, json_file, indent=4)
|
json.dump(database_json, file, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
connection.close()
|
connection.close()
|
||||||
print(f"Database exported to JSON successfully: {json_file_name}")
|
print(f"Database exported to JSON successfully: {json_file_name}")
|
||||||
@ -182,7 +186,7 @@ def process_json_data(json_file_name):
|
|||||||
def main():
|
def main():
|
||||||
dump_mysql_database() # Step 1: Dump the database
|
dump_mysql_database() # Step 1: Dump the database
|
||||||
json_file_name = export_database_to_json() # Step 2: Export to JSON
|
json_file_name = export_database_to_json() # Step 2: Export to JSON
|
||||||
process_json_data(json_file_name) # Step 3: Process the JSON
|
# process_json_data(json_file_name) # Step 3: Process the JSON
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
BIN
static/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
BIN
static/images/car_make/Abarth.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
static/images/car_make/Alfa-Romeo-2.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
static/images/car_make/BAIC-1.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/car_make/BMW.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
static/images/car_make/Chevrolet.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
static/images/car_make/Citroen.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
static/images/car_make/EXEED.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/car_make/Ford.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
static/images/car_make/Forthing_dE9ZPZJ.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
static/images/car_make/GAC.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
static/images/car_make/GMC.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
static/images/car_make/Geely.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/car_make/Genesis.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/car_make/Hongqi.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
static/images/car_make/JAC.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
static/images/car_make/JMC.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
static/images/car_make/Jeep.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
static/images/car_make/Jeep_qOaP3Rw.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
static/images/car_make/Jetour.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/car_make/KIA.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
static/images/car_make/Lamborghini.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
static/images/car_make/Land-Rover.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
static/images/car_make/Lincoln_mocx6Kj.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
static/images/car_make/Lucid.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
static/images/car_make/LynkCo.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/car_make/Maxus.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
static/images/car_make/Mercedes-Benz.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
static/images/car_make/Nissan.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
static/images/car_make/Peugeot.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
static/images/car_make/Porsche.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
static/images/car_make/Rayton-Fissore.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
static/images/car_make/Renault.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
static/images/car_make/Rolls-Royce.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
static/images/car_make/Rover.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/car_make/Rover01.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/car_make/Seres.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
static/images/car_make/Smart.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
static/images/car_make/Ssangyong.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
static/images/car_make/Stelato.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
static/images/car_make/Subaru.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
static/images/car_make/Suzuki.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
static/images/car_make/TATA.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
static/images/car_make/Tank.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/images/car_make/Tesla.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
static/images/car_make/Toyota-01.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
static/images/car_make/Volkswagen.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
static/images/car_make/Volvo.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/car_make/Voyah.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
static/images/car_make/Zotye.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
static/images/car_make/haval.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
static/images/car_make/zx.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
static/images/logos/.DS_Store
vendored
BIN
static/images/logos/car_make/.DS_Store
vendored
BIN
static/images/logos/car_make/Abarth.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
static/images/logos/car_make/Alfa-Romeo-2.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
static/images/logos/car_make/Alfa-Romeo.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
static/images/logos/car_make/BAIC-1.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
static/images/logos/car_make/BMW.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
static/images/logos/car_make/BYD.webp
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
static/images/logos/car_make/Bestune.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
static/images/logos/car_make/Bestune.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
static/images/logos/car_make/Chevrolet.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
static/images/logos/car_make/Citroën.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
static/images/logos/car_make/Dongfeng-1.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
static/images/logos/car_make/EXEED.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/logos/car_make/Ford.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 105 KiB |
BIN
static/images/logos/car_make/Forthing.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
static/images/logos/car_make/GAC.png
Normal file
|
After Width: | Height: | Size: 37 KiB |