fixup! update

This commit is contained in:
Marwan Alwali 2025-03-14 02:04:21 +03:00
parent aa3abdb91e
commit 5e5eec299a
105 changed files with 7082 additions and 19579840 deletions

4
.gitignore vendored
View File

@ -4,12 +4,16 @@
*.pyc *.pyc
__pycache__ __pycache__
**/*__pycache__ **/*__pycache__
**/*/__pycache__
inventory/__pycache__
db.sqlite db.sqlite
db.sqlite3 db.sqlite3
db.sqlite3.backup db.sqlite3.backup
db.sqlite* db.sqlite*
media media
car*.json
car_inventory/settings.py car_inventory/settings.py
car_inventory/__pycache__
scripts/dsrpipe.py scripts/dsrpipe.py
# Backup files # # Backup files #
*.bak *.bak

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,830 +0,0 @@
[
{
"model": "inventory.carspecification",
"pk": 1,
"fields": {
"name": "Bodywork",
"arabic_name": "هيكل السيارة",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 2,
"fields": {
"name": "Body type",
"arabic_name": "نوع الهيكل",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 3,
"fields": {
"name": "Number of doors",
"arabic_name": "عدد الأبواب",
"id_parent": 1549
}
},
{
"model": "inventory.carspecification",
"pk": 4,
"fields": {
"name": "Number of seater",
"arabic_name": "عدد المقاعد",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 5,
"fields": {
"name": "Length",
"arabic_name": "الطول",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 6,
"fields": {
"name": "Width",
"arabic_name": "العرض",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 7,
"fields": {
"name": "Height",
"arabic_name": "الارتفاع",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 8,
"fields": {
"name": "Wheelbase",
"arabic_name": "قاعدة العجلات",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 9,
"fields": {
"name": "Front track",
"arabic_name": "المسار الأمامي",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 10,
"fields": {
"name": "Rear track",
"arabic_name": "المسافة الخلفية بين العجلات",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 11,
"fields": {
"name": "Engine",
"arabic_name": "محرك",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 12,
"fields": {
"name": "Engine type",
"arabic_name": "نوع المحرك",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 13,
"fields": {
"name": "Capacity",
"arabic_name": "السعة",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 14,
"fields": {
"name": "Engine power",
"arabic_name": "قوة المحرك",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 15,
"fields": {
"name": "Max power at RPM",
"arabic_name": "الحد الأقصى للقوة عند عدد الدورات في الدقيقة",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 16,
"fields": {
"name": "Maximum torque",
"arabic_name": "أقصى عزم دوران",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 17,
"fields": {
"name": "Injection type",
"arabic_name": "نوع الحقن",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 19,
"fields": {
"name": "Cylinder layout",
"arabic_name": "تخطيط الأسطوانات",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 20,
"fields": {
"name": "Number of cylinders",
"arabic_name": "عدد الأسطوانات",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 21,
"fields": {
"name": "Compression ratio",
"arabic_name": "نسبة الانضغاط",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 22,
"fields": {
"name": "Fuel",
"arabic_name": "وقود",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 23,
"fields": {
"name": "Gearbox and handling",
"arabic_name": "علبة التروس والتحكم",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 24,
"fields": {
"name": "Gearbox type",
"arabic_name": "نوع علبة التروس",
"id_parent": 23
}
},
{
"model": "inventory.carspecification",
"pk": 26,
"fields": {
"name": "Number of gear",
"arabic_name": "عدد التروس",
"id_parent": 23
}
},
{
"model": "inventory.carspecification",
"pk": 27,
"fields": {
"name": "Drive wheels",
"arabic_name": "عجلات القيادة",
"id_parent": 23
}
},
{
"model": "inventory.carspecification",
"pk": 29,
"fields": {
"name": "Front brakes",
"arabic_name": "الفرامل الأمامية",
"id_parent": 40
}
},
{
"model": "inventory.carspecification",
"pk": 30,
"fields": {
"name": "Rear brakes",
"arabic_name": "الفرامل الخلفية",
"id_parent": 40
}
},
{
"model": "inventory.carspecification",
"pk": 31,
"fields": {
"name": "Operating characteristics",
"arabic_name": "خصائص التشغيل",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 32,
"fields": {
"name": "Max speed",
"arabic_name": "السرعة القصوى",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 33,
"fields": {
"name": "Acceleration (0-100 km/h)",
"arabic_name": "التسارع (0-100 كم/ساعة)",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 34,
"fields": {
"name": "Curb weight",
"arabic_name": "وزن السيارة الفارغة",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 35,
"fields": {
"name": "Fuel tank capacity",
"arabic_name": "سعة خزان الوقود",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 36,
"fields": {
"name": "Wheel size",
"arabic_name": "حجم العجلة",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 37,
"fields": {
"name": "Emission standards",
"arabic_name": "معايير الانبعاثات",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 38,
"fields": {
"name": "Ground clearance",
"arabic_name": "الخلوص الأرضي",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 39,
"fields": {
"name": "Valves per cylinder",
"arabic_name": "صمامات لكل أسطوانة",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 40,
"fields": {
"name": "Suspension and brakes",
"arabic_name": "نظام التعليق والفرامل",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 41,
"fields": {
"name": "Front suspension",
"arabic_name": "التعليق الأمامي",
"id_parent": 40
}
},
{
"model": "inventory.carspecification",
"pk": 42,
"fields": {
"name": "Back suspension",
"arabic_name": "التعليق الخلفي",
"id_parent": 40
}
},
{
"model": "inventory.carspecification",
"pk": 44,
"fields": {
"name": "Max trunk capacity",
"arabic_name": "أقصى سعة لصندوق الأمتعة",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 45,
"fields": {
"name": "Min trunk capacity",
"arabic_name": "سعة صندوق الأمتعة الدنيا",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 46,
"fields": {
"name": "Boost type",
"arabic_name": "نوع التعزيز",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 47,
"fields": {
"name": "Cylinder bore",
"arabic_name": "تجويف الأسطوانة",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 48,
"fields": {
"name": "Stroke cycle",
"arabic_name": "دورة الأشواط",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 50,
"fields": {
"name": "City driving fuel consumption per 100 km",
"arabic_name": "استهلاك الوقود في القيادة داخل المدينة لكل 100 كيلومتر",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 51,
"fields": {
"name": "Highway driving fuel consumption per 100 km",
"arabic_name": "استهلاك الوقود على الطرق السريعة لكل 100 كم",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 52,
"fields": {
"name": "Mixed driving fuel consumption per 100 km",
"arabic_name": "استهلاك الوقود في القيادة المختلطة لكل 100 كيلومتر",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 55,
"fields": {
"name": "Engine model",
"arabic_name": "نموذج المحرك",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 57,
"fields": {
"name": "Turning circle",
"arabic_name": "دائرة الدوران",
"id_parent": 23
}
},
{
"model": "inventory.carspecification",
"pk": 58,
"fields": {
"name": "Full weight",
"arabic_name": "الوزن الكامل",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 59,
"fields": {
"name": "Disc size",
"arabic_name": "حجم القرص",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 61,
"fields": {
"name": "Engine placement",
"arabic_name": "موضع المحرك",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 62,
"fields": {
"name": "Cruising range",
"arabic_name": "مدى القيادة",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 66,
"fields": {
"name": "Car width with mirrors",
"arabic_name": "عرض السيارة مع المرايا",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1549,
"fields": {
"name": "General information",
"arabic_name": "معلومات عامة",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 1551,
"fields": {
"name": "Safety",
"arabic_name": "السلامة",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 1552,
"fields": {
"name": "Country",
"arabic_name": "بلد",
"id_parent": 1549
}
},
{
"model": "inventory.carspecification",
"pk": 1553,
"fields": {
"name": "Car class",
"arabic_name": "فئة السيارة",
"id_parent": 1549
}
},
{
"model": "inventory.carspecification",
"pk": 1554,
"fields": {
"name": "Clearance",
"arabic_name": "الخلوص",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1555,
"fields": {
"name": "Front track width",
"arabic_name": "عرض المسار الأمامي",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1556,
"fields": {
"name": "Back track width",
"arabic_name": "عرض المسار الخلفي",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1559,
"fields": {
"name": "Max power (kW)",
"arabic_name": "القدرة القصوى (كيلوواط)",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1561,
"fields": {
"name": "CO2 emissions",
"arabic_name": "انبعاثات ثاني أكسيد الكربون",
"id_parent": 31
}
},
{
"model": "inventory.carspecification",
"pk": 1562,
"fields": {
"name": "Safety assessment",
"arabic_name": "تقييم السلامة",
"id_parent": 1551
}
},
{
"model": "inventory.carspecification",
"pk": 1563,
"fields": {
"name": "Rating name",
"arabic_name": "اسم التقييم",
"id_parent": 1551
}
},
{
"model": "inventory.carspecification",
"pk": 1564,
"fields": {
"name": "Turnover of maximum torque",
"arabic_name": "دوران أقصى عزم",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1565,
"fields": {
"name": "Payload",
"arabic_name": "الحمولة",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1566,
"fields": {
"name": "Presence of intercooler",
"arabic_name": "وجود مبرد داخلي",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1567,
"fields": {
"name": "Trailer load (with brakes)",
"arabic_name": "حمولة المقطورة (مع الفرامل)",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1568,
"fields": {
"name": "Front/rear axle load",
"arabic_name": "حمولة المحور الأمامي/الخلفي",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1569,
"fields": {
"name": "Loading height",
"arabic_name": "ارتفاع التحميل",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1570,
"fields": {
"name": "Cargo compartment (Length x Width x Height)",
"arabic_name": "مقصورة الشحن (الطول × العرض × الارتفاع)",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1571,
"fields": {
"name": "Cargo compartment volume",
"arabic_name": "حجم حيز الأمتعة",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1631,
"fields": {
"name": "Accumulator battery",
"arabic_name": "بطارية تراكمية",
"id_parent": null
}
},
{
"model": "inventory.carspecification",
"pk": 1632,
"fields": {
"name": "Battery capacity",
"arabic_name": "سعة البطارية",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1634,
"fields": {
"name": "Electric power reserve",
"arabic_name": "احتياطي الطاقة الكهربائية",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1635,
"fields": {
"name": "Charging time",
"arabic_name": "وقت الشحن",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1641,
"fields": {
"name": "Steering wheel position",
"arabic_name": "موضع عجلة القيادة",
"id_parent": 1549
}
},
{
"model": "inventory.carspecification",
"pk": 1642,
"fields": {
"name": "Dimensions",
"arabic_name": "الأبعاد",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1644,
"fields": {
"name": "Pitch Circle Diameter",
"arabic_name": "قطر دائرة التثبيت",
"id_parent": 1
}
},
{
"model": "inventory.carspecification",
"pk": 1645,
"fields": {
"name": "Engine code",
"arabic_name": "رمز المحرك",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1647,
"fields": {
"name": "Battery type",
"arabic_name": "نوع البطارية",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1648,
"fields": {
"name": "Timing belt",
"arabic_name": "حزام التوقيت",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1649,
"fields": {
"name": "Flow calculation method",
"arabic_name": "طريقة حساب التدفق",
"id_parent": 11
}
},
{
"model": "inventory.carspecification",
"pk": 1650,
"fields": {
"name": "Battery temperature",
"arabic_name": "درجة حرارة البطارية",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1651,
"fields": {
"name": "Fast charge time",
"arabic_name": "وقت الشحن السريع",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1652,
"fields": {
"name": "Description of fast charging",
"arabic_name": "وصف الشحن السريع",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1653,
"fields": {
"name": "Charging connector type",
"arabic_name": "نوع موصل الشحن",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1654,
"fields": {
"name": "Consumption",
"arabic_name": "استهلاك",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1655,
"fields": {
"name": "Maximum charging power",
"arabic_name": "أقصى قدرة شحن",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1656,
"fields": {
"name": "Battery capacity (available)",
"arabic_name": "سعة البطارية (المتاحة)",
"id_parent": 1631
}
},
{
"model": "inventory.carspecification",
"pk": 1657,
"fields": {
"name": "Number of charging cycles",
"arabic_name": "عدد دورات الشحن",
"id_parent": 1631
}
}
]

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
# Generated by Django 5.1.5 on 2025-01-30 11:28 # Generated by Django 5.1.6 on 2025-03-06 01:43
import datetime
import django.db.models.deletion import django.db.models.deletion
import inventory.mixins import inventory.mixins
import inventory.models import inventory.models
@ -14,8 +15,12 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('appointment', '__first__'),
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'), ('contenttypes', '0002_remove_content_type_name'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ENTITY_MODEL), migrations.swappable_dependency(settings.DJANGO_LEDGER_ENTITY_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ESTIMATE_MODEL), migrations.swappable_dependency(settings.DJANGO_LEDGER_ESTIMATE_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_INVOICE_MODEL), migrations.swappable_dependency(settings.DJANGO_LEDGER_INVOICE_MODEL),
@ -94,25 +99,6 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'payments', 'verbose_name_plural': 'payments',
}, },
), ),
migrations.CreateModel(
name='SubscriptionPlan',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Name of the subscription plan', max_length=100, unique=True)),
('description', models.TextField()),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('max_users', models.PositiveIntegerField(default=1, help_text='Maximum number of users allowed')),
('max_inventory_size', models.PositiveIntegerField(default=50, help_text='Maximum number of cars in inventory')),
('support_level', models.CharField(choices=[('basic', 'Basic Support'), ('priority', 'Priority Support'), ('dedicated', 'Dedicated Support')], default='basic', help_text='Level of support provided', max_length=50)),
('custom_features', models.JSONField(blank=True, help_text='Additional features specific to this plan', null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'Subscription Plan',
'verbose_name_plural': 'Subscription Plans',
},
),
migrations.CreateModel( migrations.CreateModel(
name='VatRate', name='VatRate',
fields=[ fields=[
@ -122,23 +108,6 @@ class Migration(migrations.Migration):
('created_at', models.DateTimeField(auto_now_add=True)), ('created_at', models.DateTimeField(auto_now_add=True)),
], ],
), ),
migrations.CreateModel(
name='Activity',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('activity_type', models.CharField(choices=[('call', 'Call'), ('sms', 'SMS'), ('email', 'Email'), ('whatsapp', 'WhatsApp'), ('visit', 'Visit'), ('add_car', 'Add Car'), ('reserve_car', 'Reserve Car'), ('remove_car', 'Remove Car'), ('create_quotation', 'Create Quotation'), ('cancel_quotation', 'Cancel Quotation'), ('create_order', 'Create Order'), ('cancel_order', 'Cancel Order'), ('create_invoice', 'Create Invoice'), ('cancel_invoice', 'Cancel Invoice')], max_length=50, verbose_name='Activity Type')),
('notes', models.TextField(blank=True, null=True, verbose_name='Notes')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='activities_created', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Activity',
'verbose_name_plural': 'Activities',
},
),
migrations.CreateModel( migrations.CreateModel(
name='AdditionalServices', name='AdditionalServices',
fields=[ fields=[
@ -168,6 +137,7 @@ class Migration(migrations.Migration):
('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')),
('receiving_date', models.DateTimeField(verbose_name='Receiving Date')), ('receiving_date', models.DateTimeField(verbose_name='Receiving Date')),
('hash', models.CharField(blank=True, max_length=64, null=True, verbose_name='Hash')),
('vendor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to=settings.DJANGO_LEDGER_VENDOR_MODEL, verbose_name='Vendor')), ('vendor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to=settings.DJANGO_LEDGER_VENDOR_MODEL, verbose_name='Vendor')),
('id_car_make', models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')), ('id_car_make', models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')),
], ],
@ -242,10 +212,10 @@ class Migration(migrations.Migration):
('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')),
('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(blank=True, max_length=1, null=True, verbose_name='Text 2')),
('text3', models.CharField(max_length=1, verbose_name='Text 3')), ('text3', models.CharField(blank=True, max_length=1, null=True, verbose_name='Text 3')),
('registration_date', models.DateTimeField(verbose_name='Registration Date')), ('registration_date', models.DateTimeField(verbose_name='Registration Date')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')), ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')),
], ],
options={ options={
'verbose_name': 'Registration', 'verbose_name': 'Registration',
@ -362,6 +332,15 @@ class Migration(migrations.Migration):
('objects', inventory.models.DealerUserManager()), ('objects', inventory.models.DealerUserManager()),
], ],
), ),
migrations.CreateModel(
name='CustomGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.group', verbose_name='')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='inventory.dealer')),
],
),
migrations.CreateModel( migrations.CreateModel(
name='Customer', name='Customer',
fields=[ fields=[
@ -378,6 +357,7 @@ class Migration(migrations.Migration):
('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')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='customer_profile', to=settings.AUTH_USER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')),
], ],
options={ options={
@ -432,19 +412,78 @@ class Migration(migrations.Migration):
name='dealer', name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'), field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'),
), ),
migrations.CreateModel(
name='Activity',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('activity_type', models.CharField(choices=[('call', 'Call'), ('sms', 'SMS'), ('email', 'Email'), ('whatsapp', 'WhatsApp'), ('visit', 'Visit'), ('add_car', 'Add Car'), ('sale_car', 'Sale Car'), ('reserve_car', 'Reserve Car'), ('transfer_car', 'Transfer Car'), ('remove_car', 'Remove Car'), ('create_quotation', 'Create Quotation'), ('cancel_quotation', 'Cancel Quotation'), ('create_order', 'Create Order'), ('cancel_order', 'Cancel Order'), ('create_invoice', 'Create Invoice'), ('cancel_invoice', 'Cancel Invoice')], max_length=50, verbose_name='Activity Type')),
('notes', models.TextField(blank=True, null=True, verbose_name='Notes')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='contenttypes.contenttype')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='activities_created_by', to=settings.AUTH_USER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='inventory.dealer')),
],
options={
'verbose_name': 'Activity',
'verbose_name_plural': 'Activities',
},
),
migrations.CreateModel(
name='DealerSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('additional_info', models.JSONField(blank=True, default=dict, null=True)),
('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('dealer', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='settings', to='inventory.dealer')),
('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
],
),
migrations.CreateModel(
name='Email',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('from_email', models.TextField(blank=True, null=True, verbose_name='From Email')),
('to_email', models.TextField(blank=True, null=True, verbose_name='To Email')),
('subject', models.TextField(blank=True, null=True, verbose_name='Subject')),
('message', models.TextField(blank=True, null=True, verbose_name='Message')),
('status', models.CharField(choices=[('SENT', 'Sent'), ('FAILED', 'Failed'), ('DELIVERED', 'Delivered'), ('OPEN', 'Open'), ('DRAFT', 'Draft')], default='OPEN', max_length=20, verbose_name='Status')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='emails_created', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Email',
'verbose_name_plural': 'Emails',
},
),
migrations.CreateModel( migrations.CreateModel(
name='Lead', name='Lead',
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')),
('first_name', models.CharField(max_length=50, verbose_name='First Name')),
('last_name', models.CharField(max_length=50, verbose_name='Last Name')),
('email', models.EmailField(max_length=254, verbose_name='Email')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('lead_type', models.CharField(choices=[('customer', 'Customer'), ('organization', 'Organization')], default='customer', max_length=50, verbose_name='Lead Type')),
('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year')), ('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year')),
('source', models.CharField(choices=[('referrals', 'Referrals'), ('whatsapp', 'WhatsApp'), ('showroom', 'Showroom'), ('tiktok', 'TikTok'), ('instagram', 'Instagram'), ('x', 'X'), ('facebook', 'Facebook'), ('motory', 'Motory'), ('influencers', 'Influencers'), ('youtube', 'Youtube'), ('campaign', 'Campaign')], max_length=50, verbose_name='Source')), ('source', models.CharField(choices=[('referrals', 'Referrals'), ('whatsapp', 'WhatsApp'), ('showroom', 'Showroom'), ('tiktok', 'TikTok'), ('instagram', 'Instagram'), ('x', 'X'), ('facebook', 'Facebook'), ('motory', 'Motory'), ('influencers', 'Influencers'), ('youtube', 'Youtube'), ('campaign', 'Campaign')], max_length=50, verbose_name='Source')),
('channel', models.CharField(choices=[('walk_in', 'Walk In'), ('toll_free', 'Toll Free'), ('website', 'Website'), ('email', 'Email'), ('form', 'Form')], max_length=50, verbose_name='Channel')), ('channel', models.CharField(choices=[('walk_in', 'Walk In'), ('toll_free', 'Toll Free'), ('website', 'Website'), ('email', 'Email'), ('form', 'Form')], max_length=50, verbose_name='Channel')),
('city', models.CharField(max_length=50, verbose_name='City')), ('crn', models.CharField(blank=True, max_length=10, null=True, unique=True, verbose_name='Commercial Registration Number')),
('vrn', models.CharField(blank=True, max_length=15, null=True, unique=True, verbose_name='VAT Registration Number')),
('address', models.CharField(max_length=50, verbose_name='address')),
('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')], default='medium', max_length=10, verbose_name='Priority')), ('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')], default='medium', max_length=10, verbose_name='Priority')),
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status')), ('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status')),
('created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Created')), ('created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.customer')), ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer')),
('id_car_make', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')), ('id_car_make', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')),
('id_car_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model')), ('id_car_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model')),
@ -554,6 +593,26 @@ class Migration(migrations.Migration):
'ordering': ['-created'], 'ordering': ['-created'],
}, },
), ),
migrations.CreateModel(
name='Schedule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('purpose', models.CharField(choices=[('Product Demo', 'Product Demo'), ('Follow-Up Call', 'Follow-Up Call'), ('Contract Discussion', 'Contract Discussion'), ('Sales Meeting', 'Sales Meeting'), ('Support Call', 'Support Call'), ('Other', 'Other')], max_length=200)),
('scheduled_at', models.DateTimeField()),
('scheduled_type', models.CharField(choices=[('Call', 'Call'), ('Meeting', 'Meeting'), ('Email', 'Email')], default='Call', max_length=200)),
('duration', models.DurationField(default=datetime.timedelta(seconds=300))),
('notes', models.TextField(blank=True, null=True)),
('status', models.CharField(choices=[('Scheduled', 'Scheduled'), ('Completed', 'Completed'), ('Canceled', 'Canceled')], default='Scheduled', max_length=200)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='inventory.lead')),
('scheduled_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-scheduled_at'],
},
),
migrations.CreateModel( migrations.CreateModel(
name='Staff', name='Staff',
fields=[ fields=[
@ -561,11 +620,11 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=255, verbose_name='Name')), ('name', models.CharField(max_length=255, verbose_name='Name')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('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')),
('staff_type', models.CharField(choices=[('manager', 'Manager'), ('inventory', 'Inventory'), ('accountant', 'Accountant'), ('sales', 'Sales'), ('coordinator', 'Coordinator'), ('receptionist', 'Receptionist'), ('agent', 'Agent')], max_length=255, verbose_name='Staff Type')), ('staff_type', models.CharField(choices=[('inventory', 'Inventory'), ('accountant', 'Accountant'), ('sales', 'Sales')], max_length=255, verbose_name='Staff Type')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to='inventory.dealer')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to='inventory.dealer')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to=settings.AUTH_USER_MODEL)), ('staff_member', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to='appointment.staffmember')),
], ],
options={ options={
'verbose_name': 'Staff', 'verbose_name': 'Staff',
@ -582,15 +641,17 @@ 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')),
('stage', models.CharField(choices=[('prospect', 'Prospect'), ('proposal', 'Proposal'), ('negotiation', 'Negotiation'), ('closed_won', 'Closed Won'), ('closed_lost', 'Closed Lost')], max_length=20, verbose_name='Stage')), ('stage', models.CharField(choices=[('prospect', 'Prospect'), ('proposal', 'Proposal'), ('negotiation', 'Negotiation'), ('closed_won', 'Closed Won'), ('closed_lost', 'Closed Lost')], max_length=20, verbose_name='Stage')),
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], default='new', max_length=20, verbose_name='Status')), ('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], default='new', max_length=20, verbose_name='Status')),
('probability', models.PositiveIntegerField(validators=[inventory.models.validate_probability])), ('probability', models.PositiveIntegerField(validators=[inventory.models.validate_probability])),
('closing_date', models.DateField(verbose_name='Closing Date')), ('closing_date', models.DateField(blank=True, null=True, verbose_name='Closing Date')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('closed', models.BooleanField(default=False, verbose_name='Closed')), ('closed', models.BooleanField(default=False, verbose_name='Closed')),
('car', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.car', verbose_name='Car')), ('car', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.car', verbose_name='Car')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.customer')), ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.dealer')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.dealer')),
('estimate', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL)),
('lead', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunity', to='inventory.lead')),
('staff', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner', to='inventory.staff', verbose_name='Owner')), ('staff', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner', to='inventory.staff', verbose_name='Owner')),
], ],
options={ options={
@ -602,8 +663,8 @@ class Migration(migrations.Migration):
name='LeadStatusHistory', name='LeadStatusHistory',
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')),
('old_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], max_length=50, verbose_name='Old Status')), ('old_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], max_length=50, verbose_name='Old Status')),
('new_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], max_length=50, verbose_name='New Status')), ('new_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], max_length=50, verbose_name='New Status')),
('changed_at', models.DateTimeField(auto_now_add=True, verbose_name='Changed At')), ('changed_at', models.DateTimeField(auto_now_add=True, verbose_name='Changed At')),
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_history', to='inventory.lead')), ('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_history', to='inventory.lead')),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='status_changes', to='inventory.staff')), ('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='status_changes', to='inventory.staff')),
@ -618,40 +679,6 @@ class Migration(migrations.Migration):
name='staff', name='staff',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned', to='inventory.staff', verbose_name='Assigned'), field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned', to='inventory.staff', verbose_name='Assigned'),
), ),
migrations.CreateModel(
name='Subscription',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start_date', models.DateField(help_text='Date when the subscription starts')),
('end_date', models.DateField(help_text='Date when the subscription ends')),
('is_active', models.BooleanField(default=True)),
('billing_cycle', models.CharField(choices=[('monthly', 'Monthly'), ('annual', 'Annual')], default='monthly', help_text='Billing cycle for the subscription', max_length=10)),
('last_payment_date', models.DateField(blank=True, help_text='Date of the last payment made', null=True)),
('next_payment_date', models.DateField(blank=True, help_text='Date of the next payment due', null=True)),
('plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subscriptions', to='inventory.subscriptionplan')),
],
options={
'verbose_name': 'Subscription',
'verbose_name_plural': 'Subscriptions',
},
),
migrations.CreateModel(
name='SubscriptionUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Subscription User',
'verbose_name_plural': 'Subscription Users',
},
),
migrations.AddField(
model_name='subscription',
name='users',
field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel( migrations.CreateModel(
name='UserActivityLog', name='UserActivityLog',
fields=[ fields=[
@ -704,11 +731,23 @@ class Migration(migrations.Migration):
'unique_together': {('car', 'reserved_until')}, 'unique_together': {('car', 'reserved_until')},
}, },
), ),
migrations.CreateModel(
name='DealersMake',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('added_at', models.DateTimeField(auto_now_add=True)),
('car_make', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='car_dealers', to='inventory.carmake')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dealer_makes', to='inventory.dealer')),
],
options={
'unique_together': {('dealer', 'car_make')},
},
),
migrations.CreateModel( migrations.CreateModel(
name='CarColors', name='CarColors',
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')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.car')), ('car', models.OneToOneField(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')), ('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')), ('interior', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.interiorcolors')),
], ],

View File

@ -1,19 +0,0 @@
# Generated by Django 5.1.5 on 2025-02-04 04:37
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='carregistration',
name='car',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 09:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='lead',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -1,46 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 11:38
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0002_alter_lead_customer'),
]
operations = [
migrations.AddField(
model_name='lead',
name='email',
field=models.EmailField(default='x@tenhal.sa', max_length=254, verbose_name='Email'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='first_name',
field=models.CharField(default='test', max_length=50, verbose_name='First Name'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='last_name',
field=models.CharField(default='test', max_length=50, verbose_name='Last Name'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='phone_number',
field=phonenumber_field.modelfields.PhoneNumberField(default='056523656', max_length=128, region='SA', verbose_name='Phone Number'),
preserve_default=False,
),
migrations.AlterField(
model_name='lead',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 14:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_lead_email_lead_first_name_lead_last_name_and_more'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='city',
),
migrations.AddField(
model_name='lead',
name='address',
field=models.CharField(default='', max_length=50, verbose_name='address'),
preserve_default=False,
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 15:15
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0004_remove_lead_city_lead_address'),
]
operations = [
migrations.CreateModel(
name='Schedule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('purpose', models.CharField(max_length=200)),
('scheduled_at', models.DateTimeField()),
('notes', models.TextField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='inventory.lead')),
('scheduled_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.staff')),
],
options={
'ordering': ['-scheduled_at'],
},
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 15:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0005_schedule'),
]
operations = [
migrations.AlterField(
model_name='schedule',
name='purpose',
field=models.CharField(choices=[('Product Demo', 'Product Demo'), ('Follow-Up Call', 'Follow-Up Call'), ('Contract Discussion', 'Contract Discussion'), ('Sales Meeting', 'Sales Meeting'), ('Support Call', 'Support Call'), ('Other', 'Other')], max_length=200),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-04 15:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0006_alter_schedule_purpose'),
]
operations = [
migrations.AddField(
model_name='schedule',
name='scheduled_type',
field=models.CharField(choices=[('Call', 'Call'), ('Meeting', 'Meeting'), ('Email', 'Email')], default='Call', max_length=200),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-05 09:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0007_schedule_scheduled_type'),
]
operations = [
migrations.AddField(
model_name='schedule',
name='status',
field=models.CharField(choices=[('Scheduled', 'Scheduled'), ('Completed', 'Completed'), ('Canceled', 'Canceled')], default='Scheduled', max_length=200),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-05 10:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0008_schedule_status'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -1,27 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-05 10:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0009_alter_opportunity_customer'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='id_car_make',
),
migrations.RemoveField(
model_name='lead',
name='id_car_model',
),
migrations.AddField(
model_name='lead',
name='car',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.car', verbose_name='Car'),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-05 10:17
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0010_remove_lead_id_car_make_remove_lead_id_car_model_and_more'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='year',
),
migrations.AlterField(
model_name='schedule',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -1,14 +0,0 @@
# Generated by Django 5.1.5 on 2025-02-06 08:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_alter_carregistration_car'),
('inventory', '0011_remove_lead_year_alter_schedule_customer'),
]
operations = [
]

View File

@ -1,14 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-06 10:08
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_alter_carregistration_car'),
('inventory', '0011_remove_lead_year_alter_schedule_customer'),
]
operations = [
]

View File

@ -1,23 +0,0 @@
# Generated by Django 5.1.5 on 2025-02-07 01:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0012_merge_20250206_1151'),
]
operations = [
migrations.AlterField(
model_name='carregistration',
name='text2',
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Text 2'),
),
migrations.AlterField(
model_name='carregistration',
name='text3',
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Text 3'),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-06 12:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0013_alter_carregistration_text2_and_more'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='car',
),
migrations.AddField(
model_name='lead',
name='id_car_make',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'),
),
migrations.AddField(
model_name='lead',
name='id_car_model',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'),
),
migrations.AddField(
model_name='lead',
name='year',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year'),
),
]

View File

@ -1,14 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-09 08:16
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0012_merge_20250206_1308'),
('inventory', '0014_remove_lead_car_lead_id_car_make_lead_id_car_model_and_more'),
]
operations = [
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-09 08:23
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0015_merge_20250209_1116'),
]
operations = [
migrations.AddField(
model_name='schedule',
name='duration',
field=models.DurationField(default=datetime.timedelta(seconds=300)),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-09 11:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0016_schedule_duration'),
]
operations = [
migrations.AddField(
model_name='car',
name='hash',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='Hash'),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 5.1.5 on 2025-02-11 00:23
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0017_car_hash'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='customer',
name='user',
field=models.OneToOneField(default=4, on_delete=django.db.models.deletion.CASCADE, related_name='customer_profile', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-12 10:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0018_customer_user'),
]
operations = [
migrations.AddField(
model_name='opportunity',
name='lead',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='inventory.lead'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-12 10:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0019_opportunity_lead'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='closing_date',
field=models.DateField(blank=True, null=True, verbose_name='Closing Date'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-12 10:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0020_alter_opportunity_closing_date'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='lead',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunity', to='inventory.lead'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-12 14:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ESTIMATE_MODEL),
('inventory', '0021_alter_opportunity_lead'),
]
operations = [
migrations.AddField(
model_name='opportunity',
name='estimate',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL),
),
]

View File

@ -1,36 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-13 09:01
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contenttypes', '0002_remove_content_type_name'),
('inventory', '0022_opportunity_estimate'),
]
operations = [
migrations.CreateModel(
name='Email',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('object_id', models.PositiveIntegerField()),
('from_email', models.TextField(blank=True, null=True, verbose_name='From Email')),
('to_email', models.TextField(blank=True, null=True, verbose_name='To Email')),
('subject', models.TextField(blank=True, null=True, verbose_name='Subject')),
('body', models.TextField(blank=True, null=True, verbose_name='Body')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='emails_created', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Email',
'verbose_name_plural': 'Emails',
},
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-13 09:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0023_email'),
]
operations = [
migrations.RemoveField(
model_name='email',
name='body',
),
migrations.AddField(
model_name='email',
name='message',
field=models.TextField(blank=True, null=True, verbose_name='Message'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-13 09:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0024_remove_email_body_email_message'),
]
operations = [
migrations.AddField(
model_name='email',
name='status',
field=models.CharField(choices=[('SENT', 'Sent'), ('FAILED', 'Failed'), ('DELIVERED', 'Delivered'), ('OPEN', 'Open'), ('DRAFT', 'Draft')], default='OPEN', max_length=20, verbose_name='Status'),
),
]

View File

@ -1,29 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-17 08:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0025_email_status'),
]
operations = [
migrations.CreateModel(
name='CarHistory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event_date', models.DateField()),
('event_type', models.CharField(choices=[('PURCHASE', 'Purchase'), ('SALE', 'Sale'), ('TRANSFER', 'Transfer'), ('ACCIDENT', 'Accident'), ('MAINTENANCE', 'Maintenance'), ('SERVICE', 'Service'), ('OTHER', 'Other')], max_length=50)),
('description', models.TextField(blank=True, null=True)),
('mileage', models.IntegerField(blank=True, null=True)),
('cost', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='history', to='inventory.car')),
],
options={
'ordering': ['-event_date'],
},
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-17 08:57
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0026_carhistory'),
]
operations = [
migrations.AddField(
model_name='carhistory',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='history', to='inventory.dealer'),
preserve_default=False,
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-17 09:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0027_carhistory_dealer'),
]
operations = [
migrations.AddField(
model_name='carhistory',
name='additional_info',
field=models.JSONField(blank=True, default=dict, null=True, verbose_name='Car History Additional Info'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-17 09:03
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0028_carhistory_additional_info'),
]
operations = [
migrations.RemoveField(
model_name='carhistory',
name='cost',
),
migrations.RemoveField(
model_name='carhistory',
name='mileage',
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-17 09:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0029_remove_carhistory_cost_remove_carhistory_mileage'),
]
operations = [
migrations.AlterField(
model_name='activity',
name='activity_type',
field=models.CharField(choices=[('call', 'Call'), ('sms', 'SMS'), ('email', 'Email'), ('whatsapp', 'WhatsApp'), ('visit', 'Visit'), ('add_car', 'Add Car'), ('sale_car', 'Sale Car'), ('reserve_car', 'Reserve Car'), ('transfer_car', 'Transfer Car'), ('remove_car', 'Remove Car'), ('create_quotation', 'Create Quotation'), ('cancel_quotation', 'Cancel Quotation'), ('create_order', 'Create Order'), ('cancel_order', 'Cancel Order'), ('create_invoice', 'Create Invoice'), ('cancel_invoice', 'Cancel Invoice')], max_length=50, verbose_name='Activity Type'),
),
migrations.DeleteModel(
name='CarHistory',
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 5.1.5 on 2025-02-17 14:05
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('inventory', '0030_alter_activity_activity_type_delete_carhistory'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='activity',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='inventory.dealer'),
preserve_default=False,
),
migrations.AlterField(
model_name='activity',
name='content_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='contenttypes.contenttype'),
),
migrations.AlterField(
model_name='activity',
name='created_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='activities_created_by', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-17 17:40
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0031_activity_dealer_alter_activity_content_type_and_more'),
]
operations = [
migrations.AlterField(
model_name='carcolors',
name='car',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.car'),
),
]

View File

@ -1,32 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-19 05:25
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
# ('appointment', '0002_alter_workinghours_options'),
('inventory', '0032_alter_carcolors_car'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.RemoveField(
model_name='staff',
name='user',
),
migrations.AddField(
model_name='staff',
name='staff_member',
field=models.OneToOneField(default=5, on_delete=django.db.models.deletion.CASCADE, related_name='staff', to='appointment.staffmember'),
preserve_default=False,
),
migrations.AlterField(
model_name='schedule',
name='scheduled_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,38 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-20 01:29
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0033_remove_staff_user_staff_staff_member_and_more'),
]
operations = [
migrations.RemoveField(
model_name='subscription',
name='plan',
),
migrations.RemoveField(
model_name='subscription',
name='users',
),
migrations.RemoveField(
model_name='subscriptionuser',
name='subscription',
),
migrations.RemoveField(
model_name='subscriptionuser',
name='user',
),
migrations.DeleteModel(
name='SubscriptionPlan',
),
migrations.DeleteModel(
name='Subscription',
),
migrations.DeleteModel(
name='SubscriptionUser',
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-20 08:16
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
# ('inventory', '0037_alter_schedule_scheduled_type'),
('inventory', '0034_remove_subscription_plan_remove_subscription_users_and_more'),
]
operations = [
migrations.CreateModel(
name='CustomGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer')),
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.group', verbose_name='')),
],
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-20 08:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0038_customgroup'),
]
operations = [
migrations.AlterField(
model_name='customgroup',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='inventory.dealer'),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-23 14:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inventory', '0039_alter_customgroup_dealer'),
]
operations = [
migrations.CreateModel(
name='UserSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('language', models.CharField(choices=[('en', 'English'), ('ar', 'Arabic')], default='ar', max_length=20)),
('theme', models.CharField(choices=[('default', 'Default'), ('dark', 'Dark')], default='default', max_length=20)),
('additional_info', models.JSONField(default=dict)),
('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_ca', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_payable', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_prepaid_expense_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid_expense', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_ca', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_payable', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_prepaid_expense_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid_expense', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-23 14:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0040_usersettings'),
]
operations = [
migrations.AlterField(
model_name='usersettings',
name='additional_info',
field=models.JSONField(blank=True, default=dict, null=True),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-23 15:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inventory', '0041_alter_usersettings_additional_info'),
]
operations = [
migrations.AlterField(
model_name='usersettings',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='settings', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-23 16:23
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inventory', '0042_alter_usersettings_user'),
]
operations = [
migrations.AlterField(
model_name='usersettings',
name='user',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='settings', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-23 16:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
('inventory', '0043_alter_usersettings_user'),
]
operations = [
migrations.CreateModel(
name='DealerSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('additional_info', models.JSONField(blank=True, default=dict, null=True)),
('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_ca', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_payable', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_prepaid_expense_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid_expense', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('dealer', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='settings', to='inventory.dealer')),
('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_ca', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_payable', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_prepaid_expense_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid_expense', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
],
),
migrations.DeleteModel(
name='UserSettings',
),
]

View File

@ -1,39 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-24 09:01
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
('inventory', '0044_dealersettings_delete_usersettings'),
]
operations = [
migrations.RemoveField(
model_name='dealersettings',
name='invoice_payable_account',
),
migrations.RemoveField(
model_name='dealersettings',
name='invoice_prepaid_expense_account',
),
migrations.AddField(
model_name='dealersettings',
name='invoice_prepaid_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
migrations.AddField(
model_name='dealersettings',
name='invoice_unearned_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
migrations.AlterField(
model_name='dealersettings',
name='invoice_cash_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-24 09:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
('inventory', '0045_remove_dealersettings_invoice_payable_account_and_more'),
]
operations = [
migrations.RemoveField(
model_name='dealersettings',
name='invoice_prepaid_account',
),
migrations.AddField(
model_name='dealersettings',
name='invoice_recivable_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_recivable', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-24 09:11
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
('inventory', '0046_remove_dealersettings_invoice_prepaid_account_and_more'),
]
operations = [
migrations.RemoveField(
model_name='dealersettings',
name='invoice_recivable_account',
),
migrations.AddField(
model_name='dealersettings',
name='invoice_prepaid_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
]

View File

@ -1,39 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-24 09:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
('inventory', '0047_remove_dealersettings_invoice_recivable_account_and_more'),
]
operations = [
migrations.RemoveField(
model_name='dealersettings',
name='bill_payable_account',
),
migrations.RemoveField(
model_name='dealersettings',
name='bill_prepaid_expense_account',
),
migrations.AddField(
model_name='dealersettings',
name='bill_prepaid_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
migrations.AddField(
model_name='dealersettings',
name='bill_unearned_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
migrations.AlterField(
model_name='dealersettings',
name='bill_cash_account',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL),
),
]

View File

@ -1,33 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-26 08:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0048_remove_dealersettings_bill_payable_account_and_more'),
]
operations = [
migrations.AlterField(
model_name='lead',
name='status',
field=models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status'),
),
migrations.AlterField(
model_name='leadstatushistory',
name='new_status',
field=models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], max_length=50, verbose_name='New Status'),
),
migrations.AlterField(
model_name='leadstatushistory',
name='old_status',
field=models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], max_length=50, verbose_name='Old Status'),
),
migrations.AlterField(
model_name='opportunity',
name='status',
field=models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], default='new', max_length=20, verbose_name='Status'),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-24 17:25
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0048_remove_dealersettings_bill_payable_account_and_more'),
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
]
operations = [
migrations.AddField(
model_name='carreservation',
name='reserved_for',
field=models.ForeignKey(default='dd747dc3-39bc-411f-a17d-c930a50220fe', on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL, verbose_name='Reserved For'),
preserve_default=False,
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 5.1.6 on 2025-02-25 01:05
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0049_carreservation_reserved_for'),
]
operations = [
migrations.RemoveField(
model_name='carreservation',
name='reserved_for',
),
]

View File

@ -1,14 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-26 13:54
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0049_alter_lead_status_alter_leadstatushistory_new_status_and_more'),
('inventory', '0050_remove_carreservation_reserved_for'),
]
operations = [
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-02-27 15:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0051_merge_20250226_1654'),
]
operations = [
migrations.AddField(
model_name='lead',
name='lead_type',
field=models.CharField(choices=[('customer', 'Customer'), ('organization', 'Organization')], default='customer', max_length=50, verbose_name='Lead Type'),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 4.2.17 on 2025-03-01 21:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0052_lead_lead_type'),
]
operations = [
migrations.AddField(
model_name='lead',
name='crn',
field=models.CharField(blank=True, max_length=10, null=True, unique=True, verbose_name='Commercial Registration Number'),
),
migrations.AddField(
model_name='lead',
name='vrn',
field=models.CharField(blank=True, max_length=15, null=True, unique=True, verbose_name='VAT Registration Number'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2025-03-04 01:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0053_lead_crn_lead_vrn'),
]
operations = [
migrations.AlterField(
model_name='staff',
name='staff_type',
field=models.CharField(choices=[('inventory', 'Inventory'), ('accountant', 'Accountant'), ('sales', 'Sales')], max_length=255, verbose_name='Staff Type'),
),
]

View File

@ -1,26 +0,0 @@
# Generated by Django 5.1.6 on 2025-03-03 16:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0053_lead_crn_lead_vrn'),
]
operations = [
migrations.CreateModel(
name='DealersMake',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('added_at', models.DateTimeField(auto_now_add=True)),
('car_make', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='car_dealers', to='inventory.carmake')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dealer_makes', to='inventory.dealer')),
],
options={
'unique_together': {('dealer', 'car_make')},
},
),
]

View File

@ -1,14 +0,0 @@
# Generated by Django 4.2.17 on 2025-03-04 21:15
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0054_alter_staff_staff_type'),
('inventory', '0054_dealersmake'),
]
operations = [
]

View File

@ -1,265 +1,246 @@
aiohappyeyeballs==2.4.6 aiohappyeyeballs
aiohttp==3.11.12 aiohttp
aiohttp-retry==2.9.1 aiohttp-retry
aiosignal==1.3.2 aiosignal
alabaster==1.0.0 alabaster
albucore==0.0.23 albucore
albumentations==2.0.4 albumentations
annotated-types==0.7.0 annotated-types
anyio==4.8.0 anyio
arabic-reshaper==3.0.0 arabic-reshaper
asgiref==3.8.1 asgiref
astor==0.8.1 astor
astroid==3.3.8 astroid
attrs==25.1.0 attrs
autopep8==2.3.2 autopep8
Babel==2.15.0 Babel
beautifulsoup4==4.13.3 beautifulsoup4
bleach==6.2.0 bleach
blinker==1.9.0 blinker
Brotli==1.1.0 Brotli
cattrs==24.1.2 cattrs
certifi==2025.1.31 certifi
cffi==1.17.1 cffi
chardet==5.2.0 chardet
charset-normalizer==3.4.1 charset-normalizer
click==8.1.8 click
colorama==0.4.6 colorama
commonmark==0.9.1 commonmark
contourpy==1.3.1 contourpy
crispy-bootstrap5==2024.10 crispy-bootstrap5
cryptography==44.0.1 cryptography
cssselect2==0.7.0 cssselect2
ctranslate2==4.5.0 ctranslate2
cycler==0.12.1 cycler
Cython==3.1.0a1 Cython
decorator==5.1.1 decorator
defusedxml==0.7.1 defusedxml
desert==2020.11.18 desert
diff-match-patch==20241021 diff-match-patch
dill==0.3.9 dill
distro==1.9.0 distro
dj-rest-auth==7.0.1 dj-rest-auth
dj-shop-cart==8.0.0a2 dj-shop-cart
Django==5.1.6 Django
django-allauth==65.4.1 django-allauth
django-appointment==3.8.0 django-appointment
django-autoslug==1.9.9 django-autoslug
django-bootstrap5==24.3 django-bootstrap5
django-classy-tags==4.1.0 django-classy-tags
django-cors-headers==4.7.0 django-cors-headers
django-countries==7.6.1 django-countries
django-crispy-forms==2.3 django-crispy-forms
django-debug-toolbar==5.0.1 django-debug-toolbar
django-extensions==3.2.3 django-extensions
django-filter==25.1 django-filter
django-formtools==2.5.1 django-formtools
django-import-export==4.3.5 django-import-export
django-ledger==0.7.4.1 django-ledger
django-model-utils==5.0.0 django-model-utils
django-money==3.5.3 django-money
django-next-url-mixin==0.4.0 django-next-url-mixin
django-nine==0.2.7 django-nine
django-nonefield==0.4 django-nonefield
django-ordered-model==3.7.4 django-ordered-model
django-pdf-actions==0.1.39 django-pdf-actions
django-phonenumber-field==8.0.0 django-phonenumber-field
django-picklefield==3.2 django-picklefield
django-plans==1.2.0 django-plans
django-prometheus==2.3.1 django-prometheus
django-q2==1.7.6 django-q2
django-schema-graph==3.1.0 django-schema-graph
django-sekizai==4.1.0 django-sekizai
django-sequences==3.0 django-sequences
django-silk==5.3.2 django-silk
django-sms==0.7.0 django-sms
django-sslserver==0.22 django-sslserver
django-tables2==2.7.5 django-tables2
django-treebeard==4.7.1 django-treebeard
django-view-breadcrumbs==2.5.1 django-view-breadcrumbs
djangocms-admin-style==3.3.1 djangocms-admin-style
djangorestframework==3.15.2 djangorestframework
djangorestframework_simplejwt==5.4.0 djangorestframework_simplejwt
djangoviz==0.1.1 djangoviz
docopt==0.6.2 docopt
docutils==0.21.2 docutils
easy-thumbnails==2.10 easy-thumbnails
emoji==2.14.1 emoji
et_xmlfile==2.0.0 et_xmlfile
Faker==36.1.1 Faker
filelock==3.17.0 filelock
fire==0.7.0 fire
Flask==3.1.0 fonttools
fonttools==4.56.0 fpdf2
fpdf2==2.8.2 frozenlist
frozenlist==1.5.0 fsspec
fsspec==2025.2.0 gprof2dot
gprof2dot==2024.6.6 graphqlclient
graphqlclient==0.2.4 greenlet
greenlet==3.1.1 h11
h11==0.14.0 h2
h2==4.2.0 hpack
hpack==4.1.0 hstspreload
hstspreload==2025.1.1 httpcore
httpcore==1.0.7 httpx
httpx==0.28.1 hyperframe
hyperframe==6.1.0 icalendar
icalendar==6.1.1 idna
idna==3.10 imageio
imageio==2.37.0 imagesize
imagesize==1.4.1 imgaug
imgaug==0.4.0 iso4217
iso4217==1.12.20240625 isodate
isodate==0.7.2 isort
isort==6.0.0 itsdangerous
itsdangerous==2.2.0 Jinja2
Jinja2==3.1.5 jiter
jiter==0.8.2 joblib
joblib==1.4.2 kiwisolver
kiwisolver==1.4.8 lazy_loader
lazy_loader==0.4 ledger
ledger==1.0.1 libretranslatepy
libretranslatepy==2.1.4 lmdb
lmdb==1.6.2 lxml
lxml==5.3.1 Markdown
Markdown==3.7 markdown-it-py
markdown-it-py==3.0.0 MarkupSafe
MarkupSafe==3.0.2 marshmallow
marshmallow==3.26.1 matplotlib
matplotlib==3.10.0 mccabe
mccabe==0.7.0 mdurl
mdurl==0.1.2 MouseInfo
MouseInfo==0.1.3 mpmath
mpmath==1.3.0 multidict
multidict==6.1.0 mypy-extensions
mypy-extensions==1.0.0 networkx
networkx==3.4.2 newrelic
newrelic==10.6.0 nltk
nltk==3.9.1 num2words
num2words==0.5.14 numpy
numpy==2.2.3 oauthlib
oauthlib==3.2.2 ofxtools
ofxtools==0.9.5 openai
openai==1.63.1 opencv-contrib-python
opencv-contrib-python==4.11.0.86 opencv-python
opencv-python==4.11.0.86 opencv-python-headless
opencv-python-headless==4.11.0.86 openpyxl
openpyxl==3.1.5 opt_einsum
opt_einsum==3.4.0 outcome
outcome==1.3.0.post0 packaging
packaging==24.2 pandas
pandas==2.2.3 pango
pango==0.0.1 pdfkit
pdfkit==1.0.0 platformdirs
phonenumbers==8.13.55 prometheus_client
pillow==11.1.0 propcache
platformdirs==4.3.6 protobuf
prometheus_client==0.21.1 psycopg-binary
propcache==0.2.1 py-moneyed
protobuf==5.29.3 PyAutoGUI
psycopg==3.2.4 pyclipper
psycopg-binary==3.2.4 pycodestyle
psycopg-c==3.2.4 pycparser
py-moneyed==3.0 pydotplus
PyAutoGUI==0.9.54 pydyf
pyclipper==1.3.0.post6 PyGetWindow
pycodestyle==2.12.1 Pygments
pycparser==2.22 PyJWT
pydantic==2.10.6 pylint
pydantic_core==2.29.0 PyMsgBox
pydotplus==2.0.2 pyparsing
pydyf==0.11.0 pypdf
PyGetWindow==0.0.9 PyPDF2
Pygments==2.19.1 pyperclip
PyJWT==2.10.1 pyphen
pylint==3.3.4 pypng
PyMsgBox==1.0.9 PyRect
PyMySQL==1.1.1 PyScreeze
pyobjc-core==11.0 pyserial
pyobjc-framework-Cocoa==11.0 PySocks
pyobjc-framework-Quartz==11.0 python-bidi
pyparsing==3.2.1 python-dateutil
pypdf==5.3.0 python-docx
PyPDF2==3.0.1 python-openid
pyperclip==1.9.0 python-stdnum
pyphen==0.17.2 python3-saml
pypng==0.20220715.0 pytweening
PyRect==0.2.0 pytz
PyScreeze==1.0.1 pyvin
pyserial==3.5 pyzbar
PySocks==1.7.1 qrcode
python-bidi==0.6.3 RapidFuzz
python-dateutil==2.9.0.post0 regex
python-docx==1.1.2 reportlab
python-openid==2.2.5 requests
python-stdnum==1.20 requests-oauthlib
python3-saml==1.16.0 rfc3986
pytweening==1.2.0 rich
pytz==2025.1 rubicon-objc
pyvin==0.0.2 sacremoses
pywa==2.7.0 scikit-image
pywhat==5.1.0 scikit-learn
pywhatkit==5.4 scipy
PyYAML==6.0.2 selenium
pyzbar==0.1.9 sentencepiece
qrcode==8.0 shapely
RapidFuzz==3.12.1 simsimd
regex==2024.11.6 six
reportlab==4.3.1 sniffio
requests==2.32.3 snowballstemmer
requests-oauthlib==2.0.0 sortedcontainers
rfc3986==2.0.0 soupsieve
rich==13.9.4 sqlparse
rubicon-objc==0.5.0 stanza
sacremoses==0.1.1 stringzilla
scikit-image==0.25.1 suds
scikit-learn==1.6.1 sympy
scipy==1.15.2 tablib
selenium==4.28.1 termcolor
sentencepiece==0.2.0 threadpoolctl
shapely==2.0.7 tifffile
simsimd==6.2.1 tomli
six==1.17.0 tomlkit
sniffio==1.3.1 tqdm
snowballstemmer==2.2.0 trio
sortedcontainers==2.4.0 trio-websocket
soupsieve==2.6 typing-inspect
SQLAlchemy==2.0.38 typing_extensions
sqlparse==0.5.3 tzdata
stanza==1.10.1 Unidecode
stringzilla==3.11.3 upgrade-requirements
suds==1.2.0 urllib3
swapper==1.4.0 vishap
sympy==1.13.1 vpic-api
tablib==3.8.0 weasyprint
termcolor==2.5.0 webencodings
threadpoolctl==3.5.0 websocket-client
tifffile==2025.1.10 Werkzeug
tinycss2==1.4.0 wikipedia
tinyhtml5==2.0.0 wsproto
tomli==2.2.1 yarl
tomlkit==0.13.2 zopfli
torch==2.6.0 python-dotenv
tqdm==4.67.1 psycopg2-binary
trio==0.29.0 phonenumbers
trio-websocket==0.12.0 swapper
twilio==9.4.5 pillow
typing-inspect==0.9.0
typing_extensions==4.12.2
tzdata==2025.1
Unidecode==1.3.8
upgrade-requirements==1.7.0
urllib3==2.3.0
vin==0.6.2
vininfo==1.8.0
vishap==0.1.5
vpic-api==0.7.4
weasyprint==64.0
webencodings==0.5.1
websocket-client==1.8.0
Werkzeug==3.1.3
wikipedia==1.4.0
wsproto==1.2.0
xmlsec==1.3.14
yarl==1.18.3
zopfli==0.2.3.post1

View File

@ -1,3 +1,5 @@
import os
from dotenv import load_dotenv
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django_ledger.models.invoice import InvoiceModel from django_ledger.models.invoice import InvoiceModel
@ -17,6 +19,7 @@ import hashlib
User = get_user_model() User = get_user_model()
load_dotenv(".env")
def run(): def run():
# print(Service.objects.first().pk) # print(Service.objects.first().pk)
# print(Appointment.objects.first().client) # print(Appointment.objects.first().client)
@ -145,7 +148,8 @@ def run():
# print(Permission.objects.filter(codename__in=['view_car','view_carlocation','view_customcard','view_carcolors','view_cartransfer','view_estimatemodel','view_invoicemodel','view_saleorder'])) # print(Permission.objects.filter(codename__in=['view_car','view_carlocation','view_customcard','view_carcolors','view_cartransfer','view_estimatemodel','view_invoicemodel','view_saleorder']))
# print(Permission.objects.filter(codename__in=['view_estimatemodel','view_invoicemodel','view_saleorder'])) # print(Permission.objects.filter(codename__in=['view_estimatemodel','view_invoicemodel','view_saleorder']))
# CustomGroup.objects.filter(name='Accountant').last().set_default_permissions() # CustomGroup.objects.filter(name='Accountant').last().set_default_permissions()
CustomGroup.objects.filter(name='Inventory').last().set_default_permissions() # CustomGroup.objects.filter(name='Inventory').last().set_default_permissions()
# EntityManagementModel.objects.create(entity=,user=) # EntityManagementModel.objects.create(entity=,user=)
# print(Permission.objects.filter(codename__icontains='customermodel').first().codename) # print(Permission.objects.filter(codename__icontains='customermodel').first().codename)
print(os.getenv("DJANGO_ALLOWED_HOSTS"))

View File

@ -273,3 +273,15 @@ select.admin-autocomplete {
display: block; display: block;
padding: 6px; padding: 6px;
} }
.errors .select2-selection {
border: 1px solid var(--error-fg);
}
.errors .select2-selection {
border: 1px solid var(--error-fg);
}
.errors .select2-selection {
border: 1px solid var(--error-fg);
}

View File

@ -13,6 +13,7 @@ html[data-theme="light"],
--body-fg: #333; --body-fg: #333;
--body-bg: #fff; --body-bg: #fff;
--body-quiet-color: #666; --body-quiet-color: #666;
--body-medium-color: #444;
--body-loud-color: #000; --body-loud-color: #000;
--header-color: #ffc; --header-color: #ffc;
@ -22,11 +23,11 @@ html[data-theme="light"],
--breadcrumbs-fg: #c4dce8; --breadcrumbs-fg: #c4dce8;
--breadcrumbs-link-fg: var(--body-bg); --breadcrumbs-link-fg: var(--body-bg);
--breadcrumbs-bg: var(--primary); --breadcrumbs-bg: #264b5d;
--link-fg: #417893; --link-fg: #417893;
--link-hover-color: #036; --link-hover-color: #036;
--link-selected-fg: #5b80b2; --link-selected-fg: var(--secondary);
--hairline-color: #e8e8e8; --hairline-color: #e8e8e8;
--border-color: #ccc; --border-color: #ccc;
@ -42,10 +43,10 @@ html[data-theme="light"],
--selected-row: #ffc; --selected-row: #ffc;
--button-fg: #fff; --button-fg: #fff;
--button-bg: var(--primary); --button-bg: var(--secondary);
--button-hover-bg: #609ab6; --button-hover-bg: #205067;
--default-button-bg: var(--secondary); --default-button-bg: #205067;
--default-button-hover-bg: #205067; --default-button-hover-bg: var(--secondary);
--close-button-bg: #747474; --close-button-bg: #747474;
--close-button-hover-bg: #333; --close-button-hover-bg: #333;
--delete-button-bg: #ba2121; --delete-button-bg: #ba2121;
@ -56,8 +57,6 @@ html[data-theme="light"],
--object-tools-hover-bg: var(--close-button-hover-bg); --object-tools-hover-bg: var(--close-button-hover-bg);
--font-family-primary: --font-family-primary:
-apple-system,
BlinkMacSystemFont,
"Segoe UI", "Segoe UI",
system-ui, system-ui,
Roboto, Roboto,
@ -86,6 +85,8 @@ html[data-theme="light"],
"Segoe UI Emoji", "Segoe UI Emoji",
"Segoe UI Symbol", "Segoe UI Symbol",
"Noto Color Emoji"; "Noto Color Emoji";
color-scheme: light;
} }
html, body { html, body {
@ -149,7 +150,6 @@ h1 {
margin: 0 0 20px; margin: 0 0 20px;
font-weight: 300; font-weight: 300;
font-size: 1.25rem; font-size: 1.25rem;
color: var(--body-quiet-color);
} }
h2 { h2 {
@ -165,7 +165,7 @@ h2.subhead {
h3 { h3 {
font-size: 0.875rem; font-size: 0.875rem;
margin: .8em 0 .3em 0; margin: .8em 0 .3em 0;
color: var(--body-quiet-color); color: var(--body-medium-color);
font-weight: bold; font-weight: bold;
} }
@ -173,6 +173,7 @@ h4 {
font-size: 0.75rem; font-size: 0.75rem;
margin: 1em 0 .8em 0; margin: 1em 0 .8em 0;
padding-bottom: 3px; padding-bottom: 3px;
color: var(--body-medium-color);
} }
h5 { h5 {
@ -219,6 +220,10 @@ fieldset {
border-top: 1px solid var(--hairline-color); border-top: 1px solid var(--hairline-color);
} }
details summary {
cursor: pointer;
}
blockquote { blockquote {
font-size: 0.6875rem; font-size: 0.6875rem;
color: #777; color: #777;
@ -315,7 +320,7 @@ td, th {
} }
th { th {
font-weight: 600; font-weight: 500;
text-align: left; text-align: left;
} }
@ -336,7 +341,7 @@ tfoot td {
} }
thead th.required { thead th.required {
color: var(--body-loud-color); font-weight: bold;
} }
tr.alt { tr.alt {
@ -484,8 +489,13 @@ textarea {
vertical-align: top; vertical-align: top;
} }
input[type=text], input[type=password], input[type=email], input[type=url], /*
input[type=number], input[type=tel], textarea, select, .vTextField { Minifiers remove the default (text) "type" attribute from "input" HTML tags.
Add input:not([type]) to make the CSS stylesheet work the same.
*/
input:not([type]), input[type=text], input[type=password], input[type=email],
input[type=url], input[type=number], input[type=tel], textarea, select,
.vTextField {
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
border-radius: 4px; border-radius: 4px;
padding: 5px 6px; padding: 5px 6px;
@ -494,9 +504,13 @@ input[type=number], input[type=tel], textarea, select, .vTextField {
background-color: var(--body-bg); background-color: var(--body-bg);
} }
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, /*
input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus, Minifiers remove the default (text) "type" attribute from "input" HTML tags.
textarea:focus, select:focus, .vTextField:focus { Add input:not([type]) to make the CSS stylesheet work the same.
*/
input:not([type]):focus, input[type=text]:focus, input[type=password]:focus,
input[type=email]:focus, input[type=url]:focus, input[type=number]:focus,
input[type=tel]:focus, textarea:focus, select:focus, .vTextField:focus {
border-color: var(--body-quiet-color); border-color: var(--body-quiet-color);
} }
@ -586,7 +600,7 @@ input[type=button][disabled].default {
font-weight: 400; font-weight: 400;
font-size: 0.8125rem; font-size: 0.8125rem;
text-align: left; text-align: left;
background: var(--primary); background: var(--header-bg);
color: var(--header-link-color); color: var(--header-link-color);
} }
@ -722,6 +736,11 @@ div.breadcrumbs a:focus, div.breadcrumbs a:hover {
background: url(../img/icon-viewlink.svg) 0 1px no-repeat; background: url(../img/icon-viewlink.svg) 0 1px no-repeat;
} }
.hidelink {
padding-left: 16px;
background: url(../img/icon-hidelink.svg) 0 1px no-repeat;
}
.addlink { .addlink {
padding-left: 16px; padding-left: 16px;
background: url(../img/icon-addlink.svg) 0 1px no-repeat; background: url(../img/icon-addlink.svg) 0 1px no-repeat;
@ -831,10 +850,6 @@ a.deletelink:focus, a.deletelink:hover {
height: 100%; height: 100%;
} }
#container > div {
flex-shrink: 0;
}
#container > .main { #container > .main {
display: flex; display: flex;
flex: 1 0 auto; flex: 1 0 auto;
@ -879,9 +894,10 @@ a.deletelink:focus, a.deletelink:hover {
margin-right: -300px; margin-right: -300px;
} }
#footer { @media (forced-colors: active) {
clear: both; #content-related {
padding: 10px; border: 1px solid;
}
} }
/* COLUMN TYPES */ /* COLUMN TYPES */
@ -919,7 +935,6 @@ a.deletelink:focus, a.deletelink:hover {
padding: 10px 40px; padding: 10px 40px;
background: var(--header-bg); background: var(--header-bg);
color: var(--header-color); color: var(--header-color);
overflow: hidden;
} }
#header a:link, #header a:visited, #logout-form button { #header a:link, #header a:visited, #logout-form button {
@ -930,11 +945,17 @@ a.deletelink:focus, a.deletelink:hover {
text-decoration: underline; text-decoration: underline;
} }
@media (forced-colors: active) {
#header {
border-bottom: 1px solid;
}
}
#branding { #branding {
display: flex; display: flex;
} }
#branding h1 { #site-name {
padding: 0; padding: 0;
margin: 0; margin: 0;
margin-inline-end: 20px; margin-inline-end: 20px;
@ -943,7 +964,7 @@ a.deletelink:focus, a.deletelink:hover {
color: var(--header-branding-color); color: var(--header-branding-color);
} }
#branding h1 a:link, #branding h1 a:visited { #site-name a:link, #site-name a:visited {
color: var(--accent); color: var(--accent);
} }
@ -1143,3 +1164,16 @@ a.deletelink:focus, a.deletelink:hover {
.base-svgs { .base-svgs {
display: none; display: none;
} }
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border: 0;
color: var(--body-fg);
background-color: var(--body-bg);
}

