fix vendor

This commit is contained in:
ismail 2025-05-06 17:39:10 +03:00
parent cb4366f028
commit 9d6d69f1d0
15 changed files with 202 additions and 122 deletions

View File

@ -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,]

View File

@ -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:

View File

@ -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')],

View File

@ -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'),
),
]

View File

@ -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'),
),
]

View File

@ -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 = [

View File

@ -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):

View File

@ -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/<uuid:pk>/", views.vendorDetailView, name="vendor_detail"),
path("vendors/<int:pk>/", views.vendorDetailView, name="vendor_detail"),
path("vendors/create/", views.VendorCreateView.as_view(), name="vendor_create"),
path(
"vendors/<uuid:pk>/update/",
"vendors/<int:pk>/update/",
views.VendorUpdateView.as_view(),
name="vendor_update",
),
path(
"vendors/<uuid:pk>/delete/",
"vendors/<int:pk>/delete/",
views.delete_vendor,
name="vendor_delete",
),

View File

@ -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)

BIN
static/images/logos/vendors/image.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -20,28 +20,28 @@
{% if not car.ready %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p>
<p class="mb-0 flex-1">{{ _("This car information is not complete , please add colors and finances before making it ready for sale .") }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
{% if car.get_transfer.status == "draft" %}
<div class="alert alert-outline-info d-flex align-items-center" role="alert">
<div class="alert alert-outline-info d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("Action Required , Please Approved The Tranfer Request Of This Car .") }}</p>
<p class="mb-0 flex-1">{{ _("Action Required , Please Approved The Tranfer Request Of This Car .") }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
{% if car.get_transfer and car.get_transfer.status == "approved" %}
<div class="alert alert-outline-info d-flex align-items-center" role="alert">
<div class="alert alert-outline-info d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("Car Is In Transfer Process To Another Dealer, Please Wait For The Acceptance .") }}</p>
<p class="mb-0 flex-1">{{ _("Car Is In Transfer Process To Another Dealer, Please Wait For The Acceptance .") }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
{% if car.is_reserved %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p>
<p class="mb-0 flex-1">{{ _("This car is reserved until ") }}{{ car.get_reservation.reserved_until }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
@ -98,7 +98,7 @@
{% if car.vendor %}
<tr>
<th>{% trans "Vendor"|capfirst %}</th>
<td>{{ car.vendor.vendor_name }}</td>
<td>{{ car.vendor.name }}</td>
</tr>
{% endif %}
<tr>
@ -361,7 +361,7 @@
<p class="card-header rounded-top fw-bold">{% trans 'Transfer Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<thead>
<tr>
<th>{% trans "Action" %}</th>
@ -373,7 +373,7 @@
</tr>
</thead>
<tbody>
<tr>
<td><span class="badge badge-phoenix badge-phoenix-info">Transfer</span></td>
<td>
@ -396,11 +396,11 @@
<a class="btn btn-sm btn-phoenix-success" href="{% url 'transfer_detail' car.get_transfer.pk %}">Approve</a>
{% endif %}
</td>
<td>
<td>
<a class="btn btn-sm btn-phoenix-success" href="{% url 'transfer_detail' car.get_transfer.pk %}?action=cancel">Cancel</a>
</td>
</tr>
</tbody>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -6,14 +6,24 @@
height: auto;
margin: 0 auto;
}
.disabled{
opacity: 0.5;
pointer-events: none;
}
</style>
<!-- JavaScript Section -->
<script src="{% static 'vendors/zxing/index.min.js' %}"></script>
<script src="{% static 'vendors/tesseract/tesseract.min.js' %}"></script>
<div class=" container-fluid m-0">
{% if not vendor_exists %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("Please Add A Vendor, Before Adding A Car .") }}</p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
<div class=" container-fluid m-0 {% if not vendor_exists %}disabled{% endif %}">
<form method="post" id="carForm" class="form needs-validation" novalidate>
{% csrf_token %}
{% include 'partials/form_errors.html' %}

View File

@ -27,7 +27,7 @@
<div class="row">
<div class="col-xl-9">
<form class="row g-3 mb-9" method="post" class="form" novalidate>
<form class="row g-3 mb-9" method="post" class="form" enctype="multipart/form-data" novalidate >
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}

View File

@ -114,7 +114,7 @@
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
{% endif %}
</div>
<div><a class="fs-8 fw-bold" href="">{{ vendor.vendor_name }}</a>
<div><a class="fs-8 fw-bold" href="">{{ vendor.pk }}</a>
<div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.vendor_name }}</p><span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.id}}</span>
</div>
@ -122,11 +122,11 @@
</div>
</td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="">{{ vendor.email }}</a></td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone }}</a></td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone_number }}</a></td>
<td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ vendor.contact_person }}</td>
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
{{ vendor.address_1 }}</td>
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created|date }}</td>
{{ vendor.address }}</td>
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created_at|date }}</td>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>