update
This commit is contained in:
commit
a24e5bc82b
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 10:09
|
||||
# Generated by Django 4.2.17 on 2024-12-26 10:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 10:09
|
||||
# Generated by Django 4.2.17 on 2024-12-26 10:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from django.core.validators import RegexValidator
|
||||
from django import forms
|
||||
from .mixins import AddClassMixin
|
||||
from django.forms.models import inlineformset_factory
|
||||
@ -22,7 +24,7 @@ from .models import (
|
||||
AdditionalServices
|
||||
|
||||
)
|
||||
from django.forms import ModelMultipleChoiceField
|
||||
from django.forms import ModelMultipleChoiceField, ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import django_tables2 as tables
|
||||
from django.forms import formset_factory
|
||||
@ -48,7 +50,6 @@ class DealerForm(forms.ModelForm):
|
||||
model = Dealer
|
||||
fields = ['name', 'arabic_name', 'crn', 'vrn', 'phone_number', 'address', 'logo']
|
||||
|
||||
|
||||
# Customer Form
|
||||
class CustomerForm(forms.ModelForm, AddClassMixin):
|
||||
class Meta:
|
||||
@ -257,3 +258,148 @@ class CarSelectionTable(tables.Table):
|
||||
model = Car
|
||||
fields = ['vin', 'year', 'id_car_make', 'id_car_model']
|
||||
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.")
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 10:09
|
||||
# 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 django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import inventory.mixins
|
||||
import phonenumber_field.modelfields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -13,8 +13,8 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -66,6 +66,90 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
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(
|
||||
name='ExteriorColors',
|
||||
fields=[
|
||||
@ -94,6 +178,25 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||
),
|
||||
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='Payment',
|
||||
fields=[
|
||||
@ -108,6 +211,30 @@ class Migration(migrations.Migration):
|
||||
'verbose_name_plural': 'payments',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SaleQuotation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quotation_number', models.CharField(max_length=10, unique=True)),
|
||||
('amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount')),
|
||||
('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(
|
||||
name='Subscription',
|
||||
fields=[
|
||||
@ -130,92 +257,111 @@ class Migration(migrations.Migration):
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CarFinance',
|
||||
name='Vendor',
|
||||
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')),
|
||||
('crn', models.CharField(max_length=10, unique=True, verbose_name='Commercial Registration Number')),
|
||||
('vrn', models.CharField(max_length=15, unique=True, verbose_name='VAT Registration Number')),
|
||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||
('name', models.CharField(max_length=255, verbose_name='English Name')),
|
||||
('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')),
|
||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
||||
('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')),
|
||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Car Financial Details',
|
||||
'verbose_name_plural': 'Car Financial Details',
|
||||
},
|
||||
),
|
||||
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',
|
||||
'verbose_name': 'Vendor',
|
||||
'verbose_name_plural': 'Vendors',
|
||||
},
|
||||
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',
|
||||
name='SubscriptionUser',
|
||||
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')),
|
||||
('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '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)),
|
||||
('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.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'),
|
||||
model_name='subscription',
|
||||
name='users',
|
||||
field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CarSpecification',
|
||||
name='SalesOrder',
|
||||
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')),
|
||||
('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': 'Specification',
|
||||
'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=[
|
||||
@ -245,66 +391,20 @@ class Migration(migrations.Migration):
|
||||
'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',
|
||||
name='CarRegistration',
|
||||
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')),
|
||||
('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': '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(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(
|
||||
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')),
|
||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Customer',
|
||||
'verbose_name_plural': 'Customers',
|
||||
'verbose_name': 'Registration',
|
||||
'verbose_name_plural': 'Registrations',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@ -323,152 +423,56 @@ class Migration(migrations.Migration):
|
||||
'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='additionalservices',
|
||||
name='dealer',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'),
|
||||
),
|
||||
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='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.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='SaleQuotation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quotation_number', models.CharField(max_length=10, unique=True)),
|
||||
('amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount')),
|
||||
('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')),
|
||||
],
|
||||
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='payment',
|
||||
name='quotation',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'),
|
||||
),
|
||||
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='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)),
|
||||
],
|
||||
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='subscription',
|
||||
name='users',
|
||||
field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL),
|
||||
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='Vendor',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('crn', models.CharField(max_length=10, unique=True, verbose_name='Commercial Registration Number')),
|
||||
('vrn', models.CharField(max_length=15, unique=True, verbose_name='VAT Registration Number')),
|
||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||
('name', models.CharField(max_length=255, verbose_name='English Name')),
|
||||
('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')),
|
||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
||||
('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')),
|
||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Vendor',
|
||||
'verbose_name_plural': 'Vendors',
|
||||
},
|
||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||
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(
|
||||
model_name='car',
|
||||
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(
|
||||
name='CarReservation',
|
||||
fields=[
|
||||
|
||||
21
inventory/migrations/0002_alter_dealer_user.py
Normal file
21
inventory/migrations/0002_alter_dealer_user.py
Normal 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),
|
||||
),
|
||||
]
|
||||
18
inventory/migrations/0003_alter_dealer_email.py
Normal file
18
inventory/migrations/0003_alter_dealer_email.py
Normal 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'),
|
||||
),
|
||||
]
|
||||
@ -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'),
|
||||
),
|
||||
]
|
||||
21
inventory/migrations/0005_alter_dealer_user.py
Normal file
21
inventory/migrations/0005_alter_dealer_user.py
Normal 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),
|
||||
),
|
||||
]
|
||||
@ -504,7 +504,7 @@ class Dealer(models.Model, LocalizedNameMixin):
|
||||
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"))
|
||||
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(
|
||||
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)
|
||||
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(
|
||||
"self",
|
||||
on_delete=models.SET_NULL,
|
||||
@ -529,6 +529,7 @@ class Dealer(models.Model, LocalizedNameMixin):
|
||||
default=DEALER_TYPES.Owner,
|
||||
)
|
||||
|
||||
|
||||
@property
|
||||
def get_active_plan(self):
|
||||
try:
|
||||
|
||||
@ -25,23 +25,25 @@ User = get_user_model()
|
||||
# if user:
|
||||
# user.delete()
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_dealer(instance, created, *args, **kwargs):
|
||||
if created:
|
||||
models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email)
|
||||
# @receiver(post_save, sender=User)
|
||||
# def create_dealer(instance, created, *args, **kwargs):
|
||||
# if created:
|
||||
# if not instance.dealer:
|
||||
|
||||
# models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email)
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_user_account(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
if instance.dealer_type != "Owner":
|
||||
user = User.objects.create_user(
|
||||
username=instance.name,
|
||||
email=instance.email,
|
||||
)
|
||||
user.set_password("Tenhal@123")
|
||||
user.save()
|
||||
instance.user = user
|
||||
instance.save()
|
||||
# @receiver(post_save, sender=models.Dealer)
|
||||
# def create_user_account(sender, instance, created, **kwargs):
|
||||
# if created:
|
||||
# if instance.dealer_type != "Owner":
|
||||
# user = User.objects.create_user(
|
||||
# username=instance.name,
|
||||
# email=instance.email,
|
||||
# )
|
||||
# user.set_password("Tenhal@123")
|
||||
# user.save()
|
||||
# instance.user = user
|
||||
# instance.save()
|
||||
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_car_location(sender, instance, created, **kwargs):
|
||||
@ -81,108 +83,108 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
|
||||
|
||||
|
||||
# Create Entity
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
root_dealer = instance.get_root_dealer
|
||||
if not root_dealer.entity:
|
||||
entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}"
|
||||
entity = EntityModel.create_entity(
|
||||
name=entity_name,
|
||||
admin=root_dealer.user,
|
||||
use_accrual_method=False,
|
||||
fy_start_month=1,
|
||||
)
|
||||
# @receiver(post_save, sender=models.Dealer)
|
||||
# def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
# if created:
|
||||
# root_dealer = instance.get_root_dealer
|
||||
# if not root_dealer.entity:
|
||||
# entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}"
|
||||
# entity = EntityModel.create_entity(
|
||||
# name=entity_name,
|
||||
# admin=root_dealer.user,
|
||||
# use_accrual_method=False,
|
||||
# fy_start_month=1,
|
||||
# )
|
||||
|
||||
if entity:
|
||||
instance.entity = entity
|
||||
instance.save()
|
||||
coa = entity.create_chart_of_accounts(
|
||||
assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
|
||||
)
|
||||
if coa:
|
||||
# entity.populate_default_coa(activate_accounts=True, coa_model=coa)
|
||||
print(f"Ledger entity created for Dealer: {instance.name}")
|
||||
# if entity:
|
||||
# instance.entity = entity
|
||||
# instance.save()
|
||||
# coa = entity.create_chart_of_accounts(
|
||||
# assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
|
||||
# )
|
||||
# if coa:
|
||||
# # entity.populate_default_coa(activate_accounts=True, coa_model=coa)
|
||||
# print(f"Ledger entity created for Dealer: {instance.name}")
|
||||
|
||||
# Create Cash Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="1010",
|
||||
role=roles.ASSET_CA_CASH,
|
||||
name=_("Cash"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Cash Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="1010",
|
||||
# role=roles.ASSET_CA_CASH,
|
||||
# name=_("Cash"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Accounts Receivable Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="1020",
|
||||
role=roles.ASSET_CA_RECEIVABLES,
|
||||
name=_("Accounts Receivable"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Accounts Receivable Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="1020",
|
||||
# role=roles.ASSET_CA_RECEIVABLES,
|
||||
# name=_("Accounts Receivable"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Inventory Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="1030",
|
||||
role=roles.ASSET_CA_INVENTORY,
|
||||
name=_("Inventory"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Inventory Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="1030",
|
||||
# role=roles.ASSET_CA_INVENTORY,
|
||||
# name=_("Inventory"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Accounts Payable Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="2010",
|
||||
role=roles.LIABILITY_CL_ACC_PAYABLE,
|
||||
name=_("Accounts Payable"),
|
||||
balance_type="credit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Accounts Payable Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="2010",
|
||||
# role=roles.LIABILITY_CL_ACC_PAYABLE,
|
||||
# name=_("Accounts Payable"),
|
||||
# balance_type="credit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Sales Revenue Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="4010",
|
||||
role=roles.INCOME_OPERATIONAL,
|
||||
name=_("Sales Revenue"),
|
||||
balance_type="credit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Sales Revenue Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="4010",
|
||||
# role=roles.INCOME_OPERATIONAL,
|
||||
# name=_("Sales Revenue"),
|
||||
# balance_type="credit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Cost of Goods Sold Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="5010",
|
||||
role=roles.COGS,
|
||||
name=_("Cost of Goods Sold"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Cost of Goods Sold Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="5010",
|
||||
# role=roles.COGS,
|
||||
# name=_("Cost of Goods Sold"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Rent Expense Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="6010",
|
||||
role=roles.EXPENSE_OPERATIONAL,
|
||||
name=_("Rent Expense"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Rent Expense Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="6010",
|
||||
# role=roles.EXPENSE_OPERATIONAL,
|
||||
# name=_("Rent Expense"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# Create Utilities Expense Account
|
||||
entity.create_account(
|
||||
coa_model=coa,
|
||||
code="6020",
|
||||
role=roles.EXPENSE_OPERATIONAL,
|
||||
name=_("Utilities Expense"),
|
||||
balance_type="debit",
|
||||
active=True,
|
||||
)
|
||||
# # Create Utilities Expense Account
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code="6020",
|
||||
# role=roles.EXPENSE_OPERATIONAL,
|
||||
# name=_("Utilities Expense"),
|
||||
# balance_type="debit",
|
||||
# active=True,
|
||||
# )
|
||||
|
||||
# uom_name = _("Unit")
|
||||
# unit_abbr = _("U")
|
||||
|
||||
@ -13,7 +13,8 @@ urlpatterns = [
|
||||
# Accounts URLs
|
||||
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('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/',
|
||||
allauth_views.PasswordChangeView.as_view(template_name='account/password_change.html'),
|
||||
name='account_change_password'),
|
||||
|
||||
@ -33,7 +33,7 @@ from django.forms import ChoiceField, ModelForm, RadioSelect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.contrib import messages
|
||||
from django.db.models import Sum, F, Count
|
||||
|
||||
from django.db import transaction
|
||||
from inventory.mixins import AddDealerInstanceMixin
|
||||
|
||||
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 import get_user_model
|
||||
from .utils import get_calculations
|
||||
|
||||
User = get_user_model()
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@ -95,6 +94,51 @@ def switch_language(request):
|
||||
logger.warning(f"Invalid language code: {language}")
|
||||
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):
|
||||
template_name = "dashboards/accounting.html"
|
||||
|
||||
@ -85,6 +85,7 @@
|
||||
if (!!JSON.parse(localStorage.getItem('phoenixIsNavbarVerticalCollapsed'))) {
|
||||
document.documentElement.classList.add('navbar-vertical-collapsed');
|
||||
}
|
||||
|
||||
|
||||
if (localStorage.getItem('phoenixTheme') === 'dark') {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark');
|
||||
@ -102,7 +103,7 @@
|
||||
if (localStorage.getItem('phoenixNavbarPosition') === 'combo') {
|
||||
document.documentElement.setAttribute('data-navigation-type', 'combo');
|
||||
}
|
||||
|
||||
|
||||
var config = {
|
||||
config: CONFIG,
|
||||
reset: resetConfig,
|
||||
|
||||
@ -1652,6 +1652,7 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
const createBoardInit = () => {
|
||||
const { getData } = window.phoenix.utils;
|
||||
const submit_btn = document.querySelector('#submit_btn');
|
||||
const selectors = {
|
||||
CREATE_BOARD: '[data-create-board]',
|
||||
TOGGLE_BUTTON_EL: '[data-wizard-step]',
|
||||
@ -1727,6 +1728,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Detector */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
65
templates/account/signup-wizard.html
Normal file
65
templates/account/signup-wizard.html
Normal 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 %}
|
||||
@ -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>
|
||||
<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' %}
|
||||
<img src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />
|
||||
{% else %}
|
||||
@ -683,8 +683,27 @@
|
||||
<!-- ===============================================-->
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
<script src="
|
||||
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 navbarTop = document.querySelector('.navbar-top');
|
||||
if (navbarTopStyle === 'darker') {
|
||||
@ -695,10 +714,7 @@
|
||||
var navbarVertical = document.querySelector('.navbar-vertical');
|
||||
if (navbarVertical && navbarVerticalStyle === 'darker') {
|
||||
navbarVertical.setAttribute('data-navbar-appearance', 'darker');
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
|
||||
}
|
||||
function save_as_pdf(){
|
||||
const quotationHtml = document.getElementById('quotation-html').outerHTML;
|
||||
const printWindow = window.open('', '', 'height=500,width=800');
|
||||
@ -707,6 +723,85 @@
|
||||
printWindow.print();
|
||||
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>
|
||||
|
||||
<!-- ===============================================-->
|
||||
|
||||
@ -394,21 +394,6 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
codeReader = new ZXing.BrowserMultiFormatReader();
|
||||
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(){
|
||||
stopScanner();
|
||||
try {
|
||||
|
||||
@ -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">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<!-- Call-to-Action Section -->
|
||||
<div class="bg-light py-5 text-center">
|
||||
<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>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user