View File

@ -139,6 +139,12 @@
margin: 0 0 0 30px; margin: 0 0 0 30px;
} }
@media (forced-colors: active) {
#changelist-filter {
border: 1px solid;
}
}
#changelist-filter h2 { #changelist-filter h2 {
font-size: 0.875rem; font-size: 0.875rem;
text-transform: uppercase; text-transform: uppercase;
@ -215,9 +221,9 @@
color: var(--link-hover-color); color: var(--link-hover-color);
} }
#changelist-filter #changelist-filter-clear a { #changelist-filter #changelist-filter-extra-actions {
font-size: 0.8125rem; font-size: 0.8125rem;
padding-bottom: 10px; margin-bottom: 10px;
border-bottom: 1px solid var(--hairline-color); border-bottom: 1px solid var(--hairline-color);
} }
@ -265,6 +271,15 @@
background-color: var(--selected-row); background-color: var(--selected-row);
} }
@media (forced-colors: active) {
#changelist tbody tr.selected {
background-color: SelectedItem;
}
#changelist tbody tr:has(.action-select:checked) {
background-color: SelectedItem;
}
}
#changelist .actions { #changelist .actions {
padding: 10px; padding: 10px;
background: var(--body-bg); background: var(--body-bg);

View File

@ -5,7 +5,8 @@
--body-fg: #eeeeee; --body-fg: #eeeeee;
--body-bg: #121212; --body-bg: #121212;
--body-quiet-color: #e0e0e0; --body-quiet-color: #d0d0d0;
--body-medium-color: #e0e0e0;
--body-loud-color: #ffffff; --body-loud-color: #ffffff;
--breadcrumbs-link-fg: #e0e0e0; --breadcrumbs-link-fg: #e0e0e0;
@ -29,6 +30,8 @@
--close-button-bg: #333333; --close-button-bg: #333333;
--close-button-hover-bg: #666666; --close-button-hover-bg: #666666;
color-scheme: dark;
} }
} }
@ -39,7 +42,8 @@ html[data-theme="dark"] {
--body-fg: #eeeeee; --body-fg: #eeeeee;
--body-bg: #121212; --body-bg: #121212;
--body-quiet-color: #e0e0e0; --body-quiet-color: #d0d0d0;
--body-medium-color: #e0e0e0;
--body-loud-color: #ffffff; --body-loud-color: #ffffff;
--breadcrumbs-link-fg: #e0e0e0; --breadcrumbs-link-fg: #e0e0e0;
@ -63,6 +67,8 @@ html[data-theme="dark"] {
--close-button-bg: #333333; --close-button-bg: #333333;
--close-button-hover-bg: #666666; --close-button-hover-bg: #666666;
color-scheme: dark;
} }
/* THEME SWITCH */ /* THEME SWITCH */
@ -122,16 +128,3 @@ html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark {
html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { html[data-theme="light"] .theme-toggle svg.theme-icon-when-light {
display: block; display: block;
} }
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border: 0;
color: var(--body-fg);
background-color: var(--body-bg);
}

