diff --git a/haikalbot/migrations/0001_initial.py b/haikalbot/migrations/0001_initial.py index c8e7dec7..45d94ed1 100644 --- a/haikalbot/migrations/0001_initial.py +++ b/haikalbot/migrations/0001_initial.py @@ -1,6 +1,5 @@ -# Generated by Django 5.1.4 on 2024-12-22 21:55 +# Generated by Django 4.2.17 on 2024-12-26 10:12 -import django.db.models.deletion from django.db import migrations, models @@ -9,7 +8,6 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('inventory', '0001_initial'), ] operations = [ @@ -20,7 +18,6 @@ class Migration(migrations.Migration): ('user_message', models.TextField()), ('chatbot_response', models.TextField()), ('timestamp', models.DateTimeField(auto_now_add=True)), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer')), ], ), ] diff --git a/haikalbot/migrations/0002_initial.py b/haikalbot/migrations/0002_initial.py new file mode 100644 index 00000000..28c8cd2c --- /dev/null +++ b/haikalbot/migrations/0002_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.17 on 2024-12-26 10:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('haikalbot', '0001_initial'), + ('inventory', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='chatlog', + name='dealer', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer'), + ), + ] 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 aa3b2b0b..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-09 13:58 +# Generated by Django 4.2.17 on 2024-12-26 10:12 -import django.db.models.deletion -import inventory.mixins -import phonenumber_field.modelfields from decimal import Decimal from 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): @@ -14,16 +14,34 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('django_ledger', '0017_alter_accountmodel_unique_together_and_more'), ] operations = [ + migrations.CreateModel( + name='AdditionalServices', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Name')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('description', models.TextField(verbose_name='Description')), + ('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')), + ('taxable', models.BooleanField(default=False, verbose_name='taxable')), + ('uom', models.CharField(choices=[('Kg', 'Kg'), ('L', 'L'), ('m', 'm'), ('cm', 'cm'), ('m2', 'm2'), ('m3', 'm3'), ('m3', 'm3')], max_length=10, verbose_name='Unit of Measurement')), + ], + options={ + 'verbose_name': 'Additional Services', + 'verbose_name_plural': 'Additional Services', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), migrations.CreateModel( name='Car', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('vin', models.CharField(max_length=17, unique=True, verbose_name='VIN')), ('year', models.IntegerField(verbose_name='Year')), - ('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged')], default='available', max_length=10, verbose_name='Status')), + ('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status')), ('stock_type', models.CharField(choices=[('new', 'New'), ('used', 'Used')], default='new', max_length=10, verbose_name='Stock Type')), ('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')), ('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')), @@ -48,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=[ @@ -77,203 +179,81 @@ class Migration(migrations.Migration): bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), migrations.CreateModel( - name='CarFinance', + name='Organization', 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')), - ('profit_margin', models.DecimalField(decimal_places=2, editable=False, max_digits=14, verbose_name='Profit Margin')), - ('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')), - ('registration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Registration Fee')), - ('administration_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Administration Fee')), - ('transportation_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Transportation Fee')), - ('custom_card_fee', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Custom Card Fee')), - ('vat_rate', models.DecimalField(decimal_places=2, default=Decimal('0.15'), max_digits=14, verbose_name='VAT Rate')), - ('administration_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Administration VAT')), - ('transportation_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Transportation VAT')), - ('custom_card_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Custom Card VAT')), - ('selling_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Selling VAT')), - ('total_vat_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=12, verbose_name='Total VAT')), - ('total_before_vat', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Before VAT')), - ('total', models.DecimalField(decimal_places=2, default=Decimal('0.00'), editable=False, max_digits=14, verbose_name='Total Amount')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')), - ], - ), - migrations.AddField( - model_name='car', - name='id_car_make', - field=models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'), - ), - migrations.CreateModel( - name='CarModel', - fields=[ - ('id_car_model', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('id_car_make', models.ForeignKey(db_column='id_car_make', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake')), - ], - options={ - 'verbose_name': 'Model', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.AddField( - model_name='car', - name='id_car_model', - field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'), - ), - migrations.CreateModel( - name='CarRegistration', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('plate_number', models.IntegerField(verbose_name='Plate Number')), - ('text1', models.CharField(max_length=1, verbose_name='Text 1')), - ('text2', models.CharField(max_length=1, verbose_name='Text 2')), - ('text3', models.CharField(max_length=1, verbose_name='Text 3')), - ('registration_date', models.DateTimeField(verbose_name='Registration Date')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')), - ], - options={ - 'verbose_name': 'Registration', - 'verbose_name_plural': 'Registrations', - }, - ), - migrations.CreateModel( - name='CarSerie', - fields=[ - ('id_car_serie', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('id_car_model', models.ForeignKey(db_column='id_car_model', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')), - ], - options={ - 'verbose_name': 'Series', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.AddField( - model_name='car', - name='id_car_serie', - field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'), - ), - migrations.CreateModel( - name='CarSpecification', - fields=[ - ('id_car_specification', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('id_parent', models.ForeignKey(blank=True, db_column='id_parent', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')), - ], - options={ - 'verbose_name': 'Specification', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='CarTrim', - fields=[ - ('id_car_trim', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('arabic_name', models.CharField(max_length=255)), - ('start_production_year', models.IntegerField(blank=True, null=True)), - ('end_production_year', models.IntegerField(blank=True, null=True)), - ('id_car_serie', models.ForeignKey(db_column='id_car_serie', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie')), - ], - options={ - 'verbose_name': 'Trim', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='CarSpecificationValue', - fields=[ - ('id_car_specification_value', models.AutoField(primary_key=True, serialize=False)), - ('value', models.CharField(max_length=500)), - ('unit', models.CharField(blank=True, max_length=255, null=True)), - ('id_car_specification', models.ForeignKey(db_column='id_car_specification', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')), - ('id_car_trim', models.ForeignKey(db_column='id_car_trim', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim')), - ], - options={ - 'verbose_name': 'Specification Value', - }, - ), - migrations.AddField( - model_name='car', - name='id_car_trim', - field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'), - ), - migrations.CreateModel( - name='CustomCard', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')), - ('custom_date', models.DateField(verbose_name='Custom Date')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')), - ], - options={ - 'verbose_name': 'Custom Card', - 'verbose_name_plural': 'Custom Cards', - }, - ), - migrations.CreateModel( - name='Dealer', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('crn', models.CharField(max_length=10, verbose_name='Commercial Registration Number')), - ('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')), + ('name', models.CharField(max_length=255, verbose_name='Name')), ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('name', models.CharField(max_length=255, verbose_name='English Name')), + ('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')), + ('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')), ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), ('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')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)), + ('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': 'Dealer', - 'verbose_name_plural': 'Dealers', + 'verbose_name': 'Organization', + 'verbose_name_plural': 'Organizations', }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), migrations.CreateModel( - name='Customer', + name='Payment', 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')), + ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), + ('payment_method', models.CharField(choices=[('cash', 'cash'), ('credit', 'credit'), ('transfer', 'transfer'), ('debit', 'debit'), ('SADAD', 'SADAD')], max_length=50, verbose_name='method')), + ('reference_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='reference number')), + ('payment_date', models.DateField(auto_now_add=True, verbose_name='date')), ], options={ - 'verbose_name': 'Customer', - 'verbose_name_plural': 'Customers', + 'verbose_name': 'payment', + 'verbose_name_plural': 'payments', }, ), - migrations.AddField( - model_name='car', - name='dealer', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'), - ), migrations.CreateModel( name='SaleQuotation', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('remarks', models.TextField(blank=True, null=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.customer')), + ('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='SaleQuotationCar', + name='Subscription', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car')), - ('financial_details', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_finances', to='inventory.carfinance')), - ('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation')), + ('plan', models.CharField(max_length=255)), + ('start_date', models.DateField()), + ('end_date', models.DateField()), + ('max_users', models.IntegerField()), + ('is_active', models.BooleanField(default=True)), + ], + ), + migrations.CreateModel( + name='SubscriptionPlan', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField()), + ('price', models.DecimalField(decimal_places=2, max_digits=10)), + ('max_users', models.IntegerField()), ], ), migrations.CreateModel( @@ -296,21 +276,215 @@ class Migration(migrations.Migration): }, bases=(models.Model, inventory.mixins.LocalizedNameMixin), ), + migrations.CreateModel( + name='SubscriptionUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='subscription', + name='users', + field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL), + ), + migrations.CreateModel( + name='SalesOrder', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), + ('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')), + ('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')), + ], + ), + migrations.CreateModel( + name='SaleQuotationCar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.PositiveIntegerField(default=1, verbose_name='Quantity')), + ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car')), + ('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation')), + ], + ), + migrations.CreateModel( + name='Representative', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Name')), + ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), + ('id_number', models.CharField(max_length=10, verbose_name='ID Number')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), + ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), + ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')), + ('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')), + ], + options={ + 'verbose_name': 'Representative', + 'verbose_name_plural': 'Representatives', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), + migrations.CreateModel( + name='Refund', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), + ('reason', models.TextField(blank=True, verbose_name='reason')), + ('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')), + ('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')), + ], + options={ + 'verbose_name': 'refund', + 'verbose_name_plural': 'refunds', + }, + ), + migrations.AddField( + model_name='payment', + name='quotation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'), + ), + migrations.AddField( + model_name='customer', + name='dealer', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer'), + ), + migrations.CreateModel( + name='CustomCard', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('custom_number', models.CharField(max_length=255, verbose_name='Custom Number')), + ('custom_date', models.DateField(verbose_name='Custom Date')), + ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car')), + ], + options={ + 'verbose_name': 'Custom Card', + 'verbose_name_plural': 'Custom Cards', + }, + ), + migrations.CreateModel( + name='CarTrim', + fields=[ + ('id_car_trim', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255)), + ('arabic_name', models.CharField(max_length=255)), + ('start_production_year', models.IntegerField(blank=True, null=True)), + ('end_production_year', models.IntegerField(blank=True, null=True)), + ('id_car_model', models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel')), + ('id_car_serie', models.ForeignKey(db_column='id_car_serie', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie')), + ], + options={ + 'verbose_name': 'Trim', + }, + bases=(models.Model, inventory.mixins.LocalizedNameMixin), + ), + migrations.CreateModel( + name='CarSpecificationValue', + fields=[ + ('id_car_specification_value', models.AutoField(primary_key=True, serialize=False)), + ('value', models.CharField(max_length=500)), + ('unit', models.CharField(blank=True, max_length=255, null=True)), + ('id_car_specification', models.ForeignKey(db_column='id_car_specification', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carspecification')), + ('id_car_trim', models.ForeignKey(db_column='id_car_trim', on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim')), + ], + options={ + 'verbose_name': 'Specification Value', + }, + ), + migrations.CreateModel( + name='CarRegistration', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('plate_number', models.IntegerField(verbose_name='Plate Number')), + ('text1', models.CharField(max_length=1, verbose_name='Text 1')), + ('text2', models.CharField(max_length=1, verbose_name='Text 2')), + ('text3', models.CharField(max_length=1, verbose_name='Text 3')), + ('registration_date', models.DateTimeField(verbose_name='Registration Date')), + ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='inventory.car', verbose_name='Car')), + ], + options={ + 'verbose_name': 'Registration', + 'verbose_name_plural': 'Registrations', + }, + ), + migrations.CreateModel( + name='CarLocation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField(blank=True, help_text='Optional description about the showroom placement.', null=True, verbose_name='Description')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Updated')), + ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='location', to='inventory.car', verbose_name='Car')), + ('owner', models.ForeignKey(help_text='Dealer who owns the car.', on_delete=django.db.models.deletion.CASCADE, related_name='owned_cars', to='inventory.dealer', verbose_name='Owner')), + ('showroom', models.ForeignKey(help_text='Dealer where the car is displayed (can be the owner).', on_delete=django.db.models.deletion.CASCADE, related_name='showroom_cars', to='inventory.dealer', verbose_name='Showroom')), + ], + options={ + 'verbose_name': 'Car Location', + 'verbose_name_plural': 'Car Locations', + }, + ), + migrations.CreateModel( + name='CarFinance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cost_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Cost Price')), + ('selling_price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Selling Price')), + ('discount_amount', models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=14, verbose_name='Discount Amount')), + ('additional_services', models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices')), + ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car')), + ], + options={ + 'verbose_name': 'Car Financial Details', + 'verbose_name_plural': 'Car Financial Details', + }, + ), + migrations.AddField( + model_name='car', + name='dealer', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'), + ), + migrations.AddField( + model_name='car', + name='id_car_make', + field=models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'), + ), + migrations.AddField( + model_name='car', + name='id_car_model', + field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'), + ), + migrations.AddField( + model_name='car', + name='id_car_serie', + field=models.ForeignKey(blank=True, db_column='id_car_serie', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carserie', verbose_name='Series'), + ), + migrations.AddField( + model_name='car', + name='id_car_trim', + field=models.ForeignKey(blank=True, db_column='id_car_trim', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.cartrim', verbose_name='Trim'), + ), migrations.AddField( 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=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('reserved_at', models.DateTimeField(auto_now_add=True)), - ('reserved_until', models.DateTimeField()), - ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car')), - ('reserved_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('reserved_at', models.DateTimeField(auto_now_add=True, verbose_name='Reserved At')), + ('reserved_until', models.DateTimeField(verbose_name='Reserved Until')), + ('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car', verbose_name='Car')), + ('reserved_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to=settings.AUTH_USER_MODEL, verbose_name='Reserved By')), ], options={ + 'verbose_name': 'Car Reservation', + 'verbose_name_plural': 'Car Reservations', 'ordering': ['-reserved_at'], 'unique_together': {('car', 'reserved_until')}, }, diff --git a/inventory/migrations/0002_additionalservices_subscription_subscriptionplan_and_more.py b/inventory/migrations/0002_additionalservices_subscription_subscriptionplan_and_more.py deleted file mode 100644 index 698a9aad..00000000 --- a/inventory/migrations/0002_additionalservices_subscription_subscriptionplan_and_more.py +++ /dev/null @@ -1,335 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-22 21:55 - -import django.db.models.deletion -import inventory.mixins -import phonenumber_field.modelfields -from decimal import Decimal -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('django_ledger', '0017_alter_accountmodel_unique_together_and_more'), - ('inventory', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='AdditionalServices', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('display_name', models.CharField(max_length=255, verbose_name='Display Name')), - ('description', models.TextField(verbose_name='Description')), - ('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')), - ], - options={ - 'verbose_name': 'Additional Services', - 'verbose_name_plural': 'Additional Services', - }, - ), - migrations.CreateModel( - name='Subscription', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('plan', models.CharField(max_length=255)), - ('start_date', models.DateField()), - ('end_date', models.DateField()), - ('max_users', models.IntegerField()), - ('is_active', models.BooleanField(default=True)), - ], - ), - migrations.CreateModel( - name='SubscriptionPlan', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('description', models.TextField()), - ('price', models.DecimalField(decimal_places=2, max_digits=10)), - ('max_users', models.IntegerField()), - ], - ), - migrations.AlterModelOptions( - name='carfinance', - options={'verbose_name': 'Car Financial Details', 'verbose_name_plural': 'Car Financial Details'}, - ), - migrations.AlterModelOptions( - name='carreservation', - options={'ordering': ['-reserved_at'], 'verbose_name': 'Car Reservation', 'verbose_name_plural': 'Car Reservations'}, - ), - migrations.AlterModelOptions( - name='dealer', - options={'permissions': [('change_dealer_type', 'Can change dealer type')], 'verbose_name': 'Dealer', 'verbose_name_plural': 'Dealers'}, - ), - migrations.RemoveField( - model_name='carfinance', - name='administration_fee', - ), - migrations.RemoveField( - model_name='carfinance', - name='administration_vat_amount', - ), - migrations.RemoveField( - model_name='carfinance', - name='custom_card_fee', - ), - migrations.RemoveField( - model_name='carfinance', - name='custom_card_vat_amount', - ), - migrations.RemoveField( - model_name='carfinance', - name='profit_margin', - ), - migrations.RemoveField( - model_name='carfinance', - name='registration_fee', - ), - migrations.RemoveField( - model_name='carfinance', - name='selling_vat_amount', - ), - migrations.RemoveField( - model_name='carfinance', - name='total', - ), - migrations.RemoveField( - model_name='carfinance', - name='total_before_vat', - ), - migrations.RemoveField( - model_name='carfinance', - name='total_vat_amount', - ), - migrations.RemoveField( - model_name='carfinance', - name='transportation_fee', - ), - migrations.RemoveField( - model_name='carfinance', - name='transportation_vat_amount', - ), - migrations.RemoveField( - model_name='carfinance', - name='vat_rate', - ), - migrations.RemoveField( - model_name='salequotationcar', - name='financial_details', - ), - migrations.AddField( - model_name='carserie', - name='year_begin', - field=models.IntegerField(blank=True, null=True), - ), - migrations.AddField( - model_name='carserie', - name='year_end', - field=models.IntegerField(blank=True, null=True), - ), - migrations.AddField( - model_name='cartrim', - name='id_car_model', - field=models.ForeignKey(blank=True, db_column='id_car_model', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel'), - ), - migrations.AddField( - model_name='dealer', - name='dealer_type', - field=models.CharField(choices=[('Owner', 'Owner'), ('Inventory', 'Inventory'), ('Accountent', 'Accountent'), ('sales', 'Sales')], default='Owner', max_length=255, verbose_name='Dealer Type'), - ), - migrations.AddField( - model_name='dealer', - name='parent_dealer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_dealers', to='inventory.dealer', verbose_name='Parent Dealer'), - ), - migrations.AddField( - model_name='salequotation', - name='amount', - field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount'), - ), - migrations.AddField( - model_name='salequotation', - name='dealer', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer'), - ), - migrations.AddField( - model_name='salequotation', - name='entity', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.entitymodel'), - preserve_default=False, - ), - migrations.AddField( - model_name='salequotation', - name='is_approved', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='salequotation', - name='quotation_number', - field=models.CharField(default=1, max_length=10, unique=True), - preserve_default=False, - ), - migrations.AddField( - model_name='salequotation', - name='updated_at', - field=models.DateTimeField(auto_now=True, verbose_name='Updated At'), - ), - migrations.AddField( - model_name='salequotationcar', - name='quantity', - field=models.PositiveIntegerField(default=1, verbose_name='Quantity'), - ), - migrations.AlterField( - model_name='car', - name='status', - field=models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status'), - ), - migrations.AlterField( - model_name='carfinance', - name='car', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='finances', to='inventory.car'), - ), - migrations.AlterField( - model_name='carreservation', - name='car', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.car', verbose_name='Car'), - ), - migrations.AlterField( - model_name='carreservation', - name='reserved_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='Reserved At'), - ), - migrations.AlterField( - model_name='carreservation', - name='reserved_by', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to=settings.AUTH_USER_MODEL, verbose_name='Reserved By'), - ), - migrations.AlterField( - model_name='carreservation', - name='reserved_until', - field=models.DateTimeField(verbose_name='Reserved Until'), - ), - migrations.AlterField( - model_name='customcard', - name='car', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='custom_cards', to='inventory.car', verbose_name='Car'), - ), - migrations.AlterField( - model_name='dealer', - name='crn', - field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Commercial Registration Number'), - ), - migrations.AlterField( - model_name='dealer', - name='vrn', - field=models.CharField(blank=True, max_length=15, null=True, verbose_name='VAT Registration Number'), - ), - migrations.AlterField( - model_name='salequotation', - name='created_at', - field=models.DateTimeField(auto_now_add=True, verbose_name='Created At'), - ), - migrations.AlterField( - model_name='salequotation', - name='customer', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotations', to='inventory.customer', verbose_name='Customer'), - ), - migrations.AlterField( - model_name='salequotation', - name='remarks', - field=models.TextField(blank=True, null=True, verbose_name='Remarks'), - ), - migrations.AlterField( - model_name='salequotationcar', - name='car', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car'), - ), - migrations.AlterField( - model_name='salequotationcar', - name='quotation', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation'), - ), - migrations.AddField( - model_name='carfinance', - name='additional_services', - field=models.ManyToManyField(blank=True, related_name='additional_finances', to='inventory.additionalservices'), - ), - migrations.CreateModel( - name='CarLocation', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField(blank=True, help_text='Optional description about the showroom placement.', null=True, verbose_name='Description')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), - ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Updated')), - ('car', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='location', to='inventory.car', verbose_name='Car')), - ('owner', models.ForeignKey(help_text='Dealer who owns the car.', on_delete=django.db.models.deletion.CASCADE, related_name='owned_cars', to='inventory.dealer', verbose_name='Owner')), - ('showroom', models.ForeignKey(help_text='Dealer where the car is displayed (can be the owner).', on_delete=django.db.models.deletion.CASCADE, related_name='showroom_cars', to='inventory.dealer', verbose_name='Showroom')), - ], - options={ - 'verbose_name': 'Car Location', - 'verbose_name_plural': 'Car Locations', - }, - ), - migrations.CreateModel( - name='Organization', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('crn', models.CharField(max_length=15, verbose_name='Commercial Registration Number')), - ('vrn', models.CharField(max_length=15, verbose_name='VAT Registration Number')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')), - ], - options={ - 'verbose_name': 'Organization', - 'verbose_name_plural': 'Organizations', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='Representative', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')), - ('id_number', models.CharField(max_length=10, verbose_name='ID Number')), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')), - ('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')), - ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='inventory.dealer')), - ('organization', models.ManyToManyField(related_name='representatives', to='inventory.organization')), - ], - options={ - 'verbose_name': 'Representative', - 'verbose_name_plural': 'Representatives', - }, - bases=(models.Model, inventory.mixins.LocalizedNameMixin), - ), - migrations.CreateModel( - name='SalesOrder', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), - ('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')), - ('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')), - ], - ), - migrations.CreateModel( - name='SubscriptionUser', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.subscription')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.AddField( - model_name='subscription', - name='users', - field=models.ManyToManyField(through='inventory.SubscriptionUser', to=settings.AUTH_USER_MODEL), - ), - ] 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/0003_remove_additionalservices_display_name_and_more.py b/inventory/migrations/0003_remove_additionalservices_display_name_and_more.py deleted file mode 100644 index 53fe897a..00000000 --- a/inventory/migrations/0003_remove_additionalservices_display_name_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-23 08:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0002_additionalservices_subscription_subscriptionplan_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='additionalservices', - name='display_name', - ), - migrations.AddField( - model_name='additionalservices', - name='arabic_name', - field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'), - preserve_default=False, - ), - ] 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/0004_remove_additionalservices_arabic_name.py b/inventory/migrations/0004_remove_additionalservices_arabic_name.py deleted file mode 100644 index 622ecaca..00000000 --- a/inventory/migrations/0004_remove_additionalservices_arabic_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 08:07 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0003_remove_additionalservices_display_name_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='additionalservices', - name='arabic_name', - ), - ] diff --git a/inventory/migrations/0005_additionalservices_arabic_name.py b/inventory/migrations/0005_additionalservices_arabic_name.py deleted file mode 100644 index b9056578..00000000 --- a/inventory/migrations/0005_additionalservices_arabic_name.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 08:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0004_remove_additionalservices_arabic_name'), - ] - - operations = [ - migrations.AddField( - model_name='additionalservices', - name='arabic_name', - field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'), - preserve_default=False, - ), - ] 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/migrations/0006_remove_additionalservices_arabic_name.py b/inventory/migrations/0006_remove_additionalservices_arabic_name.py deleted file mode 100644 index a2ac801f..00000000 --- a/inventory/migrations/0006_remove_additionalservices_arabic_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 08:10 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0005_additionalservices_arabic_name'), - ] - - operations = [ - migrations.RemoveField( - model_name='additionalservices', - name='arabic_name', - ), - ] diff --git a/inventory/migrations/0007_additionalservices_arabic_name.py b/inventory/migrations/0007_additionalservices_arabic_name.py deleted file mode 100644 index 013a875e..00000000 --- a/inventory/migrations/0007_additionalservices_arabic_name.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 08:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0006_remove_additionalservices_arabic_name'), - ] - - operations = [ - migrations.AddField( - model_name='additionalservices', - name='arabic_name', - field=models.CharField(default='-', max_length=255, verbose_name='Arabic Name'), - preserve_default=False, - ), - ] diff --git a/inventory/migrations/0008_salequotation_status.py b/inventory/migrations/0008_salequotation_status.py deleted file mode 100644 index cf5450ac..00000000 --- a/inventory/migrations/0008_salequotation_status.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 08:35 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0007_additionalservices_arabic_name'), - ] - - operations = [ - migrations.AddField( - model_name='salequotation', - name='status', - field=models.CharField(choices=[('DRAFT', 'Draft'), ('CONFIRMED', 'Confirmed'), ('CANCELED', 'Canceled')], default='DRAFT', max_length=10, verbose_name='Status'), - ), - ] diff --git a/inventory/migrations/0009_salequotation_date_approved_and_more.py b/inventory/migrations/0009_salequotation_date_approved_and_more.py deleted file mode 100644 index 8b31c0e9..00000000 --- a/inventory/migrations/0009_salequotation_date_approved_and_more.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 09:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0008_salequotation_status'), - ] - - operations = [ - migrations.AddField( - model_name='salequotation', - name='date_approved', - field=models.DateField(blank=True, null=True, verbose_name='Approved Date'), - ), - migrations.AddField( - model_name='salequotation', - name='date_canceled', - field=models.DateField(blank=True, null=True, verbose_name='Canceled Date'), - ), - migrations.AddField( - model_name='salequotation', - name='date_draft', - field=models.DateField(blank=True, null=True, verbose_name='Draft Date'), - ), - migrations.AddField( - model_name='salequotation', - name='date_in_review', - field=models.DateField(blank=True, null=True, verbose_name='In Review Date'), - ), - migrations.AddField( - model_name='salequotation', - name='date_paid', - field=models.DateField(blank=True, null=True, verbose_name='Paid Date'), - ), - migrations.AddField( - model_name='salequotation', - name='date_void', - field=models.DateField(blank=True, null=True, verbose_name='Void Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='status', - field=models.CharField(choices=[('Draft', 'Draft'), ('Approved', 'Approved'), ('In Review', 'In Review'), ('Paid', 'Paid')], default='Draft', max_length=10, verbose_name='Status'), - ), - ] diff --git a/inventory/migrations/0010_alter_salequotation_date_approved_and_more.py b/inventory/migrations/0010_alter_salequotation_date_approved_and_more.py deleted file mode 100644 index 6a994ae2..00000000 --- a/inventory/migrations/0010_alter_salequotation_date_approved_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 09:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0009_salequotation_date_approved_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='salequotation', - name='date_approved', - field=models.DateTimeField(blank=True, null=True, verbose_name='Approved Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='date_canceled', - field=models.DateTimeField(blank=True, null=True, verbose_name='Canceled Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='date_draft', - field=models.DateTimeField(blank=True, null=True, verbose_name='Draft Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='date_in_review', - field=models.DateTimeField(blank=True, null=True, verbose_name='In Review Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='date_paid', - field=models.DateTimeField(blank=True, null=True, verbose_name='Paid Date'), - ), - migrations.AlterField( - model_name='salequotation', - name='date_void', - field=models.DateTimeField(blank=True, null=True, verbose_name='Void Date'), - ), - ] diff --git a/inventory/migrations/0011_salequotation_posted.py b/inventory/migrations/0011_salequotation_posted.py deleted file mode 100644 index 450c6708..00000000 --- a/inventory/migrations/0011_salequotation_posted.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 10:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0010_alter_salequotation_date_approved_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='salequotation', - name='posted', - field=models.BooleanField(default=False), - ), - ] diff --git a/inventory/migrations/0012_salequotation_payment_id.py b/inventory/migrations/0012_salequotation_payment_id.py deleted file mode 100644 index 24758c73..00000000 --- a/inventory/migrations/0012_salequotation_payment_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 13:46 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0011_salequotation_posted'), - ] - - operations = [ - migrations.AddField( - model_name='salequotation', - name='payment_id', - field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Payment ID'), - ), - ] diff --git a/inventory/migrations/0013_salequotation_is_paid.py b/inventory/migrations/0013_salequotation_is_paid.py deleted file mode 100644 index c3f313d5..00000000 --- a/inventory/migrations/0013_salequotation_is_paid.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 13:46 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0012_salequotation_payment_id'), - ] - - operations = [ - migrations.AddField( - model_name='salequotation', - name='is_paid', - field=models.BooleanField(default=False), - ), - ] diff --git a/inventory/migrations/0014_payment_refund.py b/inventory/migrations/0014_payment_refund.py deleted file mode 100644 index 4e5748f9..00000000 --- a/inventory/migrations/0014_payment_refund.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-24 14:43 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0013_salequotation_is_paid'), - ] - - operations = [ - migrations.CreateModel( - name='Payment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), - ('payment_method', models.CharField(choices=[('cash', 'cash'), ('credit', 'credit'), ('transfer', 'transfer'), ('debit', 'debit'), ('SADAD', 'SADAD')], max_length=50, verbose_name='method')), - ('reference_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='reference number')), - ('payment_date', models.DateField(auto_now_add=True, verbose_name='date')), - ('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation')), - ], - options={ - 'verbose_name': 'payment', - 'verbose_name_plural': 'payments', - }, - ), - migrations.CreateModel( - name='Refund', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='amount')), - ('reason', models.TextField(blank=True, verbose_name='reason')), - ('refund_date', models.DateField(auto_now_add=True, verbose_name='refund date')), - ('payment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='refund', to='inventory.payment')), - ], - options={ - 'verbose_name': 'refund', - 'verbose_name_plural': 'refunds', - }, - ), - ] diff --git a/inventory/migrations/0015_alter_salequotation_payment_id.py b/inventory/migrations/0015_alter_salequotation_payment_id.py deleted file mode 100644 index d863d075..00000000 --- a/inventory/migrations/0015_alter_salequotation_payment_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-24 14:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0014_payment_refund'), - ] - - operations = [ - migrations.AlterField( - model_name='salequotation', - name='payment_id', - field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment ID'), - ), - ] diff --git a/inventory/migrations/0016_dealer_joined_at.py b/inventory/migrations/0016_dealer_joined_at.py deleted file mode 100644 index 501ff4c4..00000000 --- a/inventory/migrations/0016_dealer_joined_at.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-25 10:37 - -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0015_alter_salequotation_payment_id'), - ] - - operations = [ - migrations.AddField( - model_name='dealer', - name='joined_at', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Joined At'), - preserve_default=False, - ), - ] diff --git a/inventory/migrations/0017_dealer_email.py b/inventory/migrations/0017_dealer_email.py deleted file mode 100644 index 2aa8aa7f..00000000 --- a/inventory/migrations/0017_dealer_email.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-25 10:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0016_dealer_joined_at'), - ] - - operations = [ - migrations.AddField( - model_name='dealer', - name='email', - field=models.EmailField(default='email@tenhal.sa', max_length=254, unique=True, verbose_name='Email'), - preserve_default=False, - ), - ] diff --git a/inventory/migrations/0018_additionalservices_taxable.py b/inventory/migrations/0018_additionalservices_taxable.py deleted file mode 100644 index 2f9b8f65..00000000 --- a/inventory/migrations/0018_additionalservices_taxable.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.4 on 2024-12-25 17:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0017_dealer_email'), - ] - - operations = [ - migrations.AddField( - model_name='additionalservices', - name='taxable', - field=models.BooleanField(default=True, verbose_name='Taxable'), - ), - ] diff --git a/inventory/migrations/0019_remove_additionalservices_taxable_and_more.py b/inventory/migrations/0019_remove_additionalservices_taxable_and_more.py deleted file mode 100644 index 728f5f69..00000000 --- a/inventory/migrations/0019_remove_additionalservices_taxable_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-26 07:13 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0018_additionalservices_taxable'), - ] - - operations = [ - migrations.RemoveField( - model_name='additionalservices', - name='taxable', - ), - migrations.RemoveField( - model_name='salequotation', - name='entity', - ), - ] diff --git a/inventory/migrations/0020_dealer_entity.py b/inventory/migrations/0020_dealer_entity.py deleted file mode 100644 index 123c9d0d..00000000 --- a/inventory/migrations/0020_dealer_entity.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-26 07:22 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('django_ledger', '0017_alter_accountmodel_unique_together_and_more'), - ('inventory', '0019_remove_additionalservices_taxable_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='dealer', - name='entity', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel'), - ), - ] diff --git a/inventory/migrations/0031_remove_salequotation_entity.py b/inventory/migrations/0031_remove_salequotation_entity.py deleted file mode 100644 index 715069b0..00000000 --- a/inventory/migrations/0031_remove_salequotation_entity.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.17 on 2024-12-26 07:58 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('inventory', '0030_account'), - ] - - operations = [ - migrations.RemoveField( - model_name='salequotation', - name='entity', - ), - ] 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 298086a2..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" @@ -133,7 +177,7 @@ class HomeView(LoginRequiredMixin, TemplateView): class WelcomeView(TemplateView): - template_name = "default.html" + template_name = "index.html" class CarCreateView(LoginRequiredMixin, CreateView): 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 %} +
+
+ +
+
+
+
+
+ {{form1|crispy}} +
+
+
+
+ {{form2|crispy}} +
+
+
+
+ {{form3|crispy}} +
+
+
+
+
+
+
+
+
+
You are all set!
+

