estimate and bank accounts
This commit is contained in:
commit
6ad4350183
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,7 +4,7 @@
|
||||
*.pyc
|
||||
__pycache__
|
||||
**/*__pycache__
|
||||
db.sqlite3
|
||||
db.sqlite
|
||||
media
|
||||
car_inventory/settings.py
|
||||
# Backup files #
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.6 on 2024-08-21 11:31
|
||||
# Generated by Django 5.1.4 on 2024-12-26 16:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
# Generated by Django 4.2.17 on 2024-12-26 10:12
|
||||
# Generated by Django 5.1.4 on 2024-12-26 16:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Generated by Django 4.2.17 on 2024-12-26 10:12
|
||||
# Generated by Django 5.1.4 on 2024-12-26 16:17
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -44,7 +44,8 @@ class PaymentForm(forms.ModelForm):
|
||||
class UserForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Dealer
|
||||
fields = ['name', 'arabic_name', 'phone_number', 'address','dealer_type']
|
||||
fields = ['name', 'arabic_name', 'phone_number', 'address','dealer_type']
|
||||
|
||||
# Dealer Form
|
||||
class DealerForm(forms.ModelForm):
|
||||
class Meta:
|
||||
@ -176,7 +177,8 @@ class CarRegistrationForm(forms.ModelForm):
|
||||
class VendorForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Vendor
|
||||
exclude = ['dealer']
|
||||
fields = ['name', 'arabic_name', 'crn', 'vrn', 'email', 'phone_number', 'contact_person', 'address', 'logo' ]
|
||||
|
||||
|
||||
|
||||
class CarColorsForm(forms.ModelForm):
|
||||
@ -266,134 +268,125 @@ class CarSelectionTable(tables.Table):
|
||||
|
||||
|
||||
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.',
|
||||
'required': _('You must add an email.'),
|
||||
}
|
||||
)
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': _('Password'),
|
||||
'required': 'required',
|
||||
}),
|
||||
error_messages={
|
||||
'required': _('This field is required.'),
|
||||
}
|
||||
)
|
||||
confirm_password = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': _('Confirm Password'),
|
||||
'required': 'required',
|
||||
}),
|
||||
error_messages={
|
||||
'required': _('This field is required.'),
|
||||
}
|
||||
)
|
||||
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.',
|
||||
'required': _('You must accept the terms and privacy policy.'),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class WizardForm2(forms.Form):
|
||||
# Phone field with SA region validation
|
||||
name = forms.CharField(
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': _('English Name'),
|
||||
'required': 'required',
|
||||
}),
|
||||
error_messages={
|
||||
'required': _('Please enter an English Name.'),
|
||||
}
|
||||
)
|
||||
arabic_name = forms.CharField(
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': _('Arabic Name'),
|
||||
'required': 'required',
|
||||
}),
|
||||
error_messages={
|
||||
'required': _('Please enter an Arabic name.'),
|
||||
}
|
||||
)
|
||||
phone_number = PhoneNumberField(
|
||||
label="Phone",
|
||||
min_length=10,
|
||||
max_length=10,
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'Phone',
|
||||
'placeholder': _('Phone'),
|
||||
'required': 'required',
|
||||
}),
|
||||
region='SA', # Enforces SA region validation
|
||||
region='SA',
|
||||
error_messages={
|
||||
'required': 'This field is required.',
|
||||
'invalid': 'Phone number must be in the format +966XXXXXXXXX (Saudi Arabia).',
|
||||
'required': _('This field is required.'),
|
||||
'invalid': _('Phone number must be in the format 05xxxxxxxx'),
|
||||
}
|
||||
)
|
||||
|
||||
class WizardForm3(forms.Form):
|
||||
# CRN field with max length of 10
|
||||
crn = forms.CharField(
|
||||
label="CRN",
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'CRN',
|
||||
'placeholder': _("Commercial Registration Number"),
|
||||
'required': 'required',
|
||||
'maxlength': '10', # HTML maxlength attribute
|
||||
'maxlength': '10',
|
||||
}),
|
||||
max_length=10, # Django max_length validation
|
||||
max_length=10,
|
||||
error_messages={
|
||||
'required': 'This field is required.',
|
||||
'max_length': 'CRN must be at most 10 characters long.',
|
||||
'max_length': 'Commercial Registration Number must be 10 characters.',
|
||||
}
|
||||
)
|
||||
|
||||
# VRN field with max length of 15
|
||||
vrn = forms.CharField(
|
||||
label="VRN",
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'VRN',
|
||||
'placeholder': _("VAT Registration Number"),
|
||||
'required': 'required',
|
||||
'maxlength': '15', # HTML maxlength attribute
|
||||
'maxlength': '15',
|
||||
}),
|
||||
max_length=15, # Django max_length validation
|
||||
max_length=15, #
|
||||
error_messages={
|
||||
'required': 'This field is required.',
|
||||
'max_length': 'VRN must be at most 15 characters long.',
|
||||
'required': _('This field is required.'),
|
||||
'max_length': _('VAT Registration Number must be 15 characters.'),
|
||||
}
|
||||
)
|
||||
|
||||
address = forms.CharField(
|
||||
label="Address",
|
||||
widget=forms.Textarea(attrs={
|
||||
'class': 'form-control',
|
||||
'rows': '4',
|
||||
'rows': '3',
|
||||
'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.',
|
||||
'required': _('This field is required.'),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
# Generated by Django 4.2.17 on 2024-12-26 10:12
|
||||
# Generated by Django 5.1.4 on 2024-12-26 16:17
|
||||
|
||||
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
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -13,8 +13,8 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -66,90 +66,6 @@ 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=[
|
||||
@ -178,25 +94,6 @@ 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=[
|
||||
@ -211,30 +108,6 @@ 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=[
|
||||
@ -257,110 +130,91 @@ class Migration(migrations.Migration):
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Vendor',
|
||||
name='CarFinance',
|
||||
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')),
|
||||
('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': 'Vendor',
|
||||
'verbose_name_plural': 'Vendors',
|
||||
'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',
|
||||
},
|
||||
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),
|
||||
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='SalesOrder',
|
||||
name='CarRegistration',
|
||||
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')),
|
||||
('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': 'Representative',
|
||||
'verbose_name_plural': 'Representatives',
|
||||
'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.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'),
|
||||
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='CustomCard',
|
||||
name='CarSpecification',
|
||||
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')),
|
||||
('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': 'Custom Card',
|
||||
'verbose_name_plural': 'Custom Cards',
|
||||
'verbose_name': 'Specification',
|
||||
},
|
||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CarTrim',
|
||||
@ -391,20 +245,66 @@ 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='CarRegistration',
|
||||
name='CustomCard',
|
||||
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')),
|
||||
('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': 'Registration',
|
||||
'verbose_name_plural': 'Registrations',
|
||||
'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', unique=True, 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=100, 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',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@ -423,56 +323,152 @@ 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='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'),
|
||||
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')),
|
||||
],
|
||||
),
|
||||
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'),
|
||||
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)),
|
||||
],
|
||||
),
|
||||
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.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='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='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=[
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
# 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),
|
||||
),
|
||||
]
|
||||
17
inventory/migrations/0002_remove_dealer_email.py
Normal file
17
inventory/migrations/0002_remove_dealer_email.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 17:33
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='dealer',
|
||||
name='email',
|
||||
),
|
||||
]
|
||||
@ -1,18 +0,0 @@
|
||||
# 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'),
|
||||
),
|
||||
]
|
||||
19
inventory/migrations/0003_alter_dealer_phone_number.py
Normal file
19
inventory/migrations/0003_alter_dealer_phone_number.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 18:27
|
||||
|
||||
import phonenumber_field.modelfields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0002_remove_dealer_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='dealer',
|
||||
name='phone_number',
|
||||
field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number'),
|
||||
),
|
||||
]
|
||||
@ -1,25 +0,0 @@
|
||||
# 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'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,24 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 23:03
|
||||
|
||||
import inventory.models
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0003_alter_dealer_phone_number'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelManagers(
|
||||
name='dealer',
|
||||
managers=[
|
||||
('objects', inventory.models.DealerUserManager()),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='dealer',
|
||||
name='entity',
|
||||
),
|
||||
]
|
||||
@ -1,21 +0,0 @@
|
||||
# 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),
|
||||
),
|
||||
]
|
||||
20
inventory/migrations/0005_dealer_entity.py
Normal file
20
inventory/migrations/0005_dealer_entity.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-26 23:57
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||
('inventory', '0004_alter_dealer_managers_remove_dealer_entity'),
|
||||
]
|
||||
|
||||
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'),
|
||||
),
|
||||
]
|
||||
19
inventory/migrations/0006_vendor_email.py
Normal file
19
inventory/migrations/0006_vendor_email.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-29 11:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0005_dealer_entity'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='vendor',
|
||||
name='email',
|
||||
field=models.EmailField(default='email@email.com', max_length=255, verbose_name='Email Address'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
20
inventory/migrations/0007_vendor_created_at.py
Normal file
20
inventory/migrations/0007_vendor_created_at.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-29 13:04
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0006_vendor_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='vendor',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created At'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -33,11 +33,11 @@ class LocalizedNameMixin:
|
||||
return getattr(self, 'name', None)
|
||||
|
||||
|
||||
class AddDealerInstanceMixin:
|
||||
def form_valid(self, form):
|
||||
if form.is_valid():
|
||||
form.instance.dealer = self.request.user.dealer.get_root_dealer
|
||||
form.save()
|
||||
return super().form_valid(form)
|
||||
else:
|
||||
return form.errors
|
||||
# class AddDealerInstanceMixin:
|
||||
# def form_valid(self, form):
|
||||
# if form.is_valid():
|
||||
# form.instance.dealer = self.request.user.dealer.get_root_dealer
|
||||
# form.save()
|
||||
# return super().form_valid(form)
|
||||
# else:
|
||||
# return form.errors
|
||||
@ -3,7 +3,7 @@ from uuid import uuid4
|
||||
from django.conf import settings
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Sum, F, Count
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.models import User, UserManager
|
||||
from django.db.models.signals import pre_save, post_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -29,6 +29,15 @@ from django.db.models import FloatField
|
||||
from .mixins import LocalizedNameMixin
|
||||
from django_ledger.models import EntityModel
|
||||
|
||||
|
||||
class DealerUserManager(UserManager):
|
||||
def create_user_with_dealer(self, email, password, dealer_name, arabic_name, crn, vrn, address, **extra_fields):
|
||||
user = self.create_user(email=email, password=password, **extra_fields)
|
||||
Dealer.objects.create(user=user, name=dealer_name, )
|
||||
|
||||
return user
|
||||
|
||||
|
||||
UNIT_CHOICES = (
|
||||
("Kg", _("Kg")),
|
||||
("L", _("L")),
|
||||
@ -147,10 +156,10 @@ class CarStockTypeChoices(models.TextChoices):
|
||||
|
||||
|
||||
class DEALER_TYPES(models.TextChoices):
|
||||
Owner = "Owner", _("Owner")
|
||||
Inventory = "Inventory", _("Inventory")
|
||||
Accountent = "Accountent", _("Accountent")
|
||||
Sales = "sales", _("Sales")
|
||||
OWNER = "Owner", _("Owner")
|
||||
INVENTORY = "Inventory", _("Inventory")
|
||||
ACCOUNTANT = "Accountent", _("Accountent")
|
||||
SALES = "sales", _("Sales")
|
||||
|
||||
|
||||
class AdditionalServices(models.Model, LocalizedNameMixin):
|
||||
@ -482,12 +491,15 @@ class Subscription(models.Model):
|
||||
is_active = models.BooleanField(default=True)
|
||||
def __str__(self):
|
||||
return self.plan
|
||||
|
||||
|
||||
class SubscriptionUser(models.Model):
|
||||
subscription = models.ForeignKey(Subscription, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
def __str__(self):
|
||||
return f"{self.subscription} - {self.user}"
|
||||
|
||||
|
||||
|
||||
class SubscriptionPlan(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField()
|
||||
@ -495,41 +507,44 @@ class SubscriptionPlan(models.Model):
|
||||
max_users = models.IntegerField() # maximum number of users per account
|
||||
def __str__(self):
|
||||
return f"{self.name} - {self.price}"
|
||||
|
||||
|
||||
# Dealer Model
|
||||
class Dealer(models.Model, LocalizedNameMixin):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
|
||||
crn = models.CharField(
|
||||
max_length=10, verbose_name=_("Commercial Registration Number"),null=True,blank=True
|
||||
)
|
||||
vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"),null=True,blank=True)
|
||||
crn = models.CharField(max_length=10,
|
||||
verbose_name=_("Commercial 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"))
|
||||
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"),unique=True)
|
||||
address = models.CharField(
|
||||
max_length=200, blank=True, null=True, verbose_name=_("Address")
|
||||
)
|
||||
logo = models.ImageField(
|
||||
upload_to="logos/users", blank=True, null=True, verbose_name=_("Logo")
|
||||
)
|
||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
||||
address = models.CharField(max_length=200,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_("Address"))
|
||||
logo = models.ImageField(upload_to="logos/users",
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_("Logo"))
|
||||
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(verbose_name="Email", unique=True, max_length=100)
|
||||
parent_dealer = models.ForeignKey(
|
||||
"self",
|
||||
on_delete=models.SET_NULL,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_("Parent Dealer"),
|
||||
related_name="sub_dealers",
|
||||
)
|
||||
dealer_type = models.CharField(
|
||||
max_length=255,
|
||||
choices=DEALER_TYPES.choices,
|
||||
verbose_name=_("Dealer Type"),
|
||||
default=DEALER_TYPES.Owner,
|
||||
)
|
||||
parent_dealer = models.ForeignKey( "self",
|
||||
on_delete=models.SET_NULL,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_("Parent Dealer"),
|
||||
related_name="sub_dealers",)
|
||||
dealer_type = models.CharField(max_length=255,
|
||||
choices=DEALER_TYPES.choices,
|
||||
verbose_name=_("Dealer Type"),
|
||||
default=DEALER_TYPES.OWNER,)
|
||||
objects = DealerUserManager()
|
||||
|
||||
|
||||
@property
|
||||
def get_active_plan(self):
|
||||
try:
|
||||
@ -549,9 +564,6 @@ class Dealer(models.Model, LocalizedNameMixin):
|
||||
return subscription_plan
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Dealer")
|
||||
verbose_name_plural = _("Dealers")
|
||||
@ -564,21 +576,47 @@ class Dealer(models.Model, LocalizedNameMixin):
|
||||
|
||||
@property
|
||||
def get_sub_dealers(self):
|
||||
if self.dealer_type == "Owner":
|
||||
if self.dealer_type == "OWNER":
|
||||
return self.sub_dealers.all()
|
||||
return None
|
||||
|
||||
|
||||
@property
|
||||
def is_parent(self):
|
||||
return self.dealer_type == "Owner"
|
||||
return self.dealer_type == "OWNER"
|
||||
@property
|
||||
def get_root_dealer(self):
|
||||
return self.parent_dealer if self.parent_dealer else self
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_dealer(instance, created, *args, **kwargs):
|
||||
if created:
|
||||
Dealer.objects.create(user=instance)
|
||||
# @receiver(post_save, sender=User)
|
||||
# def create_dealer(instance, created, *args, **kwargs):
|
||||
# if created:
|
||||
# Dealer.objects.create(user=instance)
|
||||
|
||||
|
||||
# class STAFF_TYPES(models.TextChoices):
|
||||
# # Owner = "Owner", _("Owner")
|
||||
# MANAGER = "manager", _("Manager")
|
||||
# INVENTORY = "inventory", _("Inventory")
|
||||
# ACCOUNTANT = "accountant", _("Accountant")
|
||||
# SALES = "sales", _("Sales")
|
||||
# RECEPTIONIST = "receptionist", _("Receptionist")
|
||||
# TECHNICIAN = "technician", _("Technician")
|
||||
# DRIVER = "driver", _("Driver")
|
||||
#
|
||||
#
|
||||
# class Staff(models.Model, LocalizedNameMixin):
|
||||
# user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="staff")
|
||||
# dealer = models.ForeignKey(Dealer, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
# name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||
# arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||
# staff_type = models.CharField(choices=STAFF_TYPES.choices, max_length=255, verbose_name=_("Staff Type"))
|
||||
# created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
||||
# updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))
|
||||
#
|
||||
# class Meta:
|
||||
# verbose_name = _("Staff")
|
||||
# verbose_name_plural = _("Staff")
|
||||
# permissions = []
|
||||
|
||||
|
||||
# Vendor Model
|
||||
@ -594,12 +632,14 @@ class Vendor(models.Model, LocalizedNameMixin):
|
||||
name = models.CharField(max_length=255, verbose_name=_("English Name"))
|
||||
contact_person = models.CharField(max_length=100, verbose_name=_("Contact Person"))
|
||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
||||
email = models.EmailField(max_length=255, verbose_name=_("Email Address"))
|
||||
address = models.CharField(
|
||||
max_length=200, blank=True, null=True, verbose_name=_("Address")
|
||||
)
|
||||
logo = models.ImageField(
|
||||
upload_to="logos/vendors", blank=True, null=True, verbose_name=_("Logo")
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Vendor")
|
||||
@ -611,9 +651,9 @@ class Vendor(models.Model, LocalizedNameMixin):
|
||||
|
||||
# Customer Model
|
||||
class Customer(models.Model):
|
||||
dealer = models.ForeignKey(
|
||||
Dealer, on_delete=models.CASCADE, related_name="customers"
|
||||
)
|
||||
dealer = models.ForeignKey(Dealer,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="customers")
|
||||
first_name = models.CharField(max_length=50, verbose_name=_("First Name"))
|
||||
middle_name = models.CharField(
|
||||
max_length=50, blank=True, null=True, verbose_name=_("Middle Name")
|
||||
@ -644,8 +684,6 @@ class Customer(models.Model):
|
||||
return f"{self.first_name} {self.middle_name} {self.last_name}"
|
||||
|
||||
|
||||
|
||||
|
||||
class Organization(models.Model, LocalizedNameMixin):
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='organizations')
|
||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||
|
||||
@ -80,6 +80,9 @@ def elm(vin):
|
||||
|
||||
|
||||
def get_ledger_data(request):
|
||||
entity = EntityModel.objects.filter(name="Marwan2").first()
|
||||
data = entity.get_items_all()
|
||||
print(data)
|
||||
data = {}
|
||||
entity = EntityModel.objects.filter(name=request.user.dealer.name).first()
|
||||
data['bills'] = entity.get_bills()
|
||||
data['invoices'] = entity.get_invoices()
|
||||
data['income'] = entity.get_income_statement()
|
||||
return data
|
||||
@ -1,9 +1,5 @@
|
||||
from random import randint
|
||||
|
||||
from django.db.models.signals import post_save, post_delete, pre_delete, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
from django_ledger.models import EntityModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.auth import get_user_model
|
||||
from django_ledger.io import roles
|
||||
@ -24,14 +20,14 @@ User = get_user_model()
|
||||
# user = instance.user
|
||||
# if user:
|
||||
# user.delete()
|
||||
|
||||
#
|
||||
# @receiver(post_save, sender=User)
|
||||
# def create_dealer(instance, created, *args, **kwargs):
|
||||
# if created:
|
||||
# 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:
|
||||
@ -45,6 +41,7 @@ User = get_user_model()
|
||||
# instance.user = user
|
||||
# instance.save()
|
||||
|
||||
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_car_location(sender, instance, created, **kwargs):
|
||||
"""
|
||||
@ -83,114 +80,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 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")
|
||||
#
|
||||
# entity.create_uom(uom_name, unit_abbr)
|
||||
# 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 Vendor
|
||||
|
||||
Binary file not shown.
@ -3,13 +3,10 @@ from django import template
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
@register.filter(name='percentage')
|
||||
def percentage(value):
|
||||
try:
|
||||
value = float(value) * 100
|
||||
return f'{value:.0f}%'
|
||||
except (ValueError, TypeError):
|
||||
return value
|
||||
if value is not None:
|
||||
return '{0:,.2f}%'.format(value * 100)
|
||||
|
||||
|
||||
@register.filter
|
||||
|
||||
@ -11,10 +11,10 @@ urlpatterns = [
|
||||
path('welcome/', views.WelcomeView.as_view(), name='welcome'),
|
||||
|
||||
# Accounts URLs
|
||||
path('login/', allauth_views.LoginView.as_view(template_name='account/login.html'), name='account_login'),
|
||||
path('login/', views.Login.as_view(), 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/', views.SignupView, name='account_signup'),
|
||||
path('signup/', views.dealer_signup, name='account_signup'),
|
||||
path('password/change/',
|
||||
allauth_views.PasswordChangeView.as_view(template_name='account/password_change.html'),
|
||||
name='account_change_password'),
|
||||
@ -25,13 +25,13 @@ urlpatterns = [
|
||||
allauth_views.PasswordResetDoneView.as_view(template_name='account/password_reset_done.html'),
|
||||
name='account_password_reset_done'),
|
||||
path('login/code/', allauth_views.RequestLoginCodeView.as_view(template_name='account/request_login_code.html')),
|
||||
#Dashboards
|
||||
path('dashboards/accounting/', views.AccountingDashboard.as_view(), name='accounting'),
|
||||
|
||||
# Dealer URLs
|
||||
path('dealers/', views.DealerListView.as_view(), name='dealer_list'),
|
||||
path('dealers/<int:pk>/', views.DealerDetailView.as_view(), name='dealer_detail'),
|
||||
path('dealers/create/', views.DealerCreateView.as_view(), name='dealer_create'),
|
||||
path('dealers/<int:pk>/update/', views.DealerUpdateView.as_view(), name='dealer_update'),
|
||||
path('dealers/<int:pk>/delete/', views.DealerDeleteView.as_view(), name='dealer_delete'),
|
||||
# path('dealers/<int:pk>/delete/', views.DealerDeleteView.as_view(), name='dealer_delete'),
|
||||
|
||||
# Customer URLs
|
||||
path('customers/', views.CustomerListView.as_view(), name='customer_list'),
|
||||
|
||||
@ -9,12 +9,6 @@ import json
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
from django.shortcuts import HttpResponse
|
||||
from django.template.loader import render_to_string
|
||||
# from weasyprint import HTML
|
||||
# from weasyprint.fonts import FontConfiguration
|
||||
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from vin import VIN
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import JsonResponse
|
||||
@ -33,14 +27,11 @@ from django.views.generic import (
|
||||
from django.utils import timezone, translation
|
||||
from django.conf import settings
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
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
|
||||
from .services import (
|
||||
elm,
|
||||
decodevin,
|
||||
@ -50,12 +41,9 @@ from .services import (
|
||||
get_ledger_data,
|
||||
)
|
||||
from . import models, forms
|
||||
from django_tables2.export.views import ExportMixin
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
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
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
@ -98,64 +86,71 @@ def switch_language(request):
|
||||
logger.warning(f"Invalid language code: {language}")
|
||||
return redirect("/")
|
||||
|
||||
def SignupView(request):
|
||||
|
||||
def dealer_signup(request, *args, **kwargs):
|
||||
if request.method == "POST":
|
||||
data = json.loads(request.body)
|
||||
wf1 = data.get("wizardValidationForm1")
|
||||
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")
|
||||
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 = User.objects.create(email=email, password=password)
|
||||
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.")
|
||||
models.Dealer.objects.create(user=user,
|
||||
name=name,
|
||||
arabic_name=arabic_name,
|
||||
crn=crn,
|
||||
vrn=vrn,
|
||||
phone_number=phone,
|
||||
address=address,
|
||||
dealer_type="OWNER",)
|
||||
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 Login(views.LoginView):
|
||||
template_name = "account/login.html"
|
||||
redirect_authenticated_user = True
|
||||
|
||||
|
||||
class HomeView(TemplateView):
|
||||
template_name = "index.html"
|
||||
|
||||
|
||||
class AccountingDashboard(LoginRequiredMixin, TemplateView):
|
||||
template_name = "dashboards/accounting.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if (
|
||||
not any(hasattr(request.user, attr) for attr in ["dealer", "subdealer"])
|
||||
or not request.user.is_authenticated
|
||||
not any(hasattr(request.user, attr) for attr in ["dealer", "subdealer"])
|
||||
or not request.user.is_authenticated
|
||||
):
|
||||
messages.error(request, _("You are not associated with any dealer."))
|
||||
# messages.error(request, _("You are not associated with any dealer."))
|
||||
return redirect("welcome")
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
@ -181,7 +176,7 @@ class HomeView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
|
||||
class WelcomeView(TemplateView):
|
||||
template_name = "index.html"
|
||||
template_name = "welcome.html"
|
||||
|
||||
|
||||
class CarCreateView(LoginRequiredMixin, CreateView):
|
||||
@ -538,7 +533,7 @@ class CarLocationCreateView(CreateView):
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
|
||||
form.instance.owner = self.request.user.dealer
|
||||
form.instance.OWNER = self.request.user.dealer
|
||||
form.save()
|
||||
messages.success(self.request, "Car saved successfully.")
|
||||
return super().form_valid(form)
|
||||
@ -625,26 +620,12 @@ def manage_reservation(request, reservation_id):
|
||||
)
|
||||
|
||||
|
||||
class DealerListView(LoginRequiredMixin, ListView):
|
||||
model = models.Dealer
|
||||
template_name = "dealer_list.html"
|
||||
context_object_name = "dealers"
|
||||
|
||||
|
||||
class DealerDetailView(LoginRequiredMixin, DetailView):
|
||||
model = models.Dealer
|
||||
template_name = "dealers/dealer_detail.html"
|
||||
context_object_name = "dealer"
|
||||
|
||||
|
||||
class DealerCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||
model = models.Dealer
|
||||
form_class = forms.DealerForm
|
||||
template_name = "dealer_form.html"
|
||||
success_url = reverse_lazy("dealer_list")
|
||||
success_message = _("Dealer created successfully.")
|
||||
|
||||
|
||||
class DealerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||
model = models.Dealer
|
||||
form_class = forms.DealerForm
|
||||
@ -662,19 +643,12 @@ class DealerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||
return form
|
||||
|
||||
def get_form_class(self):
|
||||
if self.request.user.dealer.dealer_type == "Owner":
|
||||
if self.request.user.dealer.dealer_type == "OWNER":
|
||||
return forms.DealerForm
|
||||
else:
|
||||
return forms.UserForm
|
||||
|
||||
|
||||
class DealerDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||
model = models.Dealer
|
||||
template_name = "dealer_confirm_delete.html"
|
||||
success_url = reverse_lazy("dealer_list")
|
||||
success_message = _("Dealer deleted successfully.")
|
||||
|
||||
|
||||
class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
model = models.Customer
|
||||
home_label = _("customers")
|
||||
@ -714,7 +688,6 @@ class CustomerCreateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
CreateView,
|
||||
):
|
||||
model = models.Customer
|
||||
@ -725,11 +698,11 @@ class CustomerCreateView(
|
||||
success_message = _("Customer created successfully.")
|
||||
|
||||
|
||||
|
||||
class CustomerUpdateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
UpdateView,
|
||||
):
|
||||
model = models.Customer
|
||||
@ -766,7 +739,6 @@ class VendorCreateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
CreateView,
|
||||
):
|
||||
model = models.Vendor
|
||||
@ -776,12 +748,17 @@ class VendorCreateView(
|
||||
permission_required = ("inventory.add_vendor",)
|
||||
success_message = _("Vendor created successfully.")
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.dealer = self.request.user.dealer
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
|
||||
|
||||
class VendorUpdateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
UpdateView,
|
||||
):
|
||||
model = models.Vendor
|
||||
@ -1172,7 +1149,6 @@ class UserCreateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
CreateView,
|
||||
):
|
||||
model = models.Dealer
|
||||
@ -1185,7 +1161,7 @@ class UserCreateView(
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
form.fields["dealer_type"].choices = [
|
||||
t for t in form.fields["dealer_type"].choices if t[0] != "Owner"
|
||||
t for t in form.fields["dealer_type"].choices if t[0] != "OWNER"
|
||||
]
|
||||
return form
|
||||
|
||||
@ -1215,7 +1191,6 @@ class UserUpdateView(
|
||||
LoginRequiredMixin,
|
||||
PermissionRequiredMixin,
|
||||
SuccessMessageMixin,
|
||||
AddDealerInstanceMixin,
|
||||
UpdateView,
|
||||
):
|
||||
model = models.Dealer
|
||||
@ -1402,7 +1377,8 @@ def download_quotation_pdf(request, quotation_id):
|
||||
return response
|
||||
except models.SaleQuotation.DoesNotExist:
|
||||
return HttpResponse("Quotation not found", status=404)
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
def invoice_detail(request,pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
@ -1414,6 +1390,8 @@ def invoice_detail(request,pk):
|
||||
invoice = invoice_model.filter(customer=customer,date_draft=quotation.date_draft).first()
|
||||
|
||||
return redirect('quotation_detail', pk=pk)
|
||||
|
||||
|
||||
@login_required
|
||||
def payment_invoice(request,pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
@ -1455,7 +1433,7 @@ def payment_create(request, pk):
|
||||
insatnce = form.save()
|
||||
|
||||
dealer = request.user.dealer.get_root_dealer
|
||||
entity = dealer.entity
|
||||
entity = dealer.entity
|
||||
customer = entity.get_customers().filter(customer_name=quotation.customer.get_full_name).first()
|
||||
coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
1
static/css/sweetalert2.min.css
vendored
Normal file
1
static/css/sweetalert2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -22988,7 +22988,7 @@ input:-webkit-autofill {
|
||||
box-shadow: 0 0 0 30px var(--phoenix-emphasis-bg) inset;
|
||||
}
|
||||
|
||||
input::-webkit-contacts-auto-fill-button {
|
||||
input:-webkit-contacts-auto-fill-button {
|
||||
background-color: var(--phoenix-body-color);
|
||||
}
|
||||
|
||||
|
||||
BIN
static/images/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
Binary file not shown.
BIN
static/images/logos/.DS_Store
vendored
BIN
static/images/logos/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 10 KiB |
BIN
static/images/logos/users/appicon_m3vX9GA.png
Normal file
BIN
static/images/logos/users/appicon_m3vX9GA.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
static/images/logos/vendors/muhammad-yousef-naghi_EWMMpCo.png
vendored
Normal file
BIN
static/images/logos/vendors/muhammad-yousef-naghi_EWMMpCo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
BIN
static/images/spot-illustrations/haikal-profile-8.png
Normal file
BIN
static/images/spot-illustrations/haikal-profile-8.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
@ -112,7 +112,7 @@
|
||||
|
||||
return config;
|
||||
|
||||
}));
|
||||
|
||||
//# sourceMappingURL=config.js.map
|
||||
var phoenixIsRTL = window.config.config.phoenixIsRTL;
|
||||
if (phoenixIsRTL) {
|
||||
@ -127,3 +127,4 @@
|
||||
linkRTL.setAttribute('disabled', true);
|
||||
userLinkRTL.setAttribute('disabled', true);
|
||||
}
|
||||
}));
|
||||
File diff suppressed because one or more lines are too long
6
static/js/sweetalert2.all.min.js
vendored
Normal file
6
static/js/sweetalert2.all.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -754,7 +754,7 @@
|
||||
color:
|
||||
getItemFromStore('phoenixTheme') === 'dark'
|
||||
? getColor('primary')
|
||||
: getColor('primary-light')
|
||||
: getColor('primary')
|
||||
},
|
||||
data: profitData[0]
|
||||
},
|
||||
@ -772,7 +772,7 @@
|
||||
color:
|
||||
getItemFromStore('phoenixTheme') === 'dark'
|
||||
? getColor('success')
|
||||
: getColor('success-light')
|
||||
: getColor('success')
|
||||
},
|
||||
data: revenueData[0]
|
||||
},
|
||||
@ -788,7 +788,7 @@
|
||||
color:
|
||||
getItemFromStore('phoenixTheme') === 'dark'
|
||||
? getColor('info')
|
||||
: getColor('info-light')
|
||||
: getColor('info')
|
||||
},
|
||||
data: expansesData[0]
|
||||
}
|
||||
|
||||
45512
static/vendors/echarts/echarts.min.js
vendored
45512
static/vendors/echarts/echarts.min.js
vendored
File diff suppressed because one or more lines are too long
1752
static/vendors/feather-icons/feather.min.js
vendored
1752
static/vendors/feather-icons/feather.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,68 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US" dir="ltr" data-navigation-type="default" data-navbar-horizontal-shape="default">
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n static %}
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Document Title-->
|
||||
<!-- ===============================================-->
|
||||
<title>Phoenix</title>
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Favicons-->
|
||||
<!-- ===============================================-->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="../../../assets/img/favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="../../../assets/img/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="../../../assets/img/favicons/favicon-16x16.png">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="../../../assets/img/favicons/favicon.ico">
|
||||
<link rel="manifest" href="../../../assets/img/favicons/manifest.json">
|
||||
<meta name="msapplication-TileImage" content="../../../assets/img/favicons/mstile-150x150.png">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<script src="../../../vendors/simplebar/simplebar.min.js"></script>
|
||||
<script src="../../../assets/js/config.js"></script>
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Stylesheets-->
|
||||
<!-- ===============================================-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;400;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link href="../../../vendors/simplebar/simplebar.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
||||
<link href="../../../assets/css/theme-rtl.min.css" type="text/css" rel="stylesheet" id="style-rtl">
|
||||
<link href="../../../assets/css/theme.min.css" type="text/css" rel="stylesheet" id="style-default">
|
||||
<link href="../../../assets/css/user-rtl.min.css" type="text/css" rel="stylesheet" id="user-style-rtl">
|
||||
<link href="../../../assets/css/user.min.css" type="text/css" rel="stylesheet" id="user-style-default">
|
||||
<script>
|
||||
var phoenixIsRTL = window.config.config.phoenixIsRTL;
|
||||
if (phoenixIsRTL) {
|
||||
var linkDefault = document.getElementById('style-default');
|
||||
var userLinkDefault = document.getElementById('user-style-default');
|
||||
linkDefault.setAttribute('disabled', true);
|
||||
userLinkDefault.setAttribute('disabled', true);
|
||||
document.querySelector('html').setAttribute('dir', 'rtl');
|
||||
} else {
|
||||
var linkRTL = document.getElementById('style-rtl');
|
||||
var userLinkRTL = document.getElementById('user-style-rtl');
|
||||
linkRTL.setAttribute('disabled', true);
|
||||
userLinkRTL.setAttribute('disabled', true);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Main Content-->
|
||||
<!-- ===============================================-->
|
||||
<main class="main" id="top">
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row flex-center min-vh-100 py-5">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4"><a class="d-flex flex-center text-decoration-none mb-4" href="../../../index.html">
|
||||
@ -94,206 +33,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var navbarTopStyle = window.config.config.phoenixNavbarTopStyle;
|
||||
var navbarTop = document.querySelector('.navbar-top');
|
||||
if (navbarTopStyle === 'darker') {
|
||||
navbarTop.setAttribute('data-navbar-appearance', 'darker');
|
||||
}
|
||||
|
||||
var navbarVerticalStyle = window.config.config.phoenixNavbarVerticalStyle;
|
||||
var navbarVertical = document.querySelector('.navbar-vertical');
|
||||
if (navbarVertical && navbarVerticalStyle === 'darker') {
|
||||
navbarVertical.setAttribute('data-navbar-appearance', 'darker');
|
||||
}
|
||||
</script>
|
||||
<div class="support-chat-container">
|
||||
<div class="container-fluid support-chat">
|
||||
<div class="card bg-body-emphasis">
|
||||
<div class="card-header d-flex flex-between-center px-4 py-3 border-bottom border-translucent">
|
||||
<h5 class="mb-0 d-flex align-items-center gap-2">Demo widget<span class="fa-solid fa-circle text-success fs-11"></span></h5>
|
||||
<div class="btn-reveal-trigger">
|
||||
<button class="btn btn-link p-0 dropdown-toggle dropdown-caret-none transition-none d-flex" type="button" id="support-chat-dropdown" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h text-body"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2" aria-labelledby="support-chat-dropdown"><a class="dropdown-item" href="#!">Request a callback</a><a class="dropdown-item" href="#!">Search in chat</a><a class="dropdown-item" href="#!">Show history</a><a class="dropdown-item" href="#!">Report to Admin</a><a class="dropdown-item btn-support-chat" href="#!">Close Support</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body chat p-0">
|
||||
<div class="d-flex flex-column-reverse scrollbar h-100 p-3">
|
||||
<div class="text-end mt-6"><a class="mb-2 d-inline-flex align-items-center text-decoration-none text-body-emphasis bg-body-hover rounded-pill border border-primary py-2 ps-4 pe-3" href="#!">
|
||||
<p class="mb-0 fw-semibold fs-9">I need help with something</p><span class="fa-solid fa-paper-plane text-primary fs-9 ms-3"></span>
|
||||
</a><a class="mb-2 d-inline-flex align-items-center text-decoration-none text-body-emphasis bg-body-hover rounded-pill border border-primary py-2 ps-4 pe-3" href="#!">
|
||||
<p class="mb-0 fw-semibold fs-9">I can’t reorder a product I previously ordered</p><span class="fa-solid fa-paper-plane text-primary fs-9 ms-3"></span>
|
||||
</a><a class="mb-2 d-inline-flex align-items-center text-decoration-none text-body-emphasis bg-body-hover rounded-pill border border-primary py-2 ps-4 pe-3" href="#!">
|
||||
<p class="mb-0 fw-semibold fs-9">How do I place an order?</p><span class="fa-solid fa-paper-plane text-primary fs-9 ms-3"></span>
|
||||
</a><a class="false d-inline-flex align-items-center text-decoration-none text-body-emphasis bg-body-hover rounded-pill border border-primary py-2 ps-4 pe-3" href="#!">
|
||||
<p class="mb-0 fw-semibold fs-9">My payment method not working</p><span class="fa-solid fa-paper-plane text-primary fs-9 ms-3"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text-center mt-auto">
|
||||
<div class="avatar avatar-3xl status-online"><img class="rounded-circle border border-3 border-light-subtle" src="../../../assets/img/team/30.webp" alt="" /></div>
|
||||
<h5 class="mt-2 mb-3">Eric</h5>
|
||||
<p class="text-center text-body-emphasis mb-0">Ask us anything – we’ll get back to you here or by email within 24 hours.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center gap-2 border-top border-translucent ps-3 pe-4 py-3">
|
||||
<div class="d-flex align-items-center flex-1 gap-3 border border-translucent rounded-pill px-4">
|
||||
<input class="form-control outline-none border-0 flex-1 fs-9 px-0" type="text" placeholder="Write message" />
|
||||
<label class="btn btn-link d-flex p-0 text-body-quaternary fs-9 border-0" for="supportChatPhotos"><span class="fa-solid fa-image"></span></label>
|
||||
<input class="d-none" type="file" accept="image/*" id="supportChatPhotos" />
|
||||
<label class="btn btn-link d-flex p-0 text-body-quaternary fs-9 border-0" for="supportChatAttachment"> <span class="fa-solid fa-paperclip"></span></label>
|
||||
<input class="d-none" type="file" id="supportChatAttachment" />
|
||||
</div>
|
||||
<button class="btn p-0 border-0 send-btn"><span class="fa-solid fa-paper-plane fs-9"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-support-chat p-0 border border-translucent"><span class="fs-8 btn-text text-primary text-nowrap">Chat demo</span><span class="ping-icon-wrapper mt-n4 ms-n6 mt-sm-0 ms-sm-2 position-absolute position-sm-relative"><span class="ping-icon-bg"></span><span class="fa-solid fa-circle ping-icon"></span></span><span class="fa-solid fa-headset text-primary fs-8 d-sm-none"></span><span class="fa-solid fa-chevron-down text-primary fs-7"></span></button>
|
||||
</div>
|
||||
</main>
|
||||
<!-- ===============================================-->
|
||||
<!-- End of Main Content-->
|
||||
<!-- ===============================================-->
|
||||
|
||||
|
||||
<div class="offcanvas offcanvas-end settings-panel border-0" id="settings-offcanvas" tabindex="-1" aria-labelledby="settings-offcanvas">
|
||||
<div class="offcanvas-header align-items-start border-bottom flex-column border-translucent">
|
||||
<div class="pt-1 w-100 mb-6 d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h5 class="mb-2 me-2 lh-sm"><span class="fas fa-palette me-2 fs-8"></span>Theme Customizer</h5>
|
||||
<p class="mb-0 fs-9">Explore different styles according to your preferences</p>
|
||||
</div>
|
||||
<button class="btn p-1 fw-bolder" type="button" data-bs-dismiss="offcanvas" aria-label="Close"><span class="fas fa-times fs-8"> </span></button>
|
||||
</div>
|
||||
<button class="btn btn-phoenix-secondary w-100" data-theme-control="reset"><span class="fas fa-arrows-rotate me-2 fs-10"></span>Reset to default</button>
|
||||
</div>
|
||||
<div class="offcanvas-body scrollbar px-card" id="themeController">
|
||||
<div class="setting-panel-item mt-0">
|
||||
<h5 class="setting-panel-item-title">Color Scheme</h5>
|
||||
<div class="row gx-2">
|
||||
<div class="col-4">
|
||||
<input class="btn-check" id="themeSwitcherLight" name="theme-color" type="radio" value="light" data-theme-control="phoenixTheme" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="themeSwitcherLight"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype mb-0" src="../../../assets/img/generic/default-light.png" alt=""/></span><span class="label-text">Light</span></label>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input class="btn-check" id="themeSwitcherDark" name="theme-color" type="radio" value="dark" data-theme-control="phoenixTheme" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="themeSwitcherDark"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype mb-0" src="../../../assets/img/generic/default-dark.png" alt=""/></span><span class="label-text"> Dark</span></label>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input class="btn-check" id="themeSwitcherAuto" name="theme-color" type="radio" value="auto" data-theme-control="phoenixTheme" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="themeSwitcherAuto"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype mb-0" src="../../../assets/img/generic/auto.png" alt=""/></span><span class="label-text"> Auto</span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border border-translucent rounded-3 p-4 setting-panel-item bg-body-emphasis">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="setting-panel-item-title mb-1">RTL </h5>
|
||||
<div class="form-check form-switch mb-0">
|
||||
<input class="form-check-input ms-auto" type="checkbox" data-theme-control="phoenixIsRTL" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-0 text-body-tertiary">Change text direction</p>
|
||||
</div>
|
||||
<div class="border border-translucent rounded-3 p-4 setting-panel-item bg-body-emphasis">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="setting-panel-item-title mb-1">Support Chat </h5>
|
||||
<div class="form-check form-switch mb-0">
|
||||
<input class="form-check-input ms-auto" type="checkbox" data-theme-control="phoenixSupportChat" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-0 text-body-tertiary">Toggle support chat</p>
|
||||
</div>
|
||||
<div class="setting-panel-item">
|
||||
<h5 class="setting-panel-item-title">Navigation Type</h5>
|
||||
<div class="row gx-2">
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarPositionVertical" name="navigation-type" type="radio" value="vertical" data-theme-control="phoenixNavbarPosition" data-page-url="../../../documentation/layouts/vertical-navbar.html" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarPositionVertical"> <span class="rounded d-block"><img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/default-light.png" alt=""/><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/default-dark.png" alt=""/></span><span class="label-text">Vertical</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarPositionHorizontal" name="navigation-type" type="radio" value="horizontal" data-theme-control="phoenixNavbarPosition" data-page-url="../../../documentation/layouts/horizontal-navbar.html" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarPositionHorizontal"> <span class="rounded d-block"><img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/top-default.png" alt=""/><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/top-default-dark.png" alt=""/></span><span class="label-text"> Horizontal</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarPositionCombo" name="navigation-type" type="radio" value="combo" data-theme-control="phoenixNavbarPosition" disabled="disabled" data-page-url="../../../documentation/layouts/combo-navbar.html" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarPositionCombo"> <span class="rounded d-block"><img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/nav-combo-light.png" alt=""/><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/nav-combo-dark.png" alt=""/></span><span class="label-text"> Combo</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarPositionTopDouble" name="navigation-type" type="radio" value="dual-nav" data-theme-control="phoenixNavbarPosition" disabled="disabled" data-page-url="../../../documentation/layouts/dual-nav.html" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarPositionTopDouble"> <span class="rounded d-block"><img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/dual-light.png" alt=""/><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/dual-dark.png" alt=""/></span><span class="label-text"> Dual nav</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-warning-dark font-medium"> <span class="fa-solid fa-triangle-exclamation me-2 text-warning"></span>You can't update navigation type in this page</p>
|
||||
</div>
|
||||
<div class="setting-panel-item">
|
||||
<h5 class="setting-panel-item-title">Vertical Navbar Appearance</h5>
|
||||
<div class="row gx-2">
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbar-style-default" type="radio" name="config.name" value="default" data-theme-control="phoenixNavbarVerticalStyle" disabled="disabled" />
|
||||
<label class="btn d-block w-100 btn-navbar-style fs-9" for="navbar-style-default"> <img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/default-light.png" alt="" /><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/default-dark.png" alt="" /><span class="label-text d-dark-none"> Default</span><span class="label-text d-light-none">Default</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbar-style-dark" type="radio" name="config.name" value="darker" data-theme-control="phoenixNavbarVerticalStyle" disabled="disabled" />
|
||||
<label class="btn d-block w-100 btn-navbar-style fs-9" for="navbar-style-dark"> <img class="img-fluid img-prototype d-dark-none" src="../../../assets/img/generic/vertical-darker.png" alt="" /><img class="img-fluid img-prototype d-light-none" src="../../../assets/img/generic/vertical-lighter.png" alt="" /><span class="label-text d-dark-none"> Darker</span><span class="label-text d-light-none">Lighter</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-warning-dark font-medium"> <span class="fa-solid fa-triangle-exclamation me-2 text-warning"></span>You can't update vertical navbar appearance in this page</p>
|
||||
</div>
|
||||
<div class="setting-panel-item">
|
||||
<h5 class="setting-panel-item-title">Horizontal Navbar Shape</h5>
|
||||
<div class="row gx-2">
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarShapeDefault" name="navbar-shape" type="radio" value="default" data-theme-control="phoenixNavbarTopShape" data-page-url="../../../documentation/layouts/horizontal-navbar.html" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarShapeDefault"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype d-dark-none mb-0" src="../../../assets/img/generic/top-default.png" alt=""/><img class="img-fluid img-prototype d-light-none mb-0" src="../../../assets/img/generic/top-default-dark.png" alt=""/></span><span class="label-text">Default</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarShapeSlim" name="navbar-shape" type="radio" value="slim" data-theme-control="phoenixNavbarTopShape" data-page-url="../../../documentation/layouts/horizontal-navbar.html#horizontal-navbar-slim" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarShapeSlim"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype d-dark-none mb-0" src="../../../assets/img/generic/top-slim.png" alt=""/><img class="img-fluid img-prototype d-light-none mb-0" src="../../../assets/img/generic/top-slim-dark.png" alt=""/></span><span class="label-text"> Slim</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-warning-dark font-medium"> <span class="fa-solid fa-triangle-exclamation me-2 text-warning"></span>You can't update horizontal navbar shape in this page</p>
|
||||
</div>
|
||||
<div class="setting-panel-item">
|
||||
<h5 class="setting-panel-item-title">Horizontal Navbar Appearance</h5>
|
||||
<div class="row gx-2">
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarTopDefault" name="navbar-top-style" type="radio" value="default" data-theme-control="phoenixNavbarTopStyle" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarTopDefault"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype d-dark-none mb-0" src="../../../assets/img/generic/top-default.png" alt=""/><img class="img-fluid img-prototype d-light-none mb-0" src="../../../assets/img/generic/top-style-darker.png" alt=""/></span><span class="label-text">Default</span></label>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input class="btn-check" id="navbarTopDarker" name="navbar-top-style" type="radio" value="darker" data-theme-control="phoenixNavbarTopStyle" disabled="disabled" />
|
||||
<label class="btn d-inline-block btn-navbar-style fs-9" for="navbarTopDarker"> <span class="mb-2 rounded d-block"><img class="img-fluid img-prototype d-dark-none mb-0" src="../../../assets/img/generic/navbar-top-style-light.png" alt=""/><img class="img-fluid img-prototype d-light-none mb-0" src="../../../assets/img/generic/top-style-lighter.png" alt=""/></span><span class="label-text d-dark-none">Darker</span><span class="label-text d-light-none">Lighter</span></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-warning-dark font-medium"> <span class="fa-solid fa-triangle-exclamation me-2 text-warning"></span>You can't update horizontal navbar appearance in this page</p>
|
||||
</div><a class="bun btn-primary d-grid mb-3 text-white mt-5 btn btn-primary" href="https://themes.getbootstrap.com/product/phoenix-admin-dashboard-webapp-template/" target="_blank">Purchase template</a>
|
||||
</div>
|
||||
</div><a class="card setting-toggle" href="#settings-offcanvas" data-bs-toggle="offcanvas">
|
||||
<div class="card-body d-flex align-items-center px-2 py-1">
|
||||
<div class="position-relative rounded-start" style="height:34px;width:28px">
|
||||
<div class="settings-popover"><span class="ripple"><span class="fa-spin position-absolute all-0 d-flex flex-center"><span class="icon-spin position-absolute all-0 d-flex flex-center">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.7369 12.3941L19.1989 12.1065C18.4459 11.7041 18.0843 10.8487 18.0843 9.99495C18.0843 9.14118 18.4459 8.28582 19.1989 7.88336L19.7369 7.59581C19.9474 7.47484 20.0316 7.23291 19.9474 7.03131C19.4842 5.57973 18.6843 4.28943 17.6738 3.20075C17.5053 3.03946 17.2527 2.99914 17.0422 3.12011L16.393 3.46714C15.6883 3.84379 14.8377 3.74529 14.1476 3.3427C14.0988 3.31422 14.0496 3.28621 14.0002 3.25868C13.2568 2.84453 12.7055 2.10629 12.7055 1.25525V0.70081C12.7055 0.499202 12.5371 0.297594 12.2845 0.257272C10.7266 -0.105622 9.16879 -0.0653007 7.69516 0.257272C7.44254 0.297594 7.31623 0.499202 7.31623 0.70081V1.23474C7.31623 2.09575 6.74999 2.8362 5.99824 3.25599C5.95774 3.27861 5.91747 3.30159 5.87744 3.32493C5.15643 3.74527 4.26453 3.85902 3.53534 3.45302L2.93743 3.12011C2.72691 2.99914 2.47429 3.03946 2.30587 3.20075C1.29538 4.28943 0.495411 5.57973 0.0322686 7.03131C-0.051939 7.23291 0.0322686 7.47484 0.242788 7.59581L0.784376 7.8853C1.54166 8.29007 1.92694 9.13627 1.92694 9.99495C1.92694 10.8536 1.54166 11.6998 0.784375 12.1046L0.242788 12.3941C0.0322686 12.515 -0.051939 12.757 0.0322686 12.9586C0.495411 14.4102 1.29538 15.7005 2.30587 16.7891C2.47429 16.9504 2.72691 16.9907 2.93743 16.8698L3.58669 16.5227C4.29133 16.1461 5.14131 16.2457 5.8331 16.6455C5.88713 16.6767 5.94159 16.7074 5.99648 16.7375C6.75162 17.1511 7.31623 17.8941 7.31623 18.7552V19.2891C7.31623 19.4425 7.41373 19.5959 7.55309 19.696C7.64066 19.7589 7.74815 19.7843 7.85406 19.8046C9.35884 20.0925 10.8609 20.0456 12.2845 19.7729C12.5371 19.6923 12.7055 19.4907 12.7055 19.2891V18.7346C12.7055 17.8836 13.2568 17.1454 14.0002 16.7312C14.0496 16.7037 14.0988 16.6757 14.1476 16.6472C14.8377 16.2446 15.6883 16.1461 16.393 16.5227L17.0422 16.8698C17.2527 16.9907 17.5053 16.9504 17.6738 16.7891C18.7264 15.7005 19.4842 14.4102 19.9895 12.9586C20.0316 12.757 19.9474 12.515 19.7369 12.3941ZM10.0109 13.2005C8.1162 13.2005 6.64257 11.7893 6.64257 9.97478C6.64257 8.20063 8.1162 6.74905 10.0109 6.74905C11.8634 6.74905 13.3792 8.20063 13.3792 9.97478C13.3792 11.7893 11.8634 13.2005 10.0109 13.2005Z" fill="#2A7BE4"></path>
|
||||
</svg></span></span></span></div>
|
||||
</div><small class="text-uppercase text-body-tertiary fw-bold py-2 pe-2 ps-1 rounded-end">customize</small>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- JavaScripts-->
|
||||
<!-- ===============================================-->
|
||||
<script src="../../../vendors/popper/popper.min.js"></script>
|
||||
<script src="../../../vendors/bootstrap/bootstrap.min.js"></script>
|
||||
<script src="../../../vendors/anchorjs/anchor.min.js"></script>
|
||||
<script src="../../../vendors/is/is.min.js"></script>
|
||||
<script src="../../../vendors/fontawesome/all.min.js"></script>
|
||||
<script src="../../../vendors/lodash/lodash.min.js"></script>
|
||||
<script src="../../../vendors/list.js/list.min.js"></script>
|
||||
<script src="../../../vendors/feather-icons/feather.min.js"></script>
|
||||
<script src="../../../vendors/dayjs/dayjs.min.js"></script>
|
||||
<script src="../../../assets/js/phoenix.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
{% endblock %}
|
||||
@ -6,16 +6,21 @@
|
||||
{% block title %}{{ _("Sign In") }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row flex-center min-vh-100 py-5">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"><a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"><img src="{% static 'images/logos/logo.png' %}" alt="{% trans 'Haikal' %}" width="58" />
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<div class="container">
|
||||
<div class="row flex-center min-vh-50">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h3 class="text-body-highlight">{{ _("Sign In") }}</h3>
|
||||
{% if SOCIALACCOUNT_ENABLED %}
|
||||
<p class="text-body-tertiary">Get access to your account</p>
|
||||
<p class="text-body-tertiary">Login to your account</p>
|
||||
</div>
|
||||
|
||||
{% include "socialaccount/snippets/login.html" with page_layout="entrance" %}
|
||||
@ -34,7 +39,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block extra_body %}
|
||||
|
||||
@ -1,38 +1,39 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load i18n %}
|
||||
{% load i18n static crispy_forms_filters %}
|
||||
{% block title %}{{ _("Change Password") }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<!-- Page Header -->
|
||||
<div class="text-center mb-4">
|
||||
<h1 class="fw-bold">{{ _("Change Password") }}</h1>
|
||||
<p class="text-muted">{{ _("Ensure your account is using a strong, unique password.") }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Change Password Form -->
|
||||
<form method="post" action="{% url 'account_change_password' %}" class="needs-validation" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ redirect_field }}
|
||||
{{ form|crispy }}
|
||||
|
||||
<div class="d-grid gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-key"></i> {{ _("Change Password") }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Forgot Password Link -->
|
||||
<div class="text-center mt-3">
|
||||
<a href="{% url 'account_reset_password' %}" class="text-decoration-none">
|
||||
{{ _("Forgot Password?") }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row min-vh-100">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h1 class="fw-bold">{{ _("Change Password") }}</h1>
|
||||
<p class="text-muted">{{ _("Ensure your account is using a strong, unique password.") }}</p>
|
||||
</div>
|
||||
<form method="post" action="{% url 'account_change_password' %}" class="needs-validation" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ redirect_field }}
|
||||
{{ form|crispy }}
|
||||
<div class="text-start">
|
||||
<a href="{% url 'account_reset_password' %}" class="fs-sm-9">
|
||||
{{ _("Forgot Password?") }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-grid gap-2 mt-3">
|
||||
<button type="submit" class="btn btn-primary w-100 mb-3"><i class="bi bi-key"></i> {{ _("Change Password") }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -5,12 +5,16 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row flex-center min-vh-100 py-5">
|
||||
<div class="row min-vh-100">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"><a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"><img src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center mb-6">
|
||||
<div class="text-center">
|
||||
<h4 class="text-body-highlight">{{ _("Password Reset") }}</h4>
|
||||
<p class="text-body-tertiary">{{ _("Type your new password") }}</p>
|
||||
<form method="post" action="{% url 'account_reset_password' %}" class="needs-validation" novalidate>
|
||||
@ -28,9 +32,9 @@
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 mb-3">{{ _("Reset My Password") }}</button>
|
||||
</form>
|
||||
<p class="text-muted">
|
||||
<small class="text-muted mt-4">
|
||||
{{ _("Please contact us if you have any trouble resetting your password.") }}
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,23 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load i18n %}
|
||||
{% load i18n static %}
|
||||
|
||||
|
||||
{% 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">
|
||||
<div class="container">
|
||||
<div class="row d-flex-center min-vh-50">
|
||||
<div class="col-12 "><a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h3 class="text-body-highlight">{% trans 'Sign Up' %}</h3>
|
||||
<p class="text-body-tertiary">{% trans 'Create your account today' %}</p>
|
||||
</div>
|
||||
<div class="text-start">
|
||||
<div class="card theme-wizard" data-theme-wizard="data-theme-wizard">
|
||||
<div class="card-header 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>
|
||||
<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></span><span class="d-none d-md-block mt-1 fs-9">{% trans 'Access' %}</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>
|
||||
<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></span><span class="d-none d-md-block mt-1 fs-9">{% trans 'Account' %}</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>
|
||||
<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></span><span class="d-none d-md-block mt-1 fs-9">{% trans 'Extra' %}</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>
|
||||
<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></span><span class="d-none d-md-block mt-1 fs-9">{% trans 'Done' %}</span></div>
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -41,12 +54,12 @@
|
||||
<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 class="text-center text-sm-start"><img class="d-dark-none" src="{% static 'images/spot-illustrations/38.webp' %}" alt="" width="220"><img class="d-light-none" src="{% static 'images/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>
|
||||
<h5 class="mb-3">{% trans 'You are all set!' %}</h5>
|
||||
<p class="text-body-emphasis fs-9">{% trans 'Now you can access your account' %}<br>{% trans 'anytime' %} {% trans 'anywhere' %}</p><button class="btn btn-primary px-6" id='submit_btn'>{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,11 +68,104 @@
|
||||
</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>
|
||||
<button class="d-none btn btn-link ps-0" type="button" data-wizard-prev-btn="data-wizard-prev-btn">{% trans '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>
|
||||
<button class="btn btn-primary px-6 px-sm-6" type="submit" data-wizard-next-btn="data-wizard-next-btn">{% trans 'Next' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
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;
|
||||
}
|
||||
|
||||
const url = "{% url 'account_signup' %}";
|
||||
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(url, {
|
||||
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();
|
||||
}
|
||||
|
||||
function notify(tag,msg){
|
||||
Swal.fire({
|
||||
icon: tag,
|
||||
titleText: msg
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock content %}
|
||||
@ -6,9 +6,13 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row flex-center min-vh-100 py-5">
|
||||
<div class="row min-vh-100 text-center">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3"><a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'landing_page' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"><img src="{% static 'images/logos/logo.png' %}" alt="{% trans 'Haikal' %}" width="58" />
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
@ -69,7 +73,7 @@
|
||||
<div class="form-check mb-3">
|
||||
|
||||
<input class="form-check-input" id="termsService" type="checkbox" />
|
||||
<label class="form-label fs-9 text-transform-none" for="termsService">I accept the <a href="#!">terms </a>and <a href="#!">privacy policy</a></label>
|
||||
<label class="form-label fs-9 text-transform-none" for="termsService">I accept the <a href="">terms </a>and <a href="">privacy policy</a></label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 mb-3">{{ _("Sign Up") }}</button>
|
||||
<div class="text-center">{% trans 'Already have an account?' %}<a class="fw-bold" href="{% url 'account_login' %}"> {{ _("Sign In") }}</a></div>
|
||||
|
||||
@ -13,15 +13,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="Haikal - The Backbone of Car Qar: An innovative car inventory management system designed to streamline dealership operations. Manage inventory, sales, transfers, and accounting seamlessly with advanced analytics and intuitive tools. Inspired by Arabic origins, Haikal empowers businesses with precision and efficiency.">
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Document Title-->
|
||||
<!-- ===============================================-->
|
||||
<title>{% block title %}{% trans 'HAIKAL' %}{% endblock %}</title>
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
<!-- Favicons-->
|
||||
<!-- ===============================================-->
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'images/favicons/apple-touch-icon.png' %}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'images/favicons/favicon-32x32.png' %}">
|
||||
@ -30,8 +24,11 @@
|
||||
<link rel="manifest" href="{% static 'images/favicons/manifest.json' %}">
|
||||
<meta name="msapplication-TileImage" content="{% static 'images/logos/logo-d.png' %}">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<script src="{% static 'vendors/simplebar/simplebar.min.js' %}"></script>
|
||||
<script src="{% static 'js/config.js' %}"></script>
|
||||
<script src="{% static 'js/config.js' %}"></script>
|
||||
<script src="{% static 'js/sweetalert2.all.min.js' %}"></script>
|
||||
|
||||
|
||||
|
||||
<!-- ===============================================-->
|
||||
@ -45,7 +42,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;400;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link href="{% static 'vendors/simplebar/simplebar.min.css' %}" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/sweetalert2@11.15.3/dist/sweetalert2.min.css" rel="stylesheet">
|
||||
<link href="{% static 'css/sweetalert2.min.css' %}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
||||
{% if LANGUAGE_CODE == 'en' %}
|
||||
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
|
||||
@ -57,8 +54,8 @@
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
{% include 'messages.html' %}
|
||||
<main class="main" id="top">
|
||||
<nav class="navbar navbar-vertical navbar-expand-lg">
|
||||
<div class="collapse navbar-collapse" id="navbarVerticalCollapse">
|
||||
@ -76,7 +73,7 @@
|
||||
<ul class="nav collapse parent" data-bs-parent="#navbarVerticalCollapse" id="nv-dashboards">
|
||||
<li class="collapsed-nav-item-title d-none">Dashboards
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="#">
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'accounting' %}">
|
||||
<div class="d-flex align-items-center"><span class="nav-link-text">Accounting</span>
|
||||
</div>
|
||||
</a>
|
||||
@ -103,9 +100,9 @@
|
||||
</li>
|
||||
<hr class="my-0" />
|
||||
<li class="nav-item">
|
||||
|
||||
<!-- label-->
|
||||
<p class="navbar-vertical-label">Apps
|
||||
</p>
|
||||
<p class="navbar-vertical-label">Apps</p>
|
||||
<hr class="navbar-vertical-line" />
|
||||
<!-- parent pages-->
|
||||
<div class="nav-item-wrapper"><a class="nav-link dropdown-indicator label-1" href="#nv-inventory" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-inventory">
|
||||
@ -133,6 +130,30 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- parent pages-->
|
||||
<div class="nav-item-wrapper"><a class="nav-link dropdown-indicator label-1" href="#nv-vendors" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-vendors">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="dropdown-indicator-icon-wrapper"><span class="fas fa-caret-right dropdown-indicator-icon"></span></div><span class="nav-link-icon"><span data-feather="package"></span></span><span class="nav-link-text">{% trans 'vendors'|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="parent-wrapper label-1">
|
||||
<ul class="nav collapse parent" data-bs-parent="#navbarVerticalCollapse" id="nv-vendors">
|
||||
<li class="collapsed-nav-item-title d-none">{% trans 'vendors'|capfirst %}
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'vendor_create' %}">
|
||||
<div class="d-flex align-items-center"><span class="nav-link-text">{% trans "add vendor"|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
<!-- more inner pages-->
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'vendor_list' %}">
|
||||
<div class="d-flex align-items-center"><span class="nav-link-text">{% trans 'vendors'|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
<!-- more inner pages-->
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div> <!-- parent pages-->
|
||||
<div class="nav-item-wrapper"><a class="nav-link dropdown-indicator label-1" href="#nv-customers" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-customers">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="dropdown-indicator-icon-wrapper"><span class="fas fa-caret-right dropdown-indicator-icon"></span></div><span class="nav-link-icon"><span data-feather="users"></span></span><span class="nav-link-text">{% trans 'customers'|capfirst %}</span>
|
||||
@ -160,7 +181,7 @@
|
||||
<!-- parent pages-->
|
||||
<div class="nav-item-wrapper"><a class="nav-link dropdown-indicator label-1" href="#nv-organizations" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-organizations">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="dropdown-indicator-icon-wrapper"><span class="fas fa-caret-right dropdown-indicator-icon"></span></div><span class="nav-link-icon"><span data-feather="phone"></span></span><span class="nav-link-text">{% trans 'organizations'|capfirst %}</span>
|
||||
<div class="dropdown-indicator-icon-wrapper"><span class="fas fa-caret-right dropdown-indicator-icon"></span></div><span class="nav-link-icon"><span data-feather="activity"></span></span><span class="nav-link-text">{% trans 'organizations'|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="parent-wrapper label-1">
|
||||
@ -253,14 +274,10 @@
|
||||
|
||||
<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">
|
||||
{% if data_bs_theme == 'dark' %}
|
||||
<img src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />
|
||||
{% else %}
|
||||
<img src="{% static 'images/logos/logo-d.png' %}" alt="haikal" width="27" />
|
||||
{% endif %}
|
||||
<div class="d-flex align-items-center">
|
||||
<img class="logo-img d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="haikal" width="27" />
|
||||
<img class="logo-img d-light-none" src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />
|
||||
<h5 class="logo-text ms-2 d-none d-sm-block">{% trans 'Haikal' %}</h5>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -472,11 +489,10 @@
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
<div class="content">
|
||||
|
||||
{% include 'messages.html' %}
|
||||
{% block content %}
|
||||
<!-- Main content goes here -->
|
||||
{% endblock %}
|
||||
@ -493,146 +509,7 @@
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div class="modal fade" id="searchBoxModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="true" data-phoenix-modal="data-phoenix-modal" style="--phoenix-backdrop-opacity: 1;">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content mt-15 rounded-pill">
|
||||
<div class="modal-body p-0">
|
||||
<div class="search-box navbar-top-search-box" data-list='{"valueNames":["title"]}' style="width: auto;">
|
||||
<form class="position-relative" data-bs-toggle="search" data-bs-display="static">
|
||||
<input class="form-control search-input fuzzy-search rounded-pill form-control-lg" type="search" placeholder="Search..." aria-label="Search" />
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
|
||||
</form>
|
||||
<div class="btn-close position-absolute end-0 top-50 translate-middle cursor-pointer shadow-none" data-bs-dismiss="search">
|
||||
<button class="btn btn-link p-0" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="dropdown-menu border start-0 py-0 overflow-hidden w-100">
|
||||
<div class="scrollbar-overlay" style="max-height: 30rem;">
|
||||
<div class="list pb-3">
|
||||
<h6 class="dropdown-header text-body-highlight fs-10 py-2">24 <span class="text-body-quaternary">results</span></h6>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Recently Searched </h6>
|
||||
<div class="py-2"><a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"><span class="fa-solid fa-clock-rotate-left" data-fa-transform="shrink-2"></span> Store Macbook</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"> <span class="fa-solid fa-clock-rotate-left" data-fa-transform="shrink-2"></span> MacBook Air - 13″</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Products</h6>
|
||||
<div class="py-2"><a class="dropdown-item py-2 d-flex align-items-center" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="file-thumbnail me-2"><img class="h-100 w-100 object-fit-cover rounded-3" src="{% static 'images/products/60x60/3.png' %}" alt="" /></div>
|
||||
<div class="flex-1">
|
||||
<h6 class="mb-0 text-body-highlight title">MacBook Air - 13″</h6>
|
||||
<p class="fs-10 mb-0 d-flex text-body-tertiary"><span class="fw-medium text-body-tertiary text-opactity-85">8GB Memory - 1.6GHz - 128GB Storage</span></p>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item py-2 d-flex align-items-center" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="file-thumbnail me-2"><img class="img-fluid" src="{% static 'images/products/60x60/3.png' %}" alt="" /></div>
|
||||
<div class="flex-1">
|
||||
<h6 class="mb-0 text-body-highlight title">MacBook Pro - 13″</h6>
|
||||
<p class="fs-10 mb-0 d-flex text-body-tertiary"><span class="fw-medium text-body-tertiary text-opactity-85">30 Sep at 12:30 PM</span></p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Quick Links</h6>
|
||||
<div class="py-2"><a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"><span class="fa-solid fa-link text-body" data-fa-transform="shrink-2"></span> Support MacBook House</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"> <span class="fa-solid fa-link text-body" data-fa-transform="shrink-2"></span> Store MacBook″</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Files</h6>
|
||||
<div class="py-2"><a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"><span class="fa-solid fa-file-zipper text-body" data-fa-transform="shrink-2"></span> Library MacBook folder.rar</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"> <span class="fa-solid fa-file-lines text-body" data-fa-transform="shrink-2"></span> Feature MacBook extensions.txt</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"> <span class="fa-solid fa-image text-body" data-fa-transform="shrink-2"></span> MacBook Pro_13.jpg</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Members</h6>
|
||||
<div class="py-2"><a class="dropdown-item py-2 d-flex align-items-center" href="../pages/members.html">
|
||||
<div class="avatar avatar-l status-online me-2 text-body">
|
||||
<img class="rounded-circle " src="{% static 'images/team/40x40/10.webp' %}" alt="" />
|
||||
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h6 class="mb-0 text-body-highlight title">Carry Anna</h6>
|
||||
<p class="fs-10 mb-0 d-flex text-body-tertiary">anna@technext.it</p>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item py-2 d-flex align-items-center" href="../pages/members.html">
|
||||
<div class="avatar avatar-l me-2 text-body">
|
||||
<img class="rounded-circle " src="{% static 'images/team/40x40/12.webp' %}" alt="" />
|
||||
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h6 class="mb-0 text-body-highlight title">John Smith</h6>
|
||||
<p class="fs-10 mb-0 d-flex text-body-tertiary">smith@technext.it</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<hr class="my-0" />
|
||||
<h6 class="dropdown-header text-body-highlight fs-9 border-bottom border-translucent py-2 lh-sm">Related Searches</h6>
|
||||
<div class="py-2"><a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"><span class="fa-brands fa-firefox-browser text-body" data-fa-transform="shrink-2"></span> Search in the Web MacBook</div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="dropdown-item" href="../apps/e-commerce/landing/product-details.html">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
<div class="fw-normal text-body-highlight title"> <span class="fa-brands fa-chrome text-body" data-fa-transform="shrink-2"></span> Store MacBook″</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="fallback fw-bold fs-7 d-none">No Result Found.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="support-chat-container">
|
||||
<div class="container-fluid support-chat">
|
||||
@ -681,127 +558,11 @@
|
||||
<!-- ===============================================-->
|
||||
<!-- End of Main Content-->
|
||||
<!-- ===============================================-->
|
||||
<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') {
|
||||
navbarTop.setAttribute('data-navbar-appearance', 'darker');
|
||||
}
|
||||
|
||||
var navbarVerticalStyle = window.config.config.phoenixNavbarVerticalStyle;
|
||||
var navbarVertical = document.querySelector('.navbar-vertical');
|
||||
if (navbarVertical && navbarVerticalStyle === 'darker') {
|
||||
navbarVertical.setAttribute('data-navbar-appearance', 'darker');
|
||||
}
|
||||
function save_as_pdf(){
|
||||
const quotationHtml = document.getElementById('quotation-html').outerHTML;
|
||||
const printWindow = window.open('', '', 'height=500,width=800');
|
||||
printWindow.document.write(quotationHtml);
|
||||
printWindow.document.close();
|
||||
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>
|
||||
{% block extra_js %}{% endblock extra_js %}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,27 +4,8 @@
|
||||
{% block content %}
|
||||
|
||||
<div class="container">
|
||||
<!-- ============================================-->
|
||||
<!-- <section> begin ============================-->
|
||||
<section class="py-0">
|
||||
|
||||
<div class="container-small">
|
||||
<div class="ecommerce-topbar">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of .container-->
|
||||
|
||||
</section>
|
||||
<!-- <section> close ============================-->
|
||||
<!-- ============================================-->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ============================================-->
|
||||
<!-- <section> begin ============================-->
|
||||
<section class="pt-5 pb-9">
|
||||
|
||||
<div class="container-small">
|
||||
@ -37,7 +18,7 @@
|
||||
<div class="row g-2 g-sm-3">
|
||||
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-phoenix-secondary"><span class="fas fa-key me-2"></span>Reset password</button>
|
||||
<a href="{% url 'account_change_password' %}" class="btn btn-phoenix-secondary"><span class="fas fa-key me-2"></span>{{ _("Change Password") }}</a>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a class="btn btn-phoenix-secondary " href="#!"><span class="fa-solid fa-user-gear me-2 mb-2 mb-xxl-0"></span>Settings </a>
|
||||
@ -144,7 +125,7 @@
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="mb-5 mb-md-0 mb-lg-5 me-3">
|
||||
<div class="d-sm-flex d-md-block d-lg-flex align-items-center mb-3">
|
||||
<h3 class="mb-0">{{ dealer.get_active_plan.plan }}</h3><span class="badge ms-sm-3 ms-md-0 ms-lg-3 fs-10 text-bg-warning">{% trans 'most valuable'|upper %}</span>
|
||||
<h3 class="mb-0">{{ dealer.get_active_plan.plan|capfirst }}</h3><span class="badge ms-sm-3 ms-md-0 ms-lg-3 fs-10 text-bg-warning">{% trans 'most valuable'|upper %}</span>
|
||||
</div>
|
||||
<p class="fs-9 text-body-tertiary">{% trans 'Active until' %}: {{ dealer.get_active_plan.end_date|date}}</p>
|
||||
<div class="d-flex align-items-end mb-md-5 mb-lg-0">
|
||||
@ -156,9 +137,9 @@
|
||||
<div class="row flex-1 justify-content-end">
|
||||
<div class="col-sm-8 col-md-12">
|
||||
<div class="d-sm-flex d-md-block d-lg-flex justify-content-end align-items-end h-100">
|
||||
<ul class="list-unstyled mb-0 border-start-sm border-start-md-0 border-start-lg ps-sm-5 ps-md-0 ps-lg-5 border-warning-subtle">
|
||||
<li class="d-flex align-items-center"><span class="uil uil-check-circle text-success me-2"></span><span class="text-body-tertiary fw-semibold">{{ dealer.get_plan.description}}</span></li>
|
||||
</ul>
|
||||
<div class="list-unstyled mb-0 border-start-sm border-start-md-0 border-start-lg ps-sm-5 ps-md-0 ps-lg-5 border-warning-subtle">
|
||||
<div class="d-flex align-items-center"><span class="uil uil-check-circle text-success me-2"></span><span class="text-body-tertiary fw-semibold">{{ dealer.get_plan.description}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -51,7 +51,7 @@ function getCookie(name) {
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
const csrfToken = getCookie('csrftoken');
|
||||
const csrfToken = getCookie('token');
|
||||
|
||||
|
||||
async function sendMessage() {
|
||||
|
||||
1311
templates/index.html
1311
templates/index.html
File diff suppressed because it is too large
Load Diff
@ -58,28 +58,24 @@
|
||||
</div>
|
||||
|
||||
<!-- Specification Modal -->
|
||||
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content glossy-modal">
|
||||
<div class="modal-header bg-primary text-light">
|
||||
<h5 class="modal-title" id="specificationsModalLabel">
|
||||
{% trans 'specifications'|upper %}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="specificationsContent"></div>
|
||||
<div class="d-grid gap-2">
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-danger"
|
||||
data-bs-dismiss="modal">
|
||||
{% trans 'Close' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="specificationsModalLabel">{% trans 'specifications'|upper %}</h5>
|
||||
<button class="btn btn-close p-1" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="specificationsContent"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-outline-primary" type="button" data-bs-dismiss="modal">{% trans 'Close' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Specification Modal -->
|
||||
|
||||
<!-- Main Container -->
|
||||
<div class="d-flex flex-column min-vh-100">
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>
|
||||
|
||||
|
||||
<div class="container p-2">
|
||||
<div class="container">
|
||||
|
||||
<!-- Specification Modal -->
|
||||
<div class="modal fade" id="specificationsModal"
|
||||
@ -344,10 +344,7 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
function getCookie(name) {
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
const cookies = document.cookie.split(';');
|
||||
@ -362,7 +359,10 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
const csrfToken = getCookie('csrftoken');
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
|
||||
const csrfToken = getCookie('token');
|
||||
|
||||
const vinInput = document.getElementById('{{ form.vin.id_for_label }}');
|
||||
const stockTypeSelect = document.getElementById('{{ form.stock_type.id_for_label }}');
|
||||
@ -613,23 +613,29 @@ async function loadSpecifications(trimId){
|
||||
modelSelect.addEventListener("change", (e) => {loadSeries(e.target.value, yearSelect.value)})
|
||||
decodeVinBtn.addEventListener('click', decodeVin);
|
||||
});
|
||||
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({
|
||||
function showLoading() {
|
||||
Swal.fire({
|
||||
title: "{% trans 'Please Wait' %}",
|
||||
text: "{% trans 'Loading' %}...",
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
Swal.close();
|
||||
}
|
||||
|
||||
function notify(tag,msg){
|
||||
Swal.fire({
|
||||
icon: tag,
|
||||
titleText: msg
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@ -1,7 +1,8 @@
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
|
||||
<script>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: "top-end",
|
||||
@ -17,7 +18,8 @@
|
||||
icon: "{{ message.tags }}",
|
||||
titleText: "{{ message| safe }}"
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
@ -1,14 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
{% block title %}{{ _("Payyment Create") }}{% endblock title %}
|
||||
{% block title %}{{ _("Make Payment") }}{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ _("Payment Create") }}</div>
|
||||
<div class="card-header">{{ _("Make Payment") }}</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{% url 'payment_create' pk=quotation.pk %}">
|
||||
{% csrf_token %}
|
||||
|
||||
@ -138,7 +138,7 @@
|
||||
class="btn btn-success"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#confirmModal">
|
||||
{% trans 'Acccept' %}
|
||||
{% trans 'Accept' %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if quotation.status == 'Draft' and not quotation.is_approved %}
|
||||
|
||||
41
templates/vendors/vendor_form.html
vendored
41
templates/vendors/vendor_form.html
vendored
@ -4,36 +4,47 @@
|
||||
{% block title %}{% trans "Vendors" %}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<!-- Display Form Errors -->
|
||||
<div class="card shadow rounded">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<p class="mb-0">
|
||||
{% if customer.created %}
|
||||
<!--<i class="bi bi-pencil-square"></i>-->
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-xl-9">
|
||||
<div class="d-sm-flex justify-content-between">
|
||||
|
||||
<h3 class="mb-3">
|
||||
{% if vendor.created %}
|
||||
<!--<i class="bi bi-pencil-square"></i>-->
|
||||
{{ _("Edit Vendor") }}
|
||||
{% else %}
|
||||
<!--<i class="bi bi-person-plus"></i> -->
|
||||
{{ _("Add Vendor") }}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" class="form" novalidate>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-9">
|
||||
|
||||
<form class="row g-3 mb-9" method="post" class="form" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ redirect_field }}
|
||||
{{ form|crispy }}
|
||||
{% for error in form.errors %}
|
||||
<div class="text-danger">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="d-flex justify-content-end">
|
||||
<button class="btn btn-sm btn-success me-1" type="submit">
|
||||
<div class="d-flex mb-3">
|
||||
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-phoenix-primary me-2 px-6">{% trans "cancel"|capfirst %}</a>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<!--<i class="bi bi-save"></i> -->
|
||||
{{ _("Save") }}
|
||||
</button>
|
||||
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
184
templates/vendors/vendors_list.html
vendored
184
templates/vendors/vendors_list.html
vendored
@ -5,69 +5,146 @@
|
||||
{% block vendors %}<a class="nav-link active">{{ _("Vendors")|capfirst }}</a>{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid p-3">
|
||||
<div class="card shadow rounded">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">{{ _("Vendors")|capfirst }}</h6>
|
||||
<form method="get" class="d-inline-block">
|
||||
<div class="input-group input-group-sm">
|
||||
<button class="btn btn-secondary" type="submit">
|
||||
{{ _("Search")|capfirst }}
|
||||
</button>
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="{{ _('Enter vendor name') }}"
|
||||
value="{{ request.GET.q }}">
|
||||
<section class="pt-5 pb-9">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h2 class="mb-4">{{ _("Vendors")|capfirst }}</h2>
|
||||
|
||||
<div class="row g-3 justify-content-between mb-4">
|
||||
<div class="col-auto">
|
||||
<div class="d-md-flex justify-content-between">
|
||||
<div>
|
||||
<a href="{% url 'vendor_create' %}" class="btn btn-primary me-4"><span class="fas fa-plus me-2"></span>{{ _("Add Vendor") }}</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="d-flex">
|
||||
<div class="search-box me-2">
|
||||
<form method="get" class="d-inline-block position-relative">
|
||||
<input name="q" class="form-control search-input search" type="search" placeholder="{{ _('Enter vendor name') }}" aria-label="Search" value="{{ request.GET.q }}"/>
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
{% if request.GET.q %}
|
||||
<a href="{% url request.resolver_match.view_name %}" class="btn btn-outline-danger ms-1">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover table-striped mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>{{ _("Name")|capfirst }}</th>
|
||||
<th>{{ _("Logo")|capfirst }}</th>
|
||||
<th>{{ _("Address")|capfirst }}</th>
|
||||
<th>{{ _("Actions")|capfirst }}</th>
|
||||
</tr>
|
||||
</div>
|
||||
</div>
|
||||
{% if page_obj.object_list %}
|
||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||
|
||||
<table class="table fs-9 mb-0 leads-table border-top border-translucent">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="email" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="text-success-dark" data-feather="mail"></span></div><span>{{ _("email")|capfirst }}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div><span>Phone</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="user"></span></div><span>{{ _("Contact name")|capfirst }}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">
|
||||
{{ _("Create date") }}</th>
|
||||
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if page_obj.object_list %}
|
||||
<tbody class="list" id="leal-tables-body">
|
||||
|
||||
{% for vendor in vendors %}
|
||||
<tr>
|
||||
<td>{{ vendor.get_local_name }}</td>
|
||||
<td>
|
||||
{% if vendor.logo %}
|
||||
<img src="{{ vendor.logo.url }}"
|
||||
alt="{{ vendor.get_local_name }}"
|
||||
class="img-thumbnail"
|
||||
style="max-width: 100px;">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ vendor.address }}</td>
|
||||
<td>
|
||||
<a href="{% url 'vendor_detail' vendor.id %}" class="btn btn-success btn-sm">
|
||||
{{ _("view")|capfirst }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center">{{ _("No vendors found")|capfirst }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Delete Modal -->
|
||||
<div class="modal fade" id="deleteModal"
|
||||
data-bs-backdrop="static"
|
||||
data-bs-keyboard="false"
|
||||
tabindex="-1"
|
||||
aria-labelledby="deleteModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
|
||||
{% trans "Delete Vendor" %}
|
||||
<span data-feather="alert-circle"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p class="mb-0 text-danger fw-bold">
|
||||
{% trans "Are you sure you want to delete this vendor?" %}
|
||||
</p>
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
|
||||
{% trans "No" %}
|
||||
</button>
|
||||
<a type="button" class="btn btn-danger btn-sm" href="{% url 'vendor_delete' vendor.id %}">
|
||||
{% trans "Yes" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
|
||||
<td class="name align-middle white-space-nowrap ps-0">
|
||||
<div class="d-flex align-items-center">
|
||||
{% if vendor.logo %}
|
||||
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" />
|
||||
{% else %}
|
||||
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div><a class="fs-8 fw-bold" href="{% url 'vendor_detail' vendor.id %}">{{ vendor.name }}</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.arabic_name }}</p><span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.id}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="">{{ vendor.email }}</a></td>
|
||||
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone_number }}">{{ vendor.phone_number }}</a></td>
|
||||
<td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ vendor.contact_person }}</td>
|
||||
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
|
||||
{{ vendor.address }}</td>
|
||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created_at|date }}</td>
|
||||
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
|
||||
<div class="btn-reveal-trigger position-static">
|
||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a href="{% url 'vendor_update' vendor.id %}" class="dropdown-item text-success-dark">
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
|
||||
<!-- Optional: Pagination -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation">
|
||||
@ -108,4 +185,7 @@
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user