update in notifications and bills
This commit is contained in:
parent
042d1ac34b
commit
64f76c0f1a
BIN
db.sqlite3-shm
BIN
db.sqlite3-shm
Binary file not shown.
BIN
db.sqlite3.backup
Normal file
BIN
db.sqlite3.backup
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-12 17:20
|
# Generated by Django 4.2.17 on 2025-01-21 13:59
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-12 17:20
|
# Generated by Django 4.2.17 on 2025-01-21 13:59
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -9,8 +9,8 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('inventory', '0001_initial'),
|
|
||||||
('haikalbot', '0001_initial'),
|
('haikalbot', '0001_initial'),
|
||||||
|
('inventory', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-12 17:20
|
# Generated by Django 4.2.17 on 2025-01-21 13:59
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -15,6 +15,7 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('contenttypes', '0002_remove_content_type_name'),
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('vin', models.CharField(max_length=17, unique=True, verbose_name='VIN')),
|
||||||
('year', models.IntegerField(verbose_name='Year')),
|
('year', models.IntegerField(verbose_name='Year')),
|
||||||
('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status')),
|
('status', models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved'), ('transfer', 'Transfer')], 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')),
|
('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')),
|
('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
|
||||||
('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')),
|
('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')),
|
||||||
@ -74,138 +75,13 @@ class Migration(migrations.Migration):
|
|||||||
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
('arabic_name', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
('logo', models.ImageField(blank=True, null=True, upload_to='car_make', verbose_name='logo')),
|
('logo', models.ImageField(blank=True, null=True, upload_to='car_make', verbose_name='logo')),
|
||||||
('is_sa_import', models.BooleanField(default=False)),
|
('is_sa_import', models.BooleanField(default=False)),
|
||||||
('car_type', models.SmallIntegerField(choices=[(1, 'Car'), (2, 'Light Commercial'), (3, 'Heavy-Duty Tractors'), (4, 'Trailers'), (5, 'Medium Trucks'), (6, 'Buses'), (20, 'Motorcycles'), (21, 'Buggy'), (22, 'Moto ATV'), (23, 'Scooters'), (24, 'Karting'), (25, 'ATV'), (26, 'Snowmobiles')])),
|
('car_type', models.SmallIntegerField(blank=True, choices=[(1, 'Car'), (2, 'Light Commercial'), (3, 'Heavy-Duty Tractors'), (4, 'Trailers'), (5, 'Medium Trucks'), (6, 'Buses'), (20, 'Motorcycles'), (21, 'Buggy'), (22, 'Moto ATV'), (23, 'Scooters'), (24, 'Karting'), (25, 'ATV'), (26, 'Snowmobiles')], null=True)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Make',
|
'verbose_name': 'Make',
|
||||||
},
|
},
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='ExteriorColors',
|
|
||||||
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')),
|
|
||||||
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Exterior Colors',
|
|
||||||
'verbose_name_plural': 'Exterior Colors',
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='InteriorColors',
|
|
||||||
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')),
|
|
||||||
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Interior Colors',
|
|
||||||
'verbose_name_plural': 'Interior Colors',
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
),
|
|
||||||
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')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'payment',
|
|
||||||
'verbose_name_plural': 'payments',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SubscriptionPlan',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(help_text='Name of the subscription plan', max_length=100, unique=True)),
|
|
||||||
('description', models.TextField()),
|
|
||||||
('price', models.DecimalField(decimal_places=2, max_digits=10)),
|
|
||||||
('max_users', models.PositiveIntegerField(default=1, help_text='Maximum number of users allowed')),
|
|
||||||
('max_inventory_size', models.PositiveIntegerField(default=50, help_text='Maximum number of cars in inventory')),
|
|
||||||
('support_level', models.CharField(choices=[('basic', 'Basic Support'), ('priority', 'Priority Support'), ('dedicated', 'Dedicated Support')], default='basic', help_text='Level of support provided', max_length=50)),
|
|
||||||
('custom_features', models.JSONField(blank=True, help_text='Additional features specific to this plan', null=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Subscription Plan',
|
|
||||||
'verbose_name_plural': 'Subscription Plans',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='VatRate',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('rate', models.DecimalField(decimal_places=2, default=Decimal('0.15'), max_digits=5)),
|
|
||||||
('is_active', models.BooleanField(default=True)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Activity',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('object_id', models.PositiveIntegerField()),
|
|
||||||
('activity_type', models.CharField(choices=[('call', 'Call'), ('sms', 'SMS'), ('email', 'Email'), ('whatsapp', 'WhatsApp'), ('visit', 'Visit'), ('add_car', 'Add Car'), ('reserve_car', 'Reserve Car'), ('remove_car', 'Remove Car'), ('create_quotation', 'Create Quotation'), ('cancel_quotation', 'Cancel Quotation'), ('create_order', 'Create Order'), ('cancel_order', 'Cancel Order'), ('create_invoice', 'Create Invoice'), ('cancel_invoice', 'Cancel Invoice')], max_length=50, verbose_name='Activity Type')),
|
|
||||||
('notes', models.TextField(blank=True, null=True, verbose_name='Notes')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
|
||||||
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
|
||||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='activities_created', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Activity',
|
|
||||||
'verbose_name_plural': 'Activities',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
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=[('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='django_ledger.itemmodel', verbose_name='Item')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Additional Services',
|
|
||||||
'verbose_name_plural': 'Additional Services',
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
),
|
|
||||||
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='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(
|
migrations.CreateModel(
|
||||||
name='CarModel',
|
name='CarModel',
|
||||||
fields=[
|
fields=[
|
||||||
@ -274,7 +150,6 @@ class Migration(migrations.Migration):
|
|||||||
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')),
|
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')),
|
||||||
('national_id', models.CharField(max_length=10, unique=True, verbose_name='National ID')),
|
('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')),
|
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', unique=True, verbose_name='Phone Number')),
|
||||||
('city', models.CharField(blank=True, max_length=255, verbose_name='City')),
|
|
||||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
||||||
@ -310,51 +185,46 @@ class Migration(migrations.Migration):
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CarLocation',
|
name='ExteriorColors',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('name', models.CharField(max_length=255, verbose_name='Name')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Updated')),
|
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
||||||
('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={
|
options={
|
||||||
'verbose_name': 'Car Location',
|
'verbose_name': 'Exterior Colors',
|
||||||
'verbose_name_plural': 'Car Locations',
|
'verbose_name_plural': 'Exterior Colors',
|
||||||
},
|
},
|
||||||
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.CreateModel(
|
||||||
model_name='car',
|
name='InteriorColors',
|
||||||
name='dealer',
|
fields=[
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='inventory.dealer', verbose_name='Dealer'),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
),
|
('name', models.CharField(max_length=255, verbose_name='Name')),
|
||||||
migrations.AddField(
|
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||||
model_name='additionalservices',
|
('rgb', models.CharField(blank=True, max_length=24, null=True, verbose_name='RGB')),
|
||||||
name='dealer',
|
],
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'),
|
options={
|
||||||
|
'verbose_name': 'Interior Colors',
|
||||||
|
'verbose_name_plural': 'Interior Colors',
|
||||||
|
},
|
||||||
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Lead',
|
name='Lead',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('title', models.CharField(choices=[('mr', 'Mr'), ('mrs', 'Mrs'), ('ms', 'Ms'), ('miss', 'Miss'), ('dr', 'Dr'), ('prof', 'Prof'), ('prince', 'Prince'), ('princess', 'Princess'), ('company', 'Company'), ('na', 'N/A')], max_length=20, verbose_name='Title')),
|
|
||||||
('first_name', models.CharField(max_length=50, verbose_name='First Name')),
|
|
||||||
('last_name', models.CharField(max_length=50, verbose_name='Last Name')),
|
|
||||||
('email', models.EmailField(db_index=True, max_length=254, unique=True, verbose_name='Email')),
|
|
||||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
|
||||||
('salary', models.PositiveIntegerField(blank=True, null=True, verbose_name='Salary')),
|
|
||||||
('obligations', models.PositiveIntegerField(blank=True, null=True, verbose_name='Obligations')),
|
|
||||||
('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year')),
|
('year', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year')),
|
||||||
('source', models.CharField(choices=[('referrals', 'Referrals'), ('whatsapp', 'WhatsApp'), ('showroom', 'Showroom'), ('tiktok', 'TikTok'), ('instagram', 'Instagram'), ('x', 'X'), ('facebook', 'Facebook'), ('motory', 'Motory'), ('influencers', 'Influencers'), ('youtube', 'Youtube'), ('campaign', 'Campaign')], max_length=50, verbose_name='Source')),
|
('source', models.CharField(choices=[('referrals', 'Referrals'), ('whatsapp', 'WhatsApp'), ('showroom', 'Showroom'), ('tiktok', 'TikTok'), ('instagram', 'Instagram'), ('x', 'X'), ('facebook', 'Facebook'), ('motory', 'Motory'), ('influencers', 'Influencers'), ('youtube', 'Youtube'), ('campaign', 'Campaign')], max_length=50, verbose_name='Source')),
|
||||||
('channel', models.CharField(choices=[('walk_in', 'Walk In'), ('toll_free', 'Toll Free'), ('website', 'Website'), ('email', 'Email'), ('form', 'Form')], max_length=50, verbose_name='Channel')),
|
('channel', models.CharField(choices=[('walk_in', 'Walk In'), ('toll_free', 'Toll Free'), ('website', 'Website'), ('email', 'Email'), ('form', 'Form')], max_length=50, verbose_name='Channel')),
|
||||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
|
||||||
('city', models.CharField(max_length=50, verbose_name='City')),
|
('city', models.CharField(max_length=50, verbose_name='City')),
|
||||||
('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')], default='medium', max_length=10, verbose_name='Priority')),
|
('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')], default='medium', max_length=10, verbose_name='Priority')),
|
||||||
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status')),
|
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('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')),
|
('created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Created')),
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
||||||
|
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.customer')),
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer')),
|
('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_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')),
|
('id_car_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model')),
|
||||||
@ -364,62 +234,6 @@ class Migration(migrations.Migration):
|
|||||||
'verbose_name_plural': 'Leads',
|
'verbose_name_plural': 'Leads',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='Customer',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('title', models.CharField(choices=[('mr', 'Mr'), ('mrs', 'Mrs'), ('ms', 'Ms'), ('miss', 'Miss'), ('dr', 'Dr'), ('prof', 'Prof'), ('prince', 'Prince'), ('princess', 'Princess'), ('company', 'Company'), ('na', 'N/A')], default='na', max_length=10, verbose_name='Title')),
|
|
||||||
('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')),
|
|
||||||
('gender', models.CharField(choices=[('m', 'Male'), ('f', 'Female')], max_length=1, verbose_name='Gender')),
|
|
||||||
('dob', models.DateField(verbose_name='Date of Birth')),
|
|
||||||
('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')),
|
|
||||||
('city', models.CharField(blank=True, max_length=255, verbose_name='City')),
|
|
||||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer')),
|
|
||||||
('lead', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='converted', to='inventory.lead', verbose_name='Lead')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Customer',
|
|
||||||
'verbose_name_plural': 'Customers',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Notes',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('object_id', models.PositiveIntegerField()),
|
|
||||||
('note', models.TextField(verbose_name='Note')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
|
||||||
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
|
||||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='notes_created', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Note',
|
|
||||||
'verbose_name_plural': 'Notes',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Notification',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('message', models.CharField(max_length=255, verbose_name='Message')),
|
|
||||||
('is_read', models.BooleanField(default=False, verbose_name='Is Read')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Notification',
|
|
||||||
'verbose_name_plural': 'Notifications',
|
|
||||||
'ordering': ['-created'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Organization',
|
name='Organization',
|
||||||
fields=[
|
fields=[
|
||||||
@ -431,7 +245,8 @@ class Migration(migrations.Migration):
|
|||||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone 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')),
|
('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')),
|
('logo', models.ImageField(blank=True, null=True, upload_to='logos', verbose_name='Logo')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
||||||
|
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')),
|
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to='inventory.dealer')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -478,98 +293,6 @@ class Migration(migrations.Migration):
|
|||||||
('dealer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer')),
|
('dealer', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='payment',
|
|
||||||
name='quotation',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='inventory.salequotation'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SaleQuotationCar',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('quantity', models.PositiveIntegerField(default=1, verbose_name='Quantity')),
|
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.car', verbose_name='Car')),
|
|
||||||
('quotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotation_cars', to='inventory.salequotation', verbose_name='Quotation')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SalesOrder',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
|
||||||
('total_amount', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Total Amount')),
|
|
||||||
('quotation', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='sales_order', to='inventory.salequotation', verbose_name='Quotation')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Staff',
|
|
||||||
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')),
|
|
||||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
|
||||||
('staff_type', models.CharField(choices=[('manager', 'Manager'), ('inventory', 'Inventory'), ('accountant', 'Accountant'), ('sales', 'Sales'), ('coordinator', 'Coordinator'), ('receptionist', 'Receptionist'), ('agent', 'Agent')], max_length=255, verbose_name='Staff Type')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
|
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to='inventory.dealer')),
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='staff', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Staff',
|
|
||||||
'verbose_name_plural': 'Staff',
|
|
||||||
'permissions': [],
|
|
||||||
},
|
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
|
||||||
managers=[
|
|
||||||
('objects', inventory.models.StaffUserManager()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Opportunity',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('stage', models.CharField(choices=[('prospect', 'Prospect'), ('proposal', 'Proposal'), ('negotiation', 'Negotiation'), ('closed_won', 'Closed Won'), ('closed_lost', 'Closed Lost')], max_length=20, verbose_name='Stage')),
|
|
||||||
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], default='new', max_length=20, verbose_name='Status')),
|
|
||||||
('probability', models.PositiveIntegerField(validators=[inventory.models.validate_probability])),
|
|
||||||
('closing_date', models.DateField(verbose_name='Closing Date')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
|
||||||
('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='inventory.customer')),
|
|
||||||
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.dealer')),
|
|
||||||
('staff', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner', to='inventory.staff', verbose_name='Owner')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Opportunity',
|
|
||||||
'verbose_name_plural': 'Opportunities',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='LeadStatusHistory',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('old_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], max_length=50, verbose_name='Old Status')),
|
|
||||||
('new_status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('canceled', 'Canceled')], max_length=50, verbose_name='New Status')),
|
|
||||||
('changed_at', models.DateTimeField(auto_now_add=True, verbose_name='Changed At')),
|
|
||||||
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_history', to='inventory.lead')),
|
|
||||||
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='status_changes', to='inventory.staff')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Lead Status History',
|
|
||||||
'verbose_name_plural': 'Lead Status Histories',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='lead',
|
|
||||||
name='assigned',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned', to='inventory.staff', verbose_name='Assigned'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='customer',
|
|
||||||
name='staff',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='customer_staff', to='inventory.staff', verbose_name='Staff'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Subscription',
|
name='Subscription',
|
||||||
fields=[
|
fields=[
|
||||||
@ -719,7 +442,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=255, verbose_name='Name')),
|
('name', models.CharField(max_length=255, verbose_name='Name')),
|
||||||
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
('arabic_name', models.CharField(max_length=255, verbose_name='Arabic Name')),
|
||||||
('id_number', models.CharField(max_length=10, verbose_name='ID Number')),
|
('id_number', models.CharField(max_length=10, unique=True, verbose_name='ID Number')),
|
||||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region='SA', verbose_name='Phone Number')),
|
||||||
('email', models.EmailField(max_length=255, verbose_name='Email Address')),
|
('email', models.EmailField(max_length=255, verbose_name='Email Address')),
|
||||||
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
('address', models.CharField(blank=True, max_length=200, null=True, verbose_name='Address')),
|
||||||
@ -820,39 +543,14 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='lead',
|
model_name='lead',
|
||||||
name='assigned',
|
name='staff',
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned', to='inventory.staff', verbose_name='Assigned'),
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned', to='inventory.staff', verbose_name='Assigned'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='lead',
|
|
||||||
name='dealer',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='lead',
|
|
||||||
name='id_car_make',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='lead',
|
|
||||||
name='id_car_model',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='customer',
|
model_name='customer',
|
||||||
name='dealer',
|
name='dealer',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to='inventory.dealer'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='customer',
|
|
||||||
name='lead',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='converted', to='inventory.lead', verbose_name='Lead'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='customer',
|
|
||||||
name='staff',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='customer_staff', to='inventory.staff', verbose_name='Staff'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CustomCard',
|
name='CustomCard',
|
||||||
fields=[
|
fields=[
|
||||||
@ -881,6 +579,27 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
bases=(models.Model, inventory.mixins.LocalizedNameMixin),
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CarTransfer',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('transfer_date', models.DateTimeField(auto_now_add=True, verbose_name='Transfer Date')),
|
||||||
|
('quantity', models.IntegerField(default=1, verbose_name='Quantity')),
|
||||||
|
('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
|
||||||
|
('status', models.CharField(default='draft', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('accepted', 'Accepted'), ('success', 'Success'), ('reject', 'Reject')])),
|
||||||
|
('is_approved', models.BooleanField(default=False)),
|
||||||
|
('active', models.BooleanField(default=True)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
|
||||||
|
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_logs', to='inventory.car', verbose_name='Car')),
|
||||||
|
('from_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_out', to='inventory.dealer', verbose_name='From Dealer')),
|
||||||
|
('to_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_in', to='inventory.dealer', verbose_name='To Dealer')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Car Transfer Log',
|
||||||
|
'verbose_name_plural': 'Car Transfer Logs',
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CarSpecificationValue',
|
name='CarSpecificationValue',
|
||||||
fields=[
|
fields=[
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-13 10:20
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='carmake',
|
|
||||||
name='car_type',
|
|
||||||
field=models.SmallIntegerField(blank=True, choices=[], null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-14 12:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0002_alter_carmake_car_type'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='carmake',
|
|
||||||
name='car_type',
|
|
||||||
field=models.SmallIntegerField(blank=True, choices=[(1, 'Car'), (2, 'Light Commercial'), (3, 'Heavy-Duty Tractors'), (4, 'Trailers'), (5, 'Medium Trucks'), (6, 'Buses'), (20, 'Motorcycles'), (21, 'Buggy'), (22, 'Moto ATV'), (23, 'Scooters'), (24, 'Karting'), (25, 'ATV'), (26, 'Snowmobiles')], null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-17 00:20
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0003_alter_carmake_car_type'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name='lead',
|
|
||||||
old_name='assigned',
|
|
||||||
new_name='staff',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='customer',
|
|
||||||
name='city',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='customer',
|
|
||||||
name='lead',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='customer',
|
|
||||||
name='staff',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='address',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='email',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='first_name',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='last_name',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='obligations',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='phone_number',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='salary',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='lead',
|
|
||||||
name='title',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='organization',
|
|
||||||
name='created_at',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='lead',
|
|
||||||
name='customer',
|
|
||||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.customer'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='organization',
|
|
||||||
name='created',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='organization',
|
|
||||||
name='updated',
|
|
||||||
field=models.DateTimeField(auto_now=True, verbose_name='Updated'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='representative',
|
|
||||||
name='id_number',
|
|
||||||
field=models.CharField(max_length=10, unique=True, verbose_name='ID Number'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 12:55
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0004_rename_assigned_lead_staff_remove_customer_city_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
]
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 14:01
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0005_merge_20250119_1555'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='CarTransferLog',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('transfer_date', models.DateTimeField(auto_now_add=True, verbose_name='Transfer Date')),
|
|
||||||
('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
|
|
||||||
('cars', models.ManyToManyField(related_name='transfer_logs', to='inventory.car', verbose_name='Cars')),
|
|
||||||
('from_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_out', to='inventory.dealer', verbose_name='From Dealer')),
|
|
||||||
('to_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_in', to='inventory.dealer', verbose_name='To Dealer')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Car Transfer Log',
|
|
||||||
'verbose_name_plural': 'Car Transfer Logs',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 14:15
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0006_cartransferlog_delete_invoicemodelbase'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='cars',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='car',
|
|
||||||
field=models.ForeignKey(default=4, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_logs', to='inventory.car', verbose_name='Car'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 14:29
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0007_remove_cartransferlog_cars_cartransferlog_car'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2025, 1, 19, 14, 29, 29, 771881, tzinfo=datetime.timezone.utc), verbose_name='Created At'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='is_approved',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(default='pending', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('success', 'Success'), ('failure', 'Failure')]),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransferlog',
|
|
||||||
name='updated_at',
|
|
||||||
field=models.DateTimeField(auto_now=True, verbose_name='Updated At'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 14:31
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0008_cartransferlog_created_at_cartransferlog_is_approved_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='CarTransfer',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('transfer_date', models.DateTimeField(auto_now_add=True, verbose_name='Transfer Date')),
|
|
||||||
('remarks', models.TextField(blank=True, null=True, verbose_name='Remarks')),
|
|
||||||
('status', models.CharField(default='draft', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('success', 'Success'), ('failure', 'Failure')])),
|
|
||||||
('is_approved', models.BooleanField(default=False)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
|
|
||||||
('car', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_logs', to='inventory.car', verbose_name='Car')),
|
|
||||||
('from_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_out', to='inventory.dealer', verbose_name='From Dealer')),
|
|
||||||
('to_dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_in', to='inventory.dealer', verbose_name='To Dealer')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Car Transfer Log',
|
|
||||||
'verbose_name_plural': 'Car Transfer Logs',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='CarTransferLog',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-19 15:20
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0009_cartransfer_delete_cartransferlog'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransfer',
|
|
||||||
name='active',
|
|
||||||
field=models.BooleanField(default=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='car',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved'), ('transfer', 'Transfer')], default='available', max_length=10, verbose_name='Status'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-20 08:11
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0010_cartransfer_active_alter_car_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='cartransfer',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(default='draft', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('accept', 'Accept'), ('success', 'Success'), ('failure', 'Failure')]),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-20 08:21
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0011_alter_cartransfer_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='cartransfer',
|
|
||||||
name='quantity',
|
|
||||||
field=models.IntegerField(default=1, verbose_name='Quantity'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-20 09:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0012_cartransfer_quantity'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='cartransfer',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(default='draft', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('accept', 'Accept'), ('success', 'Success'), ('reject', 'Reject')]),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-21 08:56
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0013_alter_cartransfer_status'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='cartransfer',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(default='draft', max_length=10, verbose_name=[('draft', 'Draft'), ('approved', 'Approved'), ('pending', 'Pending'), ('accepted', 'Accepted'), ('success', 'Success'), ('reject', 'Reject')]),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -447,7 +447,7 @@ urlpatterns = [
|
|||||||
views.PaymentCreateView,
|
views.PaymentCreateView,
|
||||||
name="payment_create",
|
name="payment_create",
|
||||||
),
|
),
|
||||||
path("sales/payments/create/", views.PaymentCreateView, name="payment_create"),
|
# path("sales/payments/create/", views.PaymentCreateView, name="payment_create"),
|
||||||
path(
|
path(
|
||||||
"sales/payments/<uuid:pk>/payment_details/",
|
"sales/payments/<uuid:pk>/payment_details/",
|
||||||
views.PaymentDetailView,
|
views.PaymentDetailView,
|
||||||
|
|||||||
@ -829,6 +829,10 @@ def car_transfer_accept_reject(request, car_pk,transfer_pk):
|
|||||||
transfer.status = "reject"
|
transfer.status = "reject"
|
||||||
transfer.active = False
|
transfer.active = False
|
||||||
messages.success(request, _("Car transfer rejected successfully."))
|
messages.success(request, _("Car transfer rejected successfully."))
|
||||||
|
models.Notification.objects.create(
|
||||||
|
user=transfer.from_dealer.user,
|
||||||
|
message=f"Car transfer request from {transfer.to_dealer} is rejected.",
|
||||||
|
)
|
||||||
transfer.save()
|
transfer.save()
|
||||||
elif status == "accepted":
|
elif status == "accepted":
|
||||||
transfer.status = "accept"
|
transfer.status = "accept"
|
||||||
@ -836,6 +840,10 @@ def car_transfer_accept_reject(request, car_pk,transfer_pk):
|
|||||||
success = transfer_car(car,transfer)
|
success = transfer_car(car,transfer)
|
||||||
if success:
|
if success:
|
||||||
messages.success(request, _("Car Transfer Completed successfully."))
|
messages.success(request, _("Car Transfer Completed successfully."))
|
||||||
|
models.Notification.objects.create(
|
||||||
|
user=transfer.from_dealer.user,
|
||||||
|
message=f"Car transfer request from {transfer.to_dealer} is completed.",
|
||||||
|
)
|
||||||
return redirect("inventory_stats")
|
return redirect("inventory_stats")
|
||||||
|
|
||||||
def CarTransferPreviewView(request, car_pk,transfer_pk):
|
def CarTransferPreviewView(request, car_pk,transfer_pk):
|
||||||
@ -2549,11 +2557,11 @@ class InvoicePreviewView(LoginRequiredMixin, DetailView):
|
|||||||
# payments
|
# payments
|
||||||
|
|
||||||
|
|
||||||
def PaymentCreateView(request, pk=None):
|
def PaymentCreateView(request, pk):
|
||||||
|
print(pk)
|
||||||
invoice = InvoiceModel.objects.filter(pk=pk).first()
|
invoice = InvoiceModel.objects.filter(pk=pk).first()
|
||||||
bill = BillModel.objects.filter(pk=pk).first()
|
bill = BillModel.objects.filter(pk=pk).first()
|
||||||
model = invoice if invoice else bill
|
model = invoice if invoice else bill
|
||||||
redirect_url = 'invoice_detail' if invoice else 'bill_detail'
|
|
||||||
dealer = get_user_type(request)
|
dealer = get_user_type(request)
|
||||||
entity = dealer.entity
|
entity = dealer.entity
|
||||||
form = forms.PaymentForm()
|
form = forms.PaymentForm()
|
||||||
@ -2564,7 +2572,9 @@ def PaymentCreateView(request, pk=None):
|
|||||||
invoice = form.cleaned_data.get("invoice")
|
invoice = form.cleaned_data.get("invoice")
|
||||||
bill = form.cleaned_data.get("bill")
|
bill = form.cleaned_data.get("bill")
|
||||||
payment_method = form.cleaned_data.get("payment_method")
|
payment_method = form.cleaned_data.get("payment_method")
|
||||||
|
redirect_url = 'invoice_detail' if invoice else 'bill_detail'
|
||||||
model = invoice if invoice else bill
|
model = invoice if invoice else bill
|
||||||
|
|
||||||
if not model.is_approved():
|
if not model.is_approved():
|
||||||
model.mark_as_approved(user_model=entity.admin)
|
model.mark_as_approved(user_model=entity.admin)
|
||||||
try:
|
try:
|
||||||
@ -2572,6 +2582,7 @@ def PaymentCreateView(request, pk=None):
|
|||||||
set_invoice_payment(dealer,entity,invoice,amount,payment_method)
|
set_invoice_payment(dealer,entity,invoice,amount,payment_method)
|
||||||
elif bill:
|
elif bill:
|
||||||
set_bill_payment(dealer,entity,bill,amount,payment_method)
|
set_bill_payment(dealer,entity,bill,amount,payment_method)
|
||||||
|
messages.success(request, "Payment created successfully!")
|
||||||
return redirect(redirect_url, pk=model.pk)
|
return redirect(redirect_url, pk=model.pk)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messages.error(request, f"Error creating payment: {str(e)}")
|
messages.error(request, f"Error creating payment: {str(e)}")
|
||||||
@ -2579,8 +2590,8 @@ def PaymentCreateView(request, pk=None):
|
|||||||
messages.error(request, f"Invalid form data: {str(form.errors)}")
|
messages.error(request, f"Invalid form data: {str(form.errors)}")
|
||||||
# return redirect(redirect_url, pk=model.pk)
|
# return redirect(redirect_url, pk=model.pk)
|
||||||
form = forms.PaymentForm()
|
form = forms.PaymentForm()
|
||||||
form.initial["amount"] = model.amount_due - model.amount_paid
|
|
||||||
if model:
|
if model:
|
||||||
|
form.initial["amount"] = model.amount_due - model.amount_paid
|
||||||
if isinstance(model, InvoiceModel):
|
if isinstance(model, InvoiceModel):
|
||||||
form.initial["invoice"] = model
|
form.initial["invoice"] = model
|
||||||
form.fields['bill'].widget = HiddenInput()
|
form.fields['bill'].widget = HiddenInput()
|
||||||
@ -2630,7 +2641,12 @@ def payment_mark_as_paid(request, pk):
|
|||||||
|
|
||||||
invoice.ledger.post()
|
invoice.ledger.post()
|
||||||
invoice.ledger.save()
|
invoice.ledger.save()
|
||||||
messages.success(request, "Payment created successfully!")
|
messages.success(request, "Payment created successfully!")
|
||||||
|
else:
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
"Invoice is not fully paid. Payment cannot be marked as paid.",
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messages.error(request, f"Error: {str(e)}")
|
messages.error(request, f"Error: {str(e)}")
|
||||||
return redirect("invoice_detail", pk=invoice.pk)
|
return redirect("invoice_detail", pk=invoice.pk)
|
||||||
@ -2849,15 +2865,16 @@ def fetch_notifications(request):
|
|||||||
notifications = models.Notification.objects.filter(
|
notifications = models.Notification.objects.filter(
|
||||||
user=request.user, is_read=False
|
user=request.user, is_read=False
|
||||||
).order_by("-created")
|
).order_by("-created")
|
||||||
notifications_data = [
|
# notifications_data = [
|
||||||
{
|
# {
|
||||||
"id": notification.id,
|
# "id": notification.id,
|
||||||
"message": notification.message,
|
# "message": notification.message,
|
||||||
"created": notification.created.strftime("%Y-%m-%d %H:%M:%S"),
|
# "created": notification.created.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
}
|
# }
|
||||||
for notification in notifications
|
# for notification in notifications
|
||||||
]
|
# ]
|
||||||
return JsonResponse({"notifications": notifications_data})
|
# return JsonResponse({"notifications": notifications_data})
|
||||||
|
return render(request,'notifications.html',{'notifications_':notifications})
|
||||||
|
|
||||||
|
|
||||||
class ItemServiceCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
class ItemServiceCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
@ -3106,8 +3123,8 @@ def bill_create(request):
|
|||||||
terms = data.get("terms")
|
terms = data.get("terms")
|
||||||
vendor = entity.get_vendors().filter(pk=vendor_id).first()
|
vendor = entity.get_vendors().filter(pk=vendor_id).first()
|
||||||
|
|
||||||
items = data.get("item[]", [])
|
items = data.get("item", [])
|
||||||
quantities = data.get("quantity[]", [])
|
quantities = data.get("quantity", [])
|
||||||
|
|
||||||
if not all([items, quantities]):
|
if not all([items, quantities]):
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% block extra_js %}{% endblock extra_js %}
|
{% block customJS %}{% endblock customJS %}
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -71,7 +71,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ===============================================-->
|
<!-- ===============================================-->
|
||||||
<!-- JavaScripts-->
|
<!-- JavaScripts-->
|
||||||
<!-- ===============================================-->
|
<!-- ===============================================-->
|
||||||
@ -90,8 +89,10 @@
|
|||||||
<script src="{% static 'js/main.js' %}"></script>
|
<script src="{% static 'js/main.js' %}"></script>
|
||||||
<script src="{% static 'vendors/mapbox-gl/mapbox-gl.js' %}"></script>
|
<script src="{% static 'vendors/mapbox-gl/mapbox-gl.js' %}"></script>
|
||||||
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
|
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||||
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
|
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
|
||||||
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
|
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
{% if not notification.is_read %}
|
{% if not notification.is_read %}
|
||||||
<p class="fs-9 text-body-highlight"><span class="far fa-envelope text-success-dark fs-8 me-1"></span><span class="me-1">{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
<p class="fs-9 text-body-highlight"><span class="far fa-envelope text-success-dark fs-8 me-1"></span><span class="me-1">{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="fs-9 text-body-highlight"><span class="far fa-envelope-open text-danger-dark fs-8 me-1"></span><span>{{ notification.message }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
<p class="fs-9 text-body-highlight"><span class="far fa-envelope-open text-danger-dark fs-8 me-1"></span><span>{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="text-body-secondary fs-9 mb-0"><span class="me-1 far fa-clock"></span>{{ notification.created }}</p>
|
<p class="text-body-secondary fs-9 mb-0"><span class="me-1 far fa-clock"></span>{{ notification.created }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -300,11 +300,8 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
{% include "notifications.html" %}
|
||||||
<a class="nav-link" href="{% url 'notifications_history' %}" style="min-width: 2.25rem;" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-bs-auto-close="outside">
|
|
||||||
<span class="d-block" style="height: 20px; width: 20px;"><span data-feather="bell" style="height: 20px; width: 20px;"></span></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true">
|
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" aria-haspopup="true">
|
||||||
{% if request.LANGUAGE_CODE == 'ar' %}
|
{% if request.LANGUAGE_CODE == 'ar' %}
|
||||||
|
|||||||
@ -291,20 +291,25 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Transfer</td>
|
<td><span class="badge badge-phoenix badge-phoenix-info">Transfer</span></td>
|
||||||
<td>
|
<td>
|
||||||
{% if car.get_transfer.status == "draft" %}
|
{% if car.get_transfer.status == "draft" %}
|
||||||
|
<span class="badge badge-phoenix badge-phoenix-warning">
|
||||||
waiting for approval
|
waiting for approval
|
||||||
|
</span>
|
||||||
{% elif car.get_transfer.status == "approved" %}
|
{% elif car.get_transfer.status == "approved" %}
|
||||||
|
<span class="badge badge-phoenix badge-phoenix-info">
|
||||||
waiting for dealer acceptance
|
waiting for dealer acceptance
|
||||||
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ car.get_transfer.from_dealer }}</td>
|
<td>{{ car.get_transfer.from_dealer|title }}</td>
|
||||||
<td>{{ car.get_transfer.to_dealer }}</td>
|
<td>{{ car.get_transfer.to_dealer|title }}</td>
|
||||||
<td>{{ car.get_transfer.transfer_date }}</td>
|
<td>{{ car.get_transfer.transfer_date|date:"Y-m-d" }}</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{% if car.get_transfer.status == "draft" %}
|
{% if car.get_transfer.status == "draft" %}
|
||||||
<a href="{% url 'transfer_detail' car.get_transfer.pk %}">Approve</a>
|
<a class="btn btn-sm btn-phoenix-success" href="{% url 'transfer_detail' car.get_transfer.pk %}">Approve</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -240,7 +240,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
function calculateTotals() {
|
function calculateTotals() {
|
||||||
const table = document.getElementById('estimate-table');
|
const table = document.getElementById('estimate-table');
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
const Toast = Swal.mixin({
|
const Toast = Swal.mixin({
|
||||||
toast: true,
|
toast: true,
|
||||||
@ -115,6 +115,7 @@
|
|||||||
quantity: []
|
quantity: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Collect multi-value fields (e.g., item[], quantity[])
|
// Collect multi-value fields (e.g., item[], quantity[])
|
||||||
document.querySelectorAll('[name="item[]"]').forEach(input => {
|
document.querySelectorAll('[name="item[]"]').forEach(input => {
|
||||||
formData.item.push(input.value);
|
formData.item.push(input.value);
|
||||||
@ -122,7 +123,7 @@
|
|||||||
document.querySelectorAll('[name="quantity[]"]').forEach(input => {
|
document.querySelectorAll('[name="quantity[]"]').forEach(input => {
|
||||||
formData.quantity.push(input.value);
|
formData.quantity.push(input.value);
|
||||||
});
|
});
|
||||||
console.log(formData)
|
|
||||||
try {
|
try {
|
||||||
// Send data to the server using fetch
|
// Send data to the server using fetch
|
||||||
const response = await fetch("{% url 'bill_create' %}", {
|
const response = await fetch("{% url 'bill_create' %}", {
|
||||||
@ -154,4 +155,4 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock extra_js %}
|
{% endblock customJS %}
|
||||||
50
templates/notifications.html
Normal file
50
templates/notifications.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<li class="nav-item dropdown">
|
||||||
|
<div class="notification-count" hx-get="{% url 'fetch_notifications' %}" hx-trigger="every 10s" hx-swap="innerHTML" hx-select=".notification-count">
|
||||||
|
{% if notifications_ %}
|
||||||
|
<span class="badge bg-danger rounded-pill " id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">{{ notifications_.count }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<a class="nav-link" href="{% url 'fetch_notifications' %}" hx-get="{% url 'fetch_notifications' %}" hx-swap="innerHTML" hx-target=".card-body" hx-select=".card-body" style="min-width: 2.25rem" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-bs-auto-close="outside"><span class="d-block" style="height:20px;width:20px;"><span data-feather="bell" style="height:20px;width:20px;"></span></span></span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-end notification-dropdown-menu py-0 shadow border navbar-dropdown-caret" id="navbarDropdownNotfication" aria-labelledby="navbarDropdownNotfication">
|
||||||
|
<div class="card position-relative border-0">
|
||||||
|
<div class="card-header p-2">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<h5 class="text-body-emphasis mb-0">Notifications</h5>
|
||||||
|
<button class="btn btn-link p-0 fs-9 fw-normal" type="button">Mark all as read</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="scrollbar-overlay" style="height: 27rem;">
|
||||||
|
{% for notification in notifications_ %}
|
||||||
|
<div class="px-2 px-sm-3 py-3 notification-card position-relative read border-bottom">
|
||||||
|
<div class="d-flex align-items-center justify-content-between position-relative">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-1 me-sm-3">
|
||||||
|
<h4 class="fs-9 text-body-emphasis">System</h4>
|
||||||
|
<p class="fs-9 text-body-highlight mb-2 mb-sm-3 fw-normal">
|
||||||
|
<span class="me-1 fs-10">💬</span>{{notification.message|safe}}<span class="ms-2 text-body-quaternary text-opacity-75 fw-bold fs-10">10m</span>
|
||||||
|
</p>
|
||||||
|
<p class="text-body-secondary fs-9 mb-0">
|
||||||
|
<span class="me-1 fas fa-clock"></span><span class="fw-bold">10:41 AM</span>{{notification.created}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown notification-dropdown">
|
||||||
|
<button class="btn fs-10 btn-sm dropdown-toggle dropdown-caret-none transition-none" 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 text-body"></span></button>
|
||||||
|
<div class="dropdown-menu py-2">
|
||||||
|
<a class="dropdown-item" href="{% url 'mark_notification_as_read' notification.id %}">Mark as read</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer p-0 border-top border-translucent border-0">
|
||||||
|
<div class="my-2 text-center fw-bold fs-10 text-body-tertiary text-opactity-85"><a class="fw-bolder" href="{% url 'notifications_history' %}">Notification history</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
@ -174,7 +174,7 @@
|
|||||||
<!-- ============================================-->
|
<!-- ============================================-->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
function calculateTotals() {
|
function calculateTotals() {
|
||||||
const table = document.getElementById('estimate-table');
|
const table = document.getElementById('estimate-table');
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
const Toast = Swal.mixin({
|
const Toast = Swal.mixin({
|
||||||
toast: true,
|
toast: true,
|
||||||
@ -155,4 +155,4 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock extra_js %}
|
{% endblock customJS %}
|
||||||
@ -262,7 +262,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block customJS %}
|
||||||
<script>
|
<script>
|
||||||
function calculateTotals() {
|
function calculateTotals() {
|
||||||
const table = document.getElementById('estimate-table');
|
const table = document.getElementById('estimate-table');
|
||||||
|
|||||||
@ -12,20 +12,18 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock extra_css %}
|
{% endblock extra_css %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row {% if invoice.invoice_status == 'paid' %}paid{% endif %}">
|
<div class="row {% if model.is_paid %}paid{% endif %}">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{% if invoice.invoice_status == 'paid' %}
|
{% if model.is_paid %}
|
||||||
<div class="card-header">{{ _("Payment Already Made") }}</div>
|
<div class="card-header">{{ _("Payment Already Made") }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="card-header">{{ _("Make Payment") }}</div>
|
<div class="card-header">{{ _("Make Payment") }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if invoice %}
|
{% if model %}
|
||||||
<form method="post" action="{% url 'payment_create' pk=invoice.pk %}">
|
<form method="post" action="{% url 'payment_create' pk=model.pk %}">
|
||||||
{% else %}
|
|
||||||
<form method="post" action="{% url 'payment_create' %}">
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="d-flex justify-content-between mb-2">
|
<div class="d-flex justify-content-between mb-2">
|
||||||
<h3 class="mb-3">{% trans "Payments" %}</h3>
|
<h3 class="mb-3">{% trans "Payments" %}</h3>
|
||||||
<a href="{% url 'payment_create' %}" class="btn btn-sm btn-phoenix-success ">{% trans "Add Payment" %}</a>
|
{% comment %} <a href="{% url 'payment_create' %}" class="btn btn-sm btn-phoenix-success ">{% trans "Add Payment" %}</a> {% endcomment %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user