Now you can access your account
anytime anywhere

+
+
+
+
+
+
+ +
+ {% endblock content %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index edba6e5d..992afe40 100644 --- a/templates/base.html +++ b/templates/base.html @@ -253,7 +253,7 @@ -
+
{% if data_bs_theme == 'dark' %} haikal {% else %} @@ -683,8 +683,27 @@ - - + - diff --git a/templates/inventory/car_form.html b/templates/inventory/car_form.html index 8d8ded4c..7c37ea0f 100644 --- a/templates/inventory/car_form.html +++ b/templates/inventory/car_form.html @@ -394,21 +394,6 @@ document.addEventListener("DOMContentLoaded", function() { codeReader = new ZXing.BrowserMultiFormatReader(); let currentStream = null; -function showLoading() { - Swal.fire({ - title: "{% trans 'Please Wait' %}", - text: "{% trans 'Loading' %}...", - allowOutsideClick: false, - didOpen: () => { - Swal.showLoading(); - } - }); -} - -function hideLoading() { - Swal.close(); -} - function closeModal(){ stopScanner(); try { diff --git a/templates/welcome.html b/templates/welcome.html index bde1a109..23622fb9 100644 --- a/templates/welcome.html +++ b/templates/welcome.html @@ -23,7 +23,7 @@
@@ -58,7 +58,7 @@

{{ _("Ready to take control of your inventory?") }}

- {{ _("Join Us Today") }} + {{ _("Join Us Today") }}
{% endblock %} \ No newline at end of file