View File

@ -44,7 +44,6 @@ label {
.required label, label.required { .required label, label.required {
font-weight: bold; font-weight: bold;
color: var(--body-fg);
} }
/* RADIO BUTTONS */ /* RADIO BUTTONS */
@ -76,6 +75,20 @@ form ul.inline li {
padding-right: 7px; padding-right: 7px;
} }
/* FIELDSETS */
fieldset .fieldset-heading,
fieldset .inline-heading,
:not(.inline-related) .collapse summary {
border: 1px solid var(--header-bg);
margin: 0;
padding: 8px;
font-weight: 400;
font-size: 0.8125rem;
background: var(--header-bg);
color: var(--header-link-color);
}
/* ALIGNED FIELDSETS */ /* ALIGNED FIELDSETS */
.aligned label { .aligned label {
@ -84,14 +97,12 @@ form ul.inline li {
min-width: 160px; min-width: 160px;
width: 160px; width: 160px;
word-wrap: break-word; word-wrap: break-word;
line-height: 1;
} }
.aligned label:not(.vCheckboxLabel):after { .aligned label:not(.vCheckboxLabel):after {
content: ''; content: '';
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
height: 1.625rem;
} }
.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly { .aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly {
@ -158,6 +169,10 @@ form .aligned select + div.help {
padding-left: 10px; padding-left: 10px;
} }
form .aligned select option:checked {
background-color: var(--selected-row);
}
form .aligned ul li { form .aligned ul li {
list-style: none; list-style: none;
} }
@ -168,11 +183,7 @@ form .aligned table p {
} }
.aligned .vCheckboxLabel { .aligned .vCheckboxLabel {
float: none; padding: 1px 0 0 5px;
width: auto;
display: inline-block;
vertical-align: -3px;
padding: 0 0 5px 5px;
} }
.aligned .vCheckboxLabel + p.help, .aligned .vCheckboxLabel + p.help,
@ -194,14 +205,8 @@ fieldset .fieldBox {
width: 200px; width: 200px;
} }
form .wide p,
form .wide ul.errorlist,
form .wide input + p.help,
form .wide input + div.help {
margin-left: 200px;
}
form .wide p.help, form .wide p.help,
form .wide ul.errorlist,
form .wide div.help { form .wide div.help {
padding-left: 50px; padding-left: 50px;
} }
@ -215,35 +220,16 @@ form div.help ul {
width: 450px; width: 450px;
} }
/* COLLAPSED FIELDSETS */ /* COLLAPSIBLE FIELDSETS */
fieldset.collapsed * { .collapse summary .fieldset-heading,
display: none; .collapse summary .inline-heading {
}
fieldset.collapsed h2, fieldset.collapsed {
display: block;
}
fieldset.collapsed {
border: 1px solid var(--hairline-color);
border-radius: 4px;
overflow: hidden;
}
fieldset.collapsed h2 {
background: var(--darkened-bg);
color: var(--body-quiet-color);
}
fieldset .collapse-toggle {
color: var(--header-link-color);
}
fieldset.collapsed .collapse-toggle {
background: transparent; background: transparent;
border: none;
color: currentColor;
display: inline; display: inline;
color: var(--link-fg); margin: 0;
padding: 0;
} }
/* MONOSPACE TEXTAREAS */ /* MONOSPACE TEXTAREAS */
@ -395,14 +381,16 @@ body.popup .submit-row {
position: relative; position: relative;
} }
.inline-related h3 { .inline-related h4,
.inline-related:not(.tabular) .collapse summary {
margin: 0; margin: 0;
color: var(--body-quiet-color); color: var(--body-medium-color);
padding: 5px; padding: 5px;
font-size: 0.8125rem; font-size: 0.8125rem;
background: var(--darkened-bg); background: var(--darkened-bg);
border-top: 1px solid var(--hairline-color); border: 1px solid var(--hairline-color);
border-bottom: 1px solid var(--hairline-color); border-left-color: var(--darkened-bg);
border-right-color: var(--darkened-bg);
} }
.inline-related h3 span.delete { .inline-related h3 span.delete {
@ -421,16 +409,6 @@ body.popup .submit-row {
width: 100%; width: 100%;
} }
.inline-related fieldset.module h3 {
margin: 0;
padding: 2px 5px 3px 5px;
font-size: 0.6875rem;
text-align: left;
font-weight: bold;
background: #bcd;
color: var(--body-bg);
}
.inline-group .tabular fieldset.module { .inline-group .tabular fieldset.module {
border: none; border: none;
} }

View File

@ -21,7 +21,7 @@
} }
.login #content { .login #content {
padding: 20px 20px 0; padding: 20px;
} }
.login #container { .login #container {

