the dealer email issue not fixed

This commit is contained in:
gitea 2024-12-26 16:02:42 +00:00
parent c15d7dd696
commit 855c8f6c80
38 changed files with 948 additions and 1096 deletions

View File

@ -1,6 +1,5 @@
# Generated by Django 5.1.4 on 2024-12-22 21:55 # Generated by Django 4.2.17 on 2024-12-26 10:12
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
@ -9,7 +8,6 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('inventory', '0001_initial'),
] ]
operations = [ operations = [
@ -20,7 +18,6 @@ class Migration(migrations.Migration):
('user_message', models.TextField()), ('user_message', models.TextField()),
('chatbot_response', models.TextField()), ('chatbot_response', models.TextField()),
('timestamp', models.DateTimeField(auto_now_add=True)), ('timestamp', models.DateTimeField(auto_now_add=True)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer')),
], ],
), ),
] ]

View File

@ -0,0 +1,22 @@
# Generated by Django 4.2.17 on 2024-12-26 10:12
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('haikalbot', '0001_initial'),
('inventory', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='chatlog',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer'),
),
]

View File

@ -1,3 +1,5 @@
from phonenumber_field.formfields import PhoneNumberField
from django.core.validators import RegexValidator
from django import forms from django import forms
from .mixins import AddClassMixin from .mixins import AddClassMixin
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
@ -22,7 +24,7 @@ from .models import (
AdditionalServices AdditionalServices
) )
from django.forms import ModelMultipleChoiceField from django.forms import ModelMultipleChoiceField, ValidationError
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.forms import formset_factory from django.forms import formset_factory
@ -48,7 +50,6 @@ class DealerForm(forms.ModelForm):
model = Dealer model = Dealer
fields = ['name', 'arabic_name', 'crn', 'vrn', 'phone_number', 'address', 'logo'] fields = ['name', 'arabic_name', 'crn', 'vrn', 'phone_number', 'address', 'logo']
# Customer Form # Customer Form
class CustomerForm(forms.ModelForm, AddClassMixin): class CustomerForm(forms.ModelForm, AddClassMixin):
class Meta: class Meta:
@ -257,3 +258,148 @@ class CarSelectionTable(tables.Table):
model = Car model = Car
fields = ['vin', 'year', 'id_car_make', 'id_car_model'] fields = ['vin', 'year', 'id_car_make', 'id_car_model']
template_name = "django_tables2/bootstrap4.html" template_name = "django_tables2/bootstrap4.html"
class WizardForm1(forms.Form):
name = forms.CharField(
label="Name",
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Name',
'required': 'required',
}),
error_messages={
'required': 'Please choose a username.',
}
)
arabic_name = forms.CharField(
label="Arabic Name",
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Arabic Name',
'required': 'required',
}),
error_messages={
'required': 'Please choose an Arabic name.',
}
)
email = forms.EmailField(
label="Email*",
widget=forms.EmailInput(attrs={
'class': 'form-control',
'placeholder': 'Email address',
'pattern': '^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$',
'required': 'required',
}),
error_messages={
'required': 'You must add an email.',
}
)
terms = forms.BooleanField(
label="I accept the <a href='#!'>terms</a> and <a href='#!'>privacy policy</a>",
widget=forms.CheckboxInput(attrs={
'class': 'form-check-input',
'required': 'required',
'checked': 'checked',
}),
error_messages={
'required': 'You must accept the terms and privacy policy.',
}
)
class WizardForm2(forms.Form):
# Phone field with SA region validation
phone_number = PhoneNumberField(
label="Phone",
max_length=10,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Phone',
'required': 'required',
}),
region='SA', # Enforces SA region validation
error_messages={
'required': 'This field is required.',
'invalid': 'Phone number must be in the format +966XXXXXXXXX (Saudi Arabia).',
}
)
# CRN field with max length of 10
crn = forms.CharField(
label="CRN",
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'CRN',
'required': 'required',
'maxlength': '10', # HTML maxlength attribute
}),
max_length=10, # Django max_length validation
error_messages={
'required': 'This field is required.',
'max_length': 'CRN must be at most 10 characters long.',
}
)
# VRN field with max length of 15
vrn = forms.CharField(
label="VRN",
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'VRN',
'required': 'required',
'maxlength': '15', # HTML maxlength attribute
}),
max_length=15, # Django max_length validation
error_messages={
'required': 'This field is required.',
'max_length': 'VRN must be at most 15 characters long.',
}
)
address = forms.CharField(
label="Address",
widget=forms.Textarea(attrs={
'class': 'form-control',
'rows': '4',
'required': 'required',
}),
error_messages={
'required': 'This field is required.',
}
)
class WizardForm3(forms.Form):
password = forms.CharField(
label="Password*",
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': 'Password',
'required': 'required',
}),
error_messages={
'required': 'This field is required.',
}
)
confirm_password = forms.CharField(
label="Confirm Password*",
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': 'Confirm Password',
'required': 'required',
}),
error_messages={
'required': 'This field is required.',
}
)
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password and confirm_password and password != confirm_password:
raise forms.ValidationError("Passwords do not match.")

View File

