diff --git a/car_inventory/__pycache__/settings.cpython-311.pyc b/car_inventory/__pycache__/settings.cpython-311.pyc index 0b5df19d..92b03f6f 100644 Binary files a/car_inventory/__pycache__/settings.cpython-311.pyc and b/car_inventory/__pycache__/settings.cpython-311.pyc differ diff --git a/car_inventory/__pycache__/urls.cpython-311.pyc b/car_inventory/__pycache__/urls.cpython-311.pyc index c3b2ce49..8c3b05d2 100644 Binary files a/car_inventory/__pycache__/urls.cpython-311.pyc and b/car_inventory/__pycache__/urls.cpython-311.pyc differ diff --git a/inventory/__pycache__/forms.cpython-311.pyc b/inventory/__pycache__/forms.cpython-311.pyc index 12124502..e8abe287 100644 Binary files a/inventory/__pycache__/forms.cpython-311.pyc and b/inventory/__pycache__/forms.cpython-311.pyc differ diff --git a/inventory/__pycache__/models.cpython-311.pyc b/inventory/__pycache__/models.cpython-311.pyc index 0c155c75..70f9051c 100644 Binary files a/inventory/__pycache__/models.cpython-311.pyc and b/inventory/__pycache__/models.cpython-311.pyc differ diff --git a/inventory/__pycache__/urls.cpython-311.pyc b/inventory/__pycache__/urls.cpython-311.pyc index ad43661e..f61334df 100644 Binary files a/inventory/__pycache__/urls.cpython-311.pyc and b/inventory/__pycache__/urls.cpython-311.pyc differ diff --git a/inventory/__pycache__/utils.cpython-311.pyc b/inventory/__pycache__/utils.cpython-311.pyc index 522f9ffc..6aa2a8a8 100644 Binary files a/inventory/__pycache__/utils.cpython-311.pyc and b/inventory/__pycache__/utils.cpython-311.pyc differ diff --git a/inventory/__pycache__/views.cpython-311.pyc b/inventory/__pycache__/views.cpython-311.pyc index b2b0facf..b104ad26 100644 Binary files a/inventory/__pycache__/views.cpython-311.pyc and b/inventory/__pycache__/views.cpython-311.pyc differ diff --git a/inventory/forms.py b/inventory/forms.py index 8dcd403e..f5b397b6 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -16,7 +16,6 @@ from .models import ( Vendor, Customer, Car, - CarTransfer, CarFinance, CustomCard, CarRegistration, @@ -242,14 +241,6 @@ class CarLocationForm(forms.ModelForm): "description": forms.Textarea(attrs={"rows": 2, "class": "form-control"}), } -class CarTransferForm(forms.ModelForm): - class Meta: - model = CarTransfer - fields = ["car", "to_dealer", "remarks"] - widgets = { - "remarks": forms.Textarea(attrs={"rows": 2, "class": "form-control"}), - } - # Custom Card Form class CustomCardForm(forms.ModelForm): diff --git a/inventory/migrations/0007_delete_cartransferlog.py b/inventory/migrations/0007_delete_cartransferlog.py new file mode 100644 index 00000000..c926ee10 --- /dev/null +++ b/inventory/migrations/0007_delete_cartransferlog.py @@ -0,0 +1,16 @@ +# Generated by Django 5.1.5 on 2025-01-21 12:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0006_cartransferlog_delete_invoicemodelbase'), + ] + + operations = [ + migrations.DeleteModel( + name='CarTransferLog', + ), + ] diff --git a/inventory/models.py b/inventory/models.py index 3b708eed..eb908558 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -17,6 +17,7 @@ from django_ledger.models import ( UnitOfMeasureModel, CustomerModel, ItemModelQuerySet, + ) from django.db.models import Sum from decimal import Decimal, InvalidOperation @@ -28,105 +29,66 @@ from sqlalchemy.orm.base import object_state from .utilities.financials import get_financial_value, get_total, get_total_financials from django.db.models import FloatField from .mixins import LocalizedNameMixin -from django_ledger.models import EntityModel, ItemModel +from django_ledger.models import EntityModel,ItemModel from django_countries.fields import CountryField from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class DealerUserManager(UserManager): - def create_user_with_dealer( - self, - email, - password, - dealer_name, - arabic_name, - crn, - vrn, - address, - **extra_fields, - ): - user = self.create_user( - username=email, email=email, password=password, **extra_fields - ) - Dealer.objects.create( - user=user, - name=dealer_name, - arabic_name=arabic_name, - crn=crn, - vrn=vrn, - address=address, - **extra_fields, - ) + def create_user_with_dealer(self, email, password, dealer_name, arabic_name, crn, vrn, address, **extra_fields): + user = self.create_user(username=email, email=email, password=password, **extra_fields) + Dealer.objects.create(user=user, name=dealer_name,arabic_name=arabic_name, crn=crn, vrn=vrn, address=address, **extra_fields) return user class StaffUserManager(UserManager): - def create_user_with_staff( - self, - email, - password, - name, - arabic_name, - phone_number, - staff_type, - **extra_fields, - ): - user = self.create_user( - username=email, email=email, password=password, **extra_fields - ) - Staff.objects.create( - user=user, - name=name, - arabic_name=arabic_name, - phone_number=phone_number, - staff_type=staff_type, - **extra_fields, - ) + def create_user_with_staff(self, email, password, name, arabic_name, phone_number, staff_type, **extra_fields): + user = self.create_user(username=email, email=email, password=password, **extra_fields) + Staff.objects.create(user=user, name=name, arabic_name=arabic_name, phone_number=phone_number, staff_type=staff_type, **extra_fields) return user - - + class UnitOfMeasure(models.TextChoices): - EACH = "EA", "Each" - PAIR = "PR", "Pair" - SET = "SET", "Set" - GALLON = "GAL", "Gallon" - LITER = "L", "Liter" - METER = "M", "Meter" - KILOGRAM = "KG", "Kilogram" - HOUR = "HR", "Hour" - BOX = "BX", "Box" - ROLL = "RL", "Roll" - PACKAGE = "PKG", "Package" - DOZEN = "DZ", "Dozen" - SQUARE_METER = "SQ_M", "Square Meter" - PIECE = "PC", "Piece" - BUNDLE = "BDL", "Bundle" + EACH = 'EA', 'Each' + PAIR = 'PR', 'Pair' + SET = 'SET', 'Set' + GALLON = 'GAL', 'Gallon' + LITER = 'L', 'Liter' + METER = 'M', 'Meter' + KILOGRAM = 'KG', 'Kilogram' + HOUR = 'HR', 'Hour' + BOX = 'BX', 'Box' + ROLL = 'RL', 'Roll' + PACKAGE = 'PKG', 'Package' + DOZEN = 'DZ', 'Dozen' + SQUARE_METER = 'SQ_M', 'Square Meter' + PIECE = 'PC', 'Piece' + BUNDLE = 'BDL', 'Bundle' class VatRate(models.Model): - rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.15")) + rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.15')) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Rate: {self.rate}%" - class CarType(models.IntegerChoices): - CAR = 1, _("Car") - LIGHT_COMMERCIAL = 2, _("Light Commercial") - HEAVY_DUTY_TRACTORS = 3, _("Heavy-Duty Tractors") - TRAILERS = 4, _("Trailers") - MEDIUM_TRUCKS = 5, _("Medium Trucks") - BUSES = 6, _("Buses") - MOTORCYCLES = 20, _("Motorcycles") - BUGGY = 21, _("Buggy") - MOTO_ATV = 22, _("Moto ATV") - SCOOTERS = 23, _("Scooters") - KARTING = 24, _("Karting") - ATV = 25, _("ATV") - SNOWMOBILES = 26, _("Snowmobiles") + CAR = 1, _('Car') + LIGHT_COMMERCIAL = 2, _('Light Commercial') + HEAVY_DUTY_TRACTORS = 3, _('Heavy-Duty Tractors') + TRAILERS = 4, _('Trailers') + MEDIUM_TRUCKS = 5, _('Medium Trucks') + BUSES = 6, _('Buses') + MOTORCYCLES = 20, _('Motorcycles') + BUGGY = 21, _('Buggy') + MOTO_ATV = 22, _('Moto ATV') + SCOOTERS = 23, _('Scooters') + KARTING = 24, _('Karting') + ATV = 25, _('ATV') + SNOWMOBILES = 26, _('Snowmobiles') + class CarMake(models.Model, LocalizedNameMixin): @@ -159,9 +121,7 @@ class CarModel(models.Model, LocalizedNameMixin): class CarSerie(models.Model, LocalizedNameMixin): id_car_serie = models.AutoField(primary_key=True) - id_car_model = models.ForeignKey( - CarModel, models.DO_NOTHING, db_column="id_car_model" - ) + id_car_model = models.ForeignKey(CarModel, models.DO_NOTHING, db_column="id_car_model") name = models.CharField(max_length=255, blank=True, null=True) arabic_name = models.CharField(max_length=255, blank=True, null=True) year_begin = models.IntegerField(blank=True, null=True) @@ -177,9 +137,7 @@ class CarSerie(models.Model, LocalizedNameMixin): class CarTrim(models.Model, LocalizedNameMixin): id_car_trim = models.AutoField(primary_key=True) - id_car_serie = models.ForeignKey( - CarSerie, models.DO_NOTHING, db_column="id_car_serie" - ) + id_car_serie = models.ForeignKey(CarSerie, models.DO_NOTHING, db_column="id_car_serie") name = models.CharField(max_length=255, blank=True, null=True) arabic_name = models.CharField(max_length=255, blank=True, null=True) start_production_year = models.IntegerField(blank=True, null=True) @@ -201,7 +159,6 @@ class CarEquipment(models.Model, LocalizedNameMixin): def __str__(self): return self.name - class Meta: verbose_name = "Equipment" @@ -210,9 +167,7 @@ class CarSpecification(models.Model, LocalizedNameMixin): id_car_specification = models.AutoField(primary_key=True) name = models.CharField(max_length=255) arabic_name = models.CharField(max_length=255) - id_parent = models.ForeignKey( - "self", models.DO_NOTHING, db_column="id_parent", blank=True, null=True - ) + id_parent = models.ForeignKey("self", models.DO_NOTHING, db_column="id_parent", blank=True, null=True) def __str__(self): return self.name @@ -224,9 +179,7 @@ class CarSpecification(models.Model, LocalizedNameMixin): class CarSpecificationValue(models.Model): id_car_specification_value = models.AutoField(primary_key=True) id_car_trim = models.ForeignKey(CarTrim, models.DO_NOTHING, db_column="id_car_trim") - id_car_specification = models.ForeignKey( - CarSpecification, models.DO_NOTHING, db_column="id_car_specification" - ) + id_car_specification = models.ForeignKey(CarSpecification, models.DO_NOTHING, db_column="id_car_specification") value = models.CharField(max_length=500) unit = models.CharField(max_length=255, blank=True, null=True) @@ -241,9 +194,7 @@ class CarOption(models.Model, LocalizedNameMixin): id_car_option = models.AutoField(primary_key=True) name = models.CharField(max_length=255, blank=True, null=True) arabic_name = models.CharField(max_length=255, blank=True, null=True) - id_parent = models.ForeignKey( - "self", models.DO_NOTHING, db_column="id_parent", blank=True, null=True - ) + id_parent = models.ForeignKey("self", models.DO_NOTHING, db_column="id_parent", blank=True, null=True) def __str__(self): return self.name @@ -254,12 +205,8 @@ class CarOption(models.Model, LocalizedNameMixin): class CarOptionValue(models.Model): id_car_option_value = models.AutoField(primary_key=True) - id_car_option = models.ForeignKey( - CarOption, models.DO_NOTHING, db_column="id_car_option" - ) - id_car_equipment = models.ForeignKey( - CarEquipment, models.DO_NOTHING, db_column="id_car_equipment" - ) + id_car_option = models.ForeignKey(CarOption, models.DO_NOTHING, db_column="id_car_option") + id_car_equipment = models.ForeignKey(CarEquipment, models.DO_NOTHING, db_column="id_car_equipment") value = models.CharField(max_length=500) unit = models.CharField(max_length=255, blank=True, null=True) is_base = models.IntegerField() @@ -271,51 +218,27 @@ class CarOptionValue(models.Model): verbose_name = "Option Value" -class CarTransferStatusChoices(models.TextChoices): - draft = "draft", _("Draft") - approved = "approved", _("Approved") - pending = "pending", _("Pending") - accepted = "accepted", _("Accepted") - success = "success", _("Success") - reject = "reject", _("Reject") - - class CarStatusChoices(models.TextChoices): AVAILABLE = "available", _("Available") SOLD = "sold", _("Sold") HOLD = "hold", _("Hold") DAMAGED = "damaged", _("Damaged") - RESERVED = "reserved", _("Reserved") - TRANSFER = "transfer", _("Transfer") + RESERVED = "reserved", _("Reserved") + class CarStockTypeChoices(models.TextChoices): NEW = "new", _("New") USED = "used", _("Used") - class AdditionalServices(models.Model, LocalizedNameMixin): 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( - max_digits=14, decimal_places=2, verbose_name=_("Price") - ) + price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Price")) taxable = models.BooleanField(default=False, verbose_name=_("taxable")) - uom = models.CharField( - max_length=10, - choices=UnitOfMeasure.choices, - verbose_name=_("Unit of Measurement"), - ) - dealer = models.ForeignKey( - "Dealer", on_delete=models.CASCADE, verbose_name=_("Dealer") - ) - item = models.OneToOneField( - ItemModel, - on_delete=models.CASCADE, - verbose_name=_("Item"), - null=True, - blank=True, - ) + uom = models.CharField(max_length=10, choices=UnitOfMeasure.choices, verbose_name=_("Unit of Measurement")) + dealer = models.ForeignKey("Dealer", on_delete=models.CASCADE, verbose_name=_("Dealer")) + item = models.OneToOneField(ItemModel, on_delete=models.CASCADE, verbose_name=_("Item"),null=True, blank=True) class Meta: verbose_name = _("Additional Services") @@ -402,71 +325,13 @@ class Car(models.Model): active_reservations = self.reservations.filter(reserved_until__gt=now()) return active_reservations.exists() - def get_transfer(self): - return self.transfer_logs.filter(active=True).first() @property def get_car_group(self): return f"{self.id_car_make.get_local_name} {self.id_car_model.get_local_name}" - -class CarTransfer(models.Model): - car = models.ForeignKey( - "Car", - on_delete=models.CASCADE, - related_name="transfer_logs", - verbose_name=_("Car"), - ) - from_dealer = models.ForeignKey( - "Dealer", - on_delete=models.CASCADE, - related_name="transfers_out", - verbose_name=_("From Dealer"), - ) - to_dealer = models.ForeignKey( - "Dealer", - on_delete=models.CASCADE, - related_name="transfers_in", - verbose_name=_("To Dealer"), - ) - transfer_date = models.DateTimeField( - auto_now_add=True, verbose_name=_("Transfer Date") - ) - quantity = models.IntegerField(verbose_name=_("Quantity"),default=1) - remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks")) - status = models.CharField( - CarTransferStatusChoices.choices, - max_length=10, - default=CarTransferStatusChoices.draft, - ) - 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")) - - @property - def total_price(self): - return self.quantity * self.car.finances.cost_price - class Meta: - verbose_name = _("Car Transfer Log") - verbose_name_plural = _("Car Transfer Logs") - - def __str__(self): - return f"{self.car} Transfer car from {self.from_dealer} to {self.to_dealer}" - - class CarReservation(models.Model): - car = models.ForeignKey( - "Car", - on_delete=models.CASCADE, - related_name="reservations", - verbose_name=_("Car"), - ) - reserved_by = models.ForeignKey( - User, - on_delete=models.CASCADE, - related_name="reservations", - verbose_name=_("Reserved By"), - ) + car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Car")) + reserved_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Reserved By")) reserved_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Reserved At")) reserved_until = models.DateTimeField(verbose_name=_("Reserved Until")) @@ -475,64 +340,53 @@ class CarReservation(models.Model): return self.reserved_until > now() class Meta: - unique_together = ("car", "reserved_until") - ordering = ["-reserved_at"] + unique_together = ('car', 'reserved_until') + ordering = ['-reserved_at'] verbose_name = _("Car Reservation") verbose_name_plural = _("Car Reservations") # Car Finance Model class CarFinance(models.Model): - additional_services = models.ManyToManyField( - AdditionalServices, related_name="additional_finances", blank=True - ) - car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name="finances") - cost_price = models.DecimalField( - max_digits=14, decimal_places=2, verbose_name=_("Cost Price") - ) - selling_price = models.DecimalField( - max_digits=14, decimal_places=2, verbose_name=_("Selling Price") - ) - discount_amount = models.DecimalField( - max_digits=14, - decimal_places=2, - verbose_name=_("Discount Amount"), - default=Decimal("0.00"), - ) - + additional_services = models.ManyToManyField(AdditionalServices, related_name="additional_finances",blank=True) + car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='finances') + cost_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Cost Price")) + selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price")) + discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"), + default=Decimal('0.00')) + @property def total(self): if self.additional_services.count() > 0: - return self.selling_price + sum( - x.price for x in self.additional_services.all() - ) + return self.selling_price + sum(x.price for x in self.additional_services.all()) return self.selling_price - @property def total_discount(self): if self.discount_amount > 0: return self.total - self.discount_amount return self.total - + @property def total_vat(self): return self.total_discount + self.vat_amount - + + @property def vat_amount(self): vat = VatRate.objects.filter(is_active=True).first() if vat: - return (self.total_discount * Decimal(vat.rate)).quantize(Decimal("0.01")) - return Decimal("0.00") + return (self.total_discount * Decimal(vat.rate)).quantize(Decimal('0.01')) + return Decimal('0.00') @property def revenue(self): - return self.selling_price - self.cost_price - + return self.selling_price-self.cost_price + + def __str__(self): return f"Car: {self.car}, Selling Price: {self.selling_price}" - # def save(self, *args, **kwargs): + # def save(self, *args, **kwargs): # self.full_clean() # try: # price_after_discount = self.selling_price - self.discount_amount @@ -592,12 +446,7 @@ class CarColors(models.Model): class CustomCard(models.Model): - car = models.OneToOneField( - Car, - on_delete=models.CASCADE, - related_name="custom_cards", - verbose_name=_("Car"), - ) + car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car")) custom_number = models.CharField(max_length=255, verbose_name=_("Custom Number")) custom_date = models.DateField(verbose_name=_("Custom Date")) @@ -611,30 +460,39 @@ class CustomCard(models.Model): class CarLocation(models.Model): car = models.OneToOneField( - Car, on_delete=models.CASCADE, related_name="location", verbose_name=_("Car") + Car, + on_delete=models.CASCADE, + related_name='location', + verbose_name=_("Car") ) owner = models.ForeignKey( - "Dealer", + 'Dealer', on_delete=models.CASCADE, - related_name="owned_cars", + related_name='owned_cars', verbose_name=_("Owner"), - help_text=_("Dealer who owns the car."), + help_text=_("Dealer who owns the car.") ) showroom = models.ForeignKey( - "Dealer", + 'Dealer', on_delete=models.CASCADE, - related_name="showroom_cars", + related_name='showroom_cars', verbose_name=_("Showroom"), - help_text=_("Dealer where the car is displayed (can be the owner)."), + help_text=_("Dealer where the car is displayed (can be the owner).") ) description = models.TextField( blank=True, null=True, verbose_name=_("Description"), - help_text=_("Optional description about the showroom placement."), + help_text=_("Optional description about the showroom placement.") + ) + created_at = models.DateTimeField( + auto_now_add=True, + verbose_name=_("Created At") + ) + updated_at = models.DateTimeField( + auto_now=True, + verbose_name=_("Last Updated") ) - created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At")) - updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Last Updated")) class Meta: verbose_name = _("Car Location") @@ -661,14 +519,16 @@ class CarRegistration(models.Model): text1 = models.CharField(max_length=1, verbose_name=_("Text 1")) text2 = models.CharField(max_length=1, verbose_name=_("Text 2")) text3 = models.CharField(max_length=1, verbose_name=_("Text 3")) + # registration_type = registration_date = models.DateTimeField(verbose_name=_("Registration Date")) + registration_expiry_date = models.DateTimeField(verbose_name=_("Registration Expiry Date")) class Meta: verbose_name = _("Registration") verbose_name_plural = _("Registrations") def __str__(self): - return f"{self.plate_number} - {self.text1} {self.text2} {self.text3}" + return f"{self.text1} {self.text2} {self.text3} - {self.plate_number}" # TimestampedModel Abstract Class @@ -681,28 +541,19 @@ class TimestampedModel(models.Model): class Subscription(models.Model): - plan = models.ForeignKey( - "SubscriptionPlan", on_delete=models.CASCADE, related_name="subscriptions" - ) + plan = models.ForeignKey("SubscriptionPlan", on_delete=models.CASCADE, related_name="subscriptions") start_date = models.DateField(help_text="Date when the subscription starts") end_date = models.DateField(help_text="Date when the subscription ends") - users = models.ManyToManyField( - User, through="SubscriptionUser" - ) # many-to-many relationship with User model + users = models.ManyToManyField(User, through='SubscriptionUser') # many-to-many relationship with User model is_active = models.BooleanField(default=True) billing_cycle = models.CharField( max_length=10, - choices=[("monthly", "Monthly"), ("annual", "Annual")], - default="monthly", - help_text="Billing cycle for the subscription", + choices=[('monthly', 'Monthly'), ('annual', 'Annual')], + default='monthly', + help_text="Billing cycle for the subscription" ) - last_payment_date = models.DateField( - null=True, blank=True, help_text="Date of the last payment made" - ) - next_payment_date = models.DateField( - null=True, blank=True, help_text="Date of the next payment due" - ) - + last_payment_date = models.DateField(null=True, blank=True, help_text="Date of the last payment made") + next_payment_date = models.DateField(null=True, blank=True, help_text="Date of the next payment due") class Meta: verbose_name = _("Subscription") verbose_name_plural = _("Subscriptions") @@ -728,30 +579,18 @@ class SubscriptionUser(models.Model): class SubscriptionPlan(models.Model): - name = models.CharField( - max_length=100, unique=True, help_text=_("Name of the subscription plan") - ) + name = models.CharField(max_length=100, unique=True, help_text=_("Name of the subscription plan")) description = models.TextField() price = models.DecimalField(max_digits=10, decimal_places=2) - max_users = models.PositiveIntegerField( - help_text=_("Maximum number of users allowed"), default=1 - ) - max_inventory_size = models.PositiveIntegerField( - help_text=_("Maximum number of cars in inventory"), default=50 - ) + max_users = models.PositiveIntegerField(help_text=_("Maximum number of users allowed"), default=1) + max_inventory_size = models.PositiveIntegerField(help_text=_("Maximum number of cars in inventory"), default=50) support_level = models.CharField( max_length=50, - choices=[ - ("basic", "Basic Support"), - ("priority", "Priority Support"), - ("dedicated", "Dedicated Support"), - ], - default="basic", - help_text="Level of support provided", - ) - custom_features = models.JSONField( - blank=True, null=True, help_text=_("Additional features specific to this plan") + choices=[('basic', 'Basic Support'), ('priority', 'Priority Support'), ('dedicated', 'Dedicated Support')], + default='basic', + help_text="Level of support provided" ) + custom_features = models.JSONField(blank=True, null=True, help_text=_("Additional features specific to this plan")) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -765,27 +604,26 @@ class SubscriptionPlan(models.Model): class Dealer(models.Model, LocalizedNameMixin): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer") - crn = models.CharField( - max_length=10, - verbose_name=_("Commercial Registration Number"), - null=True, - blank=True, - ) - vrn = models.CharField( - max_length=15, verbose_name=_("VAT Registration Number"), null=True, blank=True - ) + crn = models.CharField(max_length=10, + verbose_name=_("Commercial Registration Number") + ,null=True + ,blank=True) + vrn = models.CharField(max_length=15, + verbose_name=_("VAT Registration Number"), + null=True, + blank=True) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) name = models.CharField(max_length=255, verbose_name=_("English Name")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) - address = models.CharField( - max_length=200, blank=True, null=True, verbose_name=_("Address") - ) - logo = models.ImageField( - upload_to="logos/users", blank=True, null=True, verbose_name=_("Logo") - ) - entity = models.ForeignKey( - EntityModel, on_delete=models.SET_NULL, null=True, blank=True - ) + address = models.CharField(max_length=200, + blank=True, + null=True, + verbose_name=_("Address")) + logo = models.ImageField(upload_to="logos/users", + blank=True, + null=True, + verbose_name=_("Logo")) + entity = models.ForeignKey(EntityModel, on_delete=models.SET_NULL, null=True, blank=True) joined_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Joined At")) updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At")) @@ -811,14 +649,14 @@ class Dealer(models.Model, LocalizedNameMixin): class Meta: verbose_name = _("Dealer") - verbose_name_plural = _("Dealers") + verbose_name_plural = _("Dealers") # permissions = [ # ('change_dealer_type', 'Can change dealer type'), # ] def __str__(self): return self.name - + # @property # def get_sub_dealers(self): # if self.dealer_type == "OWNER": @@ -832,18 +670,18 @@ class Dealer(models.Model, LocalizedNameMixin): # def get_root_dealer(self): # return self.parent_dealer if self.parent_dealer else self - ############################## # Additional staff types for later -# COORDINATOR = "coordinator", _("Coordinator") -# RECEPTIONIST = "receptionist", _("Receptionist") -# AGENT = "agent", _("Agent") -# TECHNICIAN = "technician", _("Technician") -# DRIVER = "driver", _("Driver") + # COORDINATOR = "coordinator", _("Coordinator") + # RECEPTIONIST = "receptionist", _("Receptionist") + # AGENT = "agent", _("Agent") + # TECHNICIAN = "technician", _("Technician") + # DRIVER = "driver", _("Driver") ############################## + class StaffTypes(models.TextChoices): MANAGER = "manager", _("Manager") INVENTORY = "inventory", _("Inventory") @@ -860,9 +698,7 @@ class Staff(models.Model, LocalizedNameMixin): name = models.CharField(max_length=255, verbose_name=_("Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) - staff_type = models.CharField( - choices=StaffTypes.choices, max_length=255, verbose_name=_("Staff Type") - ) + staff_type = models.CharField(choices=StaffTypes.choices, 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")) @@ -890,7 +726,6 @@ class Sources(models.TextChoices): YOUTUBE = "youtube", _("Youtube") CAMPAIGN = "campaign", _("Campaign") - class Channel(models.TextChoices): WALK_IN = "walk_in", _("Walk In") TOLL_FREE = "toll_free", _("Toll Free") @@ -906,7 +741,6 @@ class Status(models.TextChoices): QUALIFIED = "qualified", _("Qualified") CANCELED = "canceled", _("Canceled") - class Title(models.TextChoices): MR = "mr", _("Mr") MRS = "mrs", _("Mrs") @@ -919,7 +753,6 @@ class Title(models.TextChoices): COMPANY = "company", _("Company") NA = "na", _("N/A") - class ActionChoices(models.TextChoices): CALL = "call", _("Call") SMS = "sms", _("SMS") @@ -936,7 +769,6 @@ class ActionChoices(models.TextChoices): CREATE_INVOICE = "create_invoice", _("Create Invoice") CANCEL_INVOICE = "cancel_invoice", _("Cancel Invoice") - class Stage(models.TextChoices): PROSPECT = "prospect", _("Prospect") PROPOSAL = "proposal", _("Proposal") @@ -944,7 +776,6 @@ class Stage(models.TextChoices): CLOSED_WON = "closed_won", _("Closed Won") CLOSED_LOST = "closed_lost", _("Closed Lost") - class Priority(models.TextChoices): LOW = "low", _("Low") MEDIUM = "medium", _("Medium") @@ -952,33 +783,17 @@ class Priority(models.TextChoices): class Customer(models.Model): - dealer = models.ForeignKey( - Dealer, on_delete=models.CASCADE, related_name="customers" - ) - title = models.CharField( - choices=Title.choices, default=Title.NA, max_length=10, verbose_name=_("Title") - ) + dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE,related_name="customers") + title = models.CharField(choices=Title.choices, default=Title.NA, max_length=10, verbose_name=_("Title")) first_name = models.CharField(max_length=50, verbose_name=_("First Name")) - middle_name = models.CharField( - max_length=50, blank=True, null=True, verbose_name=_("Middle Name") - ) + middle_name = models.CharField(max_length=50, blank=True, 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"), - ) + 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(unique=True, verbose_name=_("Email")) - national_id = models.CharField( - max_length=10, unique=True, verbose_name=_("National ID") - ) - phone_number = PhoneNumberField( - region="SA", unique=True, verbose_name=_("Phone Number") - ) - address = models.CharField( - max_length=200, blank=True, null=True, verbose_name=_("Address") - ) + national_id = models.CharField(max_length=10, unique=True, verbose_name=_("National ID")) + phone_number = PhoneNumberField(region="SA", unique=True, verbose_name=_("Phone Number")) + address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) @@ -996,48 +811,33 @@ class Customer(models.Model): class Organization(models.Model, LocalizedNameMixin): - dealer = models.ForeignKey( - Dealer, on_delete=models.CASCADE, related_name="organizations" - ) + dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='organizations') name = models.CharField(max_length=255, verbose_name=_("Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) - crn = models.CharField( - max_length=15, verbose_name=_("Commercial Registration Number") - ) + crn = models.CharField(max_length=15, verbose_name=_("Commercial Registration Number")) vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) - address = models.CharField( - max_length=200, blank=True, null=True, verbose_name=_("Address") - ) - logo = models.ImageField( - upload_to="logos", blank=True, null=True, verbose_name=_("Logo") - ) + phone_number = PhoneNumberField(region='SA', verbose_name=_("Phone Number")) + address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address")) + logo = models.ImageField(upload_to="logos", blank=True, null=True, verbose_name=_("Logo")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) class Meta: verbose_name = _("Organization") verbose_name_plural = _("Organizations") - def __str__(self): return self.name class Representative(models.Model, LocalizedNameMixin): - dealer = models.ForeignKey( - Dealer, on_delete=models.CASCADE, related_name="representatives" - ) + dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='representatives') name = models.CharField(max_length=255, verbose_name=_("Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) - id_number = models.CharField( - max_length=10, unique=True, verbose_name=_("ID Number") - ) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + id_number = models.CharField(max_length=10, unique=True, verbose_name=_("ID Number")) + phone_number = PhoneNumberField(region='SA', verbose_name=_("Phone Number")) email = models.EmailField(max_length=255, verbose_name=_("Email Address")) - address = models.CharField( - max_length=200, blank=True, null=True, verbose_name=_("Address") - ) - organization = models.ManyToManyField(Organization, related_name="representatives") + address = models.CharField(max_length=200, blank=True, null=True, verbose_name=_("Address")) + organization = models.ManyToManyField(Organization, related_name='representatives') class Meta: verbose_name = _("Representative") @@ -1049,57 +849,18 @@ class Representative(models.Model, LocalizedNameMixin): class Lead(models.Model): dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="leads") - customer = models.ForeignKey( - Customer, on_delete=models.CASCADE, related_name="leads" - ) - id_car_make = models.ForeignKey( - CarMake, - on_delete=models.DO_NOTHING, - blank=True, - null=True, - verbose_name=_("Make"), - ) - id_car_model = models.ForeignKey( - CarModel, - on_delete=models.DO_NOTHING, - blank=True, - null=True, - verbose_name=_("Model"), - ) - year = models.PositiveSmallIntegerField( - verbose_name=_("Year"), blank=True, null=True - ) - source = models.CharField( - max_length=50, choices=Sources.choices, verbose_name=_("Source") - ) - channel = models.CharField( - max_length=50, choices=Channel.choices, verbose_name=_("Channel") - ) + customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="leads") + id_car_make = models.ForeignKey(CarMake, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("Make")) + id_car_model = models.ForeignKey(CarModel, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("Model")) + year = models.PositiveSmallIntegerField(verbose_name=_("Year"), blank=True, null=True) + source = models.CharField(max_length=50, choices=Sources.choices, verbose_name=_("Source")) + channel = models.CharField(max_length=50, choices=Channel.choices, verbose_name=_("Channel")) city = models.CharField(max_length=50, verbose_name=_("City")) - staff = models.ForeignKey( - Staff, - on_delete=models.SET_NULL, - blank=True, - null=True, - related_name="assigned", - verbose_name=_("Assigned"), - ) - priority = models.CharField( - max_length=10, - choices=Priority.choices, - default=Priority.MEDIUM, - verbose_name=_("Priority"), - ) - status = models.CharField( - max_length=50, - choices=Status.choices, - verbose_name=_("Status"), - db_index=True, - default=Status.NEW, - ) - created = models.DateTimeField( - auto_now_add=True, verbose_name=_("Created"), db_index=True - ) + staff = models.ForeignKey(Staff, on_delete=models.SET_NULL, blank=True, null=True, related_name="assigned", verbose_name=_("Assigned")) + priority = models.CharField(max_length=10, choices=Priority.choices, default=Priority.MEDIUM, + verbose_name=_("Priority")) + status = models.CharField(max_length=50, choices=Status.choices, verbose_name=_("Status"), db_index=True, default=Status.NEW) + created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"), db_index=True) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) class Meta: @@ -1107,22 +868,14 @@ class Lead(models.Model): verbose_name_plural = _("Leads") def __str__(self): - return f"{self.first_name} {self.last_name}" + return self.customer.get_full_name class LeadStatusHistory(models.Model): - lead = models.ForeignKey( - Lead, on_delete=models.CASCADE, related_name="status_history" - ) - old_status = models.CharField( - max_length=50, choices=Status.choices, verbose_name=_("Old Status") - ) - new_status = models.CharField( - max_length=50, choices=Status.choices, verbose_name=_("New Status") - ) - changed_by = models.ForeignKey( - Staff, on_delete=models.DO_NOTHING, related_name="status_changes" - ) + lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name="status_history") + old_status = models.CharField(max_length=50, choices=Status.choices, verbose_name=_("Old Status")) + new_status = models.CharField(max_length=50, choices=Status.choices, verbose_name=_("New Status")) + changed_by = models.ForeignKey(Staff, on_delete=models.DO_NOTHING, related_name="status_changes") changed_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Changed At")) class Meta: @@ -1139,31 +892,12 @@ def validate_probability(value): class Opportunity(models.Model): - dealer = models.ForeignKey( - Dealer, on_delete=models.CASCADE, related_name="opportunities" - ) - customer = models.ForeignKey( - Customer, on_delete=models.CASCADE, related_name="opportunities" - ) - car = models.ForeignKey( - Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car") - ) - stage = models.CharField( - max_length=20, choices=Stage.choices, verbose_name=_("Stage") - ) - status = models.CharField( - max_length=20, - choices=Status.choices, - verbose_name=_("Status"), - default=Status.NEW, - ) - staff = models.ForeignKey( - Staff, - on_delete=models.SET_NULL, - null=True, - related_name="owner", - verbose_name=_("Owner"), - ) + dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="opportunities") + customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="opportunities") + car = models.ForeignKey(Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")) + stage = models.CharField(max_length=20, choices=Stage.choices, verbose_name=_("Stage")) + status = models.CharField(max_length=20, choices=Status.choices, verbose_name=_("Status"), default=Status.NEW) + staff = models.ForeignKey(Staff, on_delete=models.SET_NULL, null=True, related_name="owner", verbose_name=_("Owner")) probability = models.PositiveIntegerField(validators=[validate_probability]) closing_date = models.DateField(verbose_name=_("Closing Date")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) @@ -1181,11 +915,9 @@ class Opportunity(models.Model): class Notes(models.Model): content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() - content_object = GenericForeignKey("content_type", "object_id") + content_object = GenericForeignKey('content_type', 'object_id') note = models.TextField(verbose_name=_("Note")) - created_by = models.ForeignKey( - User, on_delete=models.DO_NOTHING, related_name="notes_created" - ) + created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="notes_created") created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) @@ -1200,14 +932,10 @@ class Notes(models.Model): class Activity(models.Model): content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() - content_object = GenericForeignKey("content_type", "object_id") - activity_type = models.CharField( - max_length=50, choices=ActionChoices.choices, verbose_name=_("Activity Type") - ) + content_object = GenericForeignKey('content_type', 'object_id') + activity_type = models.CharField(max_length=50, choices=ActionChoices.choices, verbose_name=_("Activity Type")) notes = models.TextField(blank=True, null=True, verbose_name=_("Notes")) - created_by = models.ForeignKey( - User, on_delete=models.DO_NOTHING, related_name="activities_created" - ) + created_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name="activities_created") created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) @@ -1220,9 +948,7 @@ class Activity(models.Model): class Notification(models.Model): - user = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="notifications" - ) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="notifications") 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")) @@ -1230,7 +956,7 @@ class Notification(models.Model): class Meta: verbose_name = _("Notification") verbose_name_plural = _("Notifications") - ordering = ["-created"] + ordering = ['-created'] def __str__(self): return self.message @@ -1265,6 +991,7 @@ class Vendor(models.Model, LocalizedNameMixin): return self.name + class SaleQuotation(models.Model): quotation_number = models.CharField(max_length=10, unique=True) @@ -1276,7 +1003,7 @@ class SaleQuotation(models.Model): ] dealer = models.ForeignKey( Dealer, on_delete=models.CASCADE, related_name="sales", null=True - ) + ) customer = models.ForeignKey( Customer, on_delete=models.CASCADE, @@ -1296,47 +1023,35 @@ class SaleQuotation(models.Model): ) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At")) updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At")) - + posted = models.BooleanField(default=False) - payment_id = models.CharField( - max_length=255, null=True, blank=True, verbose_name=_("Payment ID") - ) + payment_id = models.CharField(max_length=255, null=True, blank=True, verbose_name=_("Payment ID")) is_paid = models.BooleanField(default=False) - date_draft = models.DateTimeField( - null=True, blank=True, verbose_name=_("Draft Date") - ) - date_in_review = models.DateTimeField( - null=True, blank=True, verbose_name=_("In Review Date") - ) - date_approved = models.DateTimeField( - null=True, blank=True, verbose_name=_("Approved Date") - ) - date_paid = models.DateTimeField(null=True, blank=True, verbose_name=_("Paid Date")) - date_void = models.DateTimeField(null=True, blank=True, verbose_name=_("Void Date")) - date_canceled = models.DateTimeField( - null=True, blank=True, verbose_name=_("Canceled Date") - ) + date_draft = models.DateTimeField(null=True, blank=True, verbose_name=_('Draft Date')) + date_in_review = models.DateTimeField(null=True, blank=True, verbose_name=_('In Review Date')) + date_approved = models.DateTimeField(null=True, blank=True, verbose_name=_('Approved Date')) + date_paid = models.DateTimeField(null=True, blank=True, verbose_name=_('Paid Date')) + date_void = models.DateTimeField(null=True, blank=True, verbose_name=_('Void Date')) + date_canceled = models.DateTimeField(null=True, blank=True, verbose_name=_('Canceled Date')) @property def total_quantity(self): - total_quantity = self.quotation_cars.aggregate(total=Sum("quantity"))["total"] + total_quantity = self.quotation_cars.aggregate(total=Sum('quantity'))['total'] return total_quantity or 0 @property def total(self): - total = self.quotation_cars.aggregate( - total_price=Sum(F("car__finances__selling_price") * F("quantity")) - ) + total = self.quotation_cars.aggregate(total_price=Sum(F('car__finances__selling_price') * F('quantity'))) if not total: return 0 return total["total_price"] - + @property def total_vat(self): if self.total: return float(self.total) * 0.15 + float(self.total) return 0 - + # def confirm(self): # """Confirm the quotation and lock financial details.""" # if self.status != "DRAFT": @@ -1353,11 +1068,11 @@ class SaleQuotation(models.Model): def __str__(self): return f"Quotation #{self.quotation_number} for {self.customer}" - + @property def display_quotation_number(self): return f"QN-{self.quotation_number}" - + def save(self, *args, **kwargs): if not self.quotation_number: self.quotation_number = str(next(self._get_quotation_number())).zfill(6) @@ -1365,7 +1080,7 @@ class SaleQuotation(models.Model): @classmethod def _get_quotation_number(cls): - last_quotation = cls.objects.all().order_by("id").last() + last_quotation = cls.objects.all().order_by('id').last() if last_quotation: last_quotation_number = int(last_quotation.quotation_number) else: @@ -1380,13 +1095,16 @@ class SaleQuotationCar(models.Model): related_name="quotation_cars", verbose_name=_("Quotation"), ) - car = models.ForeignKey(Car, on_delete=models.CASCADE, verbose_name=_("Car")) + car = models.ForeignKey( + Car, + on_delete=models.CASCADE, + verbose_name=_("Car") + ) quantity = models.PositiveIntegerField(default=1, verbose_name=_("Quantity")) - + @property def finance(self): return self.car.finances - @property def financial_details(self): """ @@ -1415,7 +1133,6 @@ class SaleQuotationCar(models.Model): if not self.car.finances: return Decimal("0.00") return self.car.finances.selling_price * self.quantity - @property def total_vat(self): """ @@ -1448,24 +1165,16 @@ class SalesOrder(models.Model): class Payment(models.Model): METHOD_CHOICES = [ - ("cash", _("cash")), - ("credit", _("credit")), - ("transfer", _("transfer")), - ("debit", _("debit")), - ("SADAD", _("SADAD")), + ('cash', _('cash')), + ('credit', _('credit')), + ('transfer', _('transfer')), + ('debit', _('debit')), + ('SADAD', _('SADAD')), ] - quotation = models.ForeignKey( - SaleQuotation, on_delete=models.CASCADE, related_name="payments" - ) - amount = models.DecimalField( - max_digits=10, decimal_places=2, verbose_name=_("amount") - ) - payment_method = models.CharField( - choices=METHOD_CHOICES, max_length=50, verbose_name=_("method") - ) - reference_number = models.CharField( - max_length=100, null=True, blank=True, verbose_name=_("reference number") - ) + quotation = models.ForeignKey(SaleQuotation, on_delete=models.CASCADE, related_name="payments") + amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("amount")) + payment_method = models.CharField(choices=METHOD_CHOICES, max_length=50, verbose_name=_("method")) + reference_number = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("reference number")) payment_date = models.DateField(auto_now_add=True, verbose_name=_("date")) # def save(self, *args, **kwargs): @@ -1484,12 +1193,8 @@ class Payment(models.Model): class Refund(models.Model): - payment = models.OneToOneField( - Payment, on_delete=models.CASCADE, related_name="refund" - ) - amount = models.DecimalField( - max_digits=10, decimal_places=2, verbose_name=_("amount") - ) + payment = models.OneToOneField(Payment, on_delete=models.CASCADE, related_name="refund") + amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("amount")) reason = models.TextField(blank=True, verbose_name=_("reason")) refund_date = models.DateField(auto_now_add=True, verbose_name=_("refund date")) @@ -1509,7 +1214,9 @@ class UserActivityLog(models.Model): class Meta: verbose_name = "User Activity Log" verbose_name_plural = "User Activity Logs" - ordering = ["-timestamp"] + ordering = ['-timestamp'] def __str__(self): return f"{self.user.email} - {self.action} - {self.timestamp}" + + diff --git a/inventory/signals.py b/inventory/signals.py index 3d9f36c3..2cc18ff8 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -155,7 +155,19 @@ def create_ledger_entity(sender, instance, created, **kwargs): balance_type="debit", active=True, ) - + + # Inventory Account + asset_ca_inventory = entity.create_account( + coa_model=coa, + code="1106", + role=roles.ASSET_CA_INVENTORY, + name=_("Inventory"), + balance_type="debit", + active=True, + ) + asset_ca_inventory.role_default = True + asset_ca_inventory.save() + # VAT Payable Account liability_ltl_vat_receivable = entity.create_account( coa_model=coa, @@ -325,7 +337,7 @@ def create_ledger_entity(sender, instance, created, **kwargs): # Mortgage Payable Account liability_ltl_mortgage_payable = entity.create_account( coa_model=coa, - code="2203", + code="2202", role=roles.LIABILITY_LTL_MORTGAGE_PAYABLE, name=_("Mortgage Payable"), balance_type="credit", diff --git a/templates/crm/notifications_history.html b/templates/crm/notifications_history.html index 3d4b6bfa..bf86da1e 100644 --- a/templates/crm/notifications_history.html +++ b/templates/crm/notifications_history.html @@ -13,7 +13,7 @@

{{ _("System")}}:

{% if not notification.is_read %} -

{{ notification.message|safe }} {{ notification.created|timesince }}

+

{{ notification.message }} {{ notification.created|timesince }}

{% else %}

{{ notification.message|safe }} {{ notification.created|timesince }}

{% endif %} diff --git a/templates/header.html b/templates/header.html index cfdfd189..f97c839e 100644 --- a/templates/header.html +++ b/templates/header.html @@ -344,7 +344,7 @@
- {% if user.dealer.logo %} +{% if user.dealer.logo %} {% elif user.staff.dealer.logo %} diff --git a/templates/inventory/car_detail.html b/templates/inventory/car_detail.html index 7f511f7b..d6157359 100644 --- a/templates/inventory/car_detail.html +++ b/templates/inventory/car_detail.html @@ -291,7 +291,7 @@ - Transfer + Transfer {% if car.get_transfer.status == "draft" %} @@ -301,12 +301,12 @@ waiting for dealer acceptance - {% endif %} + {% endif %} {{ car.get_transfer.from_dealer|title }} {{ car.get_transfer.to_dealer|title }} {{ car.get_transfer.transfer_date|date:"Y-m-d" }} - + {% if car.get_transfer.status == "draft" %} Approve