This commit is contained in:
Marwan Alwali 2025-05-05 18:00:04 +03:00
parent 5a76fb4fa2
commit c3a31d71e1
4 changed files with 541 additions and 716 deletions

View File

@ -96,12 +96,12 @@ class StaffForm(forms.ModelForm):
""" """
email = forms.EmailField( email = forms.EmailField(
required=True, required=True,
label="Email", label=_("Email"),
widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}), widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}),
) )
service_offered = forms.ModelMultipleChoiceField( service_offered = forms.ModelMultipleChoiceField(
label="Services Offered", label=_("Services Offered"),
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}), widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
queryset=Service.objects.all(), queryset=Service.objects.all(),
required=False,) required=False,)
@ -837,7 +837,7 @@ class WizardForm3(forms.Form):
max_length=10, max_length=10,
error_messages={ error_messages={
"required": _("This field is required."), "required": _("This field is required."),
"max_length": "Commercial Registration Number must be 10 characters.", "max_length": _("Commercial Registration Number must be 10 characters"),
}, },
) )
@ -890,11 +890,11 @@ class ItemForm(forms.Form):
""" """
item = forms.ModelChoiceField( item = forms.ModelChoiceField(
queryset=ledger_models.ItemModel.objects.all(), queryset=ledger_models.ItemModel.objects.all(),
label="Item", label=_("Item"),
required=True, required=True,
validators=[MinLengthValidator(5)], validators=[MinLengthValidator(5)],
) )
quantity = forms.DecimalField(label="Quantity", required=True) quantity = forms.DecimalField(label=_("Quantity"), required=True)
class PaymentForm(forms.Form): class PaymentForm(forms.Form):
@ -919,13 +919,13 @@ class PaymentForm(forms.Form):
""" """
invoice = forms.ModelChoiceField( invoice = forms.ModelChoiceField(
queryset=ledger_models.InvoiceModel.objects.all(), queryset=ledger_models.InvoiceModel.objects.all(),
label="Invoice", label=_("Invoice"),
required=False, required=False,
) )
bill = forms.ModelChoiceField( bill = forms.ModelChoiceField(
queryset=ledger_models.BillModel.objects.all(), label="Bill", required=False queryset=ledger_models.BillModel.objects.all(), label=_("Bill"), required=False
) )
amount = forms.DecimalField(label="Amount", required=True) amount = forms.DecimalField(label=_("Amount"), required=True)
payment_method = forms.ChoiceField( payment_method = forms.ChoiceField(
choices=[ choices=[
("cash", _("cash")), ("cash", _("cash")),
@ -934,11 +934,11 @@ class PaymentForm(forms.Form):
("debit", _("debit")), ("debit", _("debit")),
("SADAD", _("SADAD")), ("SADAD", _("SADAD")),
], ],
label="Payment Method", label=_("Payment Method"),
required=True, required=True,
) )
payment_date = forms.DateField( payment_date = forms.DateField(
label="Payment Date", widget=DateInput(attrs={"type": "date"}), required=True label=_("Payment Date"), widget=DateInput(attrs={"type": "date"}), required=True
) )
def clean_amount(self): def clean_amount(self):
@ -947,13 +947,13 @@ class PaymentForm(forms.Form):
model = invoice if invoice else bill model = invoice if invoice else bill
amount = self.cleaned_data["amount"] amount = self.cleaned_data["amount"]
if amount + model.amount_paid > model.amount_due: if amount + model.amount_paid > model.amount_due:
raise forms.ValidationError("Payment amount is greater than amount due") raise forms.ValidationError(_("Payment amount is greater than amount due"))
if amount <= 0: if amount <= 0:
raise forms.ValidationError("Payment amount must be greater than 0") raise forms.ValidationError(_("Payment amount must be greater than 0"))
if model.is_paid(): if model.is_paid():
raise forms.ValidationError("Invoice is already paid") raise forms.ValidationError(_("Invoice is already paid"))
if amount > model.amount_due: if amount > model.amount_due:
raise forms.ValidationError("Payment amount is greater than amount due") raise forms.ValidationError(_("Payment amount is greater than amount due"))
return amount return amount
@ -979,7 +979,7 @@ class EmailForm(forms.Form):
subject = forms.CharField(max_length=255) subject = forms.CharField(max_length=255)
message = forms.CharField(widget=forms.Textarea) message = forms.CharField(widget=forms.Textarea)
from_email = forms.EmailField() from_email = forms.EmailField()
to_email = forms.EmailField(label="To") to_email = forms.EmailField(label=_("To"))
class LeadForm(forms.ModelForm): class LeadForm(forms.ModelForm):
@ -999,7 +999,7 @@ class LeadForm(forms.ModelForm):
:type id_car_model: ModelChoiceField :type id_car_model: ModelChoiceField
""" """
id_car_make = forms.ModelChoiceField( id_car_make = forms.ModelChoiceField(
label="Make", label=_("Make"),
queryset=CarMake.objects.filter(is_sa_import=True), queryset=CarMake.objects.filter(is_sa_import=True),
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
@ -1016,7 +1016,7 @@ class LeadForm(forms.ModelForm):
required=True, required=True,
) )
id_car_model = forms.ModelChoiceField( id_car_model = forms.ModelChoiceField(
label="Model", label=_("Model"),
queryset=CarModel.objects.none(), queryset=CarModel.objects.none(),
widget=forms.Select(attrs={"class": "form-control form-control-sm"}), widget=forms.Select(attrs={"class": "form-control form-control-sm"}),
required=True, required=True,
@ -1291,7 +1291,7 @@ class OpportunityStatusForm(forms.Form):
:type stage: ChoiceField :type stage: ChoiceField
""" """
status = forms.ChoiceField( status = forms.ChoiceField(
label="Status", label=_("Status"),
choices=Status.choices, choices=Status.choices,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
@ -1307,7 +1307,7 @@ class OpportunityStatusForm(forms.Form):
required=True, required=True,
) )
stage = forms.ChoiceField( stage = forms.ChoiceField(
label="Stage", label=_("Stage"),
choices=Stage.choices, choices=Stage.choices,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
@ -1496,7 +1496,7 @@ class CreditCardField(forms.CharField):
# Validate using Luhn algorithm # Validate using Luhn algorithm
if not Luhn.check_luhn(cleaned_value): if not Luhn.check_luhn(cleaned_value):
raise forms.ValidationError("Please enter a valid credit card number") raise forms.ValidationError(_("Please enter a valid credit card number"))
# Add basic card type detection (optional) # Add basic card type detection (optional)
if cleaned_value.startswith('4'): if cleaned_value.startswith('4'):
@ -1526,17 +1526,17 @@ class ExpiryDateField(forms.CharField):
# Validate month # Validate month
if month < 1 or month > 12: if month < 1 or month > 12:
raise forms.ValidationError("Please enter a valid month (01-12)") raise forms.ValidationError(_("Please enter a valid month (01-12)"))
# Validate not expired # Validate not expired
current_year = datetime.now().year current_year = datetime.now().year
current_month = datetime.now().month current_month = datetime.now().month
if year < current_year or (year == current_year and month < current_month): if year < current_year or (year == current_year and month < current_month):
raise forms.ValidationError("This card appears to be expired") raise forms.ValidationError(_("This card appears to be expired"))
except (ValueError, AttributeError): except (ValueError, AttributeError):
raise forms.ValidationError("Please enter a valid expiry date in MM/YY format") raise forms.ValidationError(_("Please enter a valid expiry date in MM/YY format"))
return value return value
@ -1545,9 +1545,9 @@ class CVVField(forms.CharField):
value = super().clean(value) value = super().clean(value)
if value: if value:
if not value.isdigit(): if not value.isdigit():
raise forms.ValidationError("CVV must contain only digits") raise forms.ValidationError(_("CVV must contain only digits"))
if len(value) not in (3, 4): if len(value) not in (3, 4):
raise forms.ValidationError("CVV must be 3 or 4 digits") raise forms.ValidationError(_("CVV must be 3 or 4 digits"))
return value return value
class PaymentPlanForm(forms.Form): class PaymentPlanForm(forms.Form):
@ -1606,7 +1606,7 @@ class PaymentPlanForm(forms.Form):
'id': 'card-number', 'id': 'card-number',
}), }),
label="Card Number" label=_("Card Number")
) )
expiry_date = ExpiryDateField( expiry_date = ExpiryDateField(
@ -1617,7 +1617,7 @@ class PaymentPlanForm(forms.Form):
'id': 'expiry', 'id': 'expiry',
}), }),
label="Expiration Date" label=_("Expiration Date")
) )
cvv = CVVField( cvv = CVVField(
@ -1628,7 +1628,7 @@ class PaymentPlanForm(forms.Form):
'id': 'cvv', 'id': 'cvv',
}), }),
label="Security Code (CVV)" label=_("Security Code (CVV)")
) )
card_name = forms.CharField( card_name = forms.CharField(
@ -1640,7 +1640,7 @@ class PaymentPlanForm(forms.Form):
'id': 'card-name', 'id': 'card-name',
}), }),
label="Name on Card" label=_("Name on Card")
) )
# Terms and conditions # Terms and conditions