View File

@ -102,6 +102,12 @@
background: var(--selected-row); background: var(--selected-row);
} }
@media (forced-colors: active) {
#nav-sidebar .current-model {
background-color: SelectedItem;
}
}
.main > #nav-sidebar + .content { .main > #nav-sidebar + .content {
max-width: calc(100% - 23px); max-width: calc(100% - 23px);
} }

View File

@ -43,7 +43,7 @@ input[type="submit"], button {
justify-content: flex-start; justify-content: flex-start;
} }
#branding h1 { #site-name {
margin: 0 0 8px; margin: 0 0 8px;
line-height: 1.2; line-height: 1.2;
} }
@ -171,9 +171,14 @@ input[type="submit"], button {
/* Forms */ /* Forms */
label { label {
font-size: 0.875rem; font-size: 1rem;
} }
/*
Minifiers remove the default (text) "type" attribute from "input" HTML
tags. Add input:not([type]) to make the CSS stylesheet work the same.
*/
.form-row input:not([type]),
.form-row input[type=text], .form-row input[type=text],
.form-row input[type=password], .form-row input[type=password],
.form-row input[type=email], .form-row input[type=email],
@ -187,7 +192,7 @@ input[type="submit"], button {
margin: 0; margin: 0;
padding: 6px 8px; padding: 6px 8px;
min-height: 2.25rem; min-height: 2.25rem;
font-size: 0.875rem; font-size: 1rem;
} }
.form-row select { .form-row select {
@ -237,22 +242,6 @@ input[type="submit"], button {
padding: 7px; padding: 7px;
} }
/* Related widget */
.related-widget-wrapper {
float: none;
}
.related-widget-wrapper-link + .selector {
max-width: calc(100% - 30px);
margin-right: 15px;
}
select + .related-widget-wrapper-link,
.related-widget-wrapper-link + .related-widget-wrapper-link {
margin-left: 10px;
}
/* Selector */ /* Selector */
.selector { .selector {
@ -270,7 +259,7 @@ input[type="submit"], button {
} }
.selector .selector-filter input { .selector .selector-filter input {
width: auto; width: 100%;
min-height: 0; min-height: 0;
flex: 1 1; flex: 1 1;
} }
@ -292,7 +281,6 @@ input[type="submit"], button {
width: 26px; width: 26px;
height: 52px; height: 52px;
padding: 2px 0; padding: 2px 0;
margin: auto 15px;
border-radius: 20px; border-radius: 20px;
transform: translateY(-10px); transform: translateY(-10px);
} }
@ -336,7 +324,6 @@ input[type="submit"], button {
width: 52px; width: 52px;
height: 26px; height: 26px;
padding: 0 2px; padding: 0 2px;
margin: 15px auto;
transform: none; transform: none;
} }
@ -432,7 +419,7 @@ input[type="submit"], button {
padding: 15px 20px; padding: 15px 20px;
} }
.login #branding h1 { .login #site-name {
margin: 0; margin: 0;
} }
@ -464,14 +451,10 @@ input[type="submit"], button {
@media (max-width: 767px) { @media (max-width: 767px) {
/* Layout */ /* Layout */
#header, #content, #footer { #header, #content {
padding: 15px; padding: 15px;
} }
#footer:empty {
padding: 0;
}
div.breadcrumbs { div.breadcrumbs {
padding: 10px 15px; padding: 10px 15px;
} }
@ -582,10 +565,6 @@ input[type="submit"], button {
padding-top: 15px; padding-top: 15px;
} }
fieldset.collapsed .form-row {
display: none;
}
.aligned label { .aligned label {
width: 100%; width: 100%;
min-width: auto; min-width: auto;
@ -684,23 +663,14 @@ input[type="submit"], button {
align-self: center; align-self: center;
} }
select + .related-widget-wrapper-link,
.related-widget-wrapper-link + .related-widget-wrapper-link {
margin-left: 15px;
}
/* Selector */ /* Selector */
.selector { .selector {
flex-direction: column; flex-direction: column;
} gap: 10px 0;
.selector > * {
float: none;
} }
.selector-available, .selector-chosen { .selector-available, .selector-chosen {
margin-bottom: 0;
flex: 1 1 auto; flex: 1 1 auto;
} }
@ -710,11 +680,9 @@ input[type="submit"], button {
.selector ul.selector-chooser { .selector ul.selector-chooser {
display: block; display: block;
float: none;
width: 52px; width: 52px;
height: 26px; height: 26px;
padding: 0 2px; padding: 0 2px;
margin: 15px auto 20px;
transform: none; transform: none;
} }

View File

@ -35,11 +35,6 @@
background-position: calc(100% - 8px) 9px; background-position: calc(100% - 8px) 9px;
} }
[dir="rtl"] .related-widget-wrapper-link + .selector {
margin-right: 0;
margin-left: 15px;
}
[dir="rtl"] .selector .selector-filter label { [dir="rtl"] .selector .selector-filter label {
margin-right: 0; margin-right: 0;
margin-left: 8px; margin-left: 8px;
@ -58,6 +53,22 @@
padding-left: 0; padding-left: 0;
padding-right: 16px; padding-right: 16px;
} }
[dir="rtl"] .selector-add {
background-position: 0 -80px;
}
[dir="rtl"] .selector-remove {
background-position: 0 -120px;
}
[dir="rtl"] .active.selector-add:focus, .active.selector-add:hover {
background-position: 0 -100px;
}
[dir="rtl"] .active.selector-remove:focus, .active.selector-remove:hover {
background-position: 0 -140px;
}
} }
/* MOBILE */ /* MOBILE */
@ -81,4 +92,20 @@
[dir="rtl"] .aligned .vCheckboxLabel { [dir="rtl"] .aligned .vCheckboxLabel {
padding: 1px 5px 0 0; padding: 1px 5px 0 0;
} }
[dir="rtl"] .selector-remove {
background-position: 0 0;
}
[dir="rtl"] .active.selector-remove:focus, .active.selector-remove:hover {
background-position: 0 -20px;
}
[dir="rtl"] .selector-add {
background-position: 0 -40px;
}
[dir="rtl"] .active.selector-add:focus, .active.selector-add:hover {
background-position: 0 -60px;
}
} }

