update
This commit is contained in:
parent
916c1e8b16
commit
780eb1b35c
@ -3,6 +3,20 @@ from inventory import models
|
||||
from car_inventory import settings
|
||||
|
||||
def fetch_data(dealer):
|
||||
"""
|
||||
Fetches the total number of cars in the inventory for the specified dealer. If no cars are
|
||||
found, returns a message indicating that fact. If an error occurs during the operation,
|
||||
it returns an error message with details.
|
||||
|
||||
:param dealer: The dealer object for which the inventory information is required.
|
||||
The dealer object must be an instance of a model that includes a
|
||||
`get_local_name` method for formatting localized dealer names.
|
||||
:type dealer: Dealer
|
||||
:return: A string indicating either the total number of cars in the dealer's inventory,
|
||||
that no cars exist in the inventory, or an error message detailing what went
|
||||
wrong during the operation.
|
||||
:rtype: str
|
||||
"""
|
||||
try:
|
||||
# Annotate total cars by make, model, and trim
|
||||
cars = models.Car.objects.filter(dealer=dealer).count()
|
||||
@ -17,6 +31,22 @@ def fetch_data(dealer):
|
||||
|
||||
|
||||
def get_gpt4_response(user_input, dealer):
|
||||
"""
|
||||
Generates a response from the GPT-4 model based on the provided user input
|
||||
and the dealer's information. The function is tailored to assist with car
|
||||
inventory management, including queries about inventory, sales processes,
|
||||
car transfers, invoices, and other features specific to the Haikal system.
|
||||
|
||||
:param user_input: The text input or query provided by the user.
|
||||
:type user_input: str
|
||||
:param dealer: Dealer information or identifier used to fetch related car data
|
||||
or contextual information.
|
||||
:type dealer: Any
|
||||
:return: The generated response from the GPT-4 model as a string.
|
||||
:rtype: str
|
||||
:raises Exception: In case of an error during the API call to generate the
|
||||
GPT-4 response.
|
||||
"""
|
||||
dealer = dealer
|
||||
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||
|
||||
|
||||
@ -3,6 +3,24 @@ from inventory.models import Dealer
|
||||
|
||||
|
||||
class ChatLog(models.Model):
|
||||
"""
|
||||
Handles storage and representation of chat logs between users and chatbot.
|
||||
|
||||
This class is designed to store chat logs, which include user messages, chatbot
|
||||
responses, their associated dealer, and timestamps of when the chat entries are
|
||||
created. It supports linking chat logs to a specific dealer using a foreign key
|
||||
relationship. The class provides an easy and structured way to manage and retrieve
|
||||
historical chat data.
|
||||
|
||||
:ivar dealer: The dealer associated with this chat log.
|
||||
:type dealer: Dealer
|
||||
:ivar user_message: The message sent by the user.
|
||||
:type user_message: str
|
||||
:ivar chatbot_response: The response generated by the chatbot.
|
||||
:type chatbot_response: str
|
||||
:ivar timestamp: The date and time when the chat log entry was created.
|
||||
:type timestamp: datetime
|
||||
"""
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='chatlogs')
|
||||
user_message = models.TextField()
|
||||
chatbot_response = models.TextField()
|
||||
|
||||
@ -6,6 +6,18 @@ from .chatbot_logic import get_gpt4_response
|
||||
import json
|
||||
|
||||
class ChatbotView(LoginRequiredMixin, View):
|
||||
"""
|
||||
Represents a view for handling chatbot interactions.
|
||||
|
||||
This class handles GET and POST requests for a chatbot interface. It leverages
|
||||
`LoginRequiredMixin` to ensure that only authenticated users can access it. On GET
|
||||
requests, it renders the chatbot interface, while on POST requests, it interacts
|
||||
with a chatbot backend to process user messages and return responses.
|
||||
|
||||
:ivar request: The HTTP request object, providing metadata about the
|
||||
current session and user.
|
||||
:type request: HttpRequest
|
||||
"""
|
||||
def get(self, request):
|
||||
return render(request, "haikalbot/chatbot.html")
|
||||
|
||||
|
||||
@ -1,12 +1,41 @@
|
||||
from django.conf import settings
|
||||
|
||||
def currency_context(request):
|
||||
"""
|
||||
Provides a context dictionary containing the currency setting. This is typically
|
||||
used for rendering templates with the appropriate currency value.
|
||||
|
||||
:param request: The HTTP request object. This parameter is not used within
|
||||
the function but is included to maintain compatibility with
|
||||
context processor signature.
|
||||
:type request: HttpRequest
|
||||
|
||||
:return: A dictionary with the key 'CURRENCY' containing the value of the
|
||||
project's CURRENCY setting.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {
|
||||
'CURRENCY': settings.CURRENCY
|
||||
}
|
||||
|
||||
|
||||
def breadcrumbs(request):
|
||||
"""
|
||||
Generates a breadcrumb trail for the given request path.
|
||||
|
||||
The function processes the request's path, splits it into individual
|
||||
segments, and creates a list of breadcrumb entries, each representing
|
||||
a segment of the path. Each breadcrumb entry consists of a 'name'
|
||||
(key) and its associated 'url' (key). The 'name' is a title-cased
|
||||
representation of the path segment, and the 'url' is the cumulative URL
|
||||
path leading to that segment.
|
||||
|
||||
:param request: The request object containing the path to be processed.
|
||||
:type request: Any
|
||||
:return: A dictionary containing a list of breadcrumbs, where each
|
||||
breadcrumb is represented by a dictionary with 'name' and 'url'.
|
||||
:rtype: dict
|
||||
"""
|
||||
breadcrumbs = []
|
||||
path = request.path.strip('/').split('/')
|
||||
for i in range(len(path)):
|
||||
|
||||
@ -1,7 +1,22 @@
|
||||
from django_ledger.models import AccountModel
|
||||
import django_filters
|
||||
|
||||
class AccountModelFilter(django_filters.FilterSet):
|
||||
class AccountModelFilter(django_filters.FilterSet):
|
||||
"""
|
||||
Handles filtering functionality for the AccountModel.
|
||||
|
||||
This class is a subclass of `django_filters.FilterSet` and is used to provide
|
||||
filtering capabilities for the `AccountModel` based on its specified fields such as
|
||||
`code`, `name`, and `role`. It is designed to integrate seamlessly with Django's
|
||||
filtering framework to simplify query creation and management for this specific model.
|
||||
|
||||
The Meta class inside defines the model and fields that can be used for filtering.
|
||||
|
||||
:ivar model: The model for which filters are being applied.
|
||||
:type model: type[AccountModel]
|
||||
:ivar fields: List of fields defined in the model that can be filtered.
|
||||
:type fields: list(str)
|
||||
"""
|
||||
class Meta:
|
||||
model = AccountModel
|
||||
fields = ['code', 'name','role']
|
||||
@ -71,6 +71,21 @@ User = get_user_model()
|
||||
|
||||
|
||||
class AdditionalServiceForm(forms.ModelForm):
|
||||
"""
|
||||
A form used for creating and updating instances of the
|
||||
`AdditionalServices` model with fields for specifying
|
||||
service details such as name, price, description, tax
|
||||
applicability, and unit of measure.
|
||||
|
||||
This form is designed to streamline input validation and
|
||||
rendering for the `AdditionalServices` model.
|
||||
|
||||
:ivar Meta.model: The model to associate with this form.
|
||||
:type Meta.model: type
|
||||
:ivar Meta.fields: List of fields in the `AdditionalServices`
|
||||
model that this form includes.
|
||||
:type Meta.fields: list
|
||||
"""
|
||||
class Meta:
|
||||
model = AdditionalServices
|
||||
fields = ["name", "price", "description", "taxable", "uom"]
|
||||
@ -84,6 +99,20 @@ class AdditionalServiceForm(forms.ModelForm):
|
||||
|
||||
|
||||
class StaffForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for managing Staff entities, including associated user email updates
|
||||
and service offerings.
|
||||
|
||||
This class defines a Django ModelForm for the `Staff` model, providing fields
|
||||
to manage staff details such as name, Arabic name, phone number, staff type, and email.
|
||||
It allows selection of multiple services offered by staff through a multiple choice
|
||||
field. The form integrates email management as an additional feature.
|
||||
|
||||
:ivar email: Email address of the user associated with the staff.
|
||||
:type email: forms.EmailField
|
||||
:ivar service_offered: Collection of services offered by the staff.
|
||||
:type service_offered: forms.ModelMultipleChoiceField
|
||||
"""
|
||||
email = forms.EmailField(
|
||||
required=True,
|
||||
label="Email",
|
||||
@ -118,6 +147,28 @@ class StaffForm(forms.ModelForm):
|
||||
|
||||
# Dealer Form
|
||||
class DealerForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a Django ModelForm specifically for the `Dealer` model.
|
||||
|
||||
Designed to facilitate the creation, update, and validation of `Dealer` model
|
||||
instances through form-based data handling. This form exposes specific
|
||||
fields of the `Dealer` model for interaction.
|
||||
|
||||
:ivar name: Dealer's name.
|
||||
:type name: str
|
||||
:ivar arabic_name: Dealer's name in Arabic.
|
||||
:type arabic_name: str
|
||||
:ivar crn: Commercial Registration Number for the dealer.
|
||||
:type crn: str
|
||||
:ivar vrn: Value-added Tax Registration Number for the dealer.
|
||||
:type vrn: str
|
||||
:ivar phone_number: Contact phone number of the dealer.
|
||||
:type phone_number: str
|
||||
:ivar address: Physical address of the dealer.
|
||||
:type address: str
|
||||
:ivar logo: Logo of the dealer.
|
||||
:type logo: File
|
||||
"""
|
||||
class Meta:
|
||||
model = Dealer
|
||||
fields = [
|
||||
@ -132,6 +183,37 @@ class DealerForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CustomerForm(forms.Form):
|
||||
"""
|
||||
Represents a form for collecting customer information.
|
||||
|
||||
This form is used to gather and validate customer details such as name,
|
||||
email, phone number, national ID, tax registration details, and address.
|
||||
It includes several fields with validation constraints and specific
|
||||
requirements. It is designed to handle both required and optional fields,
|
||||
ensuring the correctness of user inputs.
|
||||
|
||||
:ivar first_name: Customer's first name.
|
||||
:type first_name: forms.CharField
|
||||
:ivar last_name: Customer's last name.
|
||||
:type last_name: forms.CharField
|
||||
:ivar arabic_name: Customer's name in Arabic.
|
||||
:type arabic_name: forms.CharField
|
||||
:ivar email: Customer's email address.
|
||||
:type email: forms.EmailField
|
||||
:ivar phone_number: Customer's phone number. Validates the format and
|
||||
ensures the number is in the Saudi Arabia region.
|
||||
:type phone_number: PhoneNumberField
|
||||
:ivar national_id: Customer's national ID. Optional field limited to
|
||||
a maximum length of 10 characters.
|
||||
:type national_id: forms.CharField
|
||||
:ivar crn: Commercial registration number (CRN) of the customer. Optional field.
|
||||
:type crn: forms.CharField
|
||||
:ivar vrn: Value-added tax registration number (VRN) of the customer.
|
||||
Optional field.
|
||||
:type vrn: forms.CharField
|
||||
:ivar address: Customer's address.
|
||||
:type address: forms.CharField
|
||||
"""
|
||||
first_name = forms.CharField()
|
||||
last_name = forms.CharField()
|
||||
arabic_name = forms.CharField()
|
||||
@ -158,6 +240,20 @@ class CustomerForm(forms.Form):
|
||||
|
||||
|
||||
class OrganizationForm(CustomerForm):
|
||||
"""
|
||||
Represents a form for collecting and handling organization-specific details.
|
||||
|
||||
This form extends the `CustomerForm` class and is tailored for organizations,
|
||||
providing fields for optional input such as the contact person and organization
|
||||
logo. The form can be used to capture all relevant data pertaining to the
|
||||
organization during interactions.
|
||||
|
||||
:ivar contact_person: Optional field to specify the name of the contact person
|
||||
for the organization.
|
||||
:type contact_person: forms.CharField
|
||||
:ivar logo: Optional field to upload the logo of the organization.
|
||||
:type logo: forms.ImageField
|
||||
"""
|
||||
contact_person = forms.CharField(required=False)
|
||||
logo = forms.ImageField(required=False)
|
||||
|
||||
@ -188,6 +284,21 @@ class CarForm(
|
||||
forms.ModelForm,
|
||||
AddClassMixin,
|
||||
):
|
||||
"""
|
||||
A form class for creating and updating `Car` model instances.
|
||||
|
||||
This class extends `forms.ModelForm` and `AddClassMixin` to customize
|
||||
form fields for the `Car` model. It manages custom field configurations,
|
||||
such as filtering queryset and setting widgets, and is designed to be used
|
||||
for handling the form representation of the `Car` model within a user interface.
|
||||
|
||||
:ivar Meta.model: Specifies the model associated with this form.
|
||||
:type Meta.model: Car
|
||||
:ivar Meta.fields: Specifies the fields included in the form.
|
||||
:type Meta.fields: list
|
||||
:ivar Meta.widgets: Defines the widgets for specific fields.
|
||||
:type Meta.widgets: dict
|
||||
"""
|
||||
class Meta:
|
||||
model = Car
|
||||
fields = [
|
||||
@ -234,6 +345,23 @@ class CarForm(
|
||||
|
||||
|
||||
class CarUpdateForm(forms.ModelForm, AddClassMixin):
|
||||
"""
|
||||
Form class used to update Car instances through a Django ModelForm. This class
|
||||
extends `forms.ModelForm` and applies custom widgets and field configurations
|
||||
to support specific requirements for the Car model.
|
||||
|
||||
The form is intended for managing Car-related information, allowing inputs
|
||||
for vendor details, status, stock type, mileage, receiving date, and remarks.
|
||||
It also provides customization options for field configurations through its
|
||||
initialization method.
|
||||
|
||||
:ivar Meta.model: The model associated with the form, which is `Car`.
|
||||
:ivar Meta.fields: Fields of the `Car` model included in the form: "vendor",
|
||||
"status", "stock_type", "mileage", "receiving_date", "remarks".
|
||||
:ivar Meta.widgets: Custom widgets for specific fields. The "receiving_date" field
|
||||
uses a `DateTimeInput` configured with `datetime-local` attributes, while
|
||||
"remarks" uses a `Textarea` with a specific row configuration.
|
||||
"""
|
||||
class Meta:
|
||||
model = Car
|
||||
fields = [
|
||||
@ -269,6 +397,17 @@ class CarUpdateForm(forms.ModelForm, AddClassMixin):
|
||||
|
||||
|
||||
class CarFinanceForm(forms.ModelForm):
|
||||
"""
|
||||
Handles the form logic for car finance, including processing
|
||||
additional financial services selected through the UI.
|
||||
|
||||
This class is used for creating or modifying instances of the CarFinance model.
|
||||
It provides a mechanism to associate additional financial services with a car
|
||||
finance application through a multiple choice selection.
|
||||
|
||||
:ivar additional_finances: A field that allows selecting multiple
|
||||
additional services associated with a car finance application.
|
||||
"""
|
||||
additional_finances = forms.ModelMultipleChoiceField(
|
||||
queryset=AdditionalServices.objects.all(),
|
||||
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
|
||||
@ -300,6 +439,17 @@ class CarFinanceForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CarLocationForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a Django ModelForm for managing CarLocation instances.
|
||||
|
||||
This form is designed to create or update `CarLocation` model objects.
|
||||
It provides a user-friendly interface for inputting data, including custom
|
||||
widget configurations for the `description` field.
|
||||
|
||||
:ivar Meta: Contains metadata for the form, including the associated model,
|
||||
specified fields, and custom widget configurations.
|
||||
:type Meta: class
|
||||
"""
|
||||
class Meta:
|
||||
model = CarLocation
|
||||
fields = ["showroom", "description"]
|
||||
@ -309,6 +459,20 @@ class CarLocationForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CarTransferForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for transferring a car to a dealer.
|
||||
|
||||
This form is used to facilitate the transfer of a car from one entity
|
||||
to a dealer. It extends the ModelForm framework to provide functionality
|
||||
specific to car transfer operations.
|
||||
|
||||
:ivar model: The model associated with this form.
|
||||
:type model: Type[CarTransfer]
|
||||
:ivar fields: The fields included in the form.
|
||||
:type fields: list[str]
|
||||
:ivar widgets: Custom widgets applied to the form fields.
|
||||
:type widgets: dict[str, Any]
|
||||
"""
|
||||
class Meta:
|
||||
model = CarTransfer
|
||||
fields = ["car", "to_dealer", "remarks"]
|
||||
@ -319,6 +483,20 @@ class CarTransferForm(forms.ModelForm):
|
||||
|
||||
# Custom Card Form
|
||||
class CustomCardForm(forms.ModelForm):
|
||||
"""
|
||||
Representation of a custom card form used for collecting and validating custom card data.
|
||||
|
||||
This form is a subclass of ``forms.ModelForm`` and is specifically tailored for
|
||||
the ``CustomCard`` model. It provides a user-friendly interface by predefining
|
||||
the fields and allowing customization of widgets and labels for seamless user
|
||||
interaction. The form integrates with Django's model validation system to ensure
|
||||
data integrity before saving to the database.
|
||||
|
||||
:ivar custom_date: The custom date field that accepts user input for a date
|
||||
value. This field uses a custom widget to render a date input type and
|
||||
includes a specific label for localized presentation.
|
||||
:type custom_date: forms.DateTimeField
|
||||
"""
|
||||
custom_date = forms.DateTimeField(
|
||||
widget=forms.DateInput(attrs={"type": "date"}),
|
||||
label=_("Custom Date"),
|
||||
@ -331,6 +509,23 @@ class CustomCardForm(forms.ModelForm):
|
||||
|
||||
# Car Registration Form
|
||||
class CarRegistrationForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a Django form for car registration.
|
||||
|
||||
This class is a Django ModelForm specifically designed to handle car
|
||||
registration data. It is linked to the `CarRegistration` model and
|
||||
provides fields for entering or managing a license plate number,
|
||||
additional textual fields, and the registration date. This form also
|
||||
customizes the widget for the `registration_date` field to use a
|
||||
datetime-local input.
|
||||
|
||||
:ivar Meta.model: The `CarRegistration` model to associate with this form.
|
||||
:type Meta.model: Model
|
||||
:ivar Meta.fields: List of fields to include in the form.
|
||||
:type Meta.fields: list
|
||||
:ivar Meta.widgets: Custom widget configurations for specific fields.
|
||||
:type Meta.widgets: dict
|
||||
"""
|
||||
class Meta:
|
||||
model = CarRegistration
|
||||
fields = ["plate_number", "text1", "text2", "text3", "registration_date"]
|
||||
@ -343,6 +538,16 @@ class CarRegistrationForm(forms.ModelForm):
|
||||
# class VendorForm(VendorModelForm):
|
||||
# pass
|
||||
class VendorForm(forms.ModelForm):
|
||||
"""
|
||||
Representation of a form used for Vendor model interactions.
|
||||
|
||||
This class extends the functionality of Django's ModelForm to facilitate
|
||||
CRUD operations for the Vendor model. It includes validation and mapping of
|
||||
fields defined in the Vendor model to their corresponding form fields.
|
||||
|
||||
:ivar Meta: Inner class to define metadata for the Vendor form.
|
||||
:type Meta: Type[VendorForm.Meta]
|
||||
"""
|
||||
class Meta:
|
||||
model = Vendor
|
||||
fields = [
|
||||
@ -359,6 +564,21 @@ class VendorForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CarColorsForm(forms.ModelForm):
|
||||
"""
|
||||
Handles the dynamic customization and validation of color selection forms
|
||||
for car exterior and interior.
|
||||
|
||||
This class provides a mechanism to dynamically populate querysets and choices
|
||||
for exterior and interior color fields in the form, as well as enforce
|
||||
business rules such as ensuring that the user selects values for both
|
||||
exterior and interior colors.
|
||||
|
||||
:ivar Meta.model: The model associated with this form, which is ``CarColors``.
|
||||
:type Meta.model: Model
|
||||
:ivar Meta.fields: List of form fields that correspond to model attributes
|
||||
to include in the form, namely ``exterior`` and ``interior``.
|
||||
:type Meta.fields: list
|
||||
"""
|
||||
class Meta:
|
||||
model = CarColors
|
||||
fields = ["exterior", "interior"]
|
||||
@ -435,6 +655,20 @@ class CarColorsForm(forms.ModelForm):
|
||||
|
||||
|
||||
class RepresentativeForm(forms.ModelForm):
|
||||
"""
|
||||
A form for creating or updating instances of the Representative model.
|
||||
|
||||
The RepresentativeForm class inherits from Django's ModelForm and is customized
|
||||
to work with the Representative model. This class initializes a form instance
|
||||
with fields relevant to a representative, including their name, contact details,
|
||||
and associated organization. It supports dynamic customization by passing additional
|
||||
parameters during initialization.
|
||||
|
||||
:ivar Meta.model: The Django model associated with this form.
|
||||
:type Meta.model: type
|
||||
:ivar Meta.fields: The fields from the model to include in the form.
|
||||
:type Meta.fields: list of str
|
||||
"""
|
||||
class Meta:
|
||||
model = Representative
|
||||
fields = [
|
||||
@ -452,6 +686,20 @@ class RepresentativeForm(forms.ModelForm):
|
||||
|
||||
|
||||
class CarSelectionTable(tables.Table):
|
||||
"""
|
||||
Creates a table for car selection using Django Tables2.
|
||||
|
||||
This class is used to generate a table with a checkbox column for selecting cars.
|
||||
It leverages Django Tables2 functionality to display table rows corresponding to
|
||||
cars, along with metadata for VIN, year, car make, and car model. The table is
|
||||
rendered using the Bootstrap 4 template for consistent styling.
|
||||
|
||||
:ivar select: Checkbox column for selecting a car, linked to the primary key.
|
||||
:type select: CheckBoxColumn
|
||||
:ivar Meta: Metadata containing configuration for the table, including the
|
||||
model, fields, and template.
|
||||
:type Meta: django_tables2.tables.Table.Meta
|
||||
"""
|
||||
select = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||
|
||||
class Meta:
|
||||
@ -461,6 +709,31 @@ class CarSelectionTable(tables.Table):
|
||||
|
||||
|
||||
class WizardForm1(forms.Form):
|
||||
"""
|
||||
Represents a form used for the first step of a wizard validation process.
|
||||
|
||||
This class is a Django form designed for a multi-step process and includes
|
||||
fields for collecting user information such as email, password, and consent
|
||||
to terms. It provides validation for fields, such as confirming password
|
||||
matching and preventing duplicate email addresses. The form incorporates user
|
||||
interaction attributes for frontend handling during the wizard workflow.
|
||||
|
||||
:ivar hx_attrs: Default attributes for htmx library operations, such as\
|
||||
defining the request behavior and target elements.
|
||||
:type hx_attrs: dict
|
||||
:ivar email: Field for entering the user's email address. Includes validation\
|
||||
to ensure uniqueness of the email.
|
||||
:type email: django.forms.EmailField
|
||||
:ivar password: Field for entering a password with a minimum length of 8 and\
|
||||
appropriate input styling.
|
||||
:type password: django.forms.CharField
|
||||
:ivar confirm_password: Field for confirming the password matches the entry\
|
||||
in the password field.
|
||||
:type confirm_password: django.forms.CharField
|
||||
:ivar terms: Field representing acceptance of the terms and privacy policy.\
|
||||
This is a required checkbox input.
|
||||
:type terms: django.forms.BooleanField
|
||||
"""
|
||||
hx_attrs = {
|
||||
"hx-post":"",
|
||||
"hx-target": "#wizardValidationForm1",
|
||||
@ -551,6 +824,27 @@ class WizardForm1(forms.Form):
|
||||
|
||||
|
||||
class WizardForm2(forms.Form):
|
||||
"""
|
||||
Form for capturing specific user details, including name, Arabic name,
|
||||
and a phone number.
|
||||
|
||||
This form is primarily designed to capture user information in both
|
||||
English and Arabic formats along with ensuring the phone number follows
|
||||
a valid format specifically for the region it is intended for. It makes
|
||||
use of form controls and placeholder attributes for user-friendly input
|
||||
handling.
|
||||
|
||||
:ivar name: English name of the user. It is a required field and provides
|
||||
user-friendly input placeholders and custom error messages.
|
||||
:type name: forms.CharField
|
||||
:ivar arabic_name: Arabic name of the user. It is a required field with
|
||||
user-friendly placeholders and custom error messages.
|
||||
:type arabic_name: forms.CharField
|
||||
:ivar phone_number: Contact phone number of the user. Validation is
|
||||
applied to ensure format compliance, with custom error handling
|
||||
and region-specific configuration.
|
||||
:type phone_number: PhoneNumberField
|
||||
"""
|
||||
name = forms.CharField(
|
||||
label=_("Name"),
|
||||
widget=forms.TextInput(
|
||||
@ -596,6 +890,24 @@ class WizardForm2(forms.Form):
|
||||
|
||||
|
||||
class WizardForm3(forms.Form):
|
||||
"""
|
||||
Form for collecting specific business-related information.
|
||||
|
||||
This class defines a Django form for collecting business information, particularly
|
||||
the Commercial Registration Number (CRN), VAT Registration Number (VRN), and the address.
|
||||
Each field has custom validation rules, user-friendly error messages, and associated
|
||||
widgets for user input.
|
||||
|
||||
:ivar crn: Field for the Commercial Registration Number (CRN), with a maximum
|
||||
length of 10 characters. This field is required.
|
||||
:type crn: django.forms.fields.CharField
|
||||
:ivar vrn: Field for the VAT Registration Number (VRN), with a maximum
|
||||
length of 15 characters. This field is required.
|
||||
:type vrn: django.forms.fields.CharField
|
||||
:ivar address: Field for the address input, supporting multi-line input,
|
||||
with validation enforcing the field to be required.
|
||||
:type address: django.forms.fields.CharField
|
||||
"""
|
||||
# CRN field with max length of 10
|
||||
crn = forms.CharField(
|
||||
label=_("CRN"),
|
||||
@ -658,6 +970,20 @@ class WizardForm3(forms.Form):
|
||||
|
||||
|
||||
class ItemForm(forms.Form):
|
||||
"""
|
||||
A form for handling item-related inputs in the application.
|
||||
|
||||
This form is used to manage user-provided data for items, including
|
||||
the selection of an item and its quantity. It enforces specific rules,
|
||||
such as a minimum length for the item and requires certain inputs.
|
||||
|
||||
:ivar item: A field representing the selection of an item from a
|
||||
predefined queryset. Subject to a minimum length validator.
|
||||
:type item: ModelChoiceField
|
||||
:ivar quantity: A field for specifying the desired quantity of the
|
||||
selected item.
|
||||
:type quantity: DecimalField
|
||||
"""
|
||||
item = forms.ModelChoiceField(
|
||||
queryset=ledger_models.ItemModel.objects.all(),
|
||||
label="Item",
|
||||
@ -671,6 +997,25 @@ class ItemForm(forms.Form):
|
||||
|
||||
|
||||
class PaymentForm(forms.Form):
|
||||
"""
|
||||
Form for handling payment-related data submission and validation.
|
||||
|
||||
This form is designed to manage various payment-related fields, including
|
||||
invoice and bill associations, payment amount and method, and payment date.
|
||||
It validates the payment amount against the outstanding dues of the specified
|
||||
invoice or bill and ensures logical correctness for the provided data.
|
||||
|
||||
:ivar invoice: Reference to an optional invoice for the payment.
|
||||
:type invoice: ModelChoiceField
|
||||
:ivar bill: Reference to an optional bill for the payment.
|
||||
:type bill: ModelChoiceField
|
||||
:ivar amount: The payment amount being submitted.
|
||||
:type amount: DecimalField
|
||||
:ivar payment_method: The method chosen to process the payment.
|
||||
:type payment_method: ChoiceField
|
||||
:ivar payment_date: The date on which the payment is made.
|
||||
:type payment_date: DateField
|
||||
"""
|
||||
invoice = forms.ModelChoiceField(
|
||||
queryset=ledger_models.InvoiceModel.objects.all(),
|
||||
label="Invoice",
|
||||
@ -712,6 +1057,24 @@ class PaymentForm(forms.Form):
|
||||
|
||||
|
||||
class EmailForm(forms.Form):
|
||||
"""
|
||||
Represents an email form for collecting and validating email data.
|
||||
|
||||
This class is designed to handle input related to email communication,
|
||||
including subject, message body, sender email, and recipient email. It
|
||||
validates the provided input to ensure they adhere to the specified
|
||||
constraints. This form is typically used in applications where users
|
||||
need to send emails through a web interface.
|
||||
|
||||
:ivar subject: The subject line of the email.
|
||||
:type subject: forms.CharField
|
||||
:ivar message: The main body content of the email.
|
||||
:type message: forms.CharField
|
||||
:ivar from_email: The sender's email address.
|
||||
:type from_email: forms.EmailField
|
||||
:ivar to_email: The recipient's email address.
|
||||
:type to_email: forms.EmailField
|
||||
"""
|
||||
subject = forms.CharField(max_length=255)
|
||||
message = forms.CharField(widget=forms.Textarea)
|
||||
from_email = forms.EmailField()
|
||||
@ -719,6 +1082,21 @@ class EmailForm(forms.Form):
|
||||
|
||||
|
||||
class LeadForm(forms.ModelForm):
|
||||
"""
|
||||
Form class for capturing lead details.
|
||||
|
||||
This class is a Django ModelForm specifically designed for the `Lead` model.
|
||||
It extends the capabilities of a standard Django form by providing customized
|
||||
handling for fields related to car make and model. The `id_car_make` field includes
|
||||
integration with htmx for dynamic model selections.
|
||||
|
||||
:ivar id_car_make: A dropdown field for selecting a car make. This field is
|
||||
dynamically updated and restricts the queryset to only South African imports.
|
||||
:type id_car_make: ModelChoiceField
|
||||
:ivar id_car_model: A dropdown field for selecting a car model. Initially, no
|
||||
options are displayed until a car make is selected.
|
||||
:type id_car_model: ModelChoiceField
|
||||
"""
|
||||
id_car_make = forms.ModelChoiceField(
|
||||
label="Make",
|
||||
queryset=CarMake.objects.filter(is_sa_import=True),
|
||||
@ -774,6 +1152,18 @@ class LeadForm(forms.ModelForm):
|
||||
|
||||
|
||||
class ScheduleForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for scheduling events, extending ModelForm to bind to the
|
||||
Schedule model.
|
||||
|
||||
Provides a user interface to create or edit schedule entries with fields for
|
||||
purpose, type, date/time of scheduling, duration, and additional notes. It
|
||||
utilizes a custom widget for scheduling date and time in a localized format.
|
||||
|
||||
:ivar scheduled_at: Field to input date and time for scheduling, using a custom
|
||||
'datetime-local' HTML widget.
|
||||
:type scheduled_at: DateTimeField
|
||||
"""
|
||||
scheduled_at = forms.DateTimeField(
|
||||
widget=DateTimeInput(attrs={"type": "datetime-local"})
|
||||
)
|
||||
@ -783,24 +1173,75 @@ class ScheduleForm(forms.ModelForm):
|
||||
|
||||
|
||||
class NoteForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for creating or editing notes.
|
||||
|
||||
This class is a Django ModelForm for the Notes model. It provides validation
|
||||
and rendering functionality for handling note data based on the specified
|
||||
fields. It is used to simplify the creation and management of note-related
|
||||
forms in Django applications.
|
||||
|
||||
:ivar Meta.model: The model associated with the ModelForm.
|
||||
:type Meta.model: type
|
||||
:ivar Meta.fields: The fields to include in the form.
|
||||
:type Meta.fields: list
|
||||
"""
|
||||
class Meta:
|
||||
model = Notes
|
||||
fields = ["note"]
|
||||
|
||||
|
||||
class ActivityForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for the Activity model, allowing users to submit or update
|
||||
data related to an activity instance.
|
||||
|
||||
This form is a subclass of Django's ModelForm, pre-configured to handle
|
||||
instances of the `Activity` model. It maps to the "activity_type" and "notes"
|
||||
fields of the model and provides validation and data-binding functionality.
|
||||
|
||||
:ivar Meta: Inner class that defines metadata for the form, including the model
|
||||
associated with the form and the fields it comprises.
|
||||
:type Meta: type
|
||||
"""
|
||||
class Meta:
|
||||
model = Activity
|
||||
fields = ["activity_type", "notes"]
|
||||
|
||||
|
||||
class OpportunityForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for creating or editing Opportunity instances.
|
||||
|
||||
This class is a Django ModelForm designed to simplify the process of
|
||||
validating and persisting data for Opportunity model instances. It
|
||||
maps fields from the Opportunity model to form fields, making it
|
||||
convenient to handle user input for operations such as creating and
|
||||
updating opportunities.
|
||||
|
||||
:ivar Meta.model: The model associated with the form.
|
||||
:type Meta.model: type
|
||||
:ivar Meta.fields: List of fields from the model included in the form.
|
||||
:type Meta.fields: list
|
||||
"""
|
||||
class Meta:
|
||||
model = Opportunity
|
||||
fields = ["customer", "car", "stage", "probability", "staff", "closing_date"]
|
||||
|
||||
|
||||
class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
||||
"""
|
||||
Represents a form for creating an Invoice model that inherits from a base
|
||||
InvoiceModelCreateFormBase.
|
||||
|
||||
This form is intended for handling the creation of invoices with additional
|
||||
field customizations. It modifies specific field widgets and defines custom
|
||||
queryset logic for a customer field.
|
||||
|
||||
:ivar fields: A dictionary containing the form fields where keys represent
|
||||
the field names and values are their respective Field objects.
|
||||
:type fields: dict
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@ -819,6 +1260,18 @@ class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
||||
|
||||
|
||||
class BillModelCreateForm(BillModelCreateFormBase):
|
||||
"""
|
||||
This class represents a form for creating a BillModel, inheriting from
|
||||
`BillModelCreateFormBase`.
|
||||
|
||||
It customizes the form fields by hiding certain account-related input fields,
|
||||
such as `cash_account`, `prepaid_account`, and `unearned_account`. This form
|
||||
is intended for specific use cases where these accounts should not be visible
|
||||
or interactable by the user.
|
||||
|
||||
:ivar fields: A dictionary of all fields used in the form.
|
||||
:type fields: dict
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@ -831,6 +1284,22 @@ class BillModelCreateForm(BillModelCreateFormBase):
|
||||
|
||||
|
||||
class SaleOrderForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for creating or updating sales orders.
|
||||
|
||||
This class is a Django ModelForm designed for handling the form
|
||||
representation of the SaleOrder model. It defines specific fields
|
||||
and their associated widgets to customize the input representation.
|
||||
|
||||
:ivar Meta.model: The model associated with this form. It is required
|
||||
for linking the form to the SaleOrder model.
|
||||
:type Meta.model: Type[models.Model]
|
||||
:ivar Meta.fields: List of fields from the model to be used in the form.
|
||||
:type Meta.fields: List[str]
|
||||
:ivar Meta.widgets: Dictionary defining specific widgets to be applied
|
||||
for fields, such as customizing their appearance.
|
||||
:type Meta.widgets: Dict[str, Any]
|
||||
"""
|
||||
class Meta:
|
||||
model = SaleOrder
|
||||
fields = ["estimate", "payment_method", "comments"]
|
||||
@ -840,6 +1309,32 @@ class SaleOrderForm(forms.ModelForm):
|
||||
|
||||
|
||||
class EstimateModelCreateForm(EstimateModelCreateFormBase):
|
||||
"""
|
||||
Defines the EstimateModelCreateForm class, which is used to create and manage
|
||||
forms for EstimateModel. This form handles the rendering and validation
|
||||
of specific fields, their input widgets, and labels.
|
||||
|
||||
The purpose of this class is to provide a structured way to handle
|
||||
EstimateModel instances and their related fields, ensuring a user-friendly
|
||||
form interface with proper field configuration. It facilitates fetching
|
||||
related data, such as customer queries, based on user-specific parameters.
|
||||
|
||||
:ivar ENTITY_SLUG: A string that represents the entity context in which the
|
||||
form operates.
|
||||
:type ENTITY_SLUG: str
|
||||
:ivar USER_MODEL: The user model that provides methods and objects needed
|
||||
to filter and query customers.
|
||||
:type USER_MODEL: Any
|
||||
:ivar fields: A dictionary representing fields included in the form such as
|
||||
"title", "customer", and "terms".
|
||||
:type fields: dict
|
||||
:ivar widgets: A dictionary defining custom input widgets for form fields,
|
||||
enabling specific attributes like classes and identifiers for styling or
|
||||
functionality purposes.
|
||||
:type widgets: dict
|
||||
:ivar labels: A dictionary specifying the human-readable labels for form fields.
|
||||
:type labels: dict
|
||||
"""
|
||||
class Meta:
|
||||
model = ledger_models.EstimateModel
|
||||
fields = ["title","customer", "terms"]
|
||||
@ -881,6 +1376,23 @@ class EstimateModelCreateForm(EstimateModelCreateFormBase):
|
||||
|
||||
|
||||
class OpportunityStatusForm(forms.Form):
|
||||
"""
|
||||
Form used to handle and manage the opportunity status and stage selection.
|
||||
|
||||
This form allows users to select and update the status and stage of an
|
||||
opportunity. It provides fields with pre-defined choices and custom widgets
|
||||
for enhanced interactivity within the user interface.
|
||||
|
||||
:ivar status: The selected status of the opportunity, which is managed by a
|
||||
choice field. It contains a set of predefined options for the status and
|
||||
applies a custom widget with additional attributes for UI and action
|
||||
handling.
|
||||
:type status: ChoiceField
|
||||
:ivar stage: The selected stage of the opportunity, which is managed by a
|
||||
choice field. It includes predefined stage options and utilizes a custom
|
||||
widget configured with attributes to handle UI updates dynamically.
|
||||
:type stage: ChoiceField
|
||||
"""
|
||||
status = forms.ChoiceField(
|
||||
label="Status",
|
||||
choices=Status.choices,
|
||||
@ -914,11 +1426,36 @@ class OpportunityStatusForm(forms.Form):
|
||||
)
|
||||
|
||||
class GroupForm(forms.ModelForm):
|
||||
"""
|
||||
A form for creating and updating CustomGroup objects.
|
||||
|
||||
This form is used to handle the creation and modification of CustomGroup instances.
|
||||
It is based on Django's ModelForm framework, which provides validation and transformation
|
||||
of form data into a model instance. The form is designed to manage only the `name` field
|
||||
of the `CustomGroup` model.
|
||||
|
||||
:ivar model: The model with which the form is associated, representing the `CustomGroup`.
|
||||
:type model: Type[CustomGroup]
|
||||
:ivar fields: List of fields to include in the form. In this case, only the `name` field.
|
||||
:type fields: List[str]
|
||||
"""
|
||||
class Meta:
|
||||
model = CustomGroup
|
||||
fields = ["name"]
|
||||
|
||||
class PermissionForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for managing permissions using a multiple-choice field.
|
||||
|
||||
This class is a Django ModelForm that is used to handle permission
|
||||
assignments. It provides a multiple selection widget pre-populated with
|
||||
permissions based on specific app labels. The form offers a way to submit
|
||||
and validate permission data for further processing.
|
||||
|
||||
:ivar name: A multiple-choice field that allows users to select permissions
|
||||
related to specific app labels (`inventory` and `django_ledger`).
|
||||
:type name: ModelMultipleChoiceField
|
||||
"""
|
||||
name = forms.ModelMultipleChoiceField(
|
||||
queryset=cache.get('permissions_queryset', Permission.objects.filter(content_type__app_label__in=["inventory","django_ledger"])),
|
||||
widget=forms.CheckboxSelectMultiple(),
|
||||
@ -933,6 +1470,17 @@ class PermissionForm(forms.ModelForm):
|
||||
fields = ["name"]
|
||||
|
||||
class UserGroupForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for selecting user groups.
|
||||
|
||||
This class is a Django ModelForm that is used to facilitate the selection of
|
||||
multiple user groups. It utilizes a checkbox input for group selection, backed
|
||||
by a queryset of CustomGroup instances. This form is specifically designed to
|
||||
handle input related to CustomGroup model objects.
|
||||
|
||||
:ivar name: A field for selecting multiple groups using checkboxes.
|
||||
:type name: ModelMultipleChoiceField
|
||||
"""
|
||||
name = forms.ModelMultipleChoiceField(
|
||||
queryset= CustomGroup.objects.all(),
|
||||
widget=forms.CheckboxSelectMultiple(),
|
||||
@ -943,15 +1491,50 @@ class UserGroupForm(forms.ModelForm):
|
||||
fields = ["name"]
|
||||
|
||||
class DealerSettingsForm(forms.ModelForm):
|
||||
"""
|
||||
Represents a form for managing DealerSettings.
|
||||
|
||||
This class provides a form for creating or updating `DealerSettings`
|
||||
instances. It automatically includes all fields defined in the
|
||||
`DealerSettings` model and can be used within a Django web application.
|
||||
|
||||
:ivar model: Associated model for the form.
|
||||
:type model: DealerSettings
|
||||
:ivar fields: Fields to include in the form. The value "__all__" indicates
|
||||
that all model fields should be included.
|
||||
:type fields: str
|
||||
"""
|
||||
class Meta:
|
||||
model = DealerSettings
|
||||
fields = "__all__"
|
||||
|
||||
class LeadTransferForm(forms.Form):
|
||||
"""
|
||||
Represents a form for transferring leads between staff members.
|
||||
|
||||
This class defines a Django form used for handling the transfer of leads
|
||||
to a specific staff member. It provides a mechanism to select the staff
|
||||
member to whom the lead should be transferred by offering a dropdown
|
||||
field populated by a queryset of staff objects.
|
||||
|
||||
:ivar transfer_to: Field for selecting the staff to transfer the lead to.
|
||||
:type transfer_to: ModelChoiceField
|
||||
"""
|
||||
transfer_to = forms.ModelChoiceField(label="to",queryset=Staff.objects.all())
|
||||
|
||||
|
||||
class DealersMakeForm(forms.Form):
|
||||
"""
|
||||
Form for selecting car makes related to a dealer.
|
||||
|
||||
This form allows dealers to select multiple car makes from a predefined
|
||||
set of car makes that are marked as suitable for SA import. The selected
|
||||
car makes can then be tied to the dealer.
|
||||
|
||||
:ivar dealer: The dealer instance associated with the form. This instance
|
||||
is used to filter and save car makes for a specific dealer.
|
||||
:type dealer: Dealer or None
|
||||
"""
|
||||
car_makes = forms.ModelMultipleChoiceField(
|
||||
queryset=CarMake.objects.filter(is_sa_import=True),
|
||||
widget=forms.CheckboxSelectMultiple(attrs={"class": "car-makes-grid"}),
|
||||
@ -972,6 +1555,18 @@ class DealersMakeForm(forms.Form):
|
||||
|
||||
|
||||
class JournalEntryModelCreateForm(JournalEntryModelCreateFormBase):
|
||||
"""
|
||||
Represents a form model for creating journal entries.
|
||||
|
||||
This class serves as a base for creating a form model specifically designed
|
||||
for creating new journal entries. It inherits properties and functionalities
|
||||
from `JournalEntryModelCreateFormBase`.
|
||||
|
||||
:ivar foo: Description of foo attribute.
|
||||
:type foo: str
|
||||
:ivar bar: Description of bar attribute.
|
||||
:type bar: int
|
||||
"""
|
||||
pass
|
||||
|
||||
# class LedgerModelCreateForm(LedgerModelCreateFormBase):
|
||||
|
||||
@ -14,6 +14,18 @@ logger = logging.getLogger('user_activity')
|
||||
|
||||
|
||||
class LogUserActivityMiddleware:
|
||||
"""
|
||||
Middleware for logging user activity.
|
||||
|
||||
This middleware logs the activity of authenticated users each time they make a
|
||||
request. It creates an entry in the UserActivityLog model capturing the user's
|
||||
ID, the action performed, and the timestamp. It is intended to assist in
|
||||
tracking user actions across the application for analytics or auditing purposes.
|
||||
|
||||
:ivar get_response: The next middleware or view in the WSGI request-response
|
||||
chain.
|
||||
:type get_response: Callable
|
||||
"""
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
@ -37,6 +49,17 @@ class LogUserActivityMiddleware:
|
||||
|
||||
|
||||
class InjectParamsMiddleware:
|
||||
"""
|
||||
Middleware to add processed user-related parameters to the request object.
|
||||
|
||||
This middleware processes incoming requests to extract and enhance user
|
||||
information, specifically linking user context such as `dealer` to the
|
||||
request. It allows subsequent views and middlewares to access these enriched
|
||||
request parameters with ease.
|
||||
|
||||
:ivar get_response: The callable to get the next middleware or view response.
|
||||
:type get_response: Callable
|
||||
"""
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
@ -51,6 +74,19 @@ class InjectParamsMiddleware:
|
||||
|
||||
|
||||
class InjectDealerMiddleware:
|
||||
"""
|
||||
Middleware to inject user role attributes into the request object.
|
||||
|
||||
This middleware assigns boolean attributes to the request object to indicate
|
||||
whether the user is a dealer or a staff member. It checks for the presence of
|
||||
specific user attributes (`dealer` and `staffmember`) and sets corresponding
|
||||
flags accordingly. The middleware is designed to support role-based processing
|
||||
in requests.
|
||||
|
||||
:ivar get_response: The callable provided by the Django framework
|
||||
to process the next middleware or the view in the request-response cycle.
|
||||
:type get_response: Callable
|
||||
"""
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
|
||||
@ -4,7 +4,13 @@ from django.urls import reverse, reverse_lazy
|
||||
|
||||
class AddClassMixin:
|
||||
"""
|
||||
Mixin for adding classes to a model.
|
||||
Provides functionality for automatically adding CSS classes to form field widgets.
|
||||
|
||||
This mixin is intended to be used in Django forms. It modifies the rendering of form fields
|
||||
by appending specific CSS classes to their widget attributes, enhancing their default styling.
|
||||
It distinguishes between fields with ``forms.Select`` widgets and other types of widgets to
|
||||
apply different CSS classes.
|
||||
|
||||
"""
|
||||
def add_class_to_fields(self):
|
||||
"""
|
||||
@ -22,7 +28,17 @@ class AddClassMixin:
|
||||
|
||||
class LocalizedNameMixin:
|
||||
"""
|
||||
Mixin to provide a reusable get_localized_name method.
|
||||
Provides functionality to retrieve localized names based on the current language.
|
||||
|
||||
This mixin is intended to provide language-specific name access for objects
|
||||
that support localization. It checks the current language setting and retrieves
|
||||
the appropriate name attribute (`arabic_name` for Arabic or `name` for other
|
||||
languages).
|
||||
|
||||
:ivar arabic_name: Localized name for the Arabic language.
|
||||
:type arabic_name: Optional[str]
|
||||
:ivar name: Default name used for non-Arabic languages.
|
||||
:type name: Optional[str]
|
||||
"""
|
||||
def get_local_name(self):
|
||||
"""
|
||||
|
||||
@ -55,6 +55,21 @@ class DealerUserManager(UserManager):
|
||||
|
||||
|
||||
class DealersMake(models.Model):
|
||||
"""
|
||||
Represents the relationship between a car dealer and a car make.
|
||||
|
||||
This model establishes a many-to-many relationship between dealers and
|
||||
car makes, allowing each dealer to be associated with multiple car makes
|
||||
and each car make to be associated with multiple dealers. It also keeps
|
||||
track of the date and time when the relationship was added.
|
||||
|
||||
:ivar dealer: The dealer associated with the car make.
|
||||
:type dealer: ForeignKey
|
||||
:ivar car_make: The car make associated with the dealer.
|
||||
:type car_make: ForeignKey
|
||||
:ivar added_at: The date and time when the relationship was created.
|
||||
:type added_at: DateTimeField
|
||||
"""
|
||||
dealer = models.ForeignKey("Dealer", on_delete=models.CASCADE, related_name="dealer_makes")
|
||||
car_make = models.ForeignKey("CarMake", on_delete=models.CASCADE, related_name="car_dealers")
|
||||
added_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@ -15,7 +15,18 @@ from .models import Car,CarMake,CarModel
|
||||
from inventory.haikalna import decode_vin_haikalna
|
||||
|
||||
|
||||
def get_make(item):
|
||||
def get_make(item):
|
||||
"""
|
||||
Fetches a car make object from the database based on the provided item. The function
|
||||
first attempts an exact case-insensitive match on the full string. If no match is found,
|
||||
it splits the input string by spaces and checks for a match with each fragment, stopping
|
||||
as soon as a match is found.
|
||||
|
||||
:param item: A string representing the name or a part of the name of the car make to search.
|
||||
:type item: str
|
||||
:return: The first matching CarMake object found, or None if no match is found.
|
||||
:rtype: CarMake or None
|
||||
"""
|
||||
data = CarMake.objects.filter(name__iexact=item).first()
|
||||
if not data:
|
||||
r = item.split(" ")
|
||||
@ -24,7 +35,18 @@ def get_make(item):
|
||||
break
|
||||
return data
|
||||
|
||||
def get_model(item,make):
|
||||
def get_model(item,make):
|
||||
"""
|
||||
Searches for a car model associated with a specific make by performing an
|
||||
exact case-insensitive match. If no match is found, it attempts to match
|
||||
based on individual words split from the input item.
|
||||
|
||||
:param item: A string representing the name of the car model to search for.
|
||||
:param make: An object representing the car manufacturer, which contains the
|
||||
associated car models.
|
||||
:return: Returns the first car model object that matches the search criteria,
|
||||
or None if no match is found.
|
||||
"""
|
||||
data = make.carmodel_set.filter(name__iexact=item).first()
|
||||
if not data:
|
||||
r = item.split(" ")
|
||||
@ -34,11 +56,34 @@ def get_model(item,make):
|
||||
return data
|
||||
|
||||
def normalize_name(name):
|
||||
"""
|
||||
Normalizes a given name by removing spaces and hyphens and converting it to lowercase.
|
||||
|
||||
This function is useful for ensuring consistent formatting of names by
|
||||
removing unwanted characters and applying a uniform casing. The output
|
||||
is designed to be a simple, standardized string version of the input name.
|
||||
|
||||
:param name: The name string to be normalized.
|
||||
:type name: str
|
||||
:return: A normalized string with no spaces or hyphens, all in lowercase.
|
||||
:rtype: str
|
||||
"""
|
||||
return name.replace(" ", "").replace("-", "").lower()
|
||||
|
||||
|
||||
def decodevin(vin):
|
||||
|
||||
"""
|
||||
Decodes a Vehicle Identification Number (VIN) using multiple decoding functions
|
||||
and returns the decoded result. This function attempts to decode the VIN using
|
||||
three different functions in sequence and returns the first successful result.
|
||||
If none of the decoding functions produce a valid result, the function returns None.
|
||||
|
||||
:param vin: The Vehicle Identification Number (VIN) to be decoded.
|
||||
:type vin: str
|
||||
:return: The decoded result if any decoding function is successful, or None if
|
||||
all decoding attempts fail.
|
||||
:rtype: dict | None
|
||||
"""
|
||||
if result:=decode_vin(vin):
|
||||
return result
|
||||
elif result:=elm(vin):
|
||||
@ -50,6 +95,21 @@ def decodevin(vin):
|
||||
|
||||
|
||||
def decode_vin(vin):
|
||||
"""
|
||||
Decodes a given Vehicle Identification Number (VIN) to extract vehicle details such as
|
||||
maker, model, and model year.
|
||||
|
||||
This function takes a VIN string as input, processes it using the VIN utility, and attempts
|
||||
to extract essential information about the vehicle. It returns a dictionary containing the
|
||||
decoded details if all required fields are successfully retrieved; otherwise, it returns None.
|
||||
|
||||
:param vin: The Vehicle Identification Number to be decoded.
|
||||
:type vin: str
|
||||
|
||||
:return: A dictionary containing decoded vehicle details with keys "maker", "model", and
|
||||
"modelYear", or None if any of these fields cannot be determined.
|
||||
:rtype: dict | None
|
||||
"""
|
||||
v = VIN(vin)
|
||||
data = {}
|
||||
if v:
|
||||
@ -63,6 +123,23 @@ def decode_vin(vin):
|
||||
|
||||
|
||||
def elm(vin):
|
||||
"""
|
||||
Fetches vehicle information using the provided VIN (Vehicle Identification Number)
|
||||
through the ELM API service.
|
||||
|
||||
This function sends a GET request to the ELM API endpoint with the VIN parameter
|
||||
to retrieve details about a vehicle, including its maker, model, and model year.
|
||||
The function processes the API's JSON response to extract relevant data and
|
||||
returns it if all required fields are available.
|
||||
|
||||
:param vin: Vehicle Identification Number required to query the ELM API
|
||||
service for vehicle information.
|
||||
:type vin: str
|
||||
|
||||
:return: A dictionary containing the vehicle's `maker`, `model`, and `modelYear`
|
||||
if all fields are present. Returns None if any of these fields are missing.
|
||||
:rtype: dict or None
|
||||
"""
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"app-id": settings.ELM_APP_ID,
|
||||
|
||||
@ -69,7 +69,19 @@ User = get_user_model()
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_car_location(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal to create or update the car's location when a car instance is saved.
|
||||
Signal handler to create a CarLocation entry when a new Car instance is created.
|
||||
The function ensures that the associated Car has a dealer before creating its
|
||||
CarLocation. If the dealer is missing, a ValueError is raised, and an error
|
||||
message is logged.
|
||||
|
||||
:param sender: The model class that sends the signal, typically `models.Car`.
|
||||
:type sender: Type[models.Model]
|
||||
:param instance: The actual instance of the Car model that triggered the signal.
|
||||
:param created: A boolean value indicating whether a new record was created.
|
||||
:type created: bool
|
||||
:param kwargs: Additional keyword arguments provided with the signal.
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
try:
|
||||
if created:
|
||||
@ -91,6 +103,25 @@ def create_car_location(sender, instance, created, **kwargs):
|
||||
# Create Entity
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler for creating ledger entities and initializing accounts for a new Dealer instance upon creation.
|
||||
|
||||
This signal is triggered when a new Dealer instance is saved to the database. It performs the following actions:
|
||||
1. Creates a ledger entity for the Dealer with necessary configurations.
|
||||
2. Generates a chart of accounts (COA) for the entity and assigns it as the default.
|
||||
3. Creates predefined unit of measures (UOMs) related to the entity.
|
||||
4. Initializes and assigns default accounts under various roles (e.g., assets, liabilities) for the entity with their
|
||||
respective configurations (e.g., account code, balance type).
|
||||
|
||||
This function ensures all necessary financial records and accounts are set up when a new Dealer is added, preparing the
|
||||
system for future financial transactions and accounting operations.
|
||||
|
||||
:param sender: The model class that sent the signal (in this case, Dealer).
|
||||
:param instance: The instance of the model being saved.
|
||||
:param created: A boolean indicating whether a new record was created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity_name = instance.user.dealer.name
|
||||
entity = EntityModel.create_entity(
|
||||
@ -628,7 +659,19 @@ def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_dealer_groups(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler to create and assign default groups to a Dealer instance when it
|
||||
is created. The groups are based on predefined names and assigned specific
|
||||
permissions. Uses transaction hooks to ensure groups are created only after
|
||||
successful database commit.
|
||||
|
||||
:param sender: The model class that triggered the signal.
|
||||
:type sender: Type[models.Model]
|
||||
:param instance: The instance of the model class that caused the signal to fire.
|
||||
:param created: Boolean indicating whether an instance was newly created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:type kwargs: dict
|
||||
"""
|
||||
group_names = ["Inventory", "Accountant", "Sales"]
|
||||
|
||||
def create_groups():
|
||||
@ -642,6 +685,19 @@ def create_dealer_groups(sender, instance, created, **kwargs):
|
||||
# Create Vendor
|
||||
@receiver(post_save, sender=models.Vendor)
|
||||
def create_ledger_vendor(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal function that listens for the `post_save` event on the Vendor model.
|
||||
This function is triggered after a Vendor instance is saved. If the instance
|
||||
is newly created (`created` is True), it will create necessary related entities
|
||||
such as a Vendor model in the corresponding Entity and an Account for that Vendor.
|
||||
|
||||
:param sender: The model class that triggered the signal event, which is `models.Vendor`.
|
||||
:param instance: The specific instance of the `models.Vendor` that was saved.
|
||||
:param created: A boolean indicating whether the instance is newly created (`True`)
|
||||
or updated (`False`).
|
||||
:param kwargs: Additional keyword arguments passed by the signal dispatcher.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
|
||||
additionals = to_dict(instance)
|
||||
@ -680,6 +736,19 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.CustomerModel)
|
||||
def create_customer_user(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Connects to the `post_save` signal of the `CustomerModel` to create a user object
|
||||
associated with the customer instance whenever a new `CustomerModel` instance is
|
||||
created. Retrieves customer-specific information from `additional_info` to initialize
|
||||
and configure the associated user object. Ensures the user object created has
|
||||
unusable passwords by default.
|
||||
|
||||
:param sender: The model class that sends the signal (`CustomerModel`).
|
||||
:param instance: The instance of `CustomerModel` that triggered the signal.
|
||||
:param created: A boolean indicating whether a new instance was created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
try:
|
||||
first_name = instance.additional_info.get("customer_info").get("first_name")
|
||||
@ -701,6 +770,22 @@ def create_customer_user(sender, instance, created, **kwargs):
|
||||
# Create Item
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_item_model(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler that triggers upon saving a `Car` model instance. This function is responsible
|
||||
for creating or updating an associated product in the related entity's inventory system. The
|
||||
new product is created only if it does not already exist, and additional information about the
|
||||
car is added to the product's metadata.
|
||||
|
||||
:param sender: Signal sender, typically the model class triggering the save event.
|
||||
:type sender: type
|
||||
:param instance: Instance of the `Car` model that was saved.
|
||||
:type instance: models.Car
|
||||
:param created: Flag indicating whether the model instance was newly created.
|
||||
:type created: bool
|
||||
:param kwargs: Additional keyword arguments passed by the signal mechanism.
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
entity = instance.dealer.entity
|
||||
if created:
|
||||
coa = entity.get_default_coa()
|
||||
@ -723,6 +808,18 @@ def create_item_model(sender, instance, created, **kwargs):
|
||||
# # update price - CarFinance
|
||||
@receiver(post_save, sender=models.CarFinance)
|
||||
def update_item_model_cost(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler for updating an inventory item's cost and additional information
|
||||
when a CarFinance instance is saved. This function updates the corresponding
|
||||
inventory item of the car dealer's entity associated with the car's VIN by
|
||||
modifying its default amount and updating additional data fields.
|
||||
|
||||
:param sender: The model class that triggered the signal.
|
||||
:param instance: The instance of the CarFinance that was saved.
|
||||
:param created: A boolean indicating whether the model instance was newly created.
|
||||
:param kwargs: Additional keyword arguments passed during the signal invocation.
|
||||
:return: None
|
||||
"""
|
||||
entity = instance.car.dealer.entity
|
||||
|
||||
product = entity.get_items_all().filter(name=instance.car.vin).first()
|
||||
@ -759,11 +856,38 @@ def update_item_model_cost(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.CarColors)
|
||||
def update_car_when_color_changed(sender, instance, **kwargs):
|
||||
"""
|
||||
Signal receiver to handle updates to a car instance when its related
|
||||
CarColors instance is modified. Triggered by the `post_save` signal
|
||||
for the `CarColors` model. Ensures that the associated `Car` instance
|
||||
is saved, propagating changes effectively.
|
||||
|
||||
:param sender: The model class (`CarColors`) that was saved.
|
||||
:type sender: Type[models.CarColors]
|
||||
:param instance: The specific instance of `CarColors` that was saved.
|
||||
:type instance: models.CarColors
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
car = instance.car
|
||||
car.save()
|
||||
|
||||
@receiver(post_save, sender=models.Opportunity)
|
||||
def notify_staff_on_deal_stage_change(sender, instance, **kwargs):
|
||||
"""
|
||||
Notify staff members when the stage of an Opportunity is updated. This function listens to the `post_save`
|
||||
signal for the Opportunity model and triggers a notification if the stage attribute of the Opportunity
|
||||
instance has been changed.
|
||||
|
||||
:param sender: The model class that sends the signal.
|
||||
:type sender: type[models.Opportunity]
|
||||
:param instance: The actual instance being saved in the Django ORM.
|
||||
:type instance: models.Opportunity
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
if instance.pk:
|
||||
previous = models.Opportunity.objects.get(pk=instance.pk)
|
||||
if previous.stage != instance.stage:
|
||||
@ -808,6 +932,18 @@ def notify_staff_on_deal_stage_change(sender, instance, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.AdditionalServices)
|
||||
def create_item_service(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler for creating a service item in the ItemModel when a new
|
||||
AdditionalServices instance is created. This function listens to the
|
||||
post_save signal of the AdditionalServices model and sets up the related
|
||||
ItemModel instance to represent the service.
|
||||
|
||||
:param sender: The model class that sent the signal.
|
||||
:param instance: The instance of the model being saved.
|
||||
:param created: Boolean indicating whether a new instance was created.
|
||||
:param kwargs: Additional keyword arguments provided by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity = instance.dealer.entity
|
||||
uom = entity.get_uom_all().get(unit_abbr=instance.uom)
|
||||
@ -831,6 +967,25 @@ def create_item_service(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.Lead)
|
||||
def track_lead_status_change(sender, instance, **kwargs):
|
||||
"""
|
||||
Tracks changes in the status of a Lead instance and logs the transition into the
|
||||
LeadStatusHistory model. This function is triggered after the `post_save` signal
|
||||
is emitted for a Lead instance.
|
||||
|
||||
The function compares the `status` of the updated Lead instance with its previous
|
||||
value. If the `status` has changed, it creates a new entry in the LeadStatusHistory
|
||||
model, recording the old status, the new status, and the staff responsible for the change.
|
||||
|
||||
:param sender: The model class that sent the signal.
|
||||
:type sender: Type[models.Model]
|
||||
:param instance: The actual instance being saved. It represents the Lead instance
|
||||
whose status is being tracked.
|
||||
:type instance: models.Lead
|
||||
:param kwargs: Additional keyword arguments passed by the signal. These can include
|
||||
flags such as 'created' to indicate if the instance was newly created or updated.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
if instance.pk: # Ensure the instance is being updated, not created
|
||||
try:
|
||||
old_lead = models.Lead.objects.get(pk=instance.pk)
|
||||
@ -847,6 +1002,18 @@ def track_lead_status_change(sender, instance, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.Lead)
|
||||
def notify_assigned_staff(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler that sends a notification to the staff member when a new lead is assigned.
|
||||
This function is triggered when a Lead instance is saved. If the lead has been assigned
|
||||
to a staff member, it creates a Notification object, notifying the staff member of the
|
||||
new assignment.
|
||||
|
||||
:param sender: The model class that sent the signal.
|
||||
:param instance: The instance of the model that was saved.
|
||||
:param created: A boolean indicating whether a new instance was created.
|
||||
:param kwargs: Additional keyword arguments.
|
||||
:return: None
|
||||
"""
|
||||
if instance.staff: # Check if the lead is assigned
|
||||
models.Notification.objects.create(
|
||||
user=instance.staff.staff_member.user,
|
||||
@ -857,7 +1024,15 @@ def notify_assigned_staff(sender, instance, created, **kwargs):
|
||||
@receiver(post_save, sender=models.CarReservation)
|
||||
def update_car_status_on_reservation_create(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal to update the car status to 'reserved' when a reservation is created.
|
||||
Signal handler to update the status of a car upon the creation of a car reservation.
|
||||
This function is triggered when a new instance of a CarReservation is created and saved
|
||||
to the database. It modifies the status of the associated car to reflect the RESERVED status.
|
||||
|
||||
:param sender: The model class that sends the signal (CarReservation).
|
||||
:param instance: The specific instance of the CarReservation that triggered the signal.
|
||||
:param created: A boolean indicating whether the CarReservation instance was created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
car = instance.car
|
||||
@ -867,7 +1042,18 @@ def update_car_status_on_reservation_create(sender, instance, created, **kwargs)
|
||||
@receiver(post_delete, sender=models.CarReservation)
|
||||
def update_car_status_on_reservation_delete(sender, instance, **kwargs):
|
||||
"""
|
||||
Signal to update the car status to 'available' when a reservation is deleted.
|
||||
Signal handler that updates the status of a car to available when a car reservation
|
||||
is deleted. If there are no active reservations associated with the car, the car's
|
||||
status is updated to 'AVAILABLE'. This ensures the car's status accurately reflects
|
||||
its reservability.
|
||||
|
||||
:param sender: The model class that triggers the signal (should always be
|
||||
models.CarReservation in this context).
|
||||
:type sender: type
|
||||
:param instance: The instance of the deleted reservation.
|
||||
:type instance: models.CarReservation
|
||||
:param kwargs: Additional keyword arguments.
|
||||
:type kwargs: dict
|
||||
"""
|
||||
car = instance.car
|
||||
# Check if there are no active reservations for the car
|
||||
@ -878,7 +1064,16 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
|
||||
@receiver(post_save, sender=models.CarReservation)
|
||||
def update_car_status_on_reservation_update(sender, instance, **kwargs):
|
||||
"""
|
||||
Signal to update the car status based on the reservation's active status.
|
||||
Handles the post-save signal for CarReservation model, updating the associated
|
||||
car's status based on the reservation's activity status. If the reservation is
|
||||
active, the car's status is updated to RESERVED. If the reservation is not
|
||||
active, the car's status is set to AVAILABLE if there are no other active
|
||||
reservations for the car.
|
||||
|
||||
:param sender: The model class that sent the signal.
|
||||
:param instance: The CarReservation instance that triggered the signal.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
car = instance.car
|
||||
if instance.is_active:
|
||||
@ -890,6 +1085,23 @@ def update_car_status_on_reservation_update(sender, instance, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_dealer_settings(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Triggered when a `Dealer` instance is saved. This function creates corresponding
|
||||
`DealerSettings` for a newly created `Dealer` instance. The function assigns
|
||||
default accounts for invoices and bills based on the role of the accounts
|
||||
retrieved from the associated entity of the `Dealer`.
|
||||
|
||||
:param sender: The model class that triggered the signal, specifically `Dealer`.
|
||||
:type sender: Type
|
||||
:param instance: The actual instance of the `Dealer` that was saved.
|
||||
:type instance: models.Dealer
|
||||
:param created: A boolean indicating whether a new instance was created.
|
||||
`True` if the instance was newly created; otherwise, `False`.
|
||||
:type created: bool
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
models.DealerSettings.objects.create(
|
||||
dealer=instance,
|
||||
@ -930,10 +1142,37 @@ def create_dealer_settings(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_vat(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal receiver that listens to the `post_save` signal for the `Dealer` model
|
||||
and handles the creation of a `VatRate` instance if it does not already exist.
|
||||
|
||||
This function ensures that a default VAT rate is created with a specified rate
|
||||
and is marked as active. It is connected to the Django signals framework and
|
||||
automatically executes whenever a `Dealer` instance is saved.
|
||||
|
||||
:param sender: The model class that triggered the signal (in this case, `Dealer`).
|
||||
:param instance: The instance of the model being saved.
|
||||
:param created: Boolean indicating whether a new instance was created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_make_ledger_accounts(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal receiver that creates ledger accounts for car makes associated with a dealer when a new dealer instance
|
||||
is created. This function listens to the `post_save` signal of the `Dealer` model and automatically generates
|
||||
new ledger accounts for all car makes, associating them with the given dealer's entity.
|
||||
|
||||
:param sender: The model class (`Dealer`) that triggered the signal.
|
||||
:type sender: Type[models.Dealer]
|
||||
:param instance: The instance of the `Dealer` model that triggered the signal.
|
||||
:param created: A boolean indicating whether a new `Dealer` instance was created.
|
||||
:type created: bool
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity = instance.entity
|
||||
coa = entity.get_default_coa()
|
||||
@ -976,6 +1215,27 @@ def create_make_ledger_accounts(sender, instance, created, **kwargs):
|
||||
# )
|
||||
|
||||
def save_journal(car_finance,ledger,vendor):
|
||||
"""
|
||||
Saves a journal entry pertaining to a car finance transaction for a specific ledger and vendor.
|
||||
|
||||
This function ensures that relevant accounts are updated to record financial transactions. It handles
|
||||
debiting of the inventory account and crediting of the vendor account to maintain accurate bookkeeping.
|
||||
Additionally, it creates vendor accounts dynamically if required and ties the created journal entry to
|
||||
the ledger passed as a parameter. All transactions adhere to the ledger's entity-specific Chart of
|
||||
Accounts (COA) configuration.
|
||||
|
||||
:param car_finance: Instance of the car finance object containing details about the financed car
|
||||
and its associated costs.
|
||||
:type car_finance: `CarFinance` object
|
||||
:param ledger: Ledger instance to which the journal entry is tied. This ledger must provide
|
||||
entity-specific details, including its COA and related accounts.
|
||||
:type ledger: `Ledger` object
|
||||
:param vendor: Vendor instance representing the supplier or vendor related to the car finance
|
||||
transaction. This vendor is used to derive or create the vendor account in COA.
|
||||
:type vendor: `Vendor` object
|
||||
|
||||
:return: None
|
||||
"""
|
||||
entity = ledger.entity
|
||||
coa = entity.get_default_coa()
|
||||
journal = JournalEntryModel.objects.create(
|
||||
@ -1027,6 +1287,26 @@ def save_journal(car_finance,ledger,vendor):
|
||||
|
||||
@receiver(post_save, sender=models.CarFinance)
|
||||
def update_finance_cost(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal to handle `post_save` functionality for the `CarFinance` model. This function
|
||||
creates or updates financial records related to a car's finance details in the ledger
|
||||
associated with the car's vendor and dealer. For newly created instances, a ledger is
|
||||
created or retrieved, and the `save_journal` function is executed to log the financial
|
||||
transactions.
|
||||
|
||||
This function also has commented-out logic to handle updates for already created
|
||||
instances, including journal updates or adjustments to existing financial transactions.
|
||||
|
||||
:param sender: Model class that triggered the signal
|
||||
:type sender: Model
|
||||
:param instance: Instance of the `CarFinance` model passed to the signal
|
||||
:type instance: CarFinance
|
||||
:param created: Boolean value indicating if the instance was created (`True`) or updated (`False`)
|
||||
:type created: bool
|
||||
:param kwargs: Arbitrary keyword arguments passed to the signal
|
||||
:type kwargs: dict
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity = instance.car.dealer.entity
|
||||
vendor = instance.car.vendor
|
||||
|
||||
@ -8,6 +8,45 @@ from django.utils.html import format_html
|
||||
|
||||
|
||||
class CarTable(tables.Table):
|
||||
"""
|
||||
Represents a table for displaying information about cars.
|
||||
|
||||
The `CarTable` class is a Django Tables2 table configuration designed for displaying
|
||||
details of cars, including their stock type, VIN, make, model, year, series, trim,
|
||||
mileage, price, colors, receiving date, and status. This table renders each column with
|
||||
customizable settings, including cell attributes and formatting. The class utilizes
|
||||
custom render methods to format specific columns, such as dates, localized names, and
|
||||
status badges.
|
||||
|
||||
:ivar stock_type: Specifies whether the car is new or used.
|
||||
:type stock_type: tables.Column
|
||||
:ivar vin: Contains the VIN of the car, rendered as a hyperlink to the car detail page.
|
||||
:type vin: tables.LinkColumn
|
||||
:ivar id_car_make: Defines the make (brand) of the car.
|
||||
:type id_car_make: tables.Column
|
||||
:ivar id_car_model: Defines the model of the car.
|
||||
:type id_car_model: tables.Column
|
||||
:ivar year: Specifies the year the car was manufactured.
|
||||
:type year: tables.Column
|
||||
:ivar id_car_serie: Refers to the series of the car.
|
||||
:type id_car_serie: tables.Column
|
||||
:ivar id_car_trim: Refers to the trim of the car.
|
||||
:type id_car_trim: tables.Column
|
||||
:ivar mileage: Indicates the mileage of the car.
|
||||
:type mileage: tables.Column
|
||||
:ivar selling_price: Displays the selling price, derived from a related field on the finances object.
|
||||
:type selling_price: tables.Column
|
||||
:ivar exterior_color: Displays the exterior color of the car, derived from a related field on the colors object.
|
||||
:type exterior_color: tables.Column
|
||||
:ivar interior_color: Displays the interior color of the car, derived from a related field on the colors object.
|
||||
:type interior_color: tables.Column
|
||||
:ivar receiving_date: Represents the date the car was received, formatted as the
|
||||
time elapsed since receiving or as "-" if the date is missing.
|
||||
:type receiving_date: tables.Column
|
||||
:ivar status: Shows the status of the car (e.g., available, reserved, sold, transfer)
|
||||
with badge-style formatting based on the status value.
|
||||
:type status: tables.Column
|
||||
"""
|
||||
stock_type = tables.Column(verbose_name=_("Stock Type"))
|
||||
vin = tables.LinkColumn("car_detail", args=[tables.A("pk")], verbose_name=_("VIN"), attrs={"td": {"class": "fw-bold"}})
|
||||
id_car_make = tables.Column(verbose_name=_("Make"))
|
||||
|
||||
@ -19,6 +19,36 @@ User = get_user_model()
|
||||
|
||||
# Create your tests here.
|
||||
class ModelTest(TestCase):
|
||||
"""
|
||||
Test case class designed to test models in the application. The tests
|
||||
verify model creation, related object creation, and appropriate
|
||||
functionality for specific business logic, ensuring correctness and
|
||||
reliability of the defined models.
|
||||
|
||||
This class tests the following:
|
||||
- Dealer model, including associated user and entity creation.
|
||||
- Car model, ensuring product creation and validations.
|
||||
- Testing of car finances, including finance totals and relationships.
|
||||
- Creation of additional services, ensuring the generation of corresponding
|
||||
item services.
|
||||
|
||||
:ivar vat: Vat rate created for testing purposes.
|
||||
:type vat: VatRate instance
|
||||
:ivar dealer: Dealer instance created for testing.
|
||||
:type dealer: Dealer instance
|
||||
:ivar car_make: Car make created for testing purposes.
|
||||
:type car_make: CarMake instance
|
||||
:ivar car_model: Car model created for testing purposes.
|
||||
:type car_model: CarModel instance
|
||||
:ivar car_serie: Car series created for testing purposes.
|
||||
:type car_serie: CarSerie instance
|
||||
:ivar trim: Car trim created for testing purposes.
|
||||
:type trim: CarTrim instance
|
||||
:ivar car: Car object created for testing.
|
||||
:type car: Car instance
|
||||
:ivar car_finances: Car finance object for the car under test.
|
||||
:type car_finances: CarFinance instance
|
||||
"""
|
||||
def setUp(self):
|
||||
email = "RkzgO@example.com"
|
||||
name = "John Doe"
|
||||
@ -140,6 +170,16 @@ class ModelTest(TestCase):
|
||||
|
||||
|
||||
class AuthenticationTest(TestCase):
|
||||
"""
|
||||
Represents a set of test cases for user authentication and signup validation within
|
||||
a web application. These tests ensure the correctness of authentication functionalities
|
||||
such as login and signing up with appropriate JSON data handling.
|
||||
|
||||
:ivar client: Django test client used to simulate HTTP requests within the test framework.
|
||||
:type client: Client
|
||||
:ivar url: URL for account signup endpoint used in the test cases.
|
||||
:type url: str
|
||||
"""
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.url = reverse("account_signup")
|
||||
@ -245,6 +285,20 @@ class AuthenticationTest(TestCase):
|
||||
|
||||
|
||||
class CarFinanceCalculatorTests(TestCase):
|
||||
"""
|
||||
Unit tests for the CarFinanceCalculator class.
|
||||
|
||||
This class contains various test cases to validate the correct functionality
|
||||
of the CarFinanceCalculator. It includes tests for VAT rate retrieval,
|
||||
item transactions, car data extraction, calculation of totals, fetching
|
||||
additional services, and finance-related data processing.
|
||||
|
||||
:ivar mock_model: Mocked model used to simulate interactions with the
|
||||
CarFinanceCalculator instance.
|
||||
:type mock_model: unittest.mock.MagicMock
|
||||
:ivar vat_rate: Active VAT rate used for testing VAT rate retrieval.
|
||||
:type vat_rate: VatRate
|
||||
"""
|
||||
def setUp(self):
|
||||
# Common setup for all tests
|
||||
self.mock_model = MagicMock()
|
||||
|
||||
@ -6,6 +6,17 @@ from plans.taxation import TaxationPolicy
|
||||
|
||||
|
||||
class SaudiTaxationPolicy(TaxationPolicy):
|
||||
"""
|
||||
Represents the taxation policy specific to Saudi Arabia.
|
||||
|
||||
This class inherits from TaxationPolicy and provides implementations
|
||||
of methods to retrieve default tax, issuer country code, and tax rates
|
||||
specific to Saudi Arabia. Typically used in scenarios involving
|
||||
invoicing or taxation calculation for Saudi Arabia.
|
||||
|
||||
:ivar settings: Configuration settings of the application.
|
||||
:type settings: module
|
||||
"""
|
||||
def get_default_tax(self):
|
||||
return getattr(settings, 'PLANS_TAX', None)
|
||||
|
||||
|
||||
@ -32,6 +32,20 @@ from django.utils.translation import get_language
|
||||
|
||||
|
||||
def get_jwt_token():
|
||||
"""
|
||||
Fetches a JWT token from an external authentication API.
|
||||
|
||||
This function sends a POST request to the provided authentication API endpoint with
|
||||
the required headers and payload. It retrieves a JSON Web Token (JWT) if the request
|
||||
is successful or returns None in case of a failure.
|
||||
|
||||
:raises: This function does not propagate exceptions but catches and logs
|
||||
``requests.exceptions.RequestException`` if the request fails.
|
||||
|
||||
:return: A JWT token as a string if the request is successful, or None if
|
||||
an error occurs during the process.
|
||||
:rtype: str or None
|
||||
"""
|
||||
url = "https://carapi.app/api/auth/login"
|
||||
headers = {
|
||||
"accept": "text/plain",
|
||||
@ -51,6 +65,16 @@ def get_jwt_token():
|
||||
|
||||
|
||||
def localize_some_words():
|
||||
"""
|
||||
Localize predefined words and phrases for display purposes.
|
||||
|
||||
This function is used to localize a set of predefined words or phrases
|
||||
that may be displayed in a user interface or other contexts. These
|
||||
localized words or phrases include terms like "success," "error," and
|
||||
"Forgot Password?".
|
||||
|
||||
:return: None
|
||||
"""
|
||||
success = _("success")
|
||||
error = _("error")
|
||||
forget = _("Forgot Password?")
|
||||
@ -59,6 +83,18 @@ def localize_some_words():
|
||||
|
||||
|
||||
def get_calculations(quotation):
|
||||
"""
|
||||
Calculates and summarizes financial services data related to the cars in a given
|
||||
quotation. It aggregates costs, VAT, and total amounts based on the services
|
||||
available for the cars linked to the quotation.
|
||||
|
||||
:param quotation: The quotation object containing the cars and their related
|
||||
financial details.
|
||||
:type quotation: Quotation
|
||||
:return: A dictionary with computed financial details including the services
|
||||
data, total service costs, total VAT computed, and the total including VAT.
|
||||
:rtype: dict
|
||||
"""
|
||||
context = {}
|
||||
qc_len = quotation.quotation_cars.count()
|
||||
cars = [x.car for x in quotation.quotation_cars.all()]
|
||||
@ -90,6 +126,23 @@ def get_calculations(quotation):
|
||||
|
||||
|
||||
def send_email(from_, to_, subject, message):
|
||||
"""
|
||||
Send an email with the specified subject and message.
|
||||
|
||||
This function sends an email from the given sender to the specified
|
||||
recipient with a subject and a message body. It utilizes the provided
|
||||
parameters to construct and send the email.
|
||||
|
||||
:param from_: str
|
||||
The sender's email address.
|
||||
:param to_: str
|
||||
The recipient's email address.
|
||||
:param subject: str
|
||||
The subject of the email.
|
||||
:param message: str
|
||||
The body/content of the email.
|
||||
:return: None
|
||||
"""
|
||||
subject = subject
|
||||
message = message
|
||||
from_email = from_
|
||||
@ -98,6 +151,22 @@ def send_email(from_, to_, subject, message):
|
||||
|
||||
|
||||
def get_user_type(request):
|
||||
"""
|
||||
Determine the type of user based on the given request object.
|
||||
|
||||
This function identifies the type of user from the provided request. It
|
||||
checks if the user is a dealer, staff member, or neither based on the
|
||||
attributes of the request object, returning the appropriate associated
|
||||
user type or `None` if the determination cannot be made.
|
||||
|
||||
:param request: The HTTP request object containing user and role
|
||||
information.
|
||||
:type request: Any
|
||||
:return: A dealer object if the user is a dealer, a dealer object
|
||||
associated with the staff member if the user is a staff member, or
|
||||
None if the user type cannot be identified.
|
||||
:rtype: Optional[Any]
|
||||
"""
|
||||
if request.is_dealer:
|
||||
return request.user.dealer
|
||||
elif request.is_staff:
|
||||
@ -106,6 +175,18 @@ def get_user_type(request):
|
||||
|
||||
|
||||
def get_dealer_from_instance(instance):
|
||||
"""
|
||||
Retrieve the dealer object from the given instance.
|
||||
|
||||
This function checks whether the given instance's dealer has an attribute
|
||||
`staff`. If the attribute exists, it directly returns the dealer object
|
||||
associated with the instance.
|
||||
|
||||
:param instance: The instance from which the dealer object is retrieved.
|
||||
:type instance: Any
|
||||
:return: The dealer object associated with the instance.
|
||||
:rtype: Any
|
||||
"""
|
||||
if instance.dealer.staff:
|
||||
return instance.dealer
|
||||
else:
|
||||
@ -113,6 +194,18 @@ def get_dealer_from_instance(instance):
|
||||
|
||||
|
||||
def reserve_car(car, request):
|
||||
"""
|
||||
Reserve a car for a user for 24 hours and update its status to reserved.
|
||||
|
||||
The function creates a reservation record for the specified car, sets the
|
||||
reservation expiration time, updates the car's status, and notifies the user
|
||||
about the operation outcome through success or error messages. It then redirects
|
||||
to the car detail page.
|
||||
|
||||
:param car: The car object to be reserved.
|
||||
:param request: The HTTP request object containing the user making the reservation.
|
||||
:return: Redirection to the car's detail page.
|
||||
"""
|
||||
try:
|
||||
reserved_until = timezone.now() + timezone.timedelta(hours=24)
|
||||
models.CarReservation.objects.create(
|
||||
@ -128,6 +221,17 @@ def reserve_car(car, request):
|
||||
|
||||
|
||||
def calculate_vat_amount(amount):
|
||||
"""
|
||||
Calculates the VAT (Value Added Tax) amount for a given monetary value. The method retrieves
|
||||
the first active VAT rate from the database and applies it to the provided amount. If no
|
||||
active VAT rate is found, the function will return the original amount.
|
||||
|
||||
:param amount: The monetary value to which the VAT should be applied.
|
||||
:type amount: Decimal
|
||||
:return: A tuple containing the computed VAT amount and the VAT rate as a decimal, or
|
||||
the original amount if no VAT rate is active.
|
||||
:rtype: Tuple[Decimal, Decimal] or Decimal
|
||||
"""
|
||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||
if vat:
|
||||
return ((amount * Decimal(vat.rate)).quantize(Decimal("0.01")), vat.rate)
|
||||
@ -135,6 +239,19 @@ def calculate_vat_amount(amount):
|
||||
|
||||
|
||||
def get_car_finance_data(model):
|
||||
"""
|
||||
Fetches car finance data from the provided model instance and calculates
|
||||
various related details including total prices, VAT, discounts, and
|
||||
additional services information.
|
||||
|
||||
:param model: The model instance that contains car and finance-related
|
||||
transaction data.
|
||||
:type model: Model
|
||||
:return: A dictionary containing detailed information about the car finance
|
||||
transactions, including individual car details, total quantity, calculated
|
||||
totals for prices, VAT, discounts, additional services, and the VAT rate.
|
||||
:rtype: dict
|
||||
"""
|
||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||
data = model.get_itemtxs_data()[0].all()
|
||||
total = sum(
|
||||
@ -202,6 +319,29 @@ def get_car_finance_data(model):
|
||||
|
||||
|
||||
def get_financial_values(model):
|
||||
"""
|
||||
Calculates financial values for a given model, including VAT, discounts,
|
||||
grand total, and additional services.
|
||||
|
||||
This function processes financial data related to items in the input model
|
||||
and computes aggregated values like total amounts, VAT amounts, discounts,
|
||||
and more. It also provides detailed information on cars and items as well
|
||||
as any applicable additional services.
|
||||
|
||||
:param model: The model instance containing financial and item data.
|
||||
It should have the necessary methods and attributes to fetch
|
||||
transactional records and relevant details.
|
||||
:type model: Any
|
||||
:return: A dictionary containing calculated financial details including:
|
||||
- "vat_amount": The computed VAT amount.
|
||||
- "total": The total value of all items before VAT and discounts.
|
||||
- "grand_total": The total after applying discounts and adding VAT.
|
||||
- "discount_amount": The aggregated discount amount.
|
||||
- "vat": The applicable VAT rate.
|
||||
- "car_and_item_info": A list of detailed car and item information.
|
||||
- "additional_services": A list of additional services and their prices.
|
||||
:rtype: dict
|
||||
"""
|
||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||
|
||||
if not model.get_itemtxs_data()[0].exists():
|
||||
@ -285,6 +425,23 @@ def get_financial_values(model):
|
||||
|
||||
|
||||
def set_invoice_payment(dealer, entity, invoice, amount, payment_method):
|
||||
"""
|
||||
Processes and applies a payment for a specified invoice. This function calculates
|
||||
finance details, handles associated account transactions, and updates the invoice
|
||||
status accordingly.
|
||||
|
||||
:param dealer: Dealer object responsible for processing the payment
|
||||
:type dealer: Dealer
|
||||
:param entity: Entity object associated with the invoice and payment
|
||||
:type entity: Entity
|
||||
:param invoice: The invoice object for which the payment is being made
|
||||
:type invoice: Invoice
|
||||
:param amount: The amount being paid towards the invoice
|
||||
:type amount: Decimal
|
||||
:param payment_method: The payment method used for the transaction
|
||||
:type payment_method: str
|
||||
:return: None
|
||||
"""
|
||||
calculator = CarFinanceCalculator(invoice)
|
||||
finance_data = calculator.get_finance_data()
|
||||
|
||||
@ -330,6 +487,27 @@ def set_invoice_payment(dealer, entity, invoice, amount, payment_method):
|
||||
|
||||
|
||||
def set_bill_payment(dealer, entity, bill, amount, payment_method):
|
||||
"""
|
||||
Sets the payment for a given bill by creating journal entries for the
|
||||
transaction and updating the respective accounts and the bill's status.
|
||||
|
||||
The function handles the transaction by creating a new journal entry
|
||||
linked with the specified bill, then records debit and credit
|
||||
transactions using the entity’s cash and accounts payable accounts.
|
||||
It finally updates the bill's payment status and persists changes.
|
||||
|
||||
:param dealer: The dealer making or receiving the payment.
|
||||
:type dealer: Any
|
||||
:param entity: The business entity involved in the payment transaction.
|
||||
:type entity: Any
|
||||
:param bill: The bill object representing the invoice to be paid.
|
||||
:type bill: Any
|
||||
:param amount: The amount to be paid for the bill.
|
||||
:type amount: Decimal
|
||||
:param payment_method: The method used to make the payment (e.g., cash, credit).
|
||||
:type payment_method: Any
|
||||
:return: None
|
||||
"""
|
||||
total_amount = 0
|
||||
for x in bill.get_itemtxs_data()[0].all():
|
||||
total_amount += Decimal(x.unit_cost) * Decimal(x.quantity)
|
||||
@ -369,6 +547,27 @@ def set_bill_payment(dealer, entity, bill, amount, payment_method):
|
||||
|
||||
|
||||
def transfer_to_dealer(request, cars, to_dealer, remarks=None):
|
||||
"""
|
||||
Transfers a list of cars from one dealer to another, ensuring that all cars
|
||||
originate from the same dealer and logging the transfer.
|
||||
|
||||
:param request: The HTTP request object which contains information about
|
||||
the current user and context.
|
||||
:type request: HttpRequest
|
||||
:param cars: A list of car objects to transfer.
|
||||
:type cars: list[Car]
|
||||
:param to_dealer: The dealer object representing the destination dealer.
|
||||
:type to_dealer: Dealer
|
||||
:param remarks: Optional remarks to include in the transfer log.
|
||||
Defaults to None.
|
||||
:type remarks: str, optional
|
||||
:return: None
|
||||
:rtype: NoneType
|
||||
|
||||
:raises ValueError: If no cars are selected for transfer.
|
||||
:raises ValueError: If the cars are not all from the same dealer.
|
||||
:raises ValueError: If the source and destination dealers are the same.
|
||||
"""
|
||||
dealer = get_user_type(request)
|
||||
|
||||
if not cars:
|
||||
@ -398,6 +597,28 @@ def transfer_to_dealer(request, cars, to_dealer, remarks=None):
|
||||
car.save()
|
||||
|
||||
class CarTransfer:
|
||||
"""
|
||||
Handles the process of transferring a car between dealers, automating associated tasks
|
||||
such as creating customers, invoices, products, vendors, and bills, as well as reflecting
|
||||
changes in relevant entities and systems.
|
||||
|
||||
The purpose of this class is to facilitate a smooth transfer of car ownership from one
|
||||
dealer to another. It ensures that all necessary financial, logistic, and informational
|
||||
processes are executed and updated within the system. The car's status and related
|
||||
entities are adjusted accordingly post-transfer.
|
||||
|
||||
:ivar car: Car object being transferred.
|
||||
:ivar transfer: Represents the transfer details, including source and destination dealers.
|
||||
:ivar from_dealer: The dealer transferring the car out.
|
||||
:ivar to_dealer: The dealer receiving the car.
|
||||
:ivar customer: Customer entity corresponding to the receiving dealer.
|
||||
:ivar invoice: Invoice entity created for the car transfer.
|
||||
:ivar ledger: Ledger associated with the created invoice.
|
||||
:ivar item: The inventory item corresponding to the car being transferred.
|
||||
:ivar product: The product created in the receiving dealer's ledger.
|
||||
:ivar vendor: Vendor entity related to the transferring dealer.
|
||||
:ivar bill: Bill entity created for the receiving dealer.
|
||||
"""
|
||||
def __init__(self, car, transfer):
|
||||
self.car = car
|
||||
self.transfer = transfer
|
||||
@ -700,6 +921,18 @@ class CarTransfer:
|
||||
|
||||
|
||||
def to_dict(obj):
|
||||
"""
|
||||
Convert a Python object's attributes and associated values to a dictionary,
|
||||
with special handling for specific data types such as datetime and object references.
|
||||
|
||||
:param obj: The Python object to be converted into a dictionary. Object attributes
|
||||
are dynamically introspected to create the dictionary. For objects containing
|
||||
references to other objects, specific attributes (e.g., "pk" or "id") may be used
|
||||
for conversion and representation.
|
||||
:return: A dictionary containing the key-value pairs for the object's attributes.
|
||||
Datetime values are formatted as strings in "YYYY-MM-DD HH:MM:SS" format. All other
|
||||
attributes, including nested object references, are converted to strings.
|
||||
"""
|
||||
obj_dict = vars(obj).copy()
|
||||
if "_state" in vars(obj):
|
||||
del obj_dict["_state"]
|
||||
@ -717,6 +950,24 @@ def to_dict(obj):
|
||||
return obj_dict
|
||||
|
||||
class CarFinanceCalculator:
|
||||
"""
|
||||
Class responsible for calculating car financing details.
|
||||
|
||||
This class provides methods and attributes required for calculating various
|
||||
aspects related to car financing, such as VAT calculation, pricing, discounts,
|
||||
and additional services. It processes data about cars, computes totals (e.g.,
|
||||
price, VAT, discounts), and aggregates the financial data for reporting or
|
||||
further processing.
|
||||
|
||||
:ivar model: The data model passed to the calculator for retrieving transaction data.
|
||||
:type model: Any
|
||||
:ivar vat_rate: The current active VAT rate retrieved from the database.
|
||||
:type vat_rate: Decimal
|
||||
:ivar item_transactions: A collection of item transactions retrieved from the model.
|
||||
:type item_transactions: list
|
||||
:ivar additional_services: A list of additional services with details (e.g., name, price, taxable status).
|
||||
:type additional_services: list
|
||||
"""
|
||||
VAT_OBJ_NAME = 'vat_rate'
|
||||
CAR_FINANCE_KEY = 'car_finance'
|
||||
CAR_INFO_KEY = 'car_info'
|
||||
@ -821,6 +1072,16 @@ class CarFinanceCalculator:
|
||||
|
||||
|
||||
def get_item_transactions(txs):
|
||||
"""
|
||||
Extracts and compiles relevant transaction details from a list of transactions,
|
||||
including information about cars, financing, estimates, and invoices. The extracted
|
||||
details for each transaction are stored as dictionaries in a list.
|
||||
|
||||
:param txs: A list of transaction objects from which information is extracted.
|
||||
:type txs: list
|
||||
:return: A list of dictionaries, each containing extracted transaction details.
|
||||
:rtype: list
|
||||
"""
|
||||
transactions = []
|
||||
for tx in txs:
|
||||
data = {}
|
||||
@ -844,7 +1105,21 @@ def get_item_transactions(txs):
|
||||
|
||||
def get_local_name(self):
|
||||
"""
|
||||
Returns the localized name based on the current language.
|
||||
Retrieve the localized name of the instance based on the current language.
|
||||
|
||||
This method returns the name attribute of an instance based on the currently
|
||||
active language. If the language is Arabic ('ar'), it attempts to return the
|
||||
value of the attribute `arabic_name`. If the language is not Arabic or the
|
||||
`arabic_name` attribute is not defined, it defaults to returning the value of
|
||||
the `name` attribute.
|
||||
|
||||
:param self:
|
||||
Reference to the instance of the class containing `name` and
|
||||
optionally `arabic_name` attributes.
|
||||
:return:
|
||||
The localized name based on the current language. Returns the value of
|
||||
`arabic_name` for Arabic ('ar') language, or the value of `name` for any
|
||||
other language or if `arabic_name` is not defined.
|
||||
"""
|
||||
if get_language() == 'ar':
|
||||
return getattr(self, 'arabic_name', None)
|
||||
@ -852,6 +1127,21 @@ def get_local_name(self):
|
||||
|
||||
|
||||
def handle_account_process(invoice,amount,finance_data):
|
||||
"""
|
||||
Processes accounting transactions based on an invoice, financial data,
|
||||
and related entity accounts configuration. This function handles the
|
||||
creation of accounts if they do not already exist, and processes journal
|
||||
entries and transactions.
|
||||
|
||||
:param invoice: The invoice object to process transactions for.
|
||||
:type invoice: InvoiceModel
|
||||
:param amount: Total monetary value for the transaction.
|
||||
:type amount: Decimal
|
||||
:param finance_data: Dictionary containing financial details such as
|
||||
'grand_total', 'total_vat_amount', and other related data.
|
||||
:type finance_data: dict
|
||||
:return: None
|
||||
"""
|
||||
for i in invoice.get_itemtxs_data()[0]:
|
||||
car = models.Car.objects.get(vin=invoice.get_itemtxs_data()[0].first().item_model.name)
|
||||
entity = invoice.ledger.entity
|
||||
@ -937,6 +1227,18 @@ def handle_account_process(invoice,amount,finance_data):
|
||||
# )
|
||||
|
||||
def create_make_accounts(dealer):
|
||||
"""
|
||||
Creates accounts for dealer's car makes and associates them with a default
|
||||
Chart of Accounts (CoA) if they don't already exist. The function iterates
|
||||
through all car makes associated with the dealer and creates unique inventory
|
||||
accounts for each car make. Accounts are created with a specified naming
|
||||
convention and are assigned a new account code if required.
|
||||
|
||||
:param dealer: The dealer for whom to create make accounts.
|
||||
:type dealer: Dealer
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
entity = dealer.entity
|
||||
coa = entity.get_default_coa()
|
||||
|
||||
|
||||
3157
inventory/views.py
3157
inventory/views.py
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user