diff --git a/haikalbot/migrations/0001_initial.py b/haikalbot/migrations/0001_initial.py index 0276f163..45d94ed1 100644 --- a/haikalbot/migrations/0001_initial.py +++ b/haikalbot/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.4 on 2024-12-26 10:09 +# Generated by Django 4.2.17 on 2024-12-26 10:12 from django.db import migrations, models diff --git a/haikalbot/migrations/0002_initial.py b/haikalbot/migrations/0002_initial.py index 087e82df..28c8cd2c 100644 --- a/haikalbot/migrations/0002_initial.py +++ b/haikalbot/migrations/0002_initial.py @@ -1,7 +1,7 @@ -# Generated by Django 5.1.4 on 2024-12-26 10:09 +# Generated by Django 4.2.17 on 2024-12-26 10:12 -import django.db.models.deletion from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): diff --git a/inventory/forms.py b/inventory/forms.py index 5ed86b8d..8790a225 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -1,3 +1,5 @@ +from phonenumber_field.formfields import PhoneNumberField +from django.core.validators import RegexValidator from django import forms from .mixins import AddClassMixin from django.forms.models import inlineformset_factory @@ -22,7 +24,7 @@ from .models import ( AdditionalServices ) -from django.forms import ModelMultipleChoiceField +from django.forms import ModelMultipleChoiceField, ValidationError from django.utils.translation import gettext_lazy as _ import django_tables2 as tables from django.forms import formset_factory @@ -48,7 +50,6 @@ class DealerForm(forms.ModelForm): model = Dealer fields = ['name', 'arabic_name', 'crn', 'vrn', 'phone_number', 'address', 'logo'] - # Customer Form class CustomerForm(forms.ModelForm, AddClassMixin): class Meta: @@ -257,3 +258,148 @@ class CarSelectionTable(tables.Table): model = Car fields = ['vin', 'year', 'id_car_make', 'id_car_model'] template_name = "django_tables2/bootstrap4.html" + + + + + + +class WizardForm1(forms.Form): + name = forms.CharField( + label="Name", + widget=forms.TextInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Name', + 'required': 'required', + }), + error_messages={ + 'required': 'Please choose a username.', + } + ) + arabic_name = forms.CharField( + label="Arabic Name", + widget=forms.TextInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Arabic Name', + 'required': 'required', + }), + error_messages={ + 'required': 'Please choose an Arabic name.', + } + ) + email = forms.EmailField( + label="Email*", + widget=forms.EmailInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Email address', + 'pattern': '^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$', + 'required': 'required', + }), + error_messages={ + 'required': 'You must add an email.', + } + ) + terms = forms.BooleanField( + label="I accept the terms and privacy policy", + widget=forms.CheckboxInput(attrs={ + 'class': 'form-check-input', + 'required': 'required', + 'checked': 'checked', + }), + error_messages={ + 'required': 'You must accept the terms and privacy policy.', + } + ) + + +class WizardForm2(forms.Form): + # Phone field with SA region validation + phone_number = PhoneNumberField( + label="Phone", + max_length=10, + widget=forms.TextInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Phone', + 'required': 'required', + }), + region='SA', # Enforces SA region validation + error_messages={ + 'required': 'This field is required.', + 'invalid': 'Phone number must be in the format +966XXXXXXXXX (Saudi Arabia).', + } + ) + + # CRN field with max length of 10 + crn = forms.CharField( + label="CRN", + widget=forms.TextInput(attrs={ + 'class': 'form-control', + 'placeholder': 'CRN', + 'required': 'required', + 'maxlength': '10', # HTML maxlength attribute + }), + max_length=10, # Django max_length validation + error_messages={ + 'required': 'This field is required.', + 'max_length': 'CRN must be at most 10 characters long.', + } + ) + + # VRN field with max length of 15 + vrn = forms.CharField( + label="VRN", + widget=forms.TextInput(attrs={ + 'class': 'form-control', + 'placeholder': 'VRN', + 'required': 'required', + 'maxlength': '15', # HTML maxlength attribute + }), + max_length=15, # Django max_length validation + error_messages={ + 'required': 'This field is required.', + 'max_length': 'VRN must be at most 15 characters long.', + } + ) + + address = forms.CharField( + label="Address", + widget=forms.Textarea(attrs={ + 'class': 'form-control', + 'rows': '4', + 'required': 'required', + }), + error_messages={ + 'required': 'This field is required.', + } + ) +class WizardForm3(forms.Form): + password = forms.CharField( + label="Password*", + widget=forms.PasswordInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Password', + 'required': 'required', + }), + error_messages={ + 'required': 'This field is required.', + } + ) + confirm_password = forms.CharField( + label="Confirm Password*", + widget=forms.PasswordInput(attrs={ + 'class': 'form-control', + 'placeholder': 'Confirm Password', + 'required': 'required', + }), + error_messages={ + 'required': 'This field is required.', + } + ) + + def clean(self): + cleaned_data = super().clean() + password = cleaned_data.get("password") + confirm_password = cleaned_data.get("confirm_password") + + if password and confirm_password and password != confirm_password: + raise forms.ValidationError("Passwords do not match.") diff --git a/inventory/migrations/0001_initial.py b/inventory/migrations/0001_initial.py index 4c58539b..bfa7c507 100644 --- a/inventory/migrations/0001_initial.py +++ b/inventory/migrations/0001_initial.py @@ -1,11 +1,11 @@ -# Generated by Django 5.1.4 on 2024-12-26 10:09 +# Generated by Django 4.2.17 on 2024-12-26 10:12 -import django.db.models.deletion -import inventory.mixins -import phonenumber_field.modelfields from decimal import Decimal from django.conf import settings from django.db import migrations, models +import django.db.models.deletion +import inventory.mixins +import phonenumber_field.modelfields class Migration(migrations.Migration): @@ -13,8 +13,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('django_ledger', '0017_alter_accountmodel_unique_together_and_more'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('django_ledger', '0017_alter_accountmodel_unique_together_and_more'), ] operations = [ @@ -66,6 +66,90 @@ class Migration(migrations.Migration): }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), + migrations.CreateModel( + name='CarModel', + fields=[ + ('id_car_model', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255)), + ('arabic_name', models.CharField(max_length=255)), + ('id_car_make', models.ForeignKey(db_column='id_car_make', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake')), + ], + options={ + 'verbose_name': 'Model', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), + migrations.CreateModel( + name='CarSerie', + fields=[ + ('id_car_serie', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255)), + ('arabic_name', models.CharField(max_length=255)), + ('year_begin', models.IntegerField(blank=True, null=True)), + ('year_end', models.IntegerField(blank=True, null=True)), + ('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')), + ], + options={ + 'verbose_name': 'Series', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), + migrations.CreateModel( + name='CarSpecification', + fields=[ + ('id_car_specification', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255)), + ('arabic_name', models.CharField(max_length=255)), + ('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')), + ], + options={ + 'verbose_name': 'Specification', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), + migrations.CreateModel( + name='Customer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=50, verbose_name='First Name')), + ('middle_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Middle Name')), + ('last_name', models.CharField(max_length=50, verbose_name='Last Name')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), + ('national_id', models.CharField(max_length=10, unique=True, verbose_name='National ID')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), + ], + options={ + 'verbose_name': 'Customer', + 'verbose_name_plural': 'Customers', + }, + ), + migrations.CreateModel( + name='Dealer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('crn', models.CharField(blank=True, max_length=10, null=True, verbose_name='Commercial Registration Number')), + ('vrn', models.CharField(blank=True, max_length=15, null=True, verbose_name='VAT Registration Number')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('name', models.CharField(max_length=255, verbose_name='English Name')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('logo', models.ImageField(blank=True, null=True, upload_to='logos/users', verbose_name='Logo')), + ('joined_at', models.DateTimeField(auto_now_add=True, verbose_name='Joined At')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), + ('dealer_type', models.CharField(choices=[('Owner', 'Owner'), ('Inventory', 'Inventory'), ('Accountent', 'Accountent'), ('sales', 'Sales')], default='Owner', max_length=255, verbose_name='Dealer Type')), + ('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel')), + ('parent_dealer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_dealers', to='inventory.dealer', verbose_name='Parent Dealer')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Dealer', + 'verbose_name_plural': 'Dealers', + 'permissions': [('change_dealer_type', 'Can change dealer type')], + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), migrations.CreateModel( name='ExteriorColors', fields=[ @@ -94,6 +178,25 @@ class Migration(migrations.Migration): }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), + migrations.CreateModel( + name='Organization', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Name')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')), + ('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')), + ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')), + ], + options={ + 'verbose_name': 'Organization', + 'verbose_name_plural': 'Organizations', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), migrations.CreateModel( name='Payment', fields=[ @@ -108,6 +211,30 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'payments', }, ), + migrations.CreateModel( + name='SaleQuotation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quotation_number', models.CharField(max_length=10, unique=True)), + ('amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount')), + ('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')), + ('is_approved', models.BooleanField(default=False)), + ('status', models.CharField(choices=[('Draft', 'Draft'), ('Approved', 'Approved'), ('In Review', 'In Review'), ('Paid', 'Paid')], default='Draft', max_length=10, verbose_name='Status')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')), + ('posted', models.BooleanField(default=False)), + ('payment_id', models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment ID')), + ('is_paid', models.BooleanField(default=False)), + ('date_draft', models.DateTimeField(blank=True, null=True, verbose_name='Draft Date')), + ('date_in_review', models.DateTimeField(blank=True, null=True, verbose_name='In Review Date')), + ('date_approved', models.DateTimeField(blank=True, null=True, verbose_name='Approved Date')), + ('date_paid', models.DateTimeField(blank=True, null=True, verbose_name='Paid Date')), + ('date_void', models.DateTimeField(blank=True, null=True, verbose_name='Void Date')), + ('date_canceled', models.DateTimeField(blank=True, null=True, verbose_name='Canceled Date')), + ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer')), + ('dealer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer')), + ], + ), migrations.CreateModel( name='Subscription', fields=[ @@ -130,92 +257,111 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name='CarFinance', + name='Vendor', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')), - ('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')), - ('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')), - ('additional_services', models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices')), - ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')), + ('crn', models.CharField(max_length=10, unique=True, verbose_name='Commercial Registration Number')), + ('vrn', models.CharField(max_length=15, unique=True, verbose_name='VAT Registration Number')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('name', models.CharField(max_length=255, verbose_name='English Name')), + ('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')), + ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')), ], options={ - 'verbose_name': 'Car Financial Details', - 'verbose_name_plural': 'Car Financial Details', - }, - ), - migrations.AddField( - model_name='car', - name='id_car_make', - field=models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'), - ), - migrations.CreateModel( - name='CarModel', - fields=[ - ('id_car_model', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('id_car_make', models.ForeignKey(db_column='id_car_make', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake')), - ], - options={ - 'verbose_name': 'Model', + 'verbose_name': 'Vendor', + 'verbose_name_plural': 'Vendors', }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), - migrations.AddField( - model_name='car', - name='id_car_model', - field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'), - ), migrations.CreateModel( - name='CarRegistration', + name='SubscriptionUser', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('plate_number', models.IntegerField(verbose_name='Plate Number')), - ('text1', models.CharField(max_length=1, verbose_name='Text 1')), - ('text2', models.CharField(max_length=1, verbose_name='Text 2')), - ('text3', models.CharField(max_length=1, verbose_name='Text 3')), - ('registration_date', models.DateTimeField(verbose_name='Registration Date')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')), + ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - 'verbose_name': 'Registration', - 'verbose_name_plural': 'Registrations', - }, - ), - migrations.CreateModel( - name='CarSerie', - fields=[ - ('id_car_serie', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('year_begin', models.IntegerField(blank=True, null=True)), - ('year_end', models.IntegerField(blank=True, null=True)), - ('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')), - ], - options={ - 'verbose_name': 'Series', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), migrations.AddField( - model_name='car', - name='id_car_serie', - field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'), + model_name='subscription', + name='users', + field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL), ), migrations.CreateModel( - name='CarSpecification', + name='SalesOrder', fields=[ - ('id_car_specification', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), + ('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')), + ('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')), + ], + ), + migrations.CreateModel( + name='SaleQuotationCar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.PositiveIntegerField(default=1, verbose_name='Quantity')), + ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car')), + ('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation')), + ], + ), + migrations.CreateModel( + name='Representative', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Name')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('id_number', models.CharField(max_length=10, verbose_name='ID Number')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')), + ('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')), ], options={ - 'verbose_name': 'Specification', + 'verbose_name': 'Representative', + 'verbose_name_plural': 'Representatives', }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), + migrations.CreateModel( + name='Refund', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), + ('reason', models.TextField(blank=True, verbose_name='reason')), + ('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')), + ('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')), + ], + options={ + 'verbose_name': 'refund', + 'verbose_name_plural': 'refunds', + }, + ), + migrations.AddField( + model_name='payment', + name='quotation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'), + ), + migrations.AddField( + model_name='customer', + name='dealer', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer'), + ), + migrations.CreateModel( + name='CustomCard', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')), + ('custom_date', models.DateField(verbose_name='Custom Date')), + ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')), + ], + options={ + 'verbose_name': 'Custom Card', + 'verbose_name_plural': 'Custom Cards', + }, + ), migrations.CreateModel( name='CarTrim', fields=[ @@ -245,66 +391,20 @@ class Migration(migrations.Migration): 'verbose_name': 'Specification Value', }, ), - migrations.AddField( - model_name='car', - name='id_car_trim', - field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'), - ), migrations.CreateModel( - name='CustomCard', + name='CarRegistration', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')), - ('custom_date', models.DateField(verbose_name='Custom Date')), - ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')), + ('plate_number', models.IntegerField(verbose_name='Plate Number')), + ('text1', models.CharField(max_length=1, verbose_name='Text 1')), + ('text2', models.CharField(max_length=1, verbose_name='Text 2')), + ('text3', models.CharField(max_length=1, verbose_name='Text 3')), + ('registration_date', models.DateTimeField(verbose_name='Registration Date')), + ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')), ], options={ - 'verbose_name': 'Custom Card', - 'verbose_name_plural': 'Custom Cards', - }, - ), - migrations.CreateModel( - name='Dealer', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('crn', models.CharField(blank=True, max_length=10, null=True, verbose_name='Commercial Registration Number')), - ('vrn', models.CharField(blank=True, max_length=15, null=True, verbose_name='VAT Registration Number')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('name', models.CharField(max_length=255, verbose_name='English Name')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('logo', models.ImageField(blank=True, null=True, upload_to='logos/users', verbose_name='Logo')), - ('joined_at', models.DateTimeField(auto_now_add=True, verbose_name='Joined At')), - ('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), - ('dealer_type', models.CharField(choices=[('Owner', 'Owner'), ('Inventory', 'Inventory'), ('Accountent', 'Accountent'), ('sales', 'Sales')], default='Owner', max_length=255, verbose_name='Dealer Type')), - ('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel')), - ('parent_dealer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_dealers', to='inventory.dealer', verbose_name='Parent Dealer')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Dealer', - 'verbose_name_plural': 'Dealers', - 'permissions': [('change_dealer_type', 'Can change dealer type')], - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='Customer', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('first_name', models.CharField(max_length=50, verbose_name='First Name')), - ('middle_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Middle Name')), - ('last_name', models.CharField(max_length=50, verbose_name='Last Name')), - ('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), - ('national_id', models.CharField(max_length=10, unique=True, verbose_name='National ID')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')), - ], - options={ - 'verbose_name': 'Customer', - 'verbose_name_plural': 'Customers', + 'verbose_name': 'Registration', + 'verbose_name_plural': 'Registrations', }, ), migrations.CreateModel( @@ -323,152 +423,56 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Car Locations', }, ), + migrations.CreateModel( + name='CarFinance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')), + ('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')), + ('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')), + ('additional_services', models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices')), + ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')), + ], + options={ + 'verbose_name': 'Car Financial Details', + 'verbose_name_plural': 'Car Financial Details', + }, + ), migrations.AddField( model_name='car', name='dealer', field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'), ), migrations.AddField( - model_name='additionalservices', - name='dealer', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'), - ), - migrations.CreateModel( - name='Organization', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')), - ('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')), - ], - options={ - 'verbose_name': 'Organization', - 'verbose_name_plural': 'Organizations', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='Refund', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), - ('reason', models.TextField(blank=True, verbose_name='reason')), - ('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')), - ('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')), - ], - options={ - 'verbose_name': 'refund', - 'verbose_name_plural': 'refunds', - }, - ), - migrations.CreateModel( - name='Representative', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('id_number', models.CharField(max_length=10, verbose_name='ID Number')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')), - ('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')), - ], - options={ - 'verbose_name': 'Representative', - 'verbose_name_plural': 'Representatives', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='SaleQuotation', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('quotation_number', models.CharField(max_length=10, unique=True)), - ('amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount')), - ('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')), - ('is_approved', models.BooleanField(default=False)), - ('status', models.CharField(choices=[('Draft', 'Draft'), ('Approved', 'Approved'), ('In Review', 'In Review'), ('Paid', 'Paid')], default='Draft', max_length=10, verbose_name='Status')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')), - ('posted', models.BooleanField(default=False)), - ('payment_id', models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment ID')), - ('is_paid', models.BooleanField(default=False)), - ('date_draft', models.DateTimeField(blank=True, null=True, verbose_name='Draft Date')), - ('date_in_review', models.DateTimeField(blank=True, null=True, verbose_name='In Review Date')), - ('date_approved', models.DateTimeField(blank=True, null=True, verbose_name='Approved Date')), - ('date_paid', models.DateTimeField(blank=True, null=True, verbose_name='Paid Date')), - ('date_void', models.DateTimeField(blank=True, null=True, verbose_name='Void Date')), - ('date_canceled', models.DateTimeField(blank=True, null=True, verbose_name='Canceled Date')), - ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer')), - ('dealer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer')), - ], + model_name='car', + name='id_car_make', + field=models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'), ), migrations.AddField( - model_name='payment', - name='quotation', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'), - ), - migrations.CreateModel( - name='SaleQuotationCar', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('quantity', models.PositiveIntegerField(default=1, verbose_name='Quantity')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car')), - ('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation')), - ], - ), - migrations.CreateModel( - name='SalesOrder', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), - ('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')), - ('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')), - ], - ), - migrations.CreateModel( - name='SubscriptionUser', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], + model_name='car', + name='id_car_model', + field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'), ), migrations.AddField( - model_name='subscription', - name='users', - field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL), + model_name='car', + name='id_car_serie', + field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'), ), - migrations.CreateModel( - name='Vendor', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('crn', models.CharField(max_length=10, unique=True, verbose_name='Commercial Registration Number')), - ('vrn', models.CharField(max_length=15, unique=True, verbose_name='VAT Registration Number')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('name', models.CharField(max_length=255, verbose_name='English Name')), - ('contact_person', models.CharField(max_length=100, verbose_name='Contact Person')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')), - ], - options={ - 'verbose_name': 'Vendor', - 'verbose_name_plural': 'Vendors', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), + migrations.AddField( + model_name='car', + name='id_car_trim', + field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'), ), migrations.AddField( model_name='car', name='vendor', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.vendor', verbose_name='Vendor'), ), + migrations.AddField( + model_name='additionalservices', + name='dealer', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'), + ), migrations.CreateModel( name='CarReservation', fields=[ diff --git a/inventory/migrations/0002_alter_dealer_user.py b/inventory/migrations/0002_alter_dealer_user.py new file mode 100644 index 00000000..eb26ff82 --- /dev/null +++ b/inventory/migrations/0002_alter_dealer_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.17 on 2024-12-26 14:19 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('inventory', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='dealer', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/inventory/migrations/0003_alter_dealer_email.py b/inventory/migrations/0003_alter_dealer_email.py new file mode 100644 index 00000000..c81e2d07 --- /dev/null +++ b/inventory/migrations/0003_alter_dealer_email.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.17 on 2024-12-26 15:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0002_alter_dealer_user'), + ] + + operations = [ + migrations.AlterField( + model_name='dealer', + name='email', + field=models.EmailField(max_length=100, null=True, unique=True, verbose_name='Email'), + ), + ] diff --git a/inventory/migrations/0004_alter_dealer_email_alter_dealer_phone_number.py b/inventory/migrations/0004_alter_dealer_email_alter_dealer_phone_number.py new file mode 100644 index 00000000..2fa79282 --- /dev/null +++ b/inventory/migrations/0004_alter_dealer_email_alter_dealer_phone_number.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.17 on 2024-12-26 15:51 + +from django.db import migrations, models +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0003_alter_dealer_email'), + ] + + operations = [ + migrations.AlterField( + model_name='dealer', + name='email', + field=models.EmailField(default='a@a.com', max_length=100, unique=True, verbose_name='Email'), + preserve_default=False, + ), + migrations.AlterField( + model_name='dealer', + name='phone_number', + field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number'), + ), + ] diff --git a/inventory/migrations/0005_alter_dealer_user.py b/inventory/migrations/0005_alter_dealer_user.py new file mode 100644 index 00000000..4375e77b --- /dev/null +++ b/inventory/migrations/0005_alter_dealer_user.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.17 on 2024-12-26 15:57 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('inventory', '0004_alter_dealer_email_alter_dealer_phone_number'), + ] + + operations = [ + migrations.AlterField( + model_name='dealer', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/inventory/models.py b/inventory/models.py index 9009ca6c..7adc2d81 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -504,7 +504,7 @@ class Dealer(models.Model, LocalizedNameMixin): vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number"),null=True,blank=True) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) name = models.CharField(max_length=255, verbose_name=_("English Name")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"),unique=True) address = models.CharField( max_length=200, blank=True, null=True, verbose_name=_("Address") ) @@ -513,7 +513,7 @@ class Dealer(models.Model, LocalizedNameMixin): ) entity = models.ForeignKey(EntityModel, on_delete=models.SET_NULL, null=True, blank=True) joined_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Joined At")) - email = models.EmailField(unique=True, verbose_name=_("Email")) + email = models.EmailField(verbose_name="Email", unique=True, max_length=100) parent_dealer = models.ForeignKey( "self", on_delete=models.SET_NULL, @@ -529,6 +529,7 @@ class Dealer(models.Model, LocalizedNameMixin): default=DEALER_TYPES.Owner, ) + @property def get_active_plan(self): try: diff --git a/inventory/signals.py b/inventory/signals.py index 54ed0a11..37c30f38 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -25,23 +25,25 @@ User = get_user_model() # if user: # user.delete() -@receiver(post_save, sender=User) -def create_dealer(instance, created, *args, **kwargs): - if created: - models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email) +# @receiver(post_save, sender=User) +# def create_dealer(instance, created, *args, **kwargs): +# if created: +# if not instance.dealer: + +# models.Dealer.objects.create(user=instance,name=instance.username,email=instance.email) -@receiver(post_save, sender=models.Dealer) -def create_user_account(sender, instance, created, **kwargs): - if created: - if instance.dealer_type != "Owner": - user = User.objects.create_user( - username=instance.name, - email=instance.email, - ) - user.set_password("Tenhal@123") - user.save() - instance.user = user - instance.save() +# @receiver(post_save, sender=models.Dealer) +# def create_user_account(sender, instance, created, **kwargs): +# if created: +# if instance.dealer_type != "Owner": +# user = User.objects.create_user( +# username=instance.name, +# email=instance.email, +# ) +# user.set_password("Tenhal@123") +# user.save() +# instance.user = user +# instance.save() @receiver(post_save, sender=models.Car) def create_car_location(sender, instance, created, **kwargs): @@ -81,108 +83,108 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs): # Create Entity -@receiver(post_save, sender=models.Dealer) -def create_ledger_entity(sender, instance, created, **kwargs): - if created: - root_dealer = instance.get_root_dealer - if not root_dealer.entity: - entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}" - entity = EntityModel.create_entity( - name=entity_name, - admin=root_dealer.user, - use_accrual_method=False, - fy_start_month=1, - ) +# @receiver(post_save, sender=models.Dealer) +# def create_ledger_entity(sender, instance, created, **kwargs): +# if created: +# root_dealer = instance.get_root_dealer +# if not root_dealer.entity: +# entity_name = f"{root_dealer.name}-{root_dealer.joined_at.date()}" +# entity = EntityModel.create_entity( +# name=entity_name, +# admin=root_dealer.user, +# use_accrual_method=False, +# fy_start_month=1, +# ) - if entity: - instance.entity = entity - instance.save() - coa = entity.create_chart_of_accounts( - assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA") - ) - if coa: - # entity.populate_default_coa(activate_accounts=True, coa_model=coa) - print(f"Ledger entity created for Dealer: {instance.name}") +# if entity: +# instance.entity = entity +# instance.save() +# coa = entity.create_chart_of_accounts( +# assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA") +# ) +# if coa: +# # entity.populate_default_coa(activate_accounts=True, coa_model=coa) +# print(f"Ledger entity created for Dealer: {instance.name}") - # Create Cash Account - entity.create_account( - coa_model=coa, - code="1010", - role=roles.ASSET_CA_CASH, - name=_("Cash"), - balance_type="debit", - active=True, - ) +# # Create Cash Account +# entity.create_account( +# coa_model=coa, +# code="1010", +# role=roles.ASSET_CA_CASH, +# name=_("Cash"), +# balance_type="debit", +# active=True, +# ) - # Create Accounts Receivable Account - entity.create_account( - coa_model=coa, - code="1020", - role=roles.ASSET_CA_RECEIVABLES, - name=_("Accounts Receivable"), - balance_type="debit", - active=True, - ) +# # Create Accounts Receivable Account +# entity.create_account( +# coa_model=coa, +# code="1020", +# role=roles.ASSET_CA_RECEIVABLES, +# name=_("Accounts Receivable"), +# balance_type="debit", +# active=True, +# ) - # Create Inventory Account - entity.create_account( - coa_model=coa, - code="1030", - role=roles.ASSET_CA_INVENTORY, - name=_("Inventory"), - balance_type="debit", - active=True, - ) +# # Create Inventory Account +# entity.create_account( +# coa_model=coa, +# code="1030", +# role=roles.ASSET_CA_INVENTORY, +# name=_("Inventory"), +# balance_type="debit", +# active=True, +# ) - # Create Accounts Payable Account - entity.create_account( - coa_model=coa, - code="2010", - role=roles.LIABILITY_CL_ACC_PAYABLE, - name=_("Accounts Payable"), - balance_type="credit", - active=True, - ) +# # Create Accounts Payable Account +# entity.create_account( +# coa_model=coa, +# code="2010", +# role=roles.LIABILITY_CL_ACC_PAYABLE, +# name=_("Accounts Payable"), +# balance_type="credit", +# active=True, +# ) - # Create Sales Revenue Account - entity.create_account( - coa_model=coa, - code="4010", - role=roles.INCOME_OPERATIONAL, - name=_("Sales Revenue"), - balance_type="credit", - active=True, - ) +# # Create Sales Revenue Account +# entity.create_account( +# coa_model=coa, +# code="4010", +# role=roles.INCOME_OPERATIONAL, +# name=_("Sales Revenue"), +# balance_type="credit", +# active=True, +# ) - # Create Cost of Goods Sold Account - entity.create_account( - coa_model=coa, - code="5010", - role=roles.COGS, - name=_("Cost of Goods Sold"), - balance_type="debit", - active=True, - ) +# # Create Cost of Goods Sold Account +# entity.create_account( +# coa_model=coa, +# code="5010", +# role=roles.COGS, +# name=_("Cost of Goods Sold"), +# balance_type="debit", +# active=True, +# ) - # Create Rent Expense Account - entity.create_account( - coa_model=coa, - code="6010", - role=roles.EXPENSE_OPERATIONAL, - name=_("Rent Expense"), - balance_type="debit", - active=True, - ) +# # Create Rent Expense Account +# entity.create_account( +# coa_model=coa, +# code="6010", +# role=roles.EXPENSE_OPERATIONAL, +# name=_("Rent Expense"), +# balance_type="debit", +# active=True, +# ) - # Create Utilities Expense Account - entity.create_account( - coa_model=coa, - code="6020", - role=roles.EXPENSE_OPERATIONAL, - name=_("Utilities Expense"), - balance_type="debit", - active=True, - ) +# # Create Utilities Expense Account +# entity.create_account( +# coa_model=coa, +# code="6020", +# role=roles.EXPENSE_OPERATIONAL, +# name=_("Utilities Expense"), +# balance_type="debit", +# active=True, +# ) # uom_name = _("Unit") # unit_abbr = _("U") diff --git a/inventory/urls.py b/inventory/urls.py index 1b6d75e5..d2011de3 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -13,7 +13,8 @@ urlpatterns = [ # Accounts URLs path('login/', allauth_views.LoginView.as_view(template_name='account/login.html'), name='account_login'), path('logout/', allauth_views.LogoutView.as_view(template_name='account/logout.html'), name='account_logout'), - path('signup/', allauth_views.SignupView.as_view(template_name='account/signup.html'), name='account_signup'), +# path('signup/', allauth_views.SignupView.as_view(template_name='account/signup.html'), name='account_signup'), + path('signup/', views.SignupView, name='account_signup'), path('password/change/', allauth_views.PasswordChangeView.as_view(template_name='account/password_change.html'), name='account_change_password'), diff --git a/inventory/views.py b/inventory/views.py index 296c37b6..3ebcd2ce 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -33,7 +33,7 @@ from django.forms import ChoiceField, ModelForm, RadioSelect from django.urls import reverse, reverse_lazy from django.contrib import messages from django.db.models import Sum, F, Count - +from django.db import transaction from inventory.mixins import AddDealerInstanceMixin from .services import elm, decodevin, get_make, get_model, normalize_name @@ -53,8 +53,7 @@ from django.contrib.messages.views import SuccessMessageMixin from django.contrib.auth.models import Group from django.contrib.auth import get_user_model from .utils import get_calculations - -User = get_user_model() +from django.contrib.auth.models import User logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) @@ -95,6 +94,51 @@ def switch_language(request): logger.warning(f"Invalid language code: {language}") return redirect("/") +def SignupView(request): + if request.method == "POST": + data = json.loads(request.body) + wf1 = data.get("wizardValidationForm1") + wf2 = data.get("wizardValidationForm2") + wf3 = data.get("wizardValidationForm3") + name = wf1.get("name") + arabic_name = wf1.get("arabic_name") + email = wf1.get("email") + phone = wf2.get("phone_number") + crn = wf2.get("crn") + vrn = wf2.get("vrn") + address = wf2.get("address") + password = wf3.get("password") + password_confirm = wf3.get("confirm_password") + + if password != password_confirm: + return JsonResponse({"error": "Passwords do not match."}, status=400) + + try: + with transaction.atomic(): + user = User.objects.create(username=name, email=email) + user.set_password(password) + user.save() + models.Dealer.objects.create_or_update( + user=user, + name=name, + arabic_name=arabic_name, + crn=crn, + vrn=vrn, + email=email, + phone_number=phone, + address=address, + dealer_type="Owner", + ) + print("User created successfully.") + return JsonResponse({"message": "User created successfully."}, status=200) + except Exception as e: + print("Error creating user:", e) + return JsonResponse({"error": str(e)}, status=400) + + form1 = forms.WizardForm1() + form2 = forms.WizardForm2() + form3 = forms.WizardForm3() + return render(request, "account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3}) class HomeView(LoginRequiredMixin, TemplateView): template_name = "dashboards/accounting.html" diff --git a/static/js/config.js b/static/js/config.js index be899a8e..a1967422 100644 --- a/static/js/config.js +++ b/static/js/config.js @@ -85,6 +85,7 @@ if (!!JSON.parse(localStorage.getItem('phoenixIsNavbarVerticalCollapsed'))) { document.documentElement.classList.add('navbar-vertical-collapsed'); } + if (localStorage.getItem('phoenixTheme') === 'dark') { document.documentElement.setAttribute('data-bs-theme', 'dark'); @@ -102,7 +103,7 @@ if (localStorage.getItem('phoenixNavbarPosition') === 'combo') { document.documentElement.setAttribute('data-navigation-type', 'combo'); } - + var config = { config: CONFIG, reset: resetConfig, diff --git a/static/js/phoenix.js b/static/js/phoenix.js index 20424879..85bc0880 100644 --- a/static/js/phoenix.js +++ b/static/js/phoenix.js @@ -1652,6 +1652,7 @@ /* -------------------------------------------------------------------------- */ const createBoardInit = () => { const { getData } = window.phoenix.utils; + const submit_btn = document.querySelector('#submit_btn'); const selectors = { CREATE_BOARD: '[data-create-board]', TOGGLE_BUTTON_EL: '[data-wizard-step]', @@ -1727,6 +1728,8 @@ } }; + + /* -------------------------------------------------------------------------- */ /* Detector */ /* -------------------------------------------------------------------------- */ diff --git a/templates/account/signup-wizard.html b/templates/account/signup-wizard.html new file mode 100644 index 00000000..5995ae98 --- /dev/null +++ b/templates/account/signup-wizard.html @@ -0,0 +1,65 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} +{% load i18n %} + + +{% block content %} +


Now you can access your account
anytime anywhere