diff --git a/api/views.py b/api/views.py index 84153c37..3a57ec94 100644 --- a/api/views.py +++ b/api/views.py @@ -16,7 +16,6 @@ from django.utils.decorators import method_decorator from inventory import models as inventory_models - class LoginView(APIView): permission_classes = [permissions.AllowAny,] diff --git a/inventory/forms.py b/inventory/forms.py index 30eb24c0..019e7b92 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -58,7 +58,6 @@ import django_tables2 as tables User = get_user_model() - class AdditionalServiceForm(forms.ModelForm): """ A form used for creating and updating instances of the @@ -292,10 +291,8 @@ class CarForm( self.fields["id_car_model"].choices = [ (obj.id_car_model, obj.get_local_name()) for obj in queryset ] - if "vendor" in self.fields: - self.fields["vendor"].queryset = ledger_models.VendorModel.objects.filter( - active=True - ) + # if "vendor" in self.fields: + # self.fields["vendor"].queryset = dealer.vendors.all() class CarUpdateForm(forms.ModelForm, AddClassMixin): @@ -482,7 +479,18 @@ class VendorForm(forms.ModelForm): :ivar Meta: Inner class to define metadata for the Vendor form. :type Meta: Type[VendorForm.Meta] """ - phone_number = forms.CharField(label=_("Phone Number"),min_length=10,max_length=10,validators=[RegexValidator(regex='^05[0-9]{8}$')], required=True) + phone_number = forms.CharField( + label=_("Phone Number"), + min_length=10, + max_length=13, + validators=[ + RegexValidator( + regex=r'^(\+9665|05)[0-9]{8}$', + message=_("Enter a valid Saudi phone number (05XXXXXXXX or +9665XXXXXXXX)") + ) + ], + required=True +) contact_person = forms.CharField(label=_("Contact Person")) class Meta: diff --git a/inventory/migrations/0001_initial.py b/inventory/migrations/0001_initial.py index 57b95861..6d5005e2 100644 --- a/inventory/migrations/0001_initial.py +++ b/inventory/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.7 on 2025-05-04 16:07 +# Generated by Django 5.1.7 on 2025-05-05 16:32 import datetime import django.core.validators @@ -17,17 +17,11 @@ class Migration(migrations.Migration): initial = True dependencies = [ - # ('appointment', '0002_alter_workinghours_options'), + ('appointment', '0001_initial'), ('auth', '0012_alter_user_first_name_max_length'), ('contenttypes', '0002_remove_content_type_name'), + ('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_ENTITY_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_ESTIMATE_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_INVOICE_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_ITEM_MODEL), - migrations.swappable_dependency(settings.DJANGO_LEDGER_VENDOR_MODEL), ] operations = [ @@ -92,7 +86,7 @@ class Migration(migrations.Migration): 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')), + ('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')), ], @@ -120,7 +114,7 @@ class Migration(migrations.Migration): ('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')), ('taxable', models.BooleanField(default=False, verbose_name='taxable')), ('uom', models.CharField(choices=[('EA', 'Each'), ('PR', 'Pair'), ('SET', 'Set'), ('GAL', 'Gallon'), ('L', 'Liter'), ('M', 'Meter'), ('KG', 'Kilogram'), ('HR', 'Hour'), ('BX', 'Box'), ('RL', 'Roll'), ('PKG', 'Package'), ('DZ', 'Dozen'), ('SQ_M', 'Square Meter'), ('PC', 'Piece'), ('BDL', 'Bundle')], max_length=10, verbose_name='Unit of Measurement')), - ('item', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.DJANGO_LEDGER_ITEM_MODEL, verbose_name='Item')), + ('item', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.itemmodel', verbose_name='Item')), ], options={ 'verbose_name': 'Additional Services', @@ -140,7 +134,7 @@ class Migration(migrations.Migration): ('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')), ('receiving_date', models.DateTimeField(verbose_name='Receiving Date')), ('hash', models.CharField(blank=True, max_length=64, null=True, verbose_name='Hash')), - ('vendor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to=settings.DJANGO_LEDGER_VENDOR_MODEL, verbose_name='Vendor')), + ('vendor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='django_ledger.vendormodel', verbose_name='Vendor')), ('id_car_make', 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')), ], options={ @@ -322,7 +316,7 @@ class Migration(migrations.Migration): ('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')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')), - ('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.DJANGO_LEDGER_ENTITY_MODEL)), + ('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel')), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)), ], options={ @@ -339,7 +333,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=100)), - ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.group', verbose_name='')), + ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.group', verbose_name='Group')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='inventory.dealer')), ], ), @@ -437,13 +431,13 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('additional_info', models.JSONField(blank=True, default=dict, null=True)), - ('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), - ('bill_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), - ('bill_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), + ('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to='django_ledger.accountmodel')), + ('bill_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to='django_ledger.accountmodel')), + ('bill_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to='django_ledger.accountmodel')), ('dealer', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='settings', to='inventory.dealer')), - ('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), - ('invoice_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), - ('invoice_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)), + ('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to='django_ledger.accountmodel')), + ('invoice_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to='django_ledger.accountmodel')), + ('invoice_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to='django_ledger.accountmodel')), ], ), migrations.CreateModel( @@ -485,7 +479,7 @@ class Migration(migrations.Migration): ('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status')), ('created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Created')), ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), - ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)), + ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='django_ledger.customermodel')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer')), ('id_car_make', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')), ('id_car_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model')), @@ -584,12 +578,12 @@ class Migration(migrations.Migration): name='SaleOrder', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment_method', models.CharField(choices=[('cash', 'Cash'), ('finance', 'Finance'), ('lease', 'Lease'), ('credit_card', 'Credit Card'), ('bank_transfer', 'Bank Transfer'), ('SADAD', 'SADAD')], max_length=20)), + ('payment_method', models.CharField(choices=[('cash', 'Cash'), ('finance', 'Finance'), ('lease', 'Lease'), ('credit_card', 'Credit Card'), ('bank_transfer', 'Bank Transfer'), ('sadad', 'SADAD')], max_length=20)), ('comments', models.TextField(blank=True, null=True)), ('formatted_order_id', models.CharField(editable=False, max_length=10, unique=True)), ('created', models.DateTimeField(auto_now_add=True)), - ('estimate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL, verbose_name='Estimate')), - ('invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_INVOICE_MODEL, verbose_name='Invoice')), + ('estimate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.estimatemodel', verbose_name='Estimate')), + ('invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.invoicemodel', verbose_name='Invoice')), ], options={ 'ordering': ['-created'], @@ -599,15 +593,15 @@ class Migration(migrations.Migration): name='Schedule', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('purpose', models.CharField(choices=[('Product Demo', 'Product Demo'), ('Follow-Up Call', 'Follow-Up Call'), ('Contract Discussion', 'Contract Discussion'), ('Sales Meeting', 'Sales Meeting'), ('Support Call', 'Support Call'), ('Other', 'Other')], max_length=200)), + ('purpose', models.CharField(choices=[('product_demo', 'Product Demo'), ('follow_up_call', 'Follow-Up Call'), ('contract_discussion', 'Contract Discussion'), ('sales_meeting', 'Sales Meeting'), ('support_call', 'Support Call'), ('other', 'Other')], max_length=200)), ('scheduled_at', models.DateTimeField()), - ('scheduled_type', models.CharField(choices=[('Call', 'Call'), ('Meeting', 'Meeting'), ('Email', 'Email')], default='Call', max_length=200)), + ('scheduled_type', models.CharField(choices=[('call', 'Call'), ('meeting', 'Meeting'), ('email', 'Email')], default='Call', max_length=200)), ('duration', models.DurationField(default=datetime.timedelta(seconds=300))), ('notes', models.TextField(blank=True, null=True)), - ('status', models.CharField(choices=[('Scheduled', 'Scheduled'), ('Completed', 'Completed'), ('Canceled', 'Canceled')], default='Scheduled', max_length=200)), + ('status', models.CharField(choices=[('scheduled', 'Scheduled'), ('completed', 'Completed'), ('canceled', 'Canceled')], default='Scheduled', max_length=200)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), - ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)), + ('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='django_ledger.customermodel')), ('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='inventory.lead')), ('scheduled_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], @@ -650,9 +644,9 @@ class Migration(migrations.Migration): ('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')), ('closed', models.BooleanField(default=False, verbose_name='Closed')), ('car', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.car', verbose_name='Car')), - ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)), + ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='django_ledger.customermodel')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.dealer')), - ('estimate', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL)), + ('estimate', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to='django_ledger.estimatemodel')), ('lead', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunity', to='inventory.lead')), ('staff', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner', to='inventory.staff', verbose_name='Owner')), ], @@ -710,6 +704,7 @@ class Migration(migrations.Migration): ('logo', models.ImageField(blank=True, null=True, upload_to='logos/vendors', verbose_name='Logo')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vendors', to='inventory.dealer')), + ('vendor_model', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='django_ledger.vendormodel', verbose_name='Vendor Model')), ], options={ 'verbose_name': 'Vendor', @@ -783,6 +778,7 @@ class Migration(migrations.Migration): ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to=settings.AUTH_USER_MODEL)), ], options={ + 'verbose_name': 'Payment History', 'verbose_name_plural': 'Payment Histories', 'ordering': ['-payment_date'], 'indexes': [models.Index(fields=['transaction_id'], name='inventory_p_transac_9469f3_idx'), models.Index(fields=['user'], name='inventory_p_user_id_c31626_idx'), models.Index(fields=['status'], name='inventory_p_status_abcb77_idx'), models.Index(fields=['payment_date'], name='inventory_p_payment_b3068c_idx')], diff --git a/inventory/migrations/0002_alter_vendor_vendor_model.py b/inventory/migrations/0002_alter_vendor_vendor_model.py new file mode 100644 index 00000000..01ce0129 --- /dev/null +++ b/inventory/migrations/0002_alter_vendor_vendor_model.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.7 on 2025-05-06 12:57 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'), + ('inventory', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='vendor', + name='vendor_model', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='django_ledger.vendormodel', verbose_name='Vendor Model'), + ), + ] diff --git a/inventory/migrations/0003_alter_car_vendor.py b/inventory/migrations/0003_alter_car_vendor.py new file mode 100644 index 00000000..35ce3d2c --- /dev/null +++ b/inventory/migrations/0003_alter_car_vendor.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.7 on 2025-05-06 14:31 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0002_alter_vendor_vendor_model'), + ] + + operations = [ + migrations.AlterField( + model_name='car', + name='vendor', + field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.vendor', verbose_name='Vendor'), + ), + ] diff --git a/inventory/models.py b/inventory/models.py index da4140e9..8087eb5f 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -19,7 +19,7 @@ from phonenumber_field.modelfields import PhoneNumberField from django.utils.timezone import now from django.contrib.auth.models import Group -from inventory.utils import get_user_type +from inventory.utils import get_user_type, to_dict from .mixins import LocalizedNameMixin from django_ledger.models import EntityModel, ItemModel,EstimateModel,InvoiceModel,AccountModel,EntityManagementModel from django.contrib.contenttypes.fields import GenericForeignKey @@ -376,7 +376,7 @@ class Car(models.Model): ) vendor = models.ForeignKey( - VendorModel, + "Vendor", models.DO_NOTHING, related_name="cars", verbose_name=_("Vendor"), @@ -1471,6 +1471,9 @@ class Vendor(models.Model, LocalizedNameMixin): vrn = models.CharField( max_length=15, unique=True, verbose_name=_("VAT Registration Number") ) + vendor_model = models.ForeignKey( + VendorModel, on_delete=models.DO_NOTHING, verbose_name=_("Vendor Model"),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")) contact_person = models.CharField(max_length=100, verbose_name=_("Contact Person")) @@ -1491,6 +1494,56 @@ class Vendor(models.Model, LocalizedNameMixin): def __str__(self): return self.name + def create_vendor_model(self): + entity = self.dealer.entity + additionals = to_dict(self) + if not self.vendor_model: + vendor = entity.create_vendor( + vendor_model_kwargs={ + "vendor_name": self.name, + "vendor_number": self.crn, + "address_1": self.address, + "phone": self.phone_number, + "email": self.email, + "tax_id_number": self.vrn, + "active": True, + "hidden": False, + "additional_info": additionals, + } + ) + self.vendor_model = vendor + self.save() + + def update_vendor_model(self): + additionals = to_dict(self) + self.vendor_model.vendor_name = self.name + self.vendor_model.vendor_number = self.crn + self.vendor_model.address_1 = self.address + self.vendor_model.phone = self.phone_number + self.vendor_model.email = self.email + self.vendor_model.tax_id_number = self.vrn + self.vendor_model.additional_info = additionals + self.vendor_model.save() + + def create_vendor_account(self,role): + entity = self.dealer.entity + coa = entity.get_default_coa() + last_account = entity.get_all_accounts().filter(role=role).order_by('-created').first() + + if len(last_account.code) == 4: + code = f"{int(last_account.code)}{1:03d}" + elif len(last_account.code) > 4: + code = f"{int(last_account.code)+1}" + + if not entity.get_all_accounts().filter(name=self.name, role=role,coa_model=coa,balance_type="credit",active=True).exists(): + entity.create_account( + name=self.name, + code=code, + role=role, + coa_model=coa, + balance_type="credit", + active=True + ) class Payment(models.Model): METHOD_CHOICES = [ diff --git a/inventory/signals.py b/inventory/signals.py index 4ec99603..81a38e04 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -190,41 +190,10 @@ def create_ledger_vendor(sender, instance, created, **kwargs): :return: None """ if created: - entity = EntityModel.objects.filter(admin=instance.dealer.user).first() - additionals = to_dict(instance) - vendor = entity.create_vendor( - vendor_model_kwargs={ - "vendor_name": instance.name, - "vendor_number": instance.crn, - "address_1": instance.address, - "phone": instance.phone_number, - "email": instance.email, - "tax_id_number": instance.vrn, - "active": True, - "hidden": False, - "additional_info": additionals, - } - ) - - - coa = entity.get_default_coa() - last_account = entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).order_by('-created').first() - - # code = f"{int(last_account.code)}{1:03d}" - if len(last_account.code) == 4: - code = f"{int(last_account.code)}{1:03d}" - elif len(last_account.code) > 4: - code = f"{int(last_account.code)+1}" - - account = entity.create_account( - name=instance.name, - code=code, - role=roles.LIABILITY_CL_ACC_PAYABLE, - coa_model=coa, - balance_type="credit", - active=True - ) - print(f"VendorModel created for Vendor: {instance.name}") + instance.create_vendor_model() + instance.create_vendor_account(roles.LIABILITY_CL_ACC_PAYABLE) + else: + instance.update_vendor_model() @receiver(post_save, sender=models.CustomerModel) def create_customer_user(sender, instance, created, **kwargs): diff --git a/inventory/urls.py b/inventory/urls.py index 487f11e5..14e29625 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -202,15 +202,15 @@ urlpatterns = [ path('crm/calender/', views.EmployeeCalendarView.as_view(), name='calendar_list'), # Vendor URLs path("vendors", views.VendorListView.as_view(), name="vendor_list"), - path("vendors//", views.vendorDetailView, name="vendor_detail"), + path("vendors//", views.vendorDetailView, name="vendor_detail"), path("vendors/create/", views.VendorCreateView.as_view(), name="vendor_create"), path( - "vendors//update/", + "vendors//update/", views.VendorUpdateView.as_view(), name="vendor_update", ), path( - "vendors//delete/", + "vendors//delete/", views.delete_vendor, name="vendor_delete", ), diff --git a/inventory/views.py b/inventory/views.py index f6c64236..ed76dc28 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -579,7 +579,7 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): def get_form(self, form_class=None): form = super().get_form(form_class) dealer = get_user_type(self.request) - form.fields["vendor"].queryset = dealer.entity.get_vendors().filter(active=True) + form.fields["vendor"].queryset = dealer.vendors.all() return form def get_success_url(self): @@ -595,6 +595,12 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): messages.success(self.request, _("Car saved successfully")) return super().form_valid(form) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + dealer = get_user_type(self.request) + context["vendor_exists"] = dealer.vendors.exists() + + return context def car_history(request, pk): """ @@ -1323,7 +1329,7 @@ class CarUpdateView( form = super().get_form(form_class) dealer = get_user_type(self.request) print(dealer.get_vendors()) - form.fields["vendor"].queryset = dealer.get_vendors() + form.fields["vendor"].queryset = dealer.vendors.all() return form class CarDeleteView( @@ -2193,17 +2199,17 @@ class VendorListView(LoginRequiredMixin, ListView): ordered by their creation date in descending order. :type ordering: list """ - model = VendorModel + model = models.Vendor context_object_name = "vendors" paginate_by = 10 template_name = "vendors/vendors_list.html" - ordering = ["-created"] + # ordering = ["-created"] - def get_queryset(self): - query = self.request.GET.get("q") - dealer = get_user_type(self.request) - vendors = dealer.entity.get_vendors().filter(active=True) - return apply_search_filters(vendors, query) + # def get_queryset(self): + # query = self.request.GET.get("q") + # dealer = get_user_type(self.request) + # vendors = dealer.entity.get_vendors().filter(active=True) + # return apply_search_filters(vendors, query) @login_required @@ -2295,24 +2301,24 @@ class VendorUpdateView( success_url = reverse_lazy("vendor_list") success_message = _("Vendor updated successfully") - def get_initial(self): - initial = super().get_initial() - initial = self.object.additional_info - return initial + # def get_initial(self): + # initial = super().get_initial() + # initial = self.object.additional_info + # return initial def form_valid(self, form): - instance = form.save(commit=False) - - instance.vendor_name = self.request.POST["name"] - instance.vendor_number = self.request.POST["crn"] - instance.address_1 = self.request.POST["address"] - instance.phone = self.request.POST["phone_number"] - instance.email = self.request.POST["email"] - instance.tax_id_number = self.request.POST["vrn"] - additionals = form.cleaned_data - additionals["phone_number"] = str(additionals["phone_number"]) - instance.additional_info = additionals - instance.save() + # instance = form.save(commit=False) + print(self.request.POST) + # instance.vendor_name = self.request.POST["name"] + # instance.vendor_number = self.request.POST["crn"] + # instance.address_1 = self.request.POST["address"] + # instance.phone = self.request.POST["phone_number"] + # instance.email = self.request.POST["email"] + # instance.tax_id_number = self.request.POST["vrn"] + # additionals = form.cleaned_data + # additionals["phone_number"] = str(additionals["phone_number"]) + # instance.additional_info = additionals + # instance.save() return super().form_valid(form) diff --git a/static/images/logos/vendors/image.png b/static/images/logos/vendors/image.png new file mode 100644 index 00000000..fb612b2b Binary files /dev/null and b/static/images/logos/vendors/image.png differ diff --git a/static/images/logos/vendors/logo-for-the-word-daju-48a980.jpg b/static/images/logos/vendors/logo-for-the-word-daju-48a980.jpg new file mode 100644 index 00000000..f2cfb1d9 Binary files /dev/null and b/static/images/logos/vendors/logo-for-the-word-daju-48a980.jpg differ diff --git a/templates/inventory/car_detail.html b/templates/inventory/car_detail.html index eb20a04c..7d7ae159 100644 --- a/templates/inventory/car_detail.html +++ b/templates/inventory/car_detail.html @@ -20,28 +20,28 @@ {% if not car.ready %} {% endif %} {% if car.get_transfer.status == "draft" %} -