View File

@ -171,7 +171,7 @@ class CarMake(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Make" verbose_name = _("Make")
class CarModel(models.Model, LocalizedNameMixin): class CarModel(models.Model, LocalizedNameMixin):
@ -184,7 +184,7 @@ class CarModel(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Model" verbose_name = _("Model")
class CarSerie(models.Model, LocalizedNameMixin): class CarSerie(models.Model, LocalizedNameMixin):
@ -202,7 +202,7 @@ class CarSerie(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Series" verbose_name = _("Series")
class CarTrim(models.Model, LocalizedNameMixin): class CarTrim(models.Model, LocalizedNameMixin):
@ -219,7 +219,7 @@ class CarTrim(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Trim" verbose_name = _("Trim")
class CarEquipment(models.Model, LocalizedNameMixin): class CarEquipment(models.Model, LocalizedNameMixin):
@ -233,7 +233,7 @@ class CarEquipment(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Equipment" verbose_name = _("Equipment")
class CarSpecification(models.Model, LocalizedNameMixin): class CarSpecification(models.Model, LocalizedNameMixin):
@ -248,7 +248,7 @@ class CarSpecification(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Specification" verbose_name = _("Specification")
class CarSpecificationValue(models.Model): class CarSpecificationValue(models.Model):
@ -264,7 +264,7 @@ class CarSpecificationValue(models.Model):
return f"{self.id_car_specification.name}: {self.value} {self.unit}" return f"{self.id_car_specification.name}: {self.value} {self.unit}"
class Meta: class Meta:
verbose_name = "Specification Value" verbose_name = _("Specification Value")
class CarOption(models.Model, LocalizedNameMixin): class CarOption(models.Model, LocalizedNameMixin):
@ -279,7 +279,7 @@ class CarOption(models.Model, LocalizedNameMixin):
return self.name return self.name
class Meta: class Meta:
verbose_name = "Option" verbose_name = _("Option")
class CarOptionValue(models.Model): class CarOptionValue(models.Model):
@ -298,7 +298,7 @@ class CarOptionValue(models.Model):
return f"{self.id_car_option.name}: {self.value} {self.unit}" return f"{self.id_car_option.name}: {self.value} {self.unit}"
class Meta: class Meta:
verbose_name = "Option Value" verbose_name = _("Option Value")
class CarTransferStatusChoices(models.TextChoices): class CarTransferStatusChoices(models.TextChoices):
@ -480,7 +480,7 @@ class Car(models.Model):
self.cancel_reservation() self.cancel_reservation()
self.status = CarStatusChoices.SOLD self.status = CarStatusChoices.SOLD
self.save() self.save()
Activity.objects.create(dealer=dealer,content_object=self, notes="Car Sold",created_by=request.user,activity_type=ActionChoices.SALE_CAR) Activity.objects.create(dealer=dealer,content_object=self, notes=_("Car Sold"),created_by=request.user,activity_type=ActionChoices.SALE_CAR)
def cancel_reservation(self): def cancel_reservation(self):
if self.reservations.exists(): if self.reservations.exists():
@ -801,89 +801,6 @@ class TimestampedModel(models.Model):
abstract = True abstract = True
# class Subscription(models.Model):
# 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
# 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",
# )
# 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")
#
# def __str__(self):
# return self.plan.name
#
# @property
# def total_subscribers(self):
# return self.users.count()
#
#
# class SubscriptionUser(models.Model):
# subscription = models.ForeignKey(Subscription, on_delete=models.CASCADE)
# user = models.ForeignKey(User, on_delete=models.CASCADE)
#
# class Meta:
# verbose_name = _("Subscription User")
# verbose_name_plural = _("Subscription Users")
#
# def __str__(self):
# return f"{self.subscription} - {self.user}"
#
#
# class SubscriptionPlan(models.Model):
# 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
# )
# 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")
# )
# created_at = models.DateTimeField(auto_now_add=True)
# updated_at = models.DateTimeField(auto_now=True)
#
# class Meta:
# verbose_name = _("Subscription Plan")
# verbose_name_plural = _("Subscription Plans")
#
# def __str__(self):
# return f"{self.name} - {self.price}"
class Dealer(models.Model, LocalizedNameMixin): class Dealer(models.Model, LocalizedNameMixin):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer") user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
crn = models.CharField( crn = models.CharField(
@ -966,31 +883,6 @@ class Dealer(models.Model, LocalizedNameMixin):
def __str__(self): def __str__(self):
return self.name return self.name
# @property
# def get_sub_dealers(self):
# if self.dealer_type == "OWNER":
# return self.sub_dealers.all()
# return None
#
# @property
# def is_parent(self):
# return self.dealer_type == "OWNER"
# @property
# 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")
##############################
class StaffTypes(models.TextChoices): class StaffTypes(models.TextChoices):
# MANAGER = "manager", _("Manager") # MANAGER = "manager", _("Manager")
@ -1372,22 +1264,22 @@ class Lead(models.Model):
class Schedule(models.Model): class Schedule(models.Model):
PURPOSE_CHOICES = [ PURPOSE_CHOICES = [
('Product Demo', 'Product Demo'), ('product_demo', _('Product Demo')),
('Follow-Up Call', 'Follow-Up Call'), ('follow_up_call', _('Follow-Up Call')),
('Contract Discussion', 'Contract Discussion'), ('contract_discussion', _('Contract Discussion')),
('Sales Meeting', 'Sales Meeting'), ('sales_meeting', _('Sales Meeting')),
('Support Call', 'Support Call'), ('support_call', _('Support Call')),
('Other', 'Other'), ('other', _('Other')),
] ]
ScheduledType = [ ScheduledType = [
('Call', 'Call'), ('call', _('Call')),
('Meeting', 'Meeting'), ('meeting', _('Meeting')),
('Email', 'Email'), ('email', _('Email')),
] ]
ScheduleStatusChoices = [ ScheduleStatusChoices = [
('Scheduled', 'Scheduled'), ('scheduled', _('Scheduled')),
('Completed', 'Completed'), ('completed', _('Completed')),
('Canceled', 'Canceled'), ('canceled', _('Canceled')),
] ]
lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='schedules') lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='schedules')
customer = models.ForeignKey(CustomerModel, on_delete=models.CASCADE, related_name='schedules',null=True,blank=True) customer = models.ForeignKey(CustomerModel, on_delete=models.CASCADE, related_name='schedules',null=True,blank=True)
@ -1593,198 +1485,15 @@ class Vendor(models.Model, LocalizedNameMixin):
return self.name return self.name
# class SaleQuotation(models.Model):
# quotation_number = models.CharField(max_length=10, unique=True)
#
# STATUS_CHOICES = [
# ("Draft", _("Draft")),
# ("Approved", _("Approved")),
# ("In Review", _("In Review")),
# ("Paid", _("Paid")),
# ]
# dealer = models.ForeignKey(
# Dealer, on_delete=models.CASCADE, related_name="sales", null=True
# )
# customer = models.ForeignKey(
# Customer,
# on_delete=models.CASCADE,
# related_name="quotations",
# verbose_name=_("Customer"),
# )
# amount = models.DecimalField(
# decimal_places=2,
# default=Decimal("0.00"),
# max_digits=10,
# verbose_name=_("Amount"),
# )
# remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
# is_approved = models.BooleanField(default=False)
# status = models.CharField(
# max_length=10, choices=STATUS_CHOICES, default="Draft", verbose_name=_("Status")
# )
# created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
# updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))
#
# posted = models.BooleanField(default=False)
# payment_id = models.CharField(
# 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")
# )
#
# @property
# def total_quantity(self):
# 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"))
# )
# 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":
# raise ValueError(_("Only draft quotations can be confirmed."))
# self.status = "CONFIRMED"
# self.save()
# def cancel(self):
# """Cancel the quotation."""
# if self.status == "CONFIRMED":
# raise ValueError(_("Cannot cancel a confirmed quotation."))
# self.status = "CANCELED"
# self.save()
# 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)
# super().save(*args, **kwargs)
#
# @classmethod
# def _get_quotation_number(cls):
# last_quotation = cls.objects.all().order_by("id").last()
# if last_quotation:
# last_quotation_number = int(last_quotation.quotation_number)
# else:
# last_quotation_number = 0
# return itertools.count(last_quotation_number + 1)
#
# class SaleQuotationCar(models.Model):
# quotation = models.ForeignKey(
# SaleQuotation,
# on_delete=models.CASCADE,
# related_name="quotation_cars",
# verbose_name=_("Quotation"),
# )
# 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):
# """
# Retrieve financial details dynamically from CarFinance.
# Returns a dictionary with all financial fields for better access.
# """
# car_finance = self.car.finances
# if not car_finance:
# return None
#
# return {
# "selling_price": car_finance.selling_price,
# "administration_fee": car_finance.administration_fee,
# "transportation_fee": car_finance.transportation_fee,
# "custom_card_fee": car_finance.custom_card_fee,
# "registration_fee": car_finance.registration_fee,
# "vat_amount": car_finance.vat_amount,
# # "total_amount": car_finance.total,
# }
#
# @property
# def total(self):
# """
# Calculate total price dynamically based on quantity and selling price.
# """
# if not self.car.finances:
# return Decimal("0.00")
# return self.car.finances.selling_price * self.quantity
#
# @property
# def total_vat(self):
# """
# Calculate total price dynamically based on quantity and selling price.
# """
# if not self.car.finances:
# return Decimal("0.00")
# price = float(self.car.finances.selling_price * self.quantity)
# return (price * 0.15) + price
#
# def __str__(self):
# return f"{self.car} - Quotation #{self.quotation.id}"
#
#
# class SalesOrder(models.Model):
# quotation = models.OneToOneField(
# SaleQuotation,
# on_delete=models.CASCADE,
# related_name="sales_order",
# verbose_name=_("Quotation"),
# )
# created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
# total_amount = models.DecimalField(
# max_digits=14, decimal_places=2, verbose_name=_("Total Amount")
# )
#
# def __str__(self):
# return f"Sales Order #{self.id} from Quotation #{self.quotation.id}"
class Payment(models.Model): class Payment(models.Model):
METHOD_CHOICES = [ METHOD_CHOICES = [
("cash", _("cash")), ("cash", _("cash")),
("credit", _("credit")), ("credit", _("credit")),
("transfer", _("transfer")), ("transfer", _("transfer")),
("debit", _("debit")), ("debit", _("debit")),
("SADAD", _("SADAD")), ("sadad", _("SADAD")),
] ]
# quotation = models.ForeignKey(
# SaleQuotation, on_delete=models.CASCADE, related_name="payments"
# )
amount = models.DecimalField( amount = models.DecimalField(
max_digits=10, decimal_places=2, verbose_name=_("amount") max_digits=10, decimal_places=2, verbose_name=_("amount")
) )
@ -1796,19 +1505,13 @@ class Payment(models.Model):
) )
payment_date = models.DateField(auto_now_add=True, verbose_name=_("date")) payment_date = models.DateField(auto_now_add=True, verbose_name=_("date"))
# def save(self, *args, **kwargs):
# super().save(*args, **kwargs)
# self.quotation.remaining_balance -= self.amount
# if self.quotation.remaining_balance <= 0:
# self.quotation.is_paid = True
# self.quotation.save()
class Meta: class Meta:
verbose_name = _("payment") verbose_name = _("payment")
verbose_name_plural = _("payments") verbose_name_plural = _("payments")
def __str__(self): def __str__(self):
return f"Payment of {self.amount} on {self.payment_date} for {self.quotation}" return f"Payment of {self.amount} on {self.payment_date}"
class Refund(models.Model): class Refund(models.Model):
@ -1835,8 +1538,8 @@ class UserActivityLog(models.Model):
timestamp = models.DateTimeField(auto_now_add=True) timestamp = models.DateTimeField(auto_now_add=True)
class Meta: class Meta:
verbose_name = "User Activity Log" verbose_name = _("User Activity Log")
verbose_name_plural = "User Activity Logs" verbose_name_plural = _("User Activity Logs")
ordering = ["-timestamp"] ordering = ["-timestamp"]
def __str__(self): def __str__(self):
@ -1863,7 +1566,7 @@ class SaleOrder(models.Model):
('lease', _('Lease')), ('lease', _('Lease')),
("credit_card", _("Credit Card")), ("credit_card", _("Credit Card")),
("bank_transfer", _("Bank Transfer")), ("bank_transfer", _("Bank Transfer")),
("SADAD", _("SADAD")), ("sadad", _("SADAD")),
]) ])
comments = models.TextField(blank=True, null=True) comments = models.TextField(blank=True, null=True)
formatted_order_id = models.CharField(max_length=10, unique=True, editable=False) formatted_order_id = models.CharField(max_length=10, unique=True, editable=False)
@ -2073,7 +1776,8 @@ class PaymentHistory(models.Model):
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta: class Meta:
verbose_name_plural = "Payment Histories" verbose_name = _("Payment History")
verbose_name_plural = _("Payment Histories")
ordering = ["-payment_date"] ordering = ["-payment_date"]
indexes = [ indexes = [
models.Index(fields=["transaction_id"]), models.Index(fields=["transaction_id"]),

Binary file not shown.

File diff suppressed because it is too large Load Diff