View File

@ -13,7 +13,7 @@ th {
margin-right: 1.5em; margin-right: 1.5em;
} }
.viewlink, .addlink, .changelink { .viewlink, .addlink, .changelink, .hidelink {
padding-left: 0; padding-left: 0;
padding-right: 16px; padding-right: 16px;
background-position: 100% 1px; background-position: 100% 1px;
@ -151,6 +151,7 @@ form ul.inline li {
form .aligned p.help, form .aligned p.help,
form .aligned div.help { form .aligned div.help {
margin-left: 0;
margin-right: 160px; margin-right: 160px;
padding-right: 10px; padding-right: 10px;
} }
@ -164,19 +165,13 @@ form .aligned p.time div.help.timezonewarning {
padding-right: 0; padding-right: 0;
} }
form .wide p.help, form .wide div.help { form .wide p.help,
form .wide ul.errorlist,
form .wide div.help {
padding-left: 0; padding-left: 0;
padding-right: 50px; padding-right: 50px;
} }
form .wide p,
form .wide ul.errorlist,
form .wide input + p.help,
form .wide input + div.help {
margin-right: 200px;
margin-left: 0px;
}
.submit-row { .submit-row {
text-align: right; text-align: right;
} }
@ -202,12 +197,7 @@ fieldset .fieldBox {
top: 0; top: 0;
left: auto; left: auto;
right: 10px; right: 10px;
background: url(../img/calendar-icons.svg) 0 -30px no-repeat; background: url(../img/calendar-icons.svg) 0 -15px no-repeat;
}
.calendarbox .calendarnav-previous:focus,
.calendarbox .calendarnav-previous:hover {
background-position: 0 -45px;
} }
.calendarnav-next { .calendarnav-next {
@ -217,11 +207,6 @@ fieldset .fieldBox {
background: url(../img/calendar-icons.svg) 0 0 no-repeat; background: url(../img/calendar-icons.svg) 0 0 no-repeat;
} }
.calendarbox .calendarnav-next:focus,
.calendarbox .calendarnav-next:hover {
background-position: 0 -15px;
}
.calendar caption, .calendarbox h2 { .calendar caption, .calendarbox h2 {
text-align: center; text-align: center;
} }
@ -296,3 +281,11 @@ form .form-row p.datetime {
margin-left: inherit; margin-left: inherit;
margin-right: 2px; margin-right: 2px;
} }
.inline-group .tabular td.original p {
right: 0;
}
.selector .selector-chooser {
margin: 0;
}

View File

@ -1,23 +1,23 @@
/* SELECTOR (FILTER INTERFACE) */ /* SELECTOR (FILTER INTERFACE) */
.selector { .selector {
width: 800px;
float: left;
display: flex; display: flex;
flex-grow: 1;
gap: 0 10px;
} }
.selector select { .selector select {
width: 380px;
height: 17.2em; height: 17.2em;
flex: 1 0 auto; flex: 1 0 auto;
overflow: scroll;
width: 100%;
} }
.selector-available, .selector-chosen { .selector-available, .selector-chosen {
width: 380px;
text-align: center; text-align: center;
margin-bottom: 5px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1;
} }
.selector-available h2, .selector-chosen h2 { .selector-available h2, .selector-chosen h2 {
@ -41,7 +41,7 @@
} }
.selector-chosen h2 { .selector-chosen h2 {
background: var(--primary); background: var(--secondary);
color: var(--header-link-color); color: var(--header-link-color);
} }
@ -58,6 +58,7 @@
font-size: 0.625rem; font-size: 0.625rem;
margin: 0; margin: 0;
text-align: left; text-align: left;
display: flex;
} }
.selector .selector-filter label, .selector .selector-filter label,
@ -72,9 +73,12 @@
min-width: auto; min-width: auto;
} }
.selector-filter input {
flex-grow: 1;
}
.selector .selector-available input, .selector .selector-available input,
.selector .selector-chosen input { .selector .selector-chosen input {
width: 320px;
margin-left: 8px; margin-left: 8px;
} }
@ -83,7 +87,7 @@
width: 22px; width: 22px;
background-color: var(--selected-bg); background-color: var(--selected-bg);
border-radius: 10px; border-radius: 10px;
margin: 0 5px; margin: 0;
padding: 0; padding: 0;
transform: translateY(-17px); transform: translateY(-17px);
} }
@ -147,7 +151,7 @@ a.selector-chooseall, a.selector-clearall {
display: inline-block; display: inline-block;
height: 16px; height: 16px;
text-align: left; text-align: left;
margin: 1px auto 3px; margin: 0 auto;
overflow: hidden; overflow: hidden;
font-weight: bold; font-weight: bold;
line-height: 16px; line-height: 16px;
@ -447,7 +451,7 @@ span.clearable-file-input label {
} }
.calendar td.selected a { .calendar td.selected a {
background: var(--primary); background: var(--secondary);
color: var(--button-fg); color: var(--button-fg);
} }
@ -515,36 +519,26 @@ span.clearable-file-input label {
background: url(../img/calendar-icons.svg) 0 0 no-repeat; background: url(../img/calendar-icons.svg) 0 0 no-repeat;
} }
.calendarbox .calendarnav-previous:focus,
.calendarbox .calendarnav-previous:hover {
background-position: 0 -15px;
}
.calendarnav-next { .calendarnav-next {
right: 10px; right: 10px;
background: url(../img/calendar-icons.svg) 0 -30px no-repeat; background: url(../img/calendar-icons.svg) 0 -15px no-repeat;
}
.calendarbox .calendarnav-next:focus,
.calendarbox .calendarnav-next:hover {
background-position: 0 -45px;
} }
.calendar-cancel { .calendar-cancel {
margin: 0; margin: 0;
padding: 4px 0; padding: 4px 0;
font-size: 0.75rem; font-size: 0.75rem;
background: #eee; background: var(--close-button-bg);
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
color: var(--body-fg); color: var(--button-fg);
} }
.calendar-cancel:focus, .calendar-cancel:hover { .calendar-cancel:focus, .calendar-cancel:hover {
background: #ddd; background: var(--close-button-hover-bg);
} }
.calendar-cancel a { .calendar-cancel a {
color: black; color: var(--button-fg);
display: block; display: block;
} }
@ -575,26 +569,21 @@ ul.timelist, .timelist li {
/* RELATED WIDGET WRAPPER */ /* RELATED WIDGET WRAPPER */
.related-widget-wrapper { .related-widget-wrapper {
float: left; /* display properly in form rows with multiple fields */ display: flex;
overflow: hidden; /* clear floated contents */ gap: 0 10px;
flex-grow: 1;
flex-wrap: wrap;
margin-bottom: 5px;
} }
.related-widget-wrapper-link { .related-widget-wrapper-link {
opacity: 0.3; opacity: .6;
filter: grayscale(1);
} }
.related-widget-wrapper-link:link { .related-widget-wrapper-link:link {
opacity: .8;
}
.related-widget-wrapper-link:link:focus,
.related-widget-wrapper-link:link:hover {
opacity: 1; opacity: 1;
} filter: grayscale(0);
select + .related-widget-wrapper-link,
.related-widget-wrapper-link + .related-widget-wrapper-link {
margin-left: 7px;
} }
/* GIS MAPS */ /* GIS MAPS */

View File

@ -1,4 +1,4 @@
All icons are taken from Font Awesome (http://fontawesome.io/) project. All icons are taken from Font Awesome (https://fontawesome.com/) project.
The Font Awesome font is licensed under the SIL OFL 1.1: The Font Awesome font is licensed under the SIL OFL 1.1:
- https://scripts.sil.org/OFL - https://scripts.sil.org/OFL

View File

@ -1,14 +1,63 @@
<svg width="15" height="60" viewBox="0 0 1792 7168" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<defs> <svg
<g id="previous"> width="15"
<path d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> height="30"
viewBox="0 0 1792 3584"
version="1.1"
id="svg5"
sodipodi:docname="calendar-icons.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview5"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="13.3"
inkscape:cx="15.526316"
inkscape:cy="20.977444"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg5" />
<defs
id="defs2">
<g
id="previous">
<path
d="m 1037,1395 102,-102 q 19,-19 19,-45 0,-26 -19,-45 L 832,896 1139,589 q 19,-19 19,-45 0,-26 -19,-45 L 1037,397 q -19,-19 -45,-19 -26,0 -45,19 L 493,851 q -19,19 -19,45 0,26 19,45 l 454,454 q 19,19 45,19 26,0 45,-19 z m 627,-499 q 0,209 -103,385.5 Q 1458,1458 1281.5,1561 1105,1664 896,1664 687,1664 510.5,1561 334,1458 231,1281.5 128,1105 128,896 128,687 231,510.5 334,334 510.5,231 687,128 896,128 1105,128 1281.5,231 1458,334 1561,510.5 1664,687 1664,896 Z"
id="path1" />
</g> </g>
<g id="next"> <g
<path d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> id="next">
<path
d="m 845,1395 454,-454 q 19,-19 19,-45 0,-26 -19,-45 L 845,397 q -19,-19 -45,-19 -26,0 -45,19 L 653,499 q -19,19 -19,45 0,26 19,45 l 307,307 -307,307 q -19,19 -19,45 0,26 19,45 l 102,102 q 19,19 45,19 26,0 45,-19 z m 819,-499 q 0,209 -103,385.5 Q 1458,1458 1281.5,1561 1105,1664 896,1664 687,1664 510.5,1561 334,1458 231,1281.5 128,1105 128,896 128,687 231,510.5 334,334 510.5,231 687,128 896,128 1105,128 1281.5,231 1458,334 1561,510.5 1664,687 1664,896 Z"
id="path2" />
</g> </g>
</defs> </defs>
<use xlink:href="#previous" x="0" y="0" fill="#333333" /> <use
<use xlink:href="#previous" x="0" y="1792" fill="#000000" /> xlink:href="#next"
<use xlink:href="#next" x="0" y="3584" fill="#333333" /> x="0"
<use xlink:href="#next" x="0" y="5376" fill="#000000" /> y="5376"
fill="#000000"
id="use5"
transform="translate(0,-3584)" />
<use
xlink:href="#previous"
x="0"
y="0"
fill="#333333"
id="use2"
style="fill:#000000;fill-opacity:1" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,3 +1,3 @@
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#70bf2b" d="M1600 796v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"/> <path fill="#5fa225" d="M1600 796v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 331 B

View File

@ -1,3 +1,3 @@
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path fill="#efb80b" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/> <path fill="#b48c08" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 380 B

View File

@ -1,4 +1,4 @@
/*global SelectBox, gettext, interpolate, quickElement, SelectFilter*/ /*global SelectBox, gettext, ngettext, interpolate, quickElement, SelectFilter*/
/* /*
SelectFilter2 - Turns a multiple-select box into a filter interface. SelectFilter2 - Turns a multiple-select box into a filter interface.
@ -30,6 +30,9 @@ Requires core.js and SelectBox.js.
// <div class="selector"> or <div class="selector stacked"> // <div class="selector"> or <div class="selector stacked">
const selector_div = quickElement('div', from_box.parentNode); const selector_div = quickElement('div', from_box.parentNode);
// Make sure the selector div is at the beginning so that the
// add link would be displayed to the right of the widget.
from_box.parentNode.prepend(selector_div);
selector_div.className = is_stacked ? 'selector stacked' : 'selector'; selector_div.className = is_stacked ? 'selector stacked' : 'selector';
// <div class="selector-available"> // <div class="selector-available">

View File

@ -1,4 +1,4 @@
/*global gettext, interpolate, ngettext*/ /*global gettext, interpolate, ngettext, Actions*/
'use strict'; 'use strict';
{ {
function show(selector) { function show(selector) {
@ -179,6 +179,9 @@
} }
}); });
} }
// Sync counter when navigating to the page, such as through the back
// button.
window.addEventListener('pageshow', (event) => updateCounter(actionCheckboxes, options));
}; };
// Call function fn when the DOM is loaded and ready. If it is already // Call function fn when the DOM is loaded and ready. If it is already

View File

@ -79,9 +79,11 @@
siblings.each(function() { siblings.each(function() {
const elm = $(this); const elm = $(this);
elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
elm.removeAttr('aria-disabled');
}); });
} else { } else {
siblings.removeAttr('href'); siblings.removeAttr('href');
siblings.attr('aria-disabled', true);
} }
} }
@ -94,8 +96,8 @@
// Extract the model from the popup url '.../<model>/add/' or // Extract the model from the popup url '.../<model>/add/' or
// '.../<model>/<id>/change/' depending the action (add or change). // '.../<model>/<id>/change/' depending the action (add or change).
const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)];
// Exclude autocomplete selects. // Select elements with a specific model reference and context of "available-source".
const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`); const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] [data-context="available-source"]`);
selectsRelated.forEach(function(select) { selectsRelated.forEach(function(select) {
if (currentSelect === select) { if (currentSelect === select) {

View File

@ -36,6 +36,24 @@ depends on core.js for utility functions like removeChildren or quickElement
pgettext('abbrev. month December', 'Dec') pgettext('abbrev. month December', 'Dec')
], ],
daysOfWeek: [ daysOfWeek: [
gettext('Sunday'),
gettext('Monday'),
gettext('Tuesday'),
gettext('Wednesday'),
gettext('Thursday'),
gettext('Friday'),
gettext('Saturday')
],
daysOfWeekAbbrev: [
pgettext('abbrev. day Sunday', 'Sun'),
pgettext('abbrev. day Monday', 'Mon'),
pgettext('abbrev. day Tuesday', 'Tue'),
pgettext('abbrev. day Wednesday', 'Wed'),
pgettext('abbrev. day Thursday', 'Thur'),
pgettext('abbrev. day Friday', 'Fri'),
pgettext('abbrev. day Saturday', 'Sat')
],
daysOfWeekInitial: [
pgettext('one letter Sunday', 'S'), pgettext('one letter Sunday', 'S'),
pgettext('one letter Monday', 'M'), pgettext('one letter Monday', 'M'),
pgettext('one letter Tuesday', 'T'), pgettext('one letter Tuesday', 'T'),
@ -98,7 +116,7 @@ depends on core.js for utility functions like removeChildren or quickElement
// Draw days-of-week header // Draw days-of-week header
let tableRow = quickElement('tr', tableBody); let tableRow = quickElement('tr', tableBody);
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]); quickElement('th', tableRow, CalendarNamespace.daysOfWeekInitial[(i + CalendarNamespace.firstDayOfWeek) % 7]);
} }
const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay();

View File

@ -85,6 +85,18 @@ function findPosY(obj) {
return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
}; };
Date.prototype.getAbbrevDayName = function() {
return typeof window.CalendarNamespace === "undefined"
? '0' + this.getDay()
: window.CalendarNamespace.daysOfWeekAbbrev[this.getDay()];
};
Date.prototype.getFullDayName = function() {
return typeof window.CalendarNamespace === "undefined"
? '0' + this.getDay()
: window.CalendarNamespace.daysOfWeek[this.getDay()];
};
Date.prototype.getAbbrevMonthName = function() { Date.prototype.getAbbrevMonthName = function() {
return typeof window.CalendarNamespace === "undefined" return typeof window.CalendarNamespace === "undefined"
? this.getTwoDigitMonth() ? this.getTwoDigitMonth()
@ -99,6 +111,8 @@ function findPosY(obj) {
Date.prototype.strftime = function(format) { Date.prototype.strftime = function(format) {
const fields = { const fields = {
a: this.getAbbrevDayName(),
A: this.getFullDayName(),
b: this.getAbbrevMonthName(), b: this.getAbbrevMonthName(),
B: this.getFullMonthName(), B: this.getFullMonthName(),
c: this.toString(), c: this.toString(),

View File

@ -1,4 +1,3 @@
/*global opener */
'use strict'; 'use strict';
{ {
const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse);

View File

@ -1,56 +1,51 @@
'use strict'; 'use strict';
{ {
window.addEventListener('load', function(e) { function setTheme(mode) {
if (mode !== "light" && mode !== "dark" && mode !== "auto") {
function setTheme(mode) { console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);
if (mode !== "light" && mode !== "dark" && mode !== "auto") { mode = "auto";
console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);
mode = "auto";
}
document.documentElement.dataset.theme = mode;
localStorage.setItem("theme", mode);
} }
document.documentElement.dataset.theme = mode;
localStorage.setItem("theme", mode);
}
function cycleTheme() { function cycleTheme() {
const currentTheme = localStorage.getItem("theme") || "auto"; const currentTheme = localStorage.getItem("theme") || "auto";
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
if (prefersDark) { if (prefersDark) {
// Auto (dark) -> Light -> Dark // Auto (dark) -> Light -> Dark
if (currentTheme === "auto") { if (currentTheme === "auto") {
setTheme("light"); setTheme("light");
} else if (currentTheme === "light") { } else if (currentTheme === "light") {
setTheme("dark"); setTheme("dark");
} else {
setTheme("auto");
}
} else { } else {
// Auto (light) -> Dark -> Light setTheme("auto");
if (currentTheme === "auto") { }
setTheme("dark"); } else {
} else if (currentTheme === "dark") { // Auto (light) -> Dark -> Light
setTheme("light"); if (currentTheme === "auto") {
} else { setTheme("dark");
setTheme("auto"); } else if (currentTheme === "dark") {
} setTheme("light");
} else {
setTheme("auto");
} }
} }
}
function initTheme() { function initTheme() {
// set theme defined in localStorage if there is one, or fallback to auto mode // set theme defined in localStorage if there is one, or fallback to auto mode
const currentTheme = localStorage.getItem("theme"); const currentTheme = localStorage.getItem("theme");
currentTheme ? setTheme(currentTheme) : setTheme("auto"); currentTheme ? setTheme(currentTheme) : setTheme("auto");
} }
function setupTheme() { window.addEventListener('load', function(_) {
// Attach event handlers for toggling themes const buttons = document.getElementsByClassName("theme-toggle");
const buttons = document.getElementsByClassName("theme-toggle"); Array.from(buttons).forEach((btn) => {
Array.from(buttons).forEach((btn) => { btn.addEventListener("click", cycleTheme);
btn.addEventListener("click", cycleTheme); });
});
initTheme();
}
setupTheme();
}); });
initTheme();
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
The MIT License The MIT License
Copyright (c) 2007-2017 Steven Levithan <http://xregexp.com/> Copyright (c) 2007-present Steven Levithan <http://xregexp.com/>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,13 @@
@font-face {
font-family: 'SaudiRiyalFont';
src: url('/static/assets/fonts/SaudiRiyalFont.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
.currency {
font-family: 'SaudiRiyalFont', sans-serif;
}
.color-div { .color-div {
width: 64px; width: 64px;

View File

@ -3781,6 +3781,7 @@ textarea.form-control-lg {
.form-select { .form-select {
--phoenix-form-select-bg-img: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03NS4zNDggMTI3LjE5MkM3Mi40MzgxIDEyNy4xOTIgNjkuODUxNCAxMjYuMjIyIDY3LjkxMTUgMTI0LjI4Mkw1LjgzMjE1IDYyLjIwMjNDMS42Mjg4NyA1OC4zMjIzIDEuNjI4ODcgNTEuNTMyNCA1LjgzMjE1IDQ3LjY1MjVDOS43MTIxMSA0My40NDkyIDE2LjUwMiA0My40NDkyIDIwLjM4MiA0Ny42NTI1TDc1LjM0OCAxMDIuMjk1TDEyOS45OTEgNDcuNjUyNUMxMzMuODcxIDQzLjQ0OTIgMTQwLjY2MSA0My40NDkyIDE0NC41NDEgNDcuNjUyNUMxNDguNzQ0IDUxLjUzMjQgMTQ4Ljc0NCA1OC4zMjIzIDE0NC41NDEgNjIuMjAyM0w4Mi40NjEzIDEyNC4yODJDODAuNTIxMyAxMjYuMjIyIDc3LjkzNDcgMTI3LjE5MiA3NS4zNDggMTI3LjE5MloiIGZpbGw9IiMzMTM3NEEiLz4KPC9zdmc+Cg=="); --phoenix-form-select-bg-img: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03NS4zNDggMTI3LjE5MkM3Mi40MzgxIDEyNy4xOTIgNjkuODUxNCAxMjYuMjIyIDY3LjkxMTUgMTI0LjI4Mkw1LjgzMjE1IDYyLjIwMjNDMS42Mjg4NyA1OC4zMjIzIDEuNjI4ODcgNTEuNTMyNCA1LjgzMjE1IDQ3LjY1MjVDOS43MTIxMSA0My40NDkyIDE2LjUwMiA0My40NDkyIDIwLjM4MiA0Ny42NTI1TDc1LjM0OCAxMDIuMjk1TDEyOS45OTEgNDcuNjUyNUMxMzMuODcxIDQzLjQ0OTIgMTQwLjY2MSA0My40NDkyIDE0NC41NDEgNDcuNjUyNUMxNDguNzQ0IDUxLjUzMjQgMTQ4Ljc0NCA1OC4zMjIzIDE0NC41NDEgNjIuMjAyM0w4Mi40NjEzIDEyNC4yODJDODAuNTIxMyAxMjYuMjIyIDc3LjkzNDcgMTI3LjE5MiA3NS4zNDggMTI3LjE5MloiIGZpbGw9IiMzMTM3NEEiLz4KPC9zdmc+Cg==");
display: block; display: block;
text-align: start;
width: 100%; width: 100%;
padding: 0.5rem 1rem 0.5rem 2.5rem; padding: 0.5rem 1rem 0.5rem 2.5rem;
font-size: 0.8rem; font-size: 0.8rem;
@ -4699,6 +4700,7 @@ textarea.form-control-lg {
top: 100%; top: 100%;
right: 0; right: 0;
margin-top: var(--phoenix-dropdown-spacer); margin-top: var(--phoenix-dropdown-spacer);
text-align: right;
} }
.dropdown-menu-start { .dropdown-menu-start {

View File

@ -1259,6 +1259,7 @@ progress {
font-weight: 600; font-weight: 600;
} }
.display-1 { .display-1 {
font-size: calc(1.6018371582rem + 4.2220458984vw); font-size: calc(1.6018371582rem + 4.2220458984vw);
font-weight: 400; font-weight: 400;
@ -3784,6 +3785,7 @@ textarea.form-control-lg {
--phoenix-form-select-bg-img: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03NS4zNDggMTI3LjE5MkM3Mi40MzgxIDEyNy4xOTIgNjkuODUxNCAxMjYuMjIyIDY3LjkxMTUgMTI0LjI4Mkw1LjgzMjE1IDYyLjIwMjNDMS42Mjg4NyA1OC4zMjIzIDEuNjI4ODcgNTEuNTMyNCA1LjgzMjE1IDQ3LjY1MjVDOS43MTIxMSA0My40NDkyIDE2LjUwMiA0My40NDkyIDIwLjM4MiA0Ny42NTI1TDc1LjM0OCAxMDIuMjk1TDEyOS45OTEgNDcuNjUyNUMxMzMuODcxIDQzLjQ0OTIgMTQwLjY2MSA0My40NDkyIDE0NC41NDEgNDcuNjUyNUMxNDguNzQ0IDUxLjUzMjQgMTQ4Ljc0NCA1OC4zMjIzIDE0NC41NDEgNjIuMjAyM0w4Mi40NjEzIDEyNC4yODJDODAuNTIxMyAxMjYuMjIyIDc3LjkzNDcgMTI3LjE5MiA3NS4zNDggMTI3LjE5MloiIGZpbGw9IiMzMTM3NEEiLz4KPC9zdmc+Cg=="); --phoenix-form-select-bg-img: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik03NS4zNDggMTI3LjE5MkM3Mi40MzgxIDEyNy4xOTIgNjkuODUxNCAxMjYuMjIyIDY3LjkxMTUgMTI0LjI4Mkw1LjgzMjE1IDYyLjIwMjNDMS42Mjg4NyA1OC4zMjIzIDEuNjI4ODcgNTEuNTMyNCA1LjgzMjE1IDQ3LjY1MjVDOS43MTIxMSA0My40NDkyIDE2LjUwMiA0My40NDkyIDIwLjM4MiA0Ny42NTI1TDc1LjM0OCAxMDIuMjk1TDEyOS45OTEgNDcuNjUyNUMxMzMuODcxIDQzLjQ0OTIgMTQwLjY2MSA0My40NDkyIDE0NC41NDEgNDcuNjUyNUMxNDguNzQ0IDUxLjUzMjQgMTQ4Ljc0NCA1OC4zMjIzIDE0NC41NDEgNjIuMjAyM0w4Mi40NjEzIDEyNC4yODJDODAuNTIxMyAxMjYuMjIyIDc3LjkzNDcgMTI3LjE5MiA3NS4zNDggMTI3LjE5MloiIGZpbGw9IiMzMTM3NEEiLz4KPC9zdmc+Cg==");
display: block; display: block;
width: 100%; width: 100%;
text-align: start;
padding: 0.5rem 2.5rem 0.5rem 1rem; padding: 0.5rem 2.5rem 0.5rem 1rem;
font-size: 0.8rem; font-size: 0.8rem;
font-weight: 600; font-weight: 600;
@ -3815,6 +3817,7 @@ textarea.form-control-lg {
} }
} }
.form-select:focus { .form-select:focus {
text-align: start;
border-color: #3874ff; border-color: #3874ff;
outline: 0; outline: 0;
-webkit-box-shadow: inset 0 1px 2px transparent, 0 0 0 0.25rem rgba(56, 116, 255, 0.25); -webkit-box-shadow: inset 0 1px 2px transparent, 0 0 0 0.25rem rgba(56, 116, 255, 0.25);

View File

@ -61,6 +61,7 @@
--djdt-font-color: #8393a7; --djdt-font-color: #8393a7;
--djdt-background-color: #1e293bff; --djdt-background-color: #1e293bff;
--djdt-panel-content-background-color: #0f1729ff; --djdt-panel-content-background-color: #0f1729ff;
--djdt-panel-content-table-background-color: var(--djdt-background-color);
--djdt-panel-title-background-color: #242432; --djdt-panel-title-background-color: #242432;
--djdt-djdt-panel-content-table-strip-background-color: #324154ff; --djdt-djdt-panel-content-table-strip-background-color: #324154ff;
--djdt--highlighted-background-color: #2c2a7dff; --djdt--highlighted-background-color: #2c2a7dff;
@ -301,7 +302,7 @@
font-size: 22px; font-size: 22px;
font-weight: bold; font-weight: bold;
background: #000; background: #000;
opacity: 0.5; opacity: 0.6;
} }
#djDebug #djShowToolBarButton:hover { #djDebug #djShowToolBarButton:hover {
@ -555,62 +556,94 @@
#djDebug .highlight .err { #djDebug .highlight .err {
color: var(--djdt-font-color); color: var(--djdt-font-color);
} /* Error */ } /* Error */
#djDebug .highlight .g {
color: var(--djdt-font-color); /*
} /* Generic */ Styles for pygments HTMLFormatter
#djDebug .highlight .k {
color: var(--djdt-font-color); - This should match debug_toolbar/panels/templates/views.py::template_source
font-weight: bold; - Each line needs to be prefixed with #djDebug .highlight as well.
} /* Keyword */ - The .w definition needs to include:
#djDebug .highlight .o { white-space: pre-wrap
color: var(--djdt-font-color);
} /* Operator */ To regenerate:
#djDebug .highlight .n {
color: var(--djdt-font-color); from pygments.formatters import HtmlFormatter
} /* Name */ print(HtmlFormatter(wrapcode=True).get_style_defs())
#djDebug .highlight .mi { */
color: var(--djdt-font-color); #djDebug .highlight pre { line-height: 125%; }
font-weight: bold; #djDebug .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
} /* Literal.Number.Integer */ #djDebug .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
#djDebug .highlight .l { #djDebug .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
color: var(--djdt-font-color); #djDebug .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
} /* Literal */ #djDebug .highlight .hll { background-color: #ffffcc }
#djDebug .highlight .x { #djDebug .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
color: var(--djdt-font-color); #djDebug .highlight .err { border: 1px solid #FF0000 } /* Error */
} /* Other */ #djDebug .highlight .k { color: #008000; font-weight: bold } /* Keyword */
#djDebug .highlight .p { #djDebug .highlight .o { color: #666666 } /* Operator */
color: var(--djdt-font-color); #djDebug .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
} /* Punctuation */ #djDebug .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
#djDebug .highlight .m { #djDebug .highlight .cp { color: #9C6500 } /* Comment.Preproc */
color: var(--djdt-font-color); #djDebug .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
font-weight: bold; #djDebug .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
} /* Literal.Number */ #djDebug .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
#djDebug .highlight .s { #djDebug .highlight .gd { color: #A00000 } /* Generic.Deleted */
color: var(--djdt-template-highlight-color); #djDebug .highlight .ge { font-style: italic } /* Generic.Emph */
} /* Literal.String */ #djDebug .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
#djDebug .highlight .w { #djDebug .highlight .gr { color: #E40000 } /* Generic.Error */
color: #888888; #djDebug .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
} /* Text.Whitespace */ #djDebug .highlight .gi { color: #008400 } /* Generic.Inserted */
#djDebug .highlight .il { #djDebug .highlight .go { color: #717171 } /* Generic.Output */
color: var(--djdt-font-color); #djDebug .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
font-weight: bold; #djDebug .highlight .gs { font-weight: bold } /* Generic.Strong */
} /* Literal.Number.Integer.Long */ #djDebug .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
#djDebug .highlight .na { #djDebug .highlight .gt { color: #0044DD } /* Generic.Traceback */
color: var(--djdt-template-highlight-color); #djDebug .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
} /* Name.Attribute */ #djDebug .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
#djDebug .highlight .nt { #djDebug .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
color: var(--djdt-font-color); #djDebug .highlight .kp { color: #008000 } /* Keyword.Pseudo */
font-weight: bold; #djDebug .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
} /* Name.Tag */ #djDebug .highlight .kt { color: #B00040 } /* Keyword.Type */
#djDebug .highlight .nv { #djDebug .highlight .m { color: #666666 } /* Literal.Number */
color: var(--djdt-template-highlight-color); #djDebug .highlight .s { color: #BA2121 } /* Literal.String */
} /* Name.Variable */ #djDebug .highlight .na { color: #687822 } /* Name.Attribute */
#djDebug .highlight .s2 { #djDebug .highlight .nb { color: #008000 } /* Name.Builtin */
color: var(--djdt-template-highlight-color); #djDebug .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
} /* Literal.String.Double */ #djDebug .highlight .no { color: #880000 } /* Name.Constant */
#djDebug .highlight .cp { #djDebug .highlight .nd { color: #AA22FF } /* Name.Decorator */
color: var(--djdt-template-highlight-color); #djDebug .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
} /* Comment.Preproc */ #djDebug .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
#djDebug .highlight .nf { color: #0000FF } /* Name.Function */
#djDebug .highlight .nl { color: #767600 } /* Name.Label */
#djDebug .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
#djDebug .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
#djDebug .highlight .nv { color: #19177C } /* Name.Variable */
#djDebug .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
#djDebug .highlight .w { color: #bbbbbb; white-space: pre-wrap } /* Text.Whitespace */
#djDebug .highlight .mb { color: #666666 } /* Literal.Number.Bin */
#djDebug .highlight .mf { color: #666666 } /* Literal.Number.Float */
#djDebug .highlight .mh { color: #666666 } /* Literal.Number.Hex */
#djDebug .highlight .mi { color: #666666 } /* Literal.Number.Integer */
#djDebug .highlight .mo { color: #666666 } /* Literal.Number.Oct */
#djDebug .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
#djDebug .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
#djDebug .highlight .sc { color: #BA2121 } /* Literal.String.Char */
#djDebug .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
#djDebug .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
#djDebug .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
#djDebug .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
#djDebug .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
#djDebug .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
#djDebug .highlight .sx { color: #008000 } /* Literal.String.Other */
#djDebug .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
#djDebug .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
#djDebug .highlight .ss { color: #19177C } /* Literal.String.Symbol */
#djDebug .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
#djDebug .highlight .fm { color: #0000FF } /* Name.Function.Magic */
#djDebug .highlight .vc { color: #19177C } /* Name.Variable.Class */
#djDebug .highlight .vg { color: #19177C } /* Name.Variable.Global */
#djDebug .highlight .vi { color: #19177C } /* Name.Variable.Instance */
#djDebug .highlight .vm { color: #19177C } /* Name.Variable.Magic */
#djDebug .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
#djDebug svg.djDebugLineChart { #djDebug svg.djDebugLineChart {
width: 100%; width: 100%;

View File

@ -245,7 +245,6 @@
color: getColor('secondary-bg') color: getColor('secondary-bg')
} }
}, },
zlevel: 2
}, },
{ {
type: 'line', type: 'line',

Some files were not shown because too many files have changed in this diff Show More