@ -1,11 +1,11 @@
# Generated by Django 5.1.4 on 2024-12-09 13:58 # Generated by Django 4.2.17 on 2024-12-26 10:12
import django.db.models.deletion
import inventory.mixins
import phonenumber_field.modelfields
from decimal import Decimal from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
import inventory.mixins
import phonenumber_field.modelfields
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -14,16 +14,34 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
] ]
operations = [ operations = [
migrations.CreateModel(
name='AdditionalServices',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('description', models.TextField(verbose_name='Description')),
('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')),
('taxable', models.BooleanField(default=False, verbose_name='taxable')),
('uom', models.CharField(choices=[('Kg', 'Kg'), ('L', 'L'), ('m', 'm'), ('cm', 'cm'), ('m2', 'm2'), ('m3', 'm3'), ('m3', 'm3')], max_length=10, verbose_name='Unit of Measurement')),
],
options={
'verbose_name': 'Additional Services',
'verbose_name_plural': 'Additional Services',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel( migrations.CreateModel(
name='Car', name='Car',
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')),
('vin', models.CharField(max_length=17, unique=True, verbose_name='VIN')), ('vin', models.CharField(max_length=17, unique=True, verbose_name='VIN')),
('year', models.IntegerField(verbose_name='Year')), ('year', models.IntegerField(verbose_name='Year')),
('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged')], default='available', max_length=10, verbose_name='Status')), ('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status')),
('stock_type', models.CharField(choices=[('new', 'New'), ('used', 'Used')], default='new', max_length=10, verbose_name='Stock Type')), ('stock_type', models.CharField(choices=[('new', 'New'), ('used', 'Used')], default='new', max_length=10, verbose_name='Stock Type')),
('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')), ('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')), ('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')),
@ -48,6 +66,90 @@ class Migration(migrations.Migration):
}, },
bases=(models.Model, inventory.mixins.LocalizedNameMixin), bases=(models.Model, inventory.mixins.LocalizedNameMixin),
), ),
migrations.CreateModel(
name='CarModel',
fields=[
('id_car_model', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('id_car_make', models.ForeignKey(db_column='id_car_make', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake')),
],
options={
'verbose_name': 'Model',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='CarSerie',
fields=[
('id_car_serie', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('year_begin', models.IntegerField(blank=True, null=True)),
('year_end', models.IntegerField(blank=True, null=True)),
('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')),
],
options={
'verbose_name': 'Series',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='CarSpecification',
fields=[
('id_car_specification', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
],
options={
'verbose_name': 'Specification',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='Customer',
fields=[
('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')),
('middle_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Middle Name')),
('last_name', models.CharField(max_length=50, verbose_name='Last Name')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')),
('national_id', models.CharField(max_length=10, unique=True, verbose_name='National ID')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
],
options={
'verbose_name': 'Customer',
'verbose_name_plural': 'Customers',
},
),
migrations.CreateModel(
name='Dealer',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('crn', models.CharField(blank=True, max_length=10, null=True, verbose_name='Commercial Registration Number')),
('vrn', models.CharField(blank=True, max_length=15, null=True, verbose_name='VAT Registration Number')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('name', models.CharField(max_length=255, verbose_name='English Name')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('logo', models.ImageField(blank=True, null=True, upload_to='logos/users', verbose_name='Logo')),
('joined_at', models.DateTimeField(auto_now_add=True, verbose_name='Joined At')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')),
('dealer_type', models.CharField(choices=[('Owner', 'Owner'), ('Inventory', 'Inventory'), ('Accountent', 'Accountent'), ('sales', 'Sales')], default='Owner', max_length=255, verbose_name='Dealer Type')),
('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel')),
('parent_dealer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_dealers', to='inventory.dealer', verbose_name='Parent Dealer')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Dealer',
'verbose_name_plural': 'Dealers',
'permissions': [('change_dealer_type', 'Can change dealer type')],
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel( migrations.CreateModel(
name='ExteriorColors', name='ExteriorColors',
fields=[ fields=[
@ -77,203 +179,81 @@ class Migration(migrations.Migration):
bases=(models.Model, inventory.mixins.LocalizedNameMixin), bases=(models.Model, inventory.mixins.LocalizedNameMixin),
), ),
migrations.CreateModel( migrations.CreateModel(
name='CarFinance', name='Organization',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')), ('name', models.CharField(max_length=255, verbose_name='Name')),
('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')),
('profit_margin', models.DecimalField(decimal_places=2, editable=False, max_digits=14, verbose_name='Profit Margin')),
('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')),
('registration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Registration Fee')),
('administration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Administration Fee')),
('transportation_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Transportation Fee')),
('custom_card_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Custom Card Fee')),
('vat_rate', models.DecimalField(decimal_places=2, default=Decimal('0.15'), max_digits=14, verbose_name='VAT Rate')),
('administration_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Administration VAT')),
('transportation_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Transportation VAT')),
('custom_card_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Custom Card VAT')),
('selling_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Selling VAT')),
('total_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Total VAT')),
('total_before_vat', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Before VAT')),
('total', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Amount')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')),
],
),
migrations.AddField(
model_name='car',
name='id_car_make',
field=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'),
),
migrations.CreateModel(
name='CarModel',
fields=[
('id_car_model', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('id_car_make', models.ForeignKey(db_column='id_car_make', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake')),
],
options={
'verbose_name': 'Model',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.AddField(
model_name='car',
name='id_car_model',
field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'),
),
migrations.CreateModel(
name='CarRegistration',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('plate_number', models.IntegerField(verbose_name='Plate Number')),
('text1', models.CharField(max_length=1, verbose_name='Text 1')),
('text2', models.CharField(max_length=1, verbose_name='Text 2')),
('text3', models.CharField(max_length=1, verbose_name='Text 3')),
('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')),
],
options={
'verbose_name': 'Registration',
'verbose_name_plural': 'Registrations',
},
),
migrations.CreateModel(
name='CarSerie',
fields=[
('id_car_serie', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')),
],
options={
'verbose_name': 'Series',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.AddField(
model_name='car',
name='id_car_serie',
field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'),
),
migrations.CreateModel(
name='CarSpecification',
fields=[
('id_car_specification', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
],
options={
'verbose_name': 'Specification',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='CarTrim',
fields=[
('id_car_trim', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('start_production_year', models.IntegerField(blank=True, null=True)),
('end_production_year', models.IntegerField(blank=True, null=True)),
('id_car_serie', models.ForeignKey(db_column='id_car_serie', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie')),
],
options={
'verbose_name': 'Trim',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='CarSpecificationValue',
fields=[
('id_car_specification_value', models.AutoField(primary_key=True, serialize=False)),
('value', models.CharField(max_length=500)),
('unit', models.CharField(blank=True, max_length=255, null=True)),
('id_car_specification', models.ForeignKey(db_column='id_car_specification', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
('id_car_trim', models.ForeignKey(db_column='id_car_trim', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim')),
],
options={
'verbose_name': 'Specification Value',
},
),
migrations.AddField(
model_name='car',
name='id_car_trim',
field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'),
),
migrations.CreateModel(
name='CustomCard',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')),
('custom_date', models.DateField(verbose_name='Custom Date')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')),
],
options={
'verbose_name': 'Custom Card',
'verbose_name_plural': 'Custom Cards',
},
),
migrations.CreateModel(
name='Dealer',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('crn', models.CharField(max_length=10, verbose_name='Commercial Registration Number')),
('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('name', models.CharField(max_length=255, verbose_name='English Name')), ('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')),
('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('logo', models.ImageField(blank=True, null=True, upload_to='logos/users', verbose_name='Logo')), ('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')),
], ],
options={ options={
'verbose_name': 'Dealer', 'verbose_name': 'Organization',
'verbose_name_plural': 'Dealers', 'verbose_name_plural': 'Organizations',
}, },
bases=(models.Model, inventory.mixins.LocalizedNameMixin), bases=(models.Model, inventory.mixins.LocalizedNameMixin),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Customer', name='Payment',
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')), ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')),
('middle_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Middle Name')), ('payment_method', models.CharField(choices=[('cash', 'cash'), ('credit', 'credit'), ('transfer', 'transfer'), ('debit', 'debit'), ('SADAD', 'SADAD')], max_length=50, verbose_name='method')),
('last_name', models.CharField(max_length=50, verbose_name='Last Name')), ('reference_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='reference number')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), ('payment_date', models.DateField(auto_now_add=True, verbose_name='date')),
('national_id', models.CharField(max_length=10, unique=True, verbose_name='National ID')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')),
], ],
options={ options={
'verbose_name': 'Customer', 'verbose_name': 'payment',
'verbose_name_plural': 'Customers', 'verbose_name_plural': 'payments',
}, },
), ),
migrations.AddField(
model_name='car',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'),
),
migrations.CreateModel( migrations.CreateModel(
name='SaleQuotation', name='SaleQuotation',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('remarks', models.TextField(blank=True, null=True)), ('quotation_number', models.CharField(max_length=10, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)), ('amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.customer')), ('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
('is_approved', models.BooleanField(default=False)),
('status', models.CharField(choices=[('Draft', 'Draft'), ('Approved', 'Approved'), ('In Review', 'In Review'), ('Paid', 'Paid')], default='Draft', max_length=10, verbose_name='Status')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
('posted', models.BooleanField(default=False)),
('payment_id', models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment ID')),
('is_paid', models.BooleanField(default=False)),
('date_draft', models.DateTimeField(blank=True, null=True, verbose_name='Draft Date')),
('date_in_review', models.DateTimeField(blank=True, null=True, verbose_name='In Review Date')),
('date_approved', models.DateTimeField(blank=True, null=True, verbose_name='Approved Date')),
('date_paid', models.DateTimeField(blank=True, null=True, verbose_name='Paid Date')),
('date_void', models.DateTimeField(blank=True, null=True, verbose_name='Void Date')),
('date_canceled', models.DateTimeField(blank=True, null=True, verbose_name='Canceled Date')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer')),
('dealer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='SaleQuotationCar', name='Subscription',
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, to='inventory.car')), ('plan', models.CharField(max_length=255)),
('financial_details', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_finances', to='inventory.carfinance')), ('start_date', models.DateField()),
('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation')), ('end_date', models.DateField()),
('max_users', models.IntegerField()),
('is_active', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='SubscriptionPlan',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('description', models.TextField()),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('max_users', models.IntegerField()),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -296,21 +276,215 @@ class Migration(migrations.Migration):
}, },
bases=(models.Model, inventory.mixins.LocalizedNameMixin), bases=(models.Model, inventory.mixins.LocalizedNameMixin),
), ),
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)),
],
),
migrations.AddField(
model_name='subscription',
name='users',
field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='SalesOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')),
('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')),
],
),
migrations.CreateModel(
name='SaleQuotationCar',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', models.PositiveIntegerField(default=1, verbose_name='Quantity')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car')),
('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation')),
],
),
migrations.CreateModel(
name='Representative',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('id_number', models.CharField(max_length=10, verbose_name='ID Number')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')),
('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')),
],
options={
'verbose_name': 'Representative',
'verbose_name_plural': 'Representatives',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='Refund',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')),
('reason', models.TextField(blank=True, verbose_name='reason')),
('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')),
('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')),
],
options={
'verbose_name': 'refund',
'verbose_name_plural': 'refunds',
},
),
migrations.AddField(
model_name='payment',
name='quotation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'),
),
migrations.AddField(
model_name='customer',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer'),
),
migrations.CreateModel(
name='CustomCard',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')),
('custom_date', models.DateField(verbose_name='Custom Date')),
('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')),
],
options={
'verbose_name': 'Custom Card',
'verbose_name_plural': 'Custom Cards',
},
),
migrations.CreateModel(
name='CarTrim',
fields=[
('id_car_trim', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('arabic_name', models.CharField(max_length=255)),
('start_production_year', models.IntegerField(blank=True, null=True)),
('end_production_year', models.IntegerField(blank=True, null=True)),
('id_car_model', models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')),
('id_car_serie', models.ForeignKey(db_column='id_car_serie', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie')),
],
options={
'verbose_name': 'Trim',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='CarSpecificationValue',
fields=[
('id_car_specification_value', models.AutoField(primary_key=True, serialize=False)),
('value', models.CharField(max_length=500)),
('unit', models.CharField(blank=True, max_length=255, null=True)),
('id_car_specification', models.ForeignKey(db_column='id_car_specification', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')),
('id_car_trim', models.ForeignKey(db_column='id_car_trim', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim')),
],
options={
'verbose_name': 'Specification Value',
},
),
migrations.CreateModel(
name='CarRegistration',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('plate_number', models.IntegerField(verbose_name='Plate Number')),
('text1', models.CharField(max_length=1, verbose_name='Text 1')),
('text2', models.CharField(max_length=1, verbose_name='Text 2')),
('text3', models.CharField(max_length=1, verbose_name='Text 3')),
('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')),
],
options={
'verbose_name': 'Registration',
'verbose_name_plural': 'Registrations',
},
),
migrations.CreateModel(
name='CarLocation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(blank=True, help_text='Optional description about the showroom placement.', null=True, verbose_name='Description')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Updated')),
('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='location', to='inventory.car', verbose_name='Car')),
('owner', models.ForeignKey(help_text='Dealer who owns the car.', on_delete=django.db.models.deletion.CASCADE, related_name='owned_cars', to='inventory.dealer', verbose_name='Owner')),
('showroom', models.ForeignKey(help_text='Dealer where the car is displayed (can be the owner).', on_delete=django.db.models.deletion.CASCADE, related_name='showroom_cars', to='inventory.dealer', verbose_name='Showroom')),
],
options={
'verbose_name': 'Car Location',
'verbose_name_plural': 'Car Locations',
},
),
migrations.CreateModel(
name='CarFinance',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')),
('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')),
('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')),
('additional_services', models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices')),
('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')),
],
options={
'verbose_name': 'Car Financial Details',
'verbose_name_plural': 'Car Financial Details',
},
),
migrations.AddField(
model_name='car',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'),
),
migrations.AddField(
model_name='car',
name='id_car_make',
field=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'),
),
migrations.AddField(
model_name='car',
name='id_car_model',
field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'),
),
migrations.AddField(
model_name='car',
name='id_car_serie',
field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'),
),
migrations.AddField(
model_name='car',
name='id_car_trim',
field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'),
),
migrations.AddField( migrations.AddField(
model_name='car', model_name='car',
name='vendor', name='vendor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.vendor', verbose_name='Vendor'), field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.vendor', verbose_name='Vendor'),
), ),
migrations.AddField(
model_name='additionalservices',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'),
),
migrations.CreateModel( migrations.CreateModel(
name='CarReservation', name='CarReservation',
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')),
('reserved_at', models.DateTimeField(auto_now_add=True)), ('reserved_at', models.DateTimeField(auto_now_add=True, verbose_name='Reserved At')),
('reserved_until', models.DateTimeField()), ('reserved_until', models.DateTimeField(verbose_name='Reserved Until')),
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car')), ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car', verbose_name='Car')),
('reserved_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('reserved_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to=settings.AUTH_USER_MODEL, verbose_name='Reserved By')),
], ],
options={ options={
'verbose_name': 'Car Reservation',
'verbose_name_plural': 'Car Reservations',
'ordering': ['-reserved_at'], 'ordering': ['-reserved_at'],
'unique_together': {('car', 'reserved_until')}, 'unique_together': {('car', 'reserved_until')},
}, },

View File

@ -1,335 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-22 21:55
import django.db.models.deletion
import inventory.mixins
import phonenumber_field.modelfields
from decimal import Decimal
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='AdditionalServices',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('display_name', models.CharField(max_length=255, verbose_name='Display Name')),
('description', models.TextField(verbose_name='Description')),
('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')),
],
options={
'verbose_name': 'Additional Services',
'verbose_name_plural': 'Additional Services',
},
),
migrations.CreateModel(
name='Subscription',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('plan', models.CharField(max_length=255)),
('start_date', models.DateField()),
('end_date', models.DateField()),
('max_users', models.IntegerField()),
('is_active', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='SubscriptionPlan',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('description', models.TextField()),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('max_users', models.IntegerField()),
],
),
migrations.AlterModelOptions(
name='carfinance',
options={'verbose_name': 'Car Financial Details', 'verbose_name_plural': 'Car Financial Details'},
),
migrations.AlterModelOptions(
name='carreservation',
options={'ordering': ['-reserved_at'], 'verbose_name': 'Car Reservation', 'verbose_name_plural': 'Car Reservations'},
),
migrations.AlterModelOptions(
name='dealer',
options={'permissions': [('change_dealer_type', 'Can change dealer type')], 'verbose_name': 'Dealer', 'verbose_name_plural': 'Dealers'},
),
migrations.RemoveField(
model_name='carfinance',
name='administration_fee',
),
migrations.RemoveField(
model_name='carfinance',
name='administration_vat_amount',
),
migrations.RemoveField(
model_name='carfinance',
name='custom_card_fee',
),
migrations.RemoveField(
model_name='carfinance',
name='custom_card_vat_amount',
),
migrations.RemoveField(
model_name='carfinance',
name='profit_margin',
),
migrations.RemoveField(
model_name='carfinance',
name='registration_fee',
),
migrations.RemoveField(
model_name='carfinance',
name='selling_vat_amount',
),
migrations.RemoveField(
model_name='carfinance',
name='total',
),
migrations.RemoveField(
model_name='carfinance',
name='total_before_vat',
),
migrations.RemoveField(
model_name='carfinance',
name='total_vat_amount',
),
migrations.RemoveField(
model_name='carfinance',
name='transportation_fee',
),
migrations.RemoveField(
model_name='carfinance',
name='transportation_vat_amount',
),
migrations.RemoveField(
model_name='carfinance',
name='vat_rate',
),
migrations.RemoveField(
model_name='salequotationcar',
name='financial_details',
),
migrations.AddField(
model_name='carserie',
name='year_begin',
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='carserie',
name='year_end',
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='cartrim',
name='id_car_model',
field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel'),
),
migrations.AddField(
model_name='dealer',
name='dealer_type',
field=models.CharField(choices=[('Owner', 'Owner'), ('Inventory', 'Inventory'), ('Accountent', 'Accountent'), ('sales', 'Sales')], default='Owner', max_length=255, verbose_name='Dealer Type'),
),
migrations.AddField(
model_name='dealer',
name='parent_dealer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_dealers', to='inventory.dealer', verbose_name='Parent Dealer'),
),
migrations.AddField(
model_name='salequotation',
name='amount',
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount'),
),
migrations.AddField(
model_name='salequotation',
name='dealer',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer'),
),
migrations.AddField(
model_name='salequotation',
name='entity',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.entitymodel'),
preserve_default=False,
),
migrations.AddField(
model_name='salequotation',
name='is_approved',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='salequotation',
name='quotation_number',
field=models.CharField(default=1, max_length=10, unique=True),
preserve_default=False,
),
migrations.AddField(
model_name='salequotation',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
),
migrations.AddField(
model_name='salequotationcar',
name='quantity',
field=models.PositiveIntegerField(default=1, verbose_name='Quantity'),
),
migrations.AlterField(
model_name='car',
name='status',
field=models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status'),
),
migrations.AlterField(
model_name='carfinance',
name='car',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car'),
),
migrations.AlterField(
model_name='carreservation',
name='car',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car', verbose_name='Car'),
),
migrations.AlterField(
model_name='carreservation',
name='reserved_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='Reserved At'),
),
migrations.AlterField(
model_name='carreservation',
name='reserved_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to=settings.AUTH_USER_MODEL, verbose_name='Reserved By'),
),
migrations.AlterField(
model_name='carreservation',
name='reserved_until',
field=models.DateTimeField(verbose_name='Reserved Until'),
),
migrations.AlterField(
model_name='customcard',
name='car',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car'),
),
migrations.AlterField(
model_name='dealer',
name='crn',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Commercial Registration Number'),
),
migrations.AlterField(
model_name='dealer',
name='vrn',
field=models.CharField(blank=True, max_length=15, null=True, verbose_name='VAT Registration Number'),
),
migrations.AlterField(
model_name='salequotation',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='Created At'),
),
migrations.AlterField(
model_name='salequotation',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer'),
),
migrations.AlterField(
model_name='salequotation',
name='remarks',
field=models.TextField(blank=True, null=True, verbose_name='Remarks'),
),
migrations.AlterField(
model_name='salequotationcar',
name='car',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car'),
),
migrations.AlterField(
model_name='salequotationcar',
name='quotation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation'),
),
migrations.AddField(
model_name='carfinance',
name='additional_services',
field=models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices'),
),
migrations.CreateModel(
name='CarLocation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(blank=True, help_text='Optional description about the showroom placement.', null=True, verbose_name='Description')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Updated')),
('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='location', to='inventory.car', verbose_name='Car')),
('owner', models.ForeignKey(help_text='Dealer who owns the car.', on_delete=django.db.models.deletion.CASCADE, related_name='owned_cars', to='inventory.dealer', verbose_name='Owner')),
('showroom', models.ForeignKey(help_text='Dealer where the car is displayed (can be the owner).', on_delete=django.db.models.deletion.CASCADE, related_name='showroom_cars', to='inventory.dealer', verbose_name='Showroom')),
],
options={
'verbose_name': 'Car Location',
'verbose_name_plural': 'Car Locations',
},
),
migrations.CreateModel(
name='Organization',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')),
('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')),
],
options={
'verbose_name': 'Organization',
'verbose_name_plural': 'Organizations',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='Representative',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
('id_number', models.CharField(max_length=10, verbose_name='ID Number')),
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')),
('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')),
],
options={
'verbose_name': 'Representative',
'verbose_name_plural': 'Representatives',
},
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
),
migrations.CreateModel(
name='SalesOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')),
('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')),
],
),
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)),
],
),
migrations.AddField(
model_name='subscription',
name='users',
field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2.17 on 2024-12-26 14:19
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', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='dealer',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.17 on 2024-12-26 15:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_alter_dealer_user'),
]
operations = [
migrations.AlterField(
model_name='dealer',
name='email',
field=models.EmailField(max_length=100, null=True, unique=True, verbose_name='Email'),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-23 08:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_additionalservices_subscription_subscriptionplan_and_more'),
]
operations = [
migrations.RemoveField(
model_name='additionalservices',
name='display_name',
),
migrations.AddField(
model_name='additionalservices',
name='arabic_name',
field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'),
preserve_default=False,
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 4.2.17 on 2024-12-26 15:51
from django.db import migrations, models
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_alter_dealer_email'),
]
operations = [
migrations.AlterField(
model_name='dealer',
name='email',
field=models.EmailField(default='a@a.com', max_length=100, unique=True, verbose_name='Email'),
preserve_default=False,
),
migrations.AlterField(
model_name='dealer',
name='phone_number',
field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 08:07
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_remove_additionalservices_display_name_and_more'),
]
operations = [
migrations.RemoveField(
model_name='additionalservices',
name='arabic_name',
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 08:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0004_remove_additionalservices_arabic_name'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='arabic_name',
field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2.17 on 2024-12-26 15:57
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', '0004_alter_dealer_email_alter_dealer_phone_number'),
]
operations = [
migrations.AlterField(
model_name='dealer',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 08:10
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0005_additionalservices_arabic_name'),
]
operations = [
migrations.RemoveField(
model_name='additionalservices',
name='arabic_name',
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 08:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0006_remove_additionalservices_arabic_name'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='arabic_name',
field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'),
preserve_default=False,
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 08:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0007_additionalservices_arabic_name'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='status',
field=models.CharField(choices=[('DRAFT', 'Draft'), ('CONFIRMED', 'Confirmed'), ('CANCELED', 'Canceled')], default='DRAFT', max_length=10, verbose_name='Status'),
),
]

View File

@ -1,48 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 09:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0008_salequotation_status'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='date_approved',
field=models.DateField(blank=True, null=True, verbose_name='Approved Date'),
),
migrations.AddField(
model_name='salequotation',
name='date_canceled',
field=models.DateField(blank=True, null=True, verbose_name='Canceled Date'),
),
migrations.AddField(
model_name='salequotation',
name='date_draft',
field=models.DateField(blank=True, null=True, verbose_name='Draft Date'),
),
migrations.AddField(
model_name='salequotation',
name='date_in_review',
field=models.DateField(blank=True, null=True, verbose_name='In Review Date'),
),
migrations.AddField(
model_name='salequotation',
name='date_paid',
field=models.DateField(blank=True, null=True, verbose_name='Paid Date'),
),
migrations.AddField(
model_name='salequotation',
name='date_void',
field=models.DateField(blank=True, null=True, verbose_name='Void Date'),
),
migrations.AlterField(
model_name='salequotation',
name='status',
field=models.CharField(choices=[('Draft', 'Draft'), ('Approved', 'Approved'), ('In Review', 'In Review'), ('Paid', 'Paid')], default='Draft', max_length=10, verbose_name='Status'),
),
]

View File

@ -1,43 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 09:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0009_salequotation_date_approved_and_more'),
]
operations = [
migrations.AlterField(
model_name='salequotation',
name='date_approved',
field=models.DateTimeField(blank=True, null=True, verbose_name='Approved Date'),
),
migrations.AlterField(
model_name='salequotation',
name='date_canceled',
field=models.DateTimeField(blank=True, null=True, verbose_name='Canceled Date'),
),
migrations.AlterField(
model_name='salequotation',
name='date_draft',
field=models.DateTimeField(blank=True, null=True, verbose_name='Draft Date'),
),
migrations.AlterField(
model_name='salequotation',
name='date_in_review',
field=models.DateTimeField(blank=True, null=True, verbose_name='In Review Date'),
),
migrations.AlterField(
model_name='salequotation',
name='date_paid',
field=models.DateTimeField(blank=True, null=True, verbose_name='Paid Date'),
),
migrations.AlterField(
model_name='salequotation',
name='date_void',
field=models.DateTimeField(blank=True, null=True, verbose_name='Void Date'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 10:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0010_alter_salequotation_date_approved_and_more'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='posted',
field=models.BooleanField(default=False),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 13:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0011_salequotation_posted'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='payment_id',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Payment ID'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 13:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0012_salequotation_payment_id'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='is_paid',
field=models.BooleanField(default=False),
),
]

View File

@ -1,43 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-24 14:43
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0013_salequotation_is_paid'),
]
operations = [
migrations.CreateModel(
name='Payment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')),
('payment_method', models.CharField(choices=[('cash', 'cash'), ('credit', 'credit'), ('transfer', 'transfer'), ('debit', 'debit'), ('SADAD', 'SADAD')], max_length=50, verbose_name='method')),
('reference_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='reference number')),
('payment_date', models.DateField(auto_now_add=True, verbose_name='date')),
('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation')),
],
options={
'verbose_name': 'payment',
'verbose_name_plural': 'payments',
},
),
migrations.CreateModel(
name='Refund',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')),
('reason', models.TextField(blank=True, verbose_name='reason')),
('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')),
('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')),
],
options={
'verbose_name': 'refund',
'verbose_name_plural': 'refunds',
},
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-24 14:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0014_payment_refund'),
]
operations = [
migrations.AlterField(
model_name='salequotation',
name='payment_id',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment ID'),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-25 10:37
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0015_alter_salequotation_payment_id'),
]
operations = [
migrations.AddField(
model_name='dealer',
name='joined_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Joined At'),
preserve_default=False,
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-25 10:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0016_dealer_joined_at'),
]
operations = [
migrations.AddField(
model_name='dealer',
name='email',
field=models.EmailField(default='email@tenhal.sa', max_length=254, unique=True, verbose_name='Email'),
preserve_default=False,
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.4 on 2024-12-25 17:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0017_dealer_email'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='taxable',
field=models.BooleanField(default=True, verbose_name='Taxable'),
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-26 07:13
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0018_additionalservices_taxable'),
]
operations = [
migrations.RemoveField(
model_name='additionalservices',
name='taxable',
),
migrations.RemoveField(
model_name='salequotation',
name='entity',
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-26 07:22
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0019_remove_additionalservices_taxable_and_more'),
]
operations = [
migrations.AddField(
model_name='dealer',
name='entity',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel'),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.2.17 on 2024-12-26 07:58
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0030_account'),
]
operations = [
migrations.RemoveField(
model_name='salequotation',
name='entity',
),
]

View File

@ -504,7 +504,7 @@ class Dealer(models.Model, LocalizedNameMixin):
vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"),null=True,blank=True) vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"),null=True,blank=True)
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
name = models.CharField(max_length=255, verbose_name=_("English Name")) name = models.CharField(max_length=255, verbose_name=_("English Name"))
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"),unique=True)
address = models.CharField( address = models.CharField(
max_length=200, blank=True, null=True, verbose_name=_("Address") max_length=200, blank=True, null=True, verbose_name=_("Address")
) )
@ -513,7 +513,7 @@ class Dealer(models.Model, LocalizedNameMixin):
) )
entity = models.ForeignKey(EntityModel, on_delete=models.SET_NULL, null=True, blank=True) entity = models.ForeignKey(EntityModel, on_delete=models.SET_NULL, null=True, blank=True)
joined_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Joined At")) joined_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Joined At"))
email = models.EmailField(unique=True, verbose_name=_("Email")) email = models.EmailField(verbose_name="Email", unique=True, max_length=100)
parent_dealer = models.ForeignKey( parent_dealer = models.ForeignKey(
"self", "self",
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
@ -529,6 +529,7 @@ class Dealer(models.Model, LocalizedNameMixin):
default=DEALER_TYPES.Owner, default=DEALER_TYPES.Owner,
) )
@property @property
def get_active_plan(self): def get_active_plan(self):
try: try:

View File

@ -25,23 +25,25 @@ User = get_user_model()
# if user: # if user:
# user.delete() # user.delete()
@receiver(post_save, sender=User) # @receiver(post_save, sender=User)
def create_dealer(instance, created, *args, **kwargs): # def create_dealer(instance, created, *args, **kwargs):
if created: # if created:
models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email) # if not instance.dealer:
# models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email)
@receiver(post_save, sender=models.Dealer) # @receiver(post_save, sender=models.Dealer)
def create_user_account(sender, instance, created, **kwargs): # def create_user_account(sender, instance, created, **kwargs):
if created: # if created:
if instance.dealer_type != "Owner": # if instance.dealer_type != "Owner":
user = User.objects.create_user( # user = User.objects.create_user(
username=instance.name, # username=instance.name,
email=instance.email, # email=instance.email,
) # )
user.set_password("Tenhal@123") # user.set_password("Tenhal@123")
user.save() # user.save()
instance.user = user # instance.user = user
instance.save() # instance.save()
@receiver(post_save, sender=models.Car) @receiver(post_save, sender=models.Car)
def create_car_location(sender, instance, created, **kwargs): def create_car_location(sender, instance, created, **kwargs):
@ -81,108 +83,108 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
# Create Entity # Create Entity
@receiver(post_save, sender=models.Dealer) # @receiver(post_save, sender=models.Dealer)
def create_ledger_entity(sender, instance, created, **kwargs): # def create_ledger_entity(sender, instance, created, **kwargs):
if created: # if created:
root_dealer = instance.get_root_dealer # root_dealer = instance.get_root_dealer
if not root_dealer.entity: # if not root_dealer.entity:
entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}" # entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}"
entity = EntityModel.create_entity( # entity = EntityModel.create_entity(
name=entity_name, # name=entity_name,
admin=root_dealer.user, # admin=root_dealer.user,
use_accrual_method=False, # use_accrual_method=False,
fy_start_month=1, # fy_start_month=1,
) # )
if entity: # if entity:
instance.entity = entity # instance.entity = entity
instance.save() # instance.save()
coa = entity.create_chart_of_accounts( # coa = entity.create_chart_of_accounts(
assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA") # assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
) # )
if coa: # if coa:
# entity.populate_default_coa(activate_accounts=True, coa_model=coa) # # entity.populate_default_coa(activate_accounts=True, coa_model=coa)
print(f"Ledger entity created for Dealer: {instance.name}") # print(f"Ledger entity created for Dealer: {instance.name}")
# Create Cash Account # # Create Cash Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="1010", # code="1010",
role=roles.ASSET_CA_CASH, # role=roles.ASSET_CA_CASH,
name=_("Cash"), # name=_("Cash"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# Create Accounts Receivable Account # # Create Accounts Receivable Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="1020", # code="1020",
role=roles.ASSET_CA_RECEIVABLES, # role=roles.ASSET_CA_RECEIVABLES,
name=_("Accounts Receivable"), # name=_("Accounts Receivable"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# Create Inventory Account # # Create Inventory Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="1030", # code="1030",
role=roles.ASSET_CA_INVENTORY, # role=roles.ASSET_CA_INVENTORY,
name=_("Inventory"), # name=_("Inventory"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# Create Accounts Payable Account # # Create Accounts Payable Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="2010", # code="2010",
role=roles.LIABILITY_CL_ACC_PAYABLE, # role=roles.LIABILITY_CL_ACC_PAYABLE,
name=_("Accounts Payable"), # name=_("Accounts Payable"),
balance_type="credit", # balance_type="credit",
active=True, # active=True,
) # )
# Create Sales Revenue Account # # Create Sales Revenue Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="4010", # code="4010",
role=roles.INCOME_OPERATIONAL, # role=roles.INCOME_OPERATIONAL,
name=_("Sales Revenue"), # name=_("Sales Revenue"),
balance_type="credit", # balance_type="credit",
active=True, # active=True,
) # )
# Create Cost of Goods Sold Account # # Create Cost of Goods Sold Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="5010", # code="5010",
role=roles.COGS, # role=roles.COGS,
name=_("Cost of Goods Sold"), # name=_("Cost of Goods Sold"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# Create Rent Expense Account # # Create Rent Expense Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="6010", # code="6010",
role=roles.EXPENSE_OPERATIONAL, # role=roles.EXPENSE_OPERATIONAL,
name=_("Rent Expense"), # name=_("Rent Expense"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# Create Utilities Expense Account # # Create Utilities Expense Account
entity.create_account( # entity.create_account(
coa_model=coa, # coa_model=coa,
code="6020", # code="6020",
role=roles.EXPENSE_OPERATIONAL, # role=roles.EXPENSE_OPERATIONAL,
name=_("Utilities Expense"), # name=_("Utilities Expense"),
balance_type="debit", # balance_type="debit",
active=True, # active=True,
) # )
# uom_name = _("Unit") # uom_name = _("Unit")
# unit_abbr = _("U") # unit_abbr = _("U")

View File

@ -13,7 +13,8 @@ urlpatterns = [
# Accounts URLs # Accounts URLs
path('login/', allauth_views.LoginView.as_view(template_name='account/login.html'), name='account_login'), path('login/', allauth_views.LoginView.as_view(template_name='account/login.html'), name='account_login'),
path('logout/', allauth_views.LogoutView.as_view(template_name='account/logout.html'), name='account_logout'), path('logout/', allauth_views.LogoutView.as_view(template_name='account/logout.html'), name='account_logout'),
path('signup/', allauth_views.SignupView.as_view(template_name='account/signup.html'), name='account_signup'), # path('signup/', allauth_views.SignupView.as_view(template_name='account/signup.html'), name='account_signup'),
path('signup/', views.SignupView, name='account_signup'),
path('password/change/', path('password/change/',
allauth_views.PasswordChangeView.as_view(template_name='account/password_change.html'), allauth_views.PasswordChangeView.as_view(template_name='account/password_change.html'),
name='account_change_password'), name='account_change_password'),

View File

@ -33,7 +33,7 @@ from django.forms import ChoiceField, ModelForm, RadioSelect
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.contrib import messages from django.contrib import messages
from django.db.models import Sum, F, Count from django.db.models import Sum, F, Count
from django.db import transaction
from inventory.mixins import AddDealerInstanceMixin from inventory.mixins import AddDealerInstanceMixin
from .services import elm, decodevin, get_make, get_model, normalize_name from .services import elm, decodevin, get_make, get_model, normalize_name
@ -53,8 +53,7 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from .utils import get_calculations from .utils import get_calculations
from django.contrib.auth.models import User
User = get_user_model()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@ -95,6 +94,51 @@ def switch_language(request):
logger.warning(f"Invalid language code: {language}") logger.warning(f"Invalid language code: {language}")
return redirect("/") return redirect("/")
def SignupView(request):
if request.method == "POST":
data = json.loads(request.body)
wf1 = data.get("wizardValidationForm1")
wf2 = data.get("wizardValidationForm2")
wf3 = data.get("wizardValidationForm3")
name = wf1.get("name")
arabic_name = wf1.get("arabic_name")
email = wf1.get("email")
phone = wf2.get("phone_number")
crn = wf2.get("crn")
vrn = wf2.get("vrn")
address = wf2.get("address")
password = wf3.get("password")
password_confirm = wf3.get("confirm_password")
if password != password_confirm:
return JsonResponse({"error": "Passwords do not match."}, status=400)
try:
with transaction.atomic():
user = User.objects.create(username=name, email=email)
user.set_password(password)
user.save()
models.Dealer.objects.create_or_update(
user=user,
name=name,
arabic_name=arabic_name,
crn=crn,
vrn=vrn,
email=email,
phone_number=phone,
address=address,
dealer_type="Owner",
)
print("User created successfully.")
return JsonResponse({"message": "User created successfully."}, status=200)
except Exception as e:
print("Error creating user:", e)
return JsonResponse({"error": str(e)}, status=400)
form1 = forms.WizardForm1()
form2 = forms.WizardForm2()
form3 = forms.WizardForm3()
return render(request, "account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3})
class HomeView(LoginRequiredMixin, TemplateView): class HomeView(LoginRequiredMixin, TemplateView):
template_name = "dashboards/accounting.html" template_name = "dashboards/accounting.html"
@ -133,7 +177,7 @@ class HomeView(LoginRequiredMixin, TemplateView):
class WelcomeView(TemplateView): class WelcomeView(TemplateView):
template_name = "default.html" template_name = "index.html"
class CarCreateView(LoginRequiredMixin, CreateView): class CarCreateView(LoginRequiredMixin, CreateView):

View File

@ -85,6 +85,7 @@
if (!!JSON.parse(localStorage.getItem('phoenixIsNavbarVerticalCollapsed'))) { if (!!JSON.parse(localStorage.getItem('phoenixIsNavbarVerticalCollapsed'))) {
document.documentElement.classList.add('navbar-vertical-collapsed'); document.documentElement.classList.add('navbar-vertical-collapsed');
} }
if (localStorage.getItem('phoenixTheme') === 'dark') { if (localStorage.getItem('phoenixTheme') === 'dark') {
document.documentElement.setAttribute('data-bs-theme', 'dark'); document.documentElement.setAttribute('data-bs-theme', 'dark');
@ -102,7 +103,7 @@
if (localStorage.getItem('phoenixNavbarPosition') === 'combo') { if (localStorage.getItem('phoenixNavbarPosition') === 'combo') {
document.documentElement.setAttribute('data-navigation-type', 'combo'); document.documentElement.setAttribute('data-navigation-type', 'combo');
} }
var config = { var config = {
config: CONFIG, config: CONFIG,
reset: resetConfig, reset: resetConfig,

View File

@ -1652,6 +1652,7 @@
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
const createBoardInit = () => { const createBoardInit = () => {
const { getData } = window.phoenix.utils; const { getData } = window.phoenix.utils;
const submit_btn = document.querySelector('#submit_btn');
const selectors = { const selectors = {
CREATE_BOARD: '[data-create-board]', CREATE_BOARD: '[data-create-board]',
TOGGLE_BUTTON_EL: '[data-wizard-step]', TOGGLE_BUTTON_EL: '[data-wizard-step]',
@ -1727,6 +1728,8 @@
} }
}; };
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Detector */ /* Detector */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View File

@ -0,0 +1,65 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n %}
{% block content %}
<div class="card theme-wizard mb-5" data-theme-wizard="data-theme-wizard">
<div class="card-header bg-body-highlight pt-3 pb-2 border-bottom-0">
<ul class="nav justify-content-between nav-wizard nav-wizard-success" role="tablist">
<li class="nav-item" role="presentation"><a class="nav-link active fw-semibold" href="#bootstrap-wizard-validation-tab1" data-bs-toggle="tab" data-wizard-step="1" aria-selected="true" role="tab">
<div class="text-center d-inline-block"><span class="nav-item-circle-parent"><span class="nav-item-circle"><svg class="svg-inline--fa fa-lock" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="lock" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg=""><path fill="currentColor" d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"></path></svg><!-- <span class="fas fa-lock"></span> Font Awesome fontawesome.com --></span></span><span class="d-none d-md-block mt-1 fs-9">Account</span></div>
</a></li>
<li class="nav-item" role="presentation"><a class="nav-link fw-semibold" href="#bootstrap-wizard-validation-tab2" data-bs-toggle="tab" data-wizard-step="2" aria-selected="false" tabindex="-1" role="tab">
<div class="text-center d-inline-block"><span class="nav-item-circle-parent"><span class="nav-item-circle"><svg class="svg-inline--fa fa-user" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="user" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg=""><path fill="currentColor" d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"></path></svg><!-- <span class="fas fa-user"></span> Font Awesome fontawesome.com --></span></span><span class="d-none d-md-block mt-1 fs-9">Personal</span></div>
</a></li>
<li class="nav-item" role="presentation"><a class="nav-link fw-semibold" href="#bootstrap-wizard-validation-tab3" data-bs-toggle="tab" data-wizard-step="3" aria-selected="false" tabindex="-1" role="tab">
<div class="text-center d-inline-block"><span class="nav-item-circle-parent"><span class="nav-item-circle"><svg class="svg-inline--fa fa-file-lines" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-lines" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" data-fa-i2svg=""><path fill="currentColor" d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zM112 256H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"></path></svg><!-- <span class="fas fa-file-alt"></span> Font Awesome fontawesome.com --></span></span><span class="d-none d-md-block mt-1 fs-9">Password</span></div>
</a></li>
<li class="nav-item" role="presentation"><a class="nav-link fw-semibold" href="#bootstrap-wizard-validation-tab4" data-bs-toggle="tab" data-wizard-step="4" aria-selected="false" tabindex="-1" role="tab">
<div class="text-center d-inline-block"><span class="nav-item-circle-parent"><span class="nav-item-circle"><svg class="svg-inline--fa fa-check" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg=""><path fill="currentColor" d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"></path></svg><!-- <span class="fas fa-check"></span> Font Awesome fontawesome.com --></span></span><span class="d-none d-md-block mt-1 fs-9">Done</span></div>
</a></li>
</ul>
</div>
<div class="card-body pt-4 pb-0">
<div class="tab-content">
<div class="tab-pane active" role="tabpanel" aria-labelledby="bootstrap-wizard-validation-tab1" id="bootstrap-wizard-validation-tab1">
<form class="needs-validation" id="wizardValidationForm1" novalidate="novalidate" data-wizard-form="1">
{{form1|crispy}}
</form>
</div>
<div class="tab-pane" role="tabpanel" aria-labelledby="bootstrap-wizard-validation-tab2" id="bootstrap-wizard-validation-tab2">
<form class="needs-validation" id="wizardValidationForm2" novalidate="novalidate" data-wizard-form="2">
{{form2|crispy}}
</form>
</div>
<div class="tab-pane" role="tabpanel" aria-labelledby="bootstrap-wizard-validation-tab3" id="bootstrap-wizard-validation-tab3">
<form class="needs-validation" id="wizardValidationForm3" novalidate="novalidate" data-wizard-form="3">
{{form3|crispy}}
</form>
</div>
<div class="tab-pane" role="tabpanel" aria-labelledby="bootstrap-wizard-validation-tab4" id="bootstrap-wizard-validation-tab4">
<div class="row flex-center pb-8 pt-4 gx-3 gy-4">
<div class="col-12 col-sm-auto">
<div class="text-center text-sm-start"><img class="d-dark-none" src="../../assets/img/spot-illustrations/38.webp" alt="" width="220"><img class="d-light-none" src="../../assets/img/spot-illustrations/dark_38.webp" alt="" width="220"></div>
</div>
<div class="col-12 col-sm-auto">
<div class="text-center text-sm-start">
<h5 class="mb-3">You are all set!</h5>
<p class="text-body-emphasis fs-9">Now you can access your account<br>anytime anywhere</p><button class="btn btn-primary px-6" id='submit_btn'>Submit</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer border-top-0" data-wizard-footer="data-wizard-footer">
<div class="d-flex pager wizard list-inline mb-0">
<button class="d-none btn btn-link ps-0" type="button" data-wizard-prev-btn="data-wizard-prev-btn"><svg class="svg-inline--fa fa-chevron-left me-1" data-fa-transform="shrink-3" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-left" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" data-fa-i2svg="" style="transform-origin: 0.3125em 0.5em;"><g transform="translate(160 256)"><g transform="translate(0, 0) scale(0.8125, 0.8125) rotate(0 0 0)"><path fill="currentColor" d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z" transform="translate(-160 -256)"></path></g></g></svg><!-- <span class="fas fa-chevron-left me-1" data-fa-transform="shrink-3"></span> Font Awesome fontawesome.com -->Previous</button>
<div class="flex-1 text-end">
<button class="btn btn-primary px-6 px-sm-6" type="submit" data-wizard-next-btn="data-wizard-next-btn">Next<svg class="svg-inline--fa fa-chevron-right ms-1" data-fa-transform="shrink-3" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-right" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" data-fa-i2svg="" style="transform-origin: 0.3125em 0.5em;"><g transform="translate(160 256)"><g transform="translate(0, 0) scale(0.8125, 0.8125) rotate(0 0 0)"><path fill="currentColor" d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z" transform="translate(-160 -256)"></path></g></g></svg><!-- <span class="fas fa-chevron-right ms-1" data-fa-transform="shrink-3"> </span> Font Awesome fontawesome.com --></button>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -253,7 +253,7 @@
<button class="btn navbar-toggler navbar-toggler-humburger-icon hover-bg-transparent" type="button" data-bs-toggle="collapse" data-bs-target="#navbarVerticalCollapse" aria-controls="navbarVerticalCollapse" aria-expanded="false" aria-label="Toggle Navigation"><span class="navbar-toggle-icon"><span class="toggle-line"></span></span></button> <button class="btn navbar-toggler navbar-toggler-humburger-icon hover-bg-transparent" type="button" data-bs-toggle="collapse" data-bs-target="#navbarVerticalCollapse" aria-controls="navbarVerticalCollapse" aria-expanded="false" aria-label="Toggle Navigation"><span class="navbar-toggle-icon"><span class="toggle-line"></span></span></button>
<a class="navbar-brand me-1 me-sm-3" href="{% url 'landing_page' %}"> <a class="navbar-brand me-1 me-sm-3" href="{% url 'landing_page' %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
{% if data_bs_theme == 'dark' %} {% if data_bs_theme == 'dark' %}
<img src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" /> <img src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />
{% else %} {% else %}
@ -683,8 +683,27 @@
<!-- ===============================================--> <!-- ===============================================-->
<script src="
<script> https://cdn.jsdelivr.net/npm/sweetalert2@11.15.3/dist/sweetalert2.all.min.js
"></script>
<script>
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
function notify(tag,msg){
Toast.fire({
icon: tag,
titleText: msg
});
}
var navbarTopStyle = window.config.config.phoenixNavbarTopStyle; var navbarTopStyle = window.config.config.phoenixNavbarTopStyle;
var navbarTop = document.querySelector('.navbar-top'); var navbarTop = document.querySelector('.navbar-top');
if (navbarTopStyle === 'darker') { if (navbarTopStyle === 'darker') {
@ -695,10 +714,7 @@
var navbarVertical = document.querySelector('.navbar-vertical'); var navbarVertical = document.querySelector('.navbar-vertical');
if (navbarVertical && navbarVerticalStyle === 'darker') { if (navbarVertical && navbarVerticalStyle === 'darker') {
navbarVertical.setAttribute('data-navbar-appearance', 'darker'); navbarVertical.setAttribute('data-navbar-appearance', 'darker');
} }
</script>
<script>
function save_as_pdf(){ function save_as_pdf(){
const quotationHtml = document.getElementById('quotation-html').outerHTML; const quotationHtml = document.getElementById('quotation-html').outerHTML;
const printWindow = window.open('', '', 'height=500,width=800'); const printWindow = window.open('', '', 'height=500,width=800');
@ -707,6 +723,85 @@
printWindow.print(); printWindow.print();
printWindow.close(); printWindow.close();
} }
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
let submit_btn = document.getElementById('submit_btn');
const csrfToken = getCookie('csrftoken');
submit_btn.addEventListener('click', async () => {
const allFormData = getAllFormData();
console.log(allFormData);
try {
showLoading();
const response = await fetch('http://10.10.1.120:8888/en/signup/', {
method: 'POST',
headers: {
'X-CSRFToken': csrfToken,
'Content-Type': 'application/json',
},
body: JSON.stringify(allFormData),
});
hideLoading();
const data = await response.json();
if (response.ok) {
notify("success","Account created successfully");
} else {
notify("error",data.error);
}
} catch (error) {
notify("error",error);
}
});
function getAllFormData() {
const forms = document.querySelectorAll('form');
const formData = {};
forms.forEach((form, index) => {
const formId = form.id || `form${index + 1}`;
formData[formId] = {};
const formElements = form.elements;
for (let element of formElements) {
if (element.name) {
formData[formId][element.name] = element.value;
}
}
});
return formData;
}
function showLoading() {
Swal.fire({
title: "{% trans 'Please Wait' %}",
text: "{% trans 'Loading' %}...",
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
}
});
}
function hideLoading() {
Swal.close();
}
</script> </script>
<!-- ===============================================--> <!-- ===============================================-->

View File

@ -394,21 +394,6 @@ document.addEventListener("DOMContentLoaded", function() {
codeReader = new ZXing.BrowserMultiFormatReader(); codeReader = new ZXing.BrowserMultiFormatReader();
let currentStream = null; let currentStream = null;
function showLoading() {
Swal.fire({
title: "{% trans 'Please Wait' %}",
text: "{% trans 'Loading' %}...",
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
}
});
}
function hideLoading() {
Swal.close();
}
function closeModal(){ function closeModal(){
stopScanner(); stopScanner();
try { try {

View File

@ -23,7 +23,7 @@
<div class="overlay position-absolute top-0 start-0 w-100 h-100 bg-dark bg-opacity-50 d-flex flex-column justify-content-center align-items-center"> <div class="overlay position-absolute top-0 start-0 w-100 h-100 bg-dark bg-opacity-50 d-flex flex-column justify-content-center align-items-center">
<h1 class="display-4 fw-bold">{{ _("Welcome to ") }}{{ _('HAIKAL') }}</h1> <h1 class="display-4 fw-bold">{{ _("Welcome to ") }}{{ _('HAIKAL') }}</h1>
<p class="lead">{{ _("Discover a seamless way to manage your cars, reservations, and inventory like never before!") }}</p> <p class="lead">{{ _("Discover a seamless way to manage your cars, reservations, and inventory like never before!") }}</p>
<a href="{% url 'signup' %}" class="btn btn-primary btn-lg mt-3">{{ _("Get Started") }}</a> <a href="{% url 'account_signup' %}" class="btn btn-primary btn-lg mt-3">{{ _("Get Started") }}</a>
</div> </div>
</div> </div>
@ -58,7 +58,7 @@
<!-- Call-to-Action Section --> <!-- Call-to-Action Section -->
<div class="bg-light py-5 text-center"> <div class="bg-light py-5 text-center">
<h3>{{ _("Ready to take control of your inventory?") }}</h3> <h3>{{ _("Ready to take control of your inventory?") }}</h3>
<a href="{% url 'signup' %}" class="btn btn-success btn-lg mt-3">{{ _("Join Us Today") }}</a> <a href="{% url 'account_signup' %}" class="btn btn-success btn-lg mt-3">{{ _("Join Us Today") }}</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}