diff --git a/.DS_Store b/.DS_Store index b4606620..d4706b1a 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 00000000..55b966ef --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/api/views.py b/api/views.py index 1031e3a9..3891d188 100644 --- a/api/views.py +++ b/api/views.py @@ -106,8 +106,9 @@ def car_list(request): page = request.GET.get("page", 1) per_page = 10 - cars = inventory_models.Car.objects.filter(dealer=dealer).values( + cars = inventory_models.Car.objects.all().values( "vin", + "year", "id_car_make__name", "id_car_model__name", "status" diff --git a/car_inventory/urls.py b/car_inventory/urls.py index 400f33c0..7fa793f5 100644 --- a/car_inventory/urls.py +++ b/car_inventory/urls.py @@ -28,6 +28,7 @@ urlpatterns += i18n_patterns( path('appointment/', include('appointment.urls')), path('plans/', include('plans.urls')), path("schema/", Schema.as_view()), + path('tours/', include('tours.urls')), # path('', include(tf_urls)), ) diff --git a/database.sqlite b/database.sqlite new file mode 100644 index 00000000..e69de29b diff --git a/haikal_kb.yaml b/haikal_kb.yaml new file mode 100644 index 00000000..7a97e484 --- /dev/null +++ b/haikal_kb.yaml @@ -0,0 +1,2950 @@ +metadata: + system_name: Haikal + version: '1.0' + generated_from: Django +features: + auth_login: + description: 'Persist a user id and a backend in the request. This way a user + doesn''t + + have to reauthenticate on every request. Note that data set during + + the anonymous session is retained when the user logs in.' + source: django.contrib.auth.views.auth_login + type: view_function + auth_logout: + description: 'Remove the authenticated user''s ID from the request and flush their + session + + data.' + source: django.contrib.auth.views.auth_logout + type: view_function + csrf_protect: + description: 'This decorator adds CSRF protection in exactly the same way as + + CsrfViewMiddleware, but it can be used on a per view basis. Using both, or + + using the decorator multiple times, is harmless and efficient.' + source: django.contrib.auth.views.csrf_protect + type: view_function + get_current_site: + description: 'Check if contrib.sites is installed and return either the current + + ``Site`` object or a ``RequestSite`` object based on the request.' + source: allauth.socialaccount.views.get_current_site + type: view_function + get_user_model: + description: Return the User model that is active in this project. + source: appointment.views.get_user_model + type: view_function + login_not_required: + description: Decorator for views that allows access to unauthenticated requests. + source: debug_toolbar.views.login_not_required + type: view_function + login_required: + description: 'Decorator for views that checks that the user is logged in, redirecting + + to the log-in page if necessary.' + source: allauth.socialaccount.views.login_required + type: view_function + logout_then_login: + description: Log out the user if they are logged in. Then redirect to the login + page. + source: django.contrib.auth.views.logout_then_login + type: view_function + method_decorator: + description: Convert a function decorator into a method decorator + source: allauth.socialaccount.providers.google.views.method_decorator + type: view_function + never_cache: + description: Decorator that adds headers to a response so that it will never be + cached. + source: allauth.account.views.never_cache + type: view_function + redirect_to_login: + description: Redirect the user to the login page, passing the given 'next' page. + source: django.contrib.auth.views.redirect_to_login + type: view_function + resolve_url: + description: "Return a URL appropriate for the arguments passed.\n\nThe arguments\ + \ could be:\n\n * A model: the model's `get_absolute_url()` function will\ + \ be called.\n\n * A view name, possibly with arguments: `urls.reverse()`\ + \ will be used\n to reverse-resolve the name.\n\n * A URL, which will\ + \ be returned as-is." + source: django.contrib.auth.views.resolve_url + type: view_function + sensitive_post_parameters: + description: "Indicate which POST parameters used in the decorated view are sensitive,\n\ + so that those parameters can later be treated in a special way, for example\n\ + by hiding them when logging unhandled exceptions.\n\nAccept two forms:\n\n*\ + \ with specified parameters:\n\n @sensitive_post_parameters('password', 'credit_card')\n\ + \ def my_view(request):\n pw = request.POST['password']\n cc\ + \ = request.POST['credit_card']\n ...\n\n* without any specified parameters,\ + \ in which case consider all\n variables are sensitive:\n\n @sensitive_post_parameters()\n\ + \ def my_view(request)\n ..." + source: allauth.account.views.sensitive_post_parameters + type: view_function + update_session_auth_hash: + description: 'Updating a user''s password logs out all sessions for the user. + + + Take the current request and the updated user object from which the new + + session hash will be derived and update the session hash appropriately to + + prevent a password change from logging out the session from which the + + password was changed.' + source: django.contrib.auth.views.update_session_auth_hash + type: view_function + url_has_allowed_host_and_scheme: + description: 'Return ``True`` if the url uses an allowed host and a safe scheme. + + + Always return ``False`` on an empty url. + + + If ``require_https`` is ``True``, only ''https'' will be considered a valid + + scheme, as opposed to ''http'' and ''https'' with the default, ``False``. + + + Note: "True" doesn''t entail that a URL is "safe". It may still be e.g. + + quoted incorrectly. Ensure to also use django.utils.encoding.iri_to_uri() + + on the path component of untrusted URLs.' + source: django.contrib.auth.views.url_has_allowed_host_and_scheme + type: view_function + urlsafe_base64_decode: + description: 'Decode a base64 encoded string. Add back any trailing equal signs + that + + might have been stripped.' + source: appointment.views.urlsafe_base64_decode + type: view_function + urlunsplit: + description: 'Combine the elements of a tuple as returned by urlsplit() into a + + complete URL as a string. The data argument can be any five-item iterable. + + This may result in a slightly different, but equivalent URL, if the URL that + + was parsed originally had unnecessary delimiters (for example, a ? with an + + empty query; the RFC states that these are equivalent).' + source: django.contrib.auth.views.urlunsplit + type: view_function + shortcut: + description: Redirect to an object's page based on a content-type ID and an object + ID. + source: django.contrib.contenttypes.views.shortcut + type: view_function + serve: + description: "Serve static files below a given point in the directory structure\ + \ or\nfrom locations inferred from the staticfiles finders.\n\nTo use, put a\ + \ URL pattern such as::\n\n from django.contrib.staticfiles import views\n\ + \n path('', views.serve)\n\nin your URLconf.\n\nIt uses the django.views.static.serve()\ + \ view to serve the found files." + source: django.contrib.staticfiles.views.serve + type: view_function + BillDeleteView: + description: 'Deletes a specific BillModel instance based on the primary key (pk). + + This view requires the user to be logged in and have the appropriate + + permission to delete a bill. After the delete operation is successful, + + the user is redirected to the bill list view. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param pk: Primary key of the BillModel instance to be deleted. + + :type pk: int + + :return: Redirect to the bill list view after successful deletion. + + :rtype: HttpResponseRedirect' + source: inventory.views.BillDeleteView + type: view_function + CarTransferPreviewView: + description: "Handles the preview of car transfer details and ensures that a user\ + \ has appropriate\npermissions to view the transfer based on their associated\ + \ dealer.\n\nThis view checks if the car transfer's destination dealer matches\ + \ the current user's\nassociated dealer type. If not, the user is redirected\ + \ to the car detail page. Otherwise,\nit renders the transfer preview page with\ + \ the relevant transfer details.\n\n:param request: The HTTP request object\n\ + :type request: django.http.HttpRequest\n:param car_pk: The primary key of the\ + \ car related to the transfer\n:type car_pk: int\n:param transfer_pk: The primary\ + \ key of the car transfer to preview\n:type transfer_pk: int\n:return: An HTTP\ + \ response rendering the transfer preview page or redirecting\n to the\ + \ car detail page\n:rtype: django.http.HttpResponse" + source: inventory.views.CarTransferPreviewView + type: view_function + DealerSettingsView: + description: "Handles dealer settings view where dealers can update their financial\ + \ and\npayment account settings. This view ensures validation and reassigns\ + \ form\nfields dynamically based on the dealer's account roles.\n\n:param request:\ + \ The HTTP request object received from the client. This parameter\n contains\ + \ data including HTTP headers, session, and POST data if applicable.\n:type\ + \ request: HttpRequest\n:param pk: Primary key representing the dealer for whom\ + \ the settings are being\n retrieved or modified. This identifier is used\ + \ to fetch or update dealer-\n specific settings from the database.\n:type\ + \ pk: int\n:return: An HTTP response rendering the dealer settings form or redirecting\n\ + \ to the dealer detail view after successful form submission.\n:rtype: HttpResponse" + source: inventory.views.DealerSettingsView + type: view_function + GroupDeleteview: + description: "Handles the deletion of a specific group instance. This view ensures\ + \ that only\nauthenticated users can perform the deletion. Upon successful deletion,\ + \ a\nsuccess message is displayed, and the user is redirected to the group list\ + \ page.\n\n:param request: The HTTP request object that contains metadata about\ + \ the\n request context and user information. Must be an authenticated user.\n\ + :param pk: The primary key of the group instance to be deleted.\n It specifies\ + \ which group to retrieve and delete.\n:return: The HTTP response that redirects\ + \ the user to the group list page\n after the group is successfully deleted." + source: inventory.views.GroupDeleteview + type: view_function + GroupPermissionView: + description: "Handles the view for adding or modifying permissions of a specific\ + \ group. This view\nfetches the group based on the primary key passed as a parameter,\ + \ and either displays\na form for editing permissions or processes the submitted\ + \ permissions.\n\nIf the request method is POST, the permissions of the group\ + \ are cleared and updated\nbased on the submitted data. A success message is\ + \ displayed upon completion, and\nthe user is redirected to the group's detail\ + \ page.\n\nIn case of a GET request, the view renders the form pre-filled with\ + \ the group's\ncurrent permissions.\n\n:param request: The HTTP request object.\n\ + :type request: HttpRequest\n:param pk: The primary key of the group whose permissions\ + \ are being modified.\n:type pk: int\n:return: The HTTP response depending on\ + \ the request type. For GET requests, renders\n the permission form for the\ + \ specified group. For POST requests, clears and updates\n the group's permissions\ + \ and redirects to the group's detail page.\n:rtype: HttpResponse" + source: inventory.views.GroupPermissionView + type: view_function + JournalEntryDeleteView: + description: "Handles the deletion of a specific journal entry. This view facilitates\n\ + the deletion of a journal entry identified by its primary key (pk). If the\n\ + deletion is successful, the user is redirected to the list of journal entries\n\ + for the associated ledger. If the deletion cannot proceed, an error message\n\ + is displayed, and the user is redirected back to the journal entry list.\n\n\ + :param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key (pk) of the journal entry to be deleted.\n:type pk: int\n\ + :return: A rendered HTML response for GET requests or a redirect upon\n \ + \ successful/failed deletion.\n:rtype: HttpResponse" + source: inventory.views.JournalEntryDeleteView + type: view_function + JournalEntryTransactionsView: + description: "Handles the retrieval and display of journal entry transactions\ + \ for a specific journal\nentry instance. It retrieves the journal entry and\ + \ its associated transactions, ordering\nthe transactions by account code. The\ + \ data is then rendered using the specified template.\n\n:param request: The\ + \ HTTP request object.\n:type request: django.http.HttpRequest\n:param pk: The\ + \ primary key of the journal entry to be retrieved.\n:type pk: int\n:return:\ + \ An HTTP response with the rendered template, including the journal entry and\n\ + \ its transactions.\n:rtype: django.http.HttpResponse" + source: inventory.views.JournalEntryTransactionsView + type: view_function + LeadDeleteView: + description: 'Handles the deletion of a Lead along with its associated customer + and potentially + + a related user account in the system. Ensures proper permissions and login + + are required before the operation is performed. Provides a success message + + after the deletion is complete. + + + :param request: The HTTP request object specific to the current user. + + :param pk: The primary key identifier of the Lead to be deleted. + + :return: An HTTP redirect response to the lead list page.' + source: inventory.views.LeadDeleteView + type: view_function + OrganizationDeleteView: + description: 'Handles the deletion of an organization based on the provided primary + key (pk). Looks up + + the organization and its corresponding user by email, attempts to delete both, + and provides + + appropriate success or error feedback to the user. In case of failure, an error + message is shown, + + while successful deletion redirects to the organization list. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the organization to be deleted. + + :type pk: int + + :return: An HTTP response redirecting to the organization list view. + + :rtype: HttpResponseRedirect' + source: inventory.views.OrganizationDeleteView + type: view_function + PaymentCreateView: + description: "Handles the creation of a payment entry associated with an invoice\ + \ or bill. Validates\nthe payment data against the model's current state and\ + \ reflects the changes in\ninvoice or bill records. Provides appropriate error\ + \ messages for invalid conditions\nsuch as exceeding payable amounts or attempting\ + \ payment for already fully paid models.\n\nIf successfully processed, the payment\ + \ details are saved, and the model is updated\naccordingly. This view regulates\ + \ payment for dealer-associated entities while\nensuring the model consistency.\n\ + \nThe view renders a form to submit payment details, and pre-populates the form\ + \ fields\nwith default data for the associated model if necessary.\n\n:param\ + \ request: The HTTP request object containing user request data and session\n\ + \ information. This is required to handle the request and apply the appropriate\n\ + \ processing rules.\n:param pk: The primary key of the invoice or bill being\ + \ processed. It is used to\n load the appropriate model instance for payment\ + \ processing.\n:return: An HTTP response object. Depending on the circumstances,\ + \ the response may\n redirect to the detail view of the processed invoice\ + \ or bill, re-render the\n payment form with error messages or indicate success\ + \ in payment creation." + source: inventory.views.PaymentCreateView + type: view_function + PaymentDetailView: + description: "This function handles the detail view for a payment by fetching\ + \ a journal entry\nand its associated transactions. It ensures that the request\ + \ is authenticated\nand the user has permission to view the journal entry model.\n\ + \n:param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key of the journal entry for which details are to be fetched.\n\ + :type pk: int\n:return: An HTTP response rendering the payment details template\ + \ with the journal\n entry and its associated transactions.\n:rtype:\ + \ HttpResponse" + source: inventory.views.PaymentDetailView + type: view_function + PaymentListView: + description: 'Handles the view for listing payment information associated with + the journals of a specific + + entity. This view is protected to ensure only authenticated and authorized users + can + + access it. + + + The function retrieves the related dealer object based on the current user session, + extracts + + the associated entity, and fetches all journal entries linked to the entity. + This data is + + then passed into the template for rendering. + + + :param request: The HTTP request object containing user context. + + :type request: HttpRequest + + + :return: The rendered HTML response displaying the list of payments. + + :rtype: HttpResponse' + source: inventory.views.PaymentListView + type: view_function + UserDeleteview: + description: 'Deletes a user and its associated staff member from the database + and redirects + + to the user list page. Displays a success message upon successful deletion + + of the user. + + + :param request: The HTTP request object representing the incoming request. + + :param pk: The primary key (ID) of the staff member to be deleted. + + :return: An HTTP redirect to the user list page.' + source: inventory.views.UserDeleteview + type: view_function + UserGroupView: + description: "Handles the assignment of user groups to a specific staff member.\ + \ This view\nallows updating the groups a staff member belongs to via a form\ + \ submission.\nIt processes both GET and POST requests, ensuring appropriate\ + \ group\nassignments are managed and feedback is provided to the user via messages.\n\ + \n:param request: HttpRequest object representing the HTTP request.\n:type request:\ + \ HttpRequest\n:param pk: Primary key of the staff member whose groups are being\ + \ updated.\n:type pk: int\n\n:return: Renders the user group form for GET requests\ + \ or redirects to the\n user detail page after successful submission for\ + \ POST requests.\n:rtype: HttpResponse or HttpResponseRedirect" + source: inventory.views.UserGroupView + type: view_function + account_delete: + description: 'Handles the deletion of an account object identified by its primary + key (pk). Ensures + + that the user has the necessary permissions to perform the deletion. Successfully + + deletes the account and redirects to the account list view with a success message. + + + :param request: The HTTP request object representing the current user and request + data. + + :type request: HttpRequest + + :param pk: The primary key of the account to be deleted. + + :type pk: int + + :return: An HTTP redirect response to the account list page. + + :rtype: HttpResponse' + source: inventory.views.account_delete + type: view_function + accruable_net_summary: + description: 'A convenience function that computes current net summary of accruable + models. + + "net_30" group indicates the total amount is due in 30 days or less. + + "net_0" group indicates total past due amount. + + + :param queryset: Accruable Objects Queryset. + + :return: A dictionary summarizing current net summary 0,30,60,90,90+ bill open + amounts.' + source: django_ledger.views.accruable_net_summary + type: view_function + add_activity_to_customer: + description: "Adds an activity to a specific customer.\n\nThis function allows\ + \ adding a new activity to a customer identified by their\nprimary key (`pk`).\ + \ It retrieves the customer object, processes the form for\nactivity creation,\ + \ and saves it. If the request method is POST, it validates\nthe form and associates\ + \ the activity with the respective customer. Upon\nsuccessful save, it redirects\ + \ to the customer detail view. If the request\nmethod is GET, it renders a form\ + \ for activity submission.\n\n:param request: The HTTP request object containing\ + \ metadata about the request.\n:type request: HttpRequest\n:param pk: The primary\ + \ key of the customer to which the activity will be added.\n:type pk: int\n\ + :return: An HTTP response rendered with the activity form in the context of\n\ + \ the customer, or a redirect response to the customer detail view upon\n\ + \ successful activity creation.\n:rtype: HttpResponse" + source: inventory.views.add_activity_to_customer + type: view_function + add_activity_to_lead: + description: 'Handles the process of adding a new activity to a specific lead. + This includes + + rendering a form for user input, validating the form submission, and saving + the + + new activity if the input is valid. If the method is GET, it will simply + + render the form. If the method is POST, it checks the form validity, creates + + the activity, associates it with the lead, and saves it to the database. + + + :param request: The HTTP request object containing metadata about the request + made + + :param pk: The primary key of the lead to which the activity is to be added + + :return: An HTTP response that either renders the form or redirects to the lead + detail page' + source: inventory.views.add_activity_to_lead + type: view_function + add_note_to_customer: + description: "This function allows authenticated users to add a note to a specific\ + \ customer. The\nnote creation is handled by a form, which is validated after\ + \ submission. If the form\nis valid, the note is saved and associated with the\ + \ specified customer. On successful\nsubmission, the user is redirected to the\ + \ customer detail page. If the request method\nis not POST, an empty form is\ + \ rendered.\n\n:param request: The HTTP request object containing metadata and\ + \ the method type\n (e.g., GET, POST). Should be an HttpRequest\ + \ instance.\n:param customer_id: The unique identifier (UUID) of the customer\ + \ to whom the note\n is to be added.\n:return: An HTTP response.\ + \ In the case of a successful POST request, the function\n returns a\ + \ redirect response to the customer detail page. For a GET or invalid\n \ + \ POST request, it renders the note form template with context including\n\ + \ the form and customer." + source: inventory.views.add_note_to_customer + type: view_function + add_note_to_lead: + description: "Adds a note to a specific lead. This view is accessible only to\ + \ authenticated\nusers. The function handles the POST request to create a new\ + \ note associated\nwith a lead. Upon successful submission, the note is linked\ + \ to the provided lead,\nand the user is redirected to the lead's detail page.\ + \ If the request method is\nnot POST, it initializes an empty form to add a\ + \ note.\n\n:param request: The HTTP request object\n:type request: HttpRequest\n\ + :param pk: The primary key of the lead to which the note will be added\n:type\ + \ pk: int\n:return: HTTP response object. Redirects to the lead detail page\ + \ on successful\n note creation or renders the note form template for GET\ + \ or invalid POST requests.\n:rtype: HttpResponse" + source: inventory.views.add_note_to_lead + type: view_function + add_note_to_opportunity: + description: 'Add a note to a specific opportunity identified by its primary key. + + + This function handles the addition of a note to an existing opportunity + + by processing a POST request that includes the note content. If the note + + content is missing, an error message will be displayed. If the operation + + is successful, the note is saved, and a success message is returned. + + + :param request: The HTTP request object representing the client''s request. + + :param pk: The primary key of the Opportunity to which the note is to be added. + + :type pk: int + + :return: A redirect response to the detailed view of the opportunity.' + source: inventory.views.add_note_to_opportunity + type: view_function + apply_search_filters: + description: "Apply search filters to a queryset based on a query string.\n\n\ + This function filters the provided queryset by applying a Q object for all\n\ + CharField, TextField, or EmailField fields in the model. It checks if the\n\ + query exists within these fields using case-insensitive containment (icontains).\n\ + If the query string is empty or None, the original queryset is returned\nwithout\ + \ any modifications.\n\n:param queryset: The initial queryset to apply the search\ + \ filters on.\n:param query: The search string to match against the model fields.\ + \ If None\n or an empty string, no filtering is applied.\n:return: A filtered\ + \ queryset that satisfies the search condition." + source: inventory.views.apply_search_filters + type: view_function + assign_car_makes: + description: "Assigns car makes to a dealer.\n\nThis function handles both the\ + \ display and processing of a form that allows\na dealer to assign or modify\ + \ their associated car makes. If the request\nmethod is POST, it validates and\ + \ saves the submitted form data. If the\nmethod is not POST, it displays a form\ + \ prefilled with the existing car makes\nassociated with the dealer.\n\n:param\ + \ request: The HTTP request object containing information about the\n current\ + \ request.\n:type request: HttpRequest\n:return: A rendered HTML response for\ + \ GET requests, or a redirect to the\n dealer detail page after successful\ + \ form submission.\n:rtype: HttpResponse" + source: inventory.views.assign_car_makes + type: view_function + bank_account_delete: + description: "Delete a bank account entry from the database.\n\nThis view handles\ + \ the deletion of a bank account record specified by its\nprimary key (pk).\ + \ It renders a deletion confirmation page and processes the\ndeletion if the\ + \ request method is POST. Upon successful deletion, the user is\nredirected\ + \ to the list of bank accounts and a success message is displayed.\n\n:param\ + \ request: The HTTP request object representing the client's request.\n It\ + \ contains data such as request type (GET or POST) and session\n information.\n\ + :type request: HttpRequest\n:param pk: The primary key of the bank account model\ + \ instance to be deleted.\n:type pk: int\n:return: Returns an HttpResponse object.\ + \ This can be an HTTP redirect to the\n bank account list page upon successful\ + \ deletion, or an HTML response\n rendering the confirmation template if\ + \ accessed via GET.\n:rtype: HttpResponse" + source: inventory.views.bank_account_delete + type: view_function + bill_create: + description: "Handles creation of a bill in the system, including the validation\ + \ of input data,\ncreation of transactions associated with the bill, and rendering\ + \ of the appropriate\nresponse or form. Ensures the user creating the bill has\ + \ the necessary permissions and\ncorrect input parameters for successful bill\ + \ creation and itemization.\n\n:param request: Django HttpRequest object containing\ + \ metadata and data of the HTTP request.\n:type request: HttpRequest\n:return:\ + \ JsonResponse with success/error information if the request is processed,\n\ + \ or HttpResponse rendering the form for bill creation.\n:rtype: JsonResponse\ + \ or HttpResponse" + source: inventory.views.bill_create + type: view_function + bill_mark_as_approved: + description: "Marks a bill as approved for the given bill ID (primary key) if\ + \ it is not\nalready approved. This action can only be completed by an authorized\ + \ user\nwith the corresponding permissions. Once the bill is approved, it is\ + \ saved\nand a success message is displayed. If the bill is already approved,\ + \ an\nerror message is shown instead.\n\n:param request: HttpRequest object\ + \ representing the current request.\n:param pk: Primary key of the bill to be\ + \ marked as approved.\n:return: HttpResponseRedirect to the bill detail page\ + \ after the operation is\n completed or an error/success message is\ + \ set." + source: inventory.views.bill_mark_as_approved + type: view_function + bill_mark_as_paid: + description: 'Marks a bill as paid if certain conditions are met and updates the + ledger accordingly. + + + This function is used to mark a specific bill as paid. It verifies whether the + bill + + is already paid or if the amount paid matches the amount due. If the conditions + are + + met, it updates the bill''s status, locks the journal entries in the associated + ledger, + + posts them, and saves the changes. Appropriate success or error messages are + displayed + + to the user, and the user is redirected to the bill details page. + + + :param request: The HTTP request object containing details about the request + made by the user. + + :type request: HttpRequest + + :param pk: The primary key of the bill to be marked as paid. + + :type pk: int + + :return: A redirect response to the bill details page. + + :rtype: HttpResponseRedirect' + source: inventory.views.bill_mark_as_paid + type: view_function + car_history: + description: "Fetch and display the history of activities related to a specific\ + \ car.\n\nThis view retrieves a car object based on its primary key (pk) and\ + \ gathers\nall related activity records where the content type corresponds to\ + \ the car\nmodel. The retrieved data is then rendered into a specified HTML\ + \ template\nfor presentation.\n\n:param request: The HTTP request object that\ + \ contains metadata about the\n request made by the client.\n:type request:\ + \ HttpRequest\n:param pk: The primary key of the car object to retrieve.\n:type\ + \ pk: int\n:return: An HTTP response with the rendered car history HTML template,\n\ + \ including the car and its associated activities as context data.\n:rtype:\ + \ HttpResponse" + source: inventory.views.car_history + type: view_function + car_transfer_accept_reject: + description: "Handles the acceptance or rejection of a car transfer request. Based\ + \ on the\n`status` parameter obtained from the query string, the function updates\ + \ the\ntransfer status to either 'accept' or 'reject'. If the transfer is accepted,\ + \ it\ninitiates the car transfer process. Appropriate notifications are sent,\ + \ and\nactivity records are created for both acceptance and rejection actions.\n\ + \n:param request: The HTTP request object which contains metadata about\n \ + \ the request made by the user, including session and user information.\n:param\ + \ car_pk: The primary key of the car to be transferred.\n:param transfer_pk:\ + \ The primary key of the car transfer request to be processed.\n:return: An\ + \ HTTP redirect response to the 'inventory_stats' view." + source: inventory.views.car_transfer_accept_reject + type: view_function + car_transfer_approve: + description: 'Approves or cancels a car transfer request based on the action parameter. + This view + + handles the workflow of updating the transfer status and notifying the involved + parties + + accordingly. If the transfer is canceled, it reverts the car status to "available" + and + + deactivates the transfer record. If approved, it notifies the recipient dealer + and allows + + the request to proceed for further actions. + + + :param request: The HTTP request object containing metadata and the action parameter. + + :param car_pk: Primary key of the car involved in the transfer. + + :param transfer_pk: Primary key of the transfer request to approve or cancel. + + :return: An HTTP response redirecting to the car detail page of the specified + car.' + source: inventory.views.car_transfer_approve + type: view_function + create_estimate: + description: "Creates a new estimate based on the provided data and saves it.\ + \ This function processes\na POST request and expects a JSON payload containing\ + \ details of the estimate such as\ntitle, customer, terms, items, and quantities.\ + \ It validates the input data, ensures\navailability of stocks, and updates\ + \ or creates the corresponding estimate in the database.\n\nIf `pk` is provided,\ + \ it links the created estimate with an existing opportunity. It handles\nthe\ + \ reservation of cars and updates the stock information accordingly.\n\n:param\ + \ request: The HttpRequest object containing user-specific data and state.\n\ + :type request: HttpRequest\n:param pk: An optional primary key of the existing\ + \ opportunity to associate with\n the created estimate.\n:type pk:\ + \ int, optional\n:return: A JsonResponse object with status and either the created\ + \ quotation URL\n or an error message. If the request method is not\ + \ POST, it renders the\n estimate creation form.\n:rtype: JsonResponse\ + \ or HttpResponse" + source: inventory.views.create_estimate + type: view_function + create_sale_order: + description: "Creates a sale order for a given estimate and updates associated\ + \ item and car data.\n\nThis view is responsible for handling the submission\ + \ of a sale order form linked to\na specific estimate. It ensures that the estimate\ + \ is approved if not already, updates\nthe status of the related car items as\ + \ sold, and redirects to the estimate's detailed\nview upon successful creation\ + \ of the sale order. If the request method is not POST, it\nrenders the form\ + \ for the user to input sale order details, along with other contextual\ninformation\ + \ like estimate data and car finance details.\n\n:param request: HTTP request\ + \ object.\n:type request: HttpRequest\n:param pk: Primary key of the estimate\ + \ to create a sale order for.\n:type pk: int\n:return: An HTTP response rendering\ + \ the sale order form if the method is GET or invalid\n POST data, or redirects\ + \ to the estimate detail view upon successful creation.\n:rtype: HttpResponse" + source: inventory.views.create_sale_order + type: view_function + csrf_exempt: + description: Mark a view function as being exempt from the CSRF view protection. + source: rest_framework.views.csrf_exempt + type: view_function + custom_bad_request_view: + description: 'Handles custom bad request responses by rendering a specified HTML + + template for 400 status errors. + + + :return: Rendered HTTP response rendering the error page. + + :rtype: HttpResponse' + source: inventory.views.custom_bad_request_view + type: view_function + custom_error_view: + description: 'Handles rendering the custom error page for HTTP 500 errors. + + + This function is called when an unhandled exception occurs in the application. + It renders + + a predefined template for server errors, providing a consistent error page layout + + to the users. + + + :param request: The HTTP request instance which triggered the error. + + :type request: HttpRequest + + :param exception: The exception that caused the error to trigger. Defaults to + None. + + :type exception: Exception, optional + + :return: An HttpResponse object representing the rendered error page. + + :rtype: HttpResponse' + source: inventory.views.custom_error_view + type: view_function + custom_page_not_found_view: + description: 'Custom handler for 404 errors that renders a custom HTML page + + upon encountering a Page Not Found error. + + + :param request: The HttpRequest object associated with the request. + + :type request: HttpRequest + + :param exception: The exception that triggered the 404 error, if any. + + :type exception: Exception, optional + + :return: An HttpResponse object rendering the "errors/404.html" template. + + :rtype: HttpResponse' + source: inventory.views.custom_page_not_found_view + type: view_function + custom_permission_denied_view: + description: "Handles the custom view for 403 Forbidden permission denied errors.\ + \ This\nfunction renders a custom template for the error page when users are\ + \ denied\npermission to access a particular resource or view.\n\n:param request:\ + \ Django HttpRequest object containing metadata about the request.\n:type request:\ + \ HttpRequest\n:param exception: Optional exception that caused the 403 error.\n\ + \ Defaults to None.\n:type exception: Exception | None\n:return:\ + \ HttpResponse object rendering the 403.html error page.\n:rtype: HttpResponse" + source: inventory.views.custom_permission_denied_view + type: view_function + dealer_signup: + description: "Handles the dealer signup wizard process, including forms validation,\ + \ user and group\ncreation, permissions assignment, and dealer data storage.\ + \ This view supports GET\nrequests for rendering the signup wizard page, and\ + \ POST requests for processing\nsubmitted data. The function also differentiates\ + \ between requests sent with the\n\"Hx-Request\" header for partial form validations\ + \ in the wizard.\n\n:param request: The HTTP request object representing the\ + \ client request. It contains\n metadata about the request and the POST data\ + \ for creating the dealer.\n:type request: django.http.HttpRequest\n:param args:\ + \ Optional positional arguments passed to the view during the call.\n:type args:\ + \ tuple\n:param kwargs: Optional keyword arguments passed to the view during\ + \ the call.\n:type kwargs: dict\n:return: A rendered signup wizard page or a\ + \ JSON response indicating operation success\n or failure.\n:rtype: Union[django.http.HttpResponse,\ + \ django.http.JsonResponse]" + source: inventory.views.dealer_signup + type: view_function + decode: + description: "Decodes datamatrix barcodes in `image`.\n\nArgs:\n image: `numpy.ndarray`,\ + \ `PIL.Image` or tuple (pixels, width, height)\n symbols: iter(ZBarSymbol)\ + \ the symbol types to decode; if `None`, uses\n `zbar`'s default behaviour,\ + \ which is to decode all symbol types.\n\nReturns:\n :obj:`list` of :obj:`Decoded`:\ + \ The values decoded from barcodes." + source: inventory.views.decode + type: view_function + decodevin: + description: "Decodes a Vehicle Identification Number (VIN) using multiple decoding\ + \ functions\nand returns the decoded result. This function attempts to decode\ + \ the VIN using\nthree different functions in sequence and returns the first\ + \ successful result.\nIf none of the decoding functions produce a valid result,\ + \ the function returns None.\n\n:param vin: The Vehicle Identification Number\ + \ (VIN) to be decoded.\n:type vin: str\n:return: The decoded result if any decoding\ + \ function is successful, or None if\n all decoding attempts fail.\n\ + :rtype: dict | None" + source: api.views.decodevin + type: view_function + delete_customer: + description: 'Deletes a customer from the system and deactivates the corresponding + user account. + + + This function retrieves a customer object based on the primary key (pk), + + sets their active status to False, and deactivates the linked user account + + (using the email associated with the customer). After saving these changes, + + it displays a success message to the user and redirects to the customer list + page. + + + :param request: A HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: Primary key of the customer to be deleted. + + :type pk: int + + :return: A redirect response to the customer list page. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_customer + type: view_function + delete_note: + description: 'Deletes a specific note created by the currently logged-in user + and redirects + + to the lead detail page. If the note does not exist or the user is not the creator, + + a 404 error will be raised. A success message is displayed upon successful deletion + + of the note. + + + :param request: The HTTP request object associated with the current request. + + :type request: HttpRequest + + :param pk: The primary key of the note to be deleted. + + :type pk: int + + :return: An HTTP redirection to the lead detail page of the corresponding note''s + lead. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_note + type: view_function + delete_opportunity: + description: 'Deletes an opportunity object from the database and redirects to + the opportunity + + list view. If the opportunity with the specified primary key is not found, a + 404 + + error will be raised. Displays a success message after deletion. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the opportunity object to be deleted. + + :type pk: int + + :return: An HTTP response redirecting to the opportunity list view. + + :rtype: HttpResponse' + source: inventory.views.delete_opportunity + type: view_function + delete_vendor: + description: 'Deletes an existing vendor record from the database. + + + This function allows users with valid authentication to delete a specified + + vendor object by its primary key. Upon successful deletion, a success message + + is displayed, and the user is redirected to the vendor list page. + + + :param request: HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: Primary key of the vendor object to be deleted. + + :type pk: int + + :return: HttpResponseRedirect object for redirecting to the vendor list page. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_vendor + type: view_function + estimate_mark_as: + description: 'Marks an estimate with a specified status based on the requested + action and + + permissions. The marking possibilities include review, approval, rejection, + + completion, and cancellation. The function validates whether the estimate + + can transition to the desired status before updating it. It also handles + + notifications and updates related entities if required, such as car status + + changes upon cancellation. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the estimate to be marked. + + :type pk: int + + :return: A redirect response to the estimate detail view. + + :rtype: HttpResponseRedirect' + source: inventory.views.estimate_mark_as + type: view_function + get_car_finance_data: + description: "Fetches car finance data from the provided model instance and calculates\n\ + various related details including total prices, VAT, discounts, and\nadditional\ + \ services information.\n\n:param model: The model instance that contains car\ + \ and finance-related\n transaction data.\n:type model: Model\n:return: A\ + \ dictionary containing detailed information about the car finance\n transactions,\ + \ including individual car details, total quantity, calculated\n totals for\ + \ prices, VAT, discounts, additional services, and the VAT rate.\n:rtype: dict" + source: inventory.views.get_car_finance_data + type: view_function + get_item_transactions: + description: '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' + source: inventory.views.get_item_transactions + type: view_function + get_localdate: + description: "Fetches the current local date, optionally considering time zone\ + \ settings.\n\nThis function retrieves the current local date. If the global\ + \ settings indicate\nthe use of time zones (`USE_TZ` is True), the date is determined\ + \ based on the\nlocal time zone. Otherwise, the date is based on the system's\ + \ local time without\nany time zone consideration.\n\nReturns\n-------\ndate\n\ + \ The current local date, adjusted for the time zone setting if applicable." + source: django_ledger.views.get_localdate + type: view_function + get_make: + description: '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' + source: inventory.views.get_make + type: view_function + get_model: + description: "Searches for a car model associated with a specific make by performing\ + \ an\nexact case-insensitive match. If no match is found, it attempts to match\n\ + based on individual words split from the input item.\n\n:param item: A string\ + \ representing the name of the car model to search for.\n:param make: An object\ + \ representing the car manufacturer, which contains the\n associated car\ + \ models.\n:return: Returns the first car model object that matches the search\ + \ criteria,\n or None if no match is found." + source: inventory.views.get_model + type: view_function + get_object_or_404: + description: 'Use get() to return an object, or raise an Http404 exception if + the object + + does not exist. + + + klass may be a Model, Manager, or QuerySet object. All other passed + + arguments and keyword arguments are used in the get() query. + + + Like with QuerySet.get(), MultipleObjectsReturned is raised if more than + + one object is found.' + source: plans.views.get_object_or_404 + type: view_function + get_user_type: + description: "Determine the type of user based on the given request object.\n\n\ + This function identifies the type of user from the provided request. It\nchecks\ + \ if the user is a dealer, staff member, or neither based on the\nattributes\ + \ of the request object, returning the appropriate associated\nuser type or\ + \ `None` if the determination cannot be made.\n\n:param request: The HTTP request\ + \ object containing user and role\n information.\n:type request: Any\n:return:\ + \ A dealer object if the user is a dealer, a dealer object\n associated with\ + \ the staff member if the user is a staff member, or\n None if the user type\ + \ cannot be identified.\n:rtype: Optional[Any]" + source: api.views.get_user_type + type: view_function + inventory_stats_view: + description: "Handle the inventory stats view for a dealer, displaying detailed\ + \ information\nabout the cars, including counts grouped by make, model, and\ + \ trim.\n\nThe function fetches all cars associated with the authenticated dealer,\ + \ calculates\nthe inventory statistics (e.g., total cars, reserved cars, and\ + \ cars categorized\nby make, model, and trim levels), and prepares the data\ + \ to be rendered in a\ntemplate.\n\n:param request: The HTTP request object\ + \ from the client.\n:type request: HttpRequest\n:return: An HTTP response containing\ + \ structured inventory data rendered in the\n \"inventory/inventory_stats.html\"\ + \ template.\n:rtype: HttpResponse" + source: inventory.views.inventory_stats_view + type: view_function + invoice_create: + description: "Handles the creation of a new invoice associated with a given estimate.\ + \ It validates\nthe submitted data through a form, processes the invoice, updates\ + \ related models, and\nfinalizes the estimate. If successful, redirects to the\ + \ detailed view of the created\ninvoice. If the submitted data is invalid or\ + \ the request is not a POST request, renders\nthe invoice creation form.\n\n\ + :param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key of the estimate associated with the invoice.\n:type pk:\ + \ int\n:return: An HTTP response. Redirects to the \"invoice_detail\" view upon\ + \ successful invoice\n creation or renders the invoice creation form template\ + \ otherwise.\n:rtype: HttpResponse" + source: inventory.views.invoice_create + type: view_function + invoice_mark_as: + description: 'Marks an invoice as approved if it meets the required conditions. + + + This view is responsible for marking an invoice as approved based on the provided + + `mark` parameter. If the `mark` parameter is specified as "accept" and the invoice + + is eligible for approval, it gets approved and saved. Otherwise, an error message + + is displayed. The function requires the user to be logged in and to have the + + appropriate permission to change the InvoiceModel. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: django.http.HttpRequest + + :param pk: The primary key of the invoice to be processed. + + :type pk: int + + :return: An HTTP redirect response to the invoice detail page after processing. + + :rtype: django.http.HttpResponse' + source: inventory.views.invoice_mark_as + type: view_function + lead_convert: + description: 'Converts a lead into a customer and creates a corresponding opportunity. + + + The function ensures that leads are not converted to customers more than once. + + If the lead has already been converted, an error is displayed. Otherwise, + + the lead is converted into a customer and a new opportunity is created. + + Upon successful conversion, the user is redirected to the lead list view + + and a success message is displayed. + + + :param request: The HTTP request object representing the user''s request. + + :type request: HttpRequest + + :param pk: The primary key of the lead to be converted. + + :type pk: int + + :return: An HTTP response redirecting to the lead list view. + + :rtype: HttpResponse' + source: inventory.views.lead_convert + type: view_function + lead_create: + description: 'Handles the creation of a new lead in the inventory system. + + + This function manages the rendering and processing of a form for creating a + new + + lead. It filters options for car models in the form based on the selected car + + make. For POST requests, it validates and processes the submitted form data + + and creates the lead if valid. It also creates a corresponding customer in the + + ledger system if one does not exist for the provided email. + + + :param request: The HTTP request object containing request data. + + :type request: HttpRequest + + + :return: An HTTP response object rendering the lead creation form or redirecting + to the lead list page upon success. + + :rtype: HttpResponse' + source: inventory.views.lead_create + type: view_function + lead_transfer: + description: 'Handles the transfer of a lead to a different staff member. This + view is accessible + + only to authenticated users with the ''inventory.change_lead'' permission. If + the + + request method is POST and the form data is valid, the lead''s staff is updated + + accordingly, saved, and a success message is displayed. Otherwise, an error + message + + is shown. In both cases, the user is redirected to the lead listing page. + + + :param request: The HTTP request object. + + :param pk: The primary key of the lead to be transferred. + + :return: An HTTP redirect response to the lead list view.' + source: inventory.views.lead_transfer + type: view_function + ledger_lock_all_journals: + description: 'Locks all journals associated with a specific ledger. If the ledger + is already locked, + + it will notify the user through an error message. Otherwise, it initiates the + locking of + + related journal entries, locks the ledger itself, and saves the changes to the + database. + + After the operation, it redirects the user to the journal entry list associated + with the + + ledger. + + + :param request: HttpRequest object representing the current request. + + :type request: HttpRequest + + :param entity_slug: The slug identifier of the entity. + + :type entity_slug: str + + :param pk: The primary key of the ledger to be locked. + + :type pk: int + + :return: HttpResponse redirecting to the journal entry list page of the locked + ledger. + + :rtype: HttpResponse' + source: inventory.views.ledger_lock_all_journals + type: view_function + ledger_post_all_journals: + description: 'Posts all journal entries associated with a ledger. This function + updates the ledger''s + + state to reflect that its journal entries have been posted. If the ledger is + already + + posted, an error message is displayed and the user is redirected. + + + :param request: The HTTP request object used for processing the action. + + :type request: HttpRequest + + :param entity_slug: A string representing the specific entity slug for the ledger + context. + + :type entity_slug: str + + :param pk: The primary key of the ledger to be posted. + + :type pk: int + + :return: A redirect to the journal entry list view for the specified ledger. + + :rtype: HttpResponseRedirect' + source: inventory.views.ledger_post_all_journals + type: view_function + ledger_unlock_all_journals: + description: 'Unlocks all journal entries associated with a specific ledger. This + function first checks if the + + ledger is locked. If it is already unlocked, it shows an error message and redirects + the user + + to the journal entry list page. If the ledger is locked, it unlocks the ledger, + saves changes, + + and iterates through all the locked journal entries within the ledger to unlock + them as well. + + Afterward, it redirects the user to the journal entry list page. + + + :param request: The HTTP request object containing user session and request + metadata. + + :type request: HttpRequest + + :param entity_slug: A unique string slug representing the specific entity or + organization context. + + :type entity_slug: str + + :param pk: The primary key of the ledger record to be unlocked. + + :type pk: int + + :return: A redirection to the journal entry list page for the specified ledger. + + :rtype: HttpResponseRedirect' + source: inventory.views.ledger_unlock_all_journals + type: view_function + ledger_unpost_all_journals: + description: "Unposts all journal entries for a specified ledger and marks the\ + \ ledger as unposted.\n\nThis function identifies a ledger by its primary key\ + \ (pk) and checks if it is\nalready posted. If the ledger is not posted, an\ + \ error message is displayed.\nIf it is posted, the function iterates through\ + \ its posted journal entries,\nmarks them as unposted, and saves the changes.\ + \ Finally, it marks the ledger itself\nas unposted and saves it.\n\n:param request:\ + \ The HTTP request object from the client.\n:type request: HttpRequest\n:param\ + \ entity_slug: A slug identifying the entity associated with the ledger.\n:type\ + \ entity_slug: str\n:param pk: The primary key of the ledger whose journal entries\ + \ are being unposted.\n:type pk: int\n:return: An HTTP redirect response object\ + \ directing the client to the journal entry list\n page for the specified\ + \ ledger.\n:rtype: HttpResponseRedirect" + source: inventory.views.ledger_unpost_all_journals + type: view_function + manage_reservation: + description: "Handles the management of a car reservation, providing options to\ + \ renew or\ncancel an existing reservation associated with the logged-in user.\n\ + \nRenewing a reservation extends the reservation period by an additional\n24\ + \ hours. Canceling a reservation deletes it and updates the car's status\nto\ + \ AVAILABLE. All actions require a valid reservation and are performed\nbased\ + \ on the current user's authentication and request type.\n\n:param request:\ + \ Django HttpRequest object representing the client's request.\n:type request:\ + \ HttpRequest\n:param reservation_id: The unique identifier of the car reservation\ + \ to manage.\n:type reservation_id: int\n:return: On POST requests, returns\ + \ an HTTP redirect or JSON response\n based on the action performed. On other\ + \ request methods,\n returns a JSON response with an error message.\n:rtype:\ + \ JsonResponse or HttpResponseRedirect" + source: inventory.views.manage_reservation + type: view_function + opportunity_update_status: + description: "Update the status and/or stage of a specific Opportunity instance.\ + \ This is a\nview function, which is generally tied to a URL endpoint in a Django\ + \ application.\nThe function is accessible only to authenticated users due to\ + \ the\n`@login_required` decorator.\n\nThe function retrieves the `Opportunity`\ + \ instance based on the primary key\nin the URL, updates the status or stage\ + \ of the instance based on query\nparameters in the request, saves the changes,\ + \ and then redirects to the\ndetail view of the `Opportunity`. Additionally,\ + \ a success message is displayed,\nand a custom header (`HX-Refresh`) is added\ + \ to the response.\n\n:param request: The HTTP request object containing details\ + \ of the user's\n request, such as query parameters for status and stage.\ + \ This is a\n mandatory parameter provided by Django's view function framework.\n\ + :type request: HttpRequest\n:param pk: The primary key of the `Opportunity`\ + \ instance to be updated.\n:type pk: int\n\n:return: An HTTP response object\ + \ that redirects to the updated Opportunity's\n detail page, with a success\ + \ message and the \"HX-Refresh\" header to trigger\n frontend behavior.\n\ + :rtype: HttpResponse" + source: inventory.views.opportunity_update_status + type: view_function + payment_mark_as_paid: + description: "Marks an invoice as paid if it meets the conditions of being fully\ + \ paid and eligible\nfor payment. Also ensures that related ledger journal entries\ + \ are locked and posted\nwhen the payment is marked successfully.\n\nThis function\ + \ is protected with both `login_required` and\n`permission_required` decorators,\ + \ ensuring that only logged-in users with\nappropriate permissions can execute\ + \ it.\n\n:param request: HttpRequest object containing metadata about the request.\n\ + :type request: HttpRequest\n:param pk: Primary key of the invoice to mark as\ + \ paid.\n:type pk: int\n:return: Redirect response to the invoice detail page.\n\ + :rtype: HttpResponseRedirect\n:raises: In case of an exception during the process,\ + \ an error message is\n displayed to the user through Django's messaging\ + \ framework." + source: inventory.views.payment_mark_as_paid + type: view_function + permission_required: + description: 'Decorator for views that checks whether a user has a particular + permission + + enabled, redirecting to the log-in page if necessary. + + If the raise_exception parameter is given the PermissionDenied exception + + is raised.' + source: inventory.views.permission_required + type: view_function + preview_sale_order: + description: 'Handles rendering of the sale order preview page for a specific + estimate. + + + This view retrieves an `EstimateModel` object based on the provided primary + + key (`pk`), fetches related car finance data, and renders the preview of the + + sale order associated with the given estimate. + + + :param request: The HTTP request object + + :type request: HttpRequest + + :param pk: The primary key of the `EstimateModel` to retrieve + + :type pk: int + + :return: HTTP response containing the rendered sale order preview page + + :rtype: HttpResponse' + source: inventory.views.preview_sale_order + type: view_function + redirect: + description: "Return an HttpResponseRedirect to the appropriate URL for the arguments\n\ + passed.\n\nThe arguments could be:\n\n * A model: the model's `get_absolute_url()`\ + \ function will be called.\n\n * A view name, possibly with arguments: `urls.reverse()`\ + \ will be used\n to reverse-resolve the name.\n\n * A URL, which will\ + \ be used as-is for the redirect location.\n\nIssues a temporary redirect by\ + \ default. Set permanent=True to issue a\npermanent redirect. Set preserve_request=True\ + \ to instruct the user agent\nto preserve the original HTTP method and body\ + \ when following the redirect." + source: appointment.views.redirect + type: view_function + render: + description: 'Return an HttpResponse whose content is filled with the result of + calling + + django.template.loader.render_to_string() with the passed arguments.' + source: django_pdf_actions.views.render + type: view_function + reserve_car: + description: '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.' + source: inventory.views.reserve_car + type: view_function + reserve_car_view: + description: 'Handles car reservation requests. This view requires the user to + be logged in + + and processes only POST requests. When invoked, it checks if the specified car + + is already reserved. If not, it proceeds to reserve the car for the user and + + sends an appropriate response. If the car is already reserved or if the request + + method is invalid, it provides corresponding error messages or responses. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param car_id: The unique identifier of the car to be reserved. + + :type car_id: int + + :return: A response indicating the result of the reservation process. + + :rtype: HttpResponse or JsonResponse' + source: inventory.views.reserve_car_view + type: view_function + sales_list_view: + description: "Handles the retrieval and presentation of a paginated list of item\ + \ transactions for\nsales, specific to the logged-in user's entity. Requires\ + \ the user to have appropriate\npermissions to view the list.\n\n:param request:\ + \ The HTTP request object containing metadata about the request,\n such as\ + \ HTTP method, user credentials, and sent data.\n:type request: HttpRequest\n\ + \n:return: An HTTP response with the rendered sales list page containing the\ + \ paginated\n item transactions specific to the user's entity.\n:rtype: HttpResponse" + source: inventory.views.sales_list_view + type: view_function + schedule_cancel: + description: 'Cancel a schedule by updating its status to "Canceled". The function + is protected + + by a login requirement, ensuring only authenticated users can execute it. It + + retrieves the schedule object by its primary key, updates its status, saves + the + + changes, and returns an HTTP response with status code 200. + + + :param request: The HTTP request object representing the user''s request. + + :type request: HttpRequest + + :param pk: The primary key of the schedule to be canceled. + + :type pk: int + + :return: An HTTP response object with a 200 status code upon successful execution. + + :rtype: HttpResponse' + source: inventory.views.schedule_cancel + type: view_function + schedule_lead: + description: "Handles the scheduling of a lead for an appointment.\n\nThis function\ + \ ensures that only staff members with the appropriate permissions\ncan schedule\ + \ leads. If the user is not a staff member or does not have the\nrequired inventory\ + \ permissions, they are redirected with an appropriate error\nmessage. The function\ + \ creates an appointment request and an associated appointment\nrecord upon\ + \ successful submission of the scheduling form.\n\n:param request: The HTTP\ + \ request object containing metadata about the request.\n:type request: HttpRequest\n\ + :param pk: The primary key of the lead to be scheduled.\n:type pk: int\n:return:\ + \ A rendered template or a redirection to another view based on the request\n\ + \ method and validity of the form submission.\n:rtype: HttpResponse" + source: inventory.views.schedule_lead + type: view_function + send_email_view: + description: 'View function to send an email for an estimate. This function allows + authenticated and + + authorized users to send an email containing the estimate details to the customer. + + The email includes a link to preview the estimate and a message template in + multiple + + languages. If the estimate does not have any associated items, the user will + receive + + an error message. Upon successfully sending the email, the estimate is marked + as reviewed. + + + :param request: The HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the estimate to be sent via email. + + :type pk: int + + :return: An HttpResponseRedirect to the estimate detail view. + + :rtype: HttpResponseRedirect + + :raises Http404: If the estimate with the given primary key does not exist.' + source: inventory.views.send_email_view + type: view_function + send_lead_email: + description: "Handles sending emails related to a lead. Supports creating drafts,\ + \ sending emails, and rendering\nan email composition page. Changes on the lead\ + \ or email objects, such as marking a lead as contacted\nor an email as sent,\ + \ are recorded in associated activity logs.\n\n:param request: The HTTP request\ + \ object. This contains user information, method type, and data such as\n \ + \ GET or POST payload used to draft or send the email appropriately.\n\ + \ Type: HttpRequest\n:param pk: The primary key of the lead to\ + \ which the email action is associated. It's used to retrieve\n the\ + \ lead object from the database.\n Type: int\n:param email_pk: Optional\ + \ parameter representing the primary key of an email template. When provided,\n\ + \ the respective email content is pre-populated into the email\ + \ composition form.\n Defaults to None.\n Type:\ + \ Optional[int]\n:return: When successfully sending an email, redirects the\ + \ user to the lead list page. On draft mode\n or email composition rendering,\ + \ a response object is returned to render the respective page.\n Type:\ + \ HttpResponse" + source: inventory.views.send_lead_email + type: view_function + set_bill_payment: + description: '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' + source: inventory.views.set_bill_payment + type: view_function + set_invoice_payment: + description: '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' + source: inventory.views.set_invoice_payment + type: view_function + switch_language: + description: "Switches the current language context for the user based on a request\ + \ parameter, modifies the URL path\naccordingly, and updates session and cookies\ + \ with the new language preference.\n\n:param request: The HTTP request object\ + \ containing information about the user request, including\n \ + \ the desired language to switch to and the referring URL.\n \ + \ - \"GET\" dictionary is accessed to retrieve the desired language parameter.\n\ + \ - \"META\" dictionary is used to extract the referring URL\ + \ via \"HTTP_REFERER\".\n\n:return: A redirect response object pointing to the\ + \ modified URL with the updated language\n preference, if the requested\ + \ language is valid. Otherwise, redirects to the default URL." + source: inventory.views.switch_language + type: view_function + urlparse: + description: 'Parse a URL into 6 components: + + :///;?# + + + The result is a named 6-tuple with fields corresponding to the + + above. It is either a ParseResult or ParseResultBytes object, + + depending on the type of the url parameter. + + + The username, password, hostname, and port sub-components of netloc + + can also be accessed as attributes of the returned object. + + + The scheme argument provides the default value of the scheme + + component when no scheme is found in url. + + + If allow_fragments is False, no attempt is made to separate the + + fragment component from the previous component, which can be either + + path or query. + + + Note that % escapes are not expanded.' + source: inventory.views.urlparse + type: view_function + urlunparse: + description: 'Put a parsed URL back together again. This may result in a + + slightly different, but equivalent URL, if the URL that was parsed + + originally had redundant delimiters, e.g. a ? with an empty query + + (the draft states that these are equivalent).' + source: inventory.views.urlunparse + type: view_function + vendorDetailView: + description: 'Fetches and renders the detail view for a specific vendor. + + + This function retrieves a vendor object based on the primary key (pk) + + provided in the URL, ensures the user is logged in to access the + + view, and renders the vendor detail template with the vendor''s context. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param pk: The primary key of the vendor to retrieve. + + :type pk: int + + :return: An HttpResponse object containing the rendered vendor detail page. + + :rtype: HttpResponse' + source: inventory.views.vendorDetailView + type: view_function + sync_user_email_addresses: + description: 'Keep user.email in sync with user.emailaddress_set. + + + Under some circumstances the user.email may not have ended up as + + an EmailAddress record, e.g. in the case of manually created admin + + users.' + source: allauth.account.views.sync_user_email_addresses + type: view_function + escape: + description: 'Return the given text with ampersands, quotes and angle brackets + encoded + + for use in HTML. + + + Always escape input, even if it''s already escaped and marked as such. + + This may result in double-escaping. If this is a concern, use + + conditional_escape() instead.' + source: debug_toolbar.views.escape + type: view_function + render_panel: + description: Render the contents of a panel + source: debug_toolbar.views.render_panel + type: view_function + render_with_toolbar_language: + description: Force any rendering within the view to use the toolbar's language. + source: debug_toolbar.views.render_with_toolbar_language + type: view_function + require_show_toolbar: + description: 'Async compatible decorator to restrict access to a view + + based on the Debug Toolbar''s visibility settings.' + source: debug_toolbar.views.require_show_toolbar + type: view_function + exception_handler: + description: 'Returns the response that should be used for any given exception. + + + By default we handle the REST framework `APIException`, and also + + Django''s built-in `Http404` and `PermissionDenied` exceptions. + + + Any unhandled exceptions may return `None`, which will cause a 500 error + + to be raised.' + source: rest_framework.views.exception_handler + type: view_function + get_view_description: + description: 'Given a view instance, return a textual description to represent + the view. + + This name is used in the browsable API, and in OPTIONS responses. + + + This function is the default for the `VIEW_DESCRIPTION_FUNCTION` setting.' + source: rest_framework.views.get_view_description + type: view_function + get_view_name: + description: 'Given a view instance, return a textual name to represent the view. + + This name is used in the browsable API, and in OPTIONS responses. + + + This function is the default for the `VIEW_NAME_FUNCTION` setting.' + source: rest_framework.views.get_view_name + type: view_function + patch_vary_headers: + description: 'Add (or update) the "Vary" header in the given HttpResponse object. + + newheaders is a list of header names that should be in "Vary". If headers + + contains an asterisk, then "Vary" header will consist of a single asterisk + + ''*''. Otherwise, existing headers in "Vary" aren''t removed.' + source: rest_framework.views.patch_vary_headers + type: view_function + smart_str: + description: 'Return a string representing ''s''. Treat bytestrings using the + ''encoding'' + + codec. + + + If strings_only is True, don''t convert (some) non-string-like objects.' + source: rest_framework.views.smart_str + type: view_function + add_message: + description: Attempt to add a message to the request using the 'messages' app. + source: django_ledger.views.add_message + type: view_function + format_html: + description: 'Similar to str.format, but pass all arguments through conditional_escape(), + + and call mark_safe() on the result. This function should be used instead + + of str.format or % interpolation to build up small HTML fragments.' + source: django_ledger.views.format_html + type: view_function + get_localtime: + description: "Retrieve the local time based on the specified timezone.\n\nDetermines\ + \ the local time depending on whether timezone support (``USE_TZ``) is\nenabled\ + \ in global settings. If timezone support is enabled, it uses the\n`localtime`\ + \ function to obtain the local time according to the provided\ntimezone. If\ + \ timezone support is disabled, it defaults to the current time\nwith respect\ + \ to the given timezone.\n\nParameters\n----------\ntz : timezone or None, optional\n\ + \ The timezone to determine the local time. If `None`, defaults to the system\n\ + \ timezone.\n\nReturns\n-------\ndatetime\n A datetime object representing\ + \ the calculated local time." + source: django_ledger.views.get_localtime + type: view_function + make_aware: + description: Make a naive datetime.datetime in a given time zone aware. + source: django_ledger.views.make_aware + type: view_function + analyze_prompt_sync: + description: "Synchronous function to analyze a prompt and return insights.\n\ + Perfect for Django views.\n\nArgs:\n prompt: Natural language query\n \ + \ **kwargs: Additional parameters for InsightRequest\n\nReturns:\n Dictionary\ + \ with query results" + source: haikalbot.views.analyze_prompt_sync + type: view_function + export_to_csv: + description: "Export data to CSV format.\n\nArgs:\n data: Data to export\n\ + \ filename: Base filename without extension\n\nReturns:\n HttpResponse:\ + \ Response with CSV file" + source: haikalbot.views.export_to_csv + type: view_function + export_to_excel: + description: "Export data to Excel format.\n\nArgs:\n data: Data to export\n\ + \ filename: Base filename without extension\n\nReturns:\n HttpResponse:\ + \ Response with Excel file" + source: haikalbot.views.export_to_excel + type: view_function + appointment_client_information: + description: 'This view function handles client information submission for an + appointment. + + + :param request: The request instance. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID of the appointment request. + + :return: The rendered HTML page.' + source: appointment.views.appointment_client_information + type: view_function + appointment_request: + description: 'This view function handles requests to book an appointment for a + service. + + + :param request: The request instance. + + :param service_id: The ID of the service. + + :param staff_member_id: The ID of the staff member. + + :return: The rendered HTML page.' + source: appointment.views.appointment_request + type: view_function + appointment_request_submit: + description: 'This view function handles the submission of the appointment request + form. + + + :param request: The request instance. + + :return: The rendered HTML page.' + source: appointment.views.appointment_request_submit + type: view_function + check_day_off_for_staff: + description: 'Check if the given staff member is off on the given date. + + :param staff_member: The staff member to check. + + :param date: The date to check.' + source: appointment.views.check_day_off_for_staff + type: view_function + check_q_cluster: + description: 'Checks if Django Q is properly installed and configured in the Django + settings. + + If ''django_q'' is not in INSTALLED_APPS, it warns about both ''django_q'' not + being installed + + and ''Q_CLUSTER'' likely not being configured. + + If ''django_q'' is installed but ''Q_CLUSTER'' is not configured, it only warns + about ''Q_CLUSTER''. + + Returns True if configurations are correct, otherwise False.' + source: appointment.views.check_q_cluster + type: view_function + convert_str_to_date: + description: "Convert a date string to a datetime date object.\n\n:param date_str:\ + \ The date string.\n Supported formats include `%Y-%m-%d` (like\ + \ \"2023-12-31\") and `%Y/%m/%d` (like \"2023/12/31\").\n:return: The converted\ + \ `datetime.date`'s object." + source: appointment.views.convert_str_to_date + type: view_function + create_and_save_appointment: + description: 'Create and save a new appointment based on the provided appointment + request and client data. + + + :param ar: The appointment request associated with the new appointment. + + :param client_data: The data of the client making the appointment. + + :param appointment_data: Additional data for the appointment, including phone + number, address, etc. + + :param request: The request object. + + :return: The newly created appointment.' + source: appointment.views.create_and_save_appointment + type: view_function + create_appointment: + description: 'This function creates a new appointment and redirects to the payment + page or the thank-you page. + + + :param request: The request instance. + + :param appointment_request_obj: The AppointmentRequest instance. + + :param client_data: The client data. + + :param appointment_data: The appointment data. + + :return: The redirect response.' + source: appointment.views.create_appointment + type: view_function + create_payment_info_and_get_url: + description: 'Create a new payment information entry for the appointment and return + the payment URL. + + + :param appointment: The appointment to create the payment information for. + + :return: The payment URL for the appointment.' + source: appointment.views.create_payment_info_and_get_url + type: view_function + default_thank_you: + description: 'This view function handles the default thank you page. + + + :param request: The request instance. + + :param appointment_id: The ID of the appointment. + + :return: The rendered HTML page.' + source: appointment.views.default_thank_you + type: view_function + enter_verification_code: + description: 'This view function handles the submission of the email verification + code. + + + :param request: The request instance. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID of the appointment request. + + :return: The rendered HTML page.' + source: appointment.views.enter_verification_code + type: view_function + force_str: + description: 'Similar to smart_str(), except that lazy instances are resolved + to + + strings, rather than kept as lazy objects. + + + If strings_only is True, don''t convert (some) non-string-like objects.' + source: appointment.views.force_str + type: view_function + get_appointment_data_from_session: + description: 'Get the appointment data from the session variables. + + Retrieves the phone, want_reminder, address, and additional_info stored in the + session. + + + :param request: The Django HttpRequest object. + + :return: The appointment data retrieved from the session.' + source: appointment.views.get_appointment_data_from_session + type: view_function + get_appointments_and_slots: + description: "Get appointments and available slots for a given date and service.\n\ + \nIf a service is provided, the function retrieves appointments for that service\ + \ on the given date.\nOtherwise, it retrieves all appointments for the given\ + \ date.\n\n:param date_: datetime.date, the date for which to retrieve appointments\ + \ and available slots\n:param service: Service, the service for which to retrieve\ + \ appointments\n:return: tuple, a tuple containing two elements:\n - A queryset\ + \ of appointments for the given date and service (if provided).\n - A list\ + \ of available time slots on the given date, excluding booked appointments." + source: appointment.views.get_appointments_and_slots + type: view_function + get_available_slots_ajax: + description: 'This view function handles AJAX requests to get available slots + for a selected date. + + + :param request: The request instance. + + :return: A JSON response containing available slots, selected date, an error + flag, and an optional error message.' + source: appointment.views.get_available_slots_ajax + type: view_function + get_available_slots_for_staff: + description: 'Calculate the available time slots for a given date and a staff + member. + + + :param date: The date for which to calculate the available slots + + :param staff_member: The staff member for which to calculate the available slots + + :return: A list of available time slots as strings in the format ''%I:%M %p'' + like [''10:00 AM'', ''10:30 AM'']' + source: appointment.views.get_available_slots_for_staff + type: view_function + get_current_timezone_name: + description: Return the name of the currently active time zone. + source: appointment.views.get_current_timezone_name + type: view_function + get_generic_context_with_extra: + description: Get the generic context for the admin pages with extra context. + source: appointment.views.get_generic_context_with_extra + type: view_function + get_locale: + description: 'Get the current locale based on the user''s language settings, without + the country code. + + Used in the JavaScript files. + + Can''t use the lang_country format because it is not supported. + + + :return: The current locale as a string (language code only)' + source: appointment.views.get_locale + type: view_function + get_next_available_date_ajax: + description: 'This view function handles AJAX requests to get the next available + date for a service. + + + :param request: The request instance. + + :param service_id: The ID of the service. + + :return: A JSON response containing the next available date.' + source: appointment.views.get_next_available_date_ajax + type: view_function + get_non_working_days_for_staff: + description: Return the non-working days for the given staff member or an empty + list if the staff member does not exist. + source: appointment.views.get_non_working_days_for_staff + type: view_function + get_user_by_email: + description: 'Get a user by their email address. + + + :param email: The email address of the user. + + :return: The user with the specified email address, if found; otherwise, None.' + source: appointment.views.get_user_by_email + type: view_function + get_website_name: + description: 'Get the website name from the configuration file. + + + :return: The website name' + source: appointment.views.get_website_name + type: view_function + get_weekday_num_from_date: + description: Get the number of the weekday from the given date. + source: appointment.views.get_weekday_num_from_date + type: view_function + handle_existing_email: + description: 'Handle the case where the email already exists in the database. + + + Sends a verification email to the existing user and redirects the client to + enter the verification code. + + + If the email is already in the session variables, clean the session variables + for email, phone, want_reminder, + + address, and additional_info. Then, store the current email, phone, want_reminder, + address, and additional_info + + in the session. + + + :param request: The Django HttpRequest object. + + :param client_data: The data of the client for the appointment. + + :param appointment_data: The data of the appointment. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID for the appointment request. + + :return: The redirect response to enter the verification code.' + source: appointment.views.handle_existing_email + type: view_function + has_required_email_settings: + description: Check if all required email settings are configured and warn if any + are missing. + source: appointment.views.has_required_email_settings + type: view_function + is_working_day: + description: Check if the given day is a working day for the staff member. + source: appointment.views.is_working_day + type: view_function + json_response: + description: Return a generic JSON response. + source: appointment.views.json_response + type: view_function + login: + description: 'Persist a user id and a backend in the request. This way a user + doesn''t + + have to reauthenticate on every request. Note that data set during + + the anonymous session is retained when the user logs in.' + source: appointment.views.login + type: view_function + notify_admin_about_appointment: + description: Notify the admin and the staff member about a new appointment request. + source: appointment.views.notify_admin_about_appointment + type: view_function + notify_admin_about_reschedule: + description: Notify the admin and the staff member about a rescheduled appointment + request. + source: appointment.views.notify_admin_about_reschedule + type: view_function + redirect_to_payment_or_thank_you_page: + description: 'This function redirects to the payment page or the thank-you page + based on the configuration. + + + :param appointment: The Appointment instance. + + :return: The redirect response.' + source: appointment.views.redirect_to_payment_or_thank_you_page + type: view_function + require_ajax: + description: 'Decorator to require a request to be AJAX. + + Usage: @require_ajax' + source: appointment.views.require_ajax + type: view_function + send_reschedule_confirmation_email: + description: Send a rescheduling confirmation email to the client. + source: appointment.views.send_reschedule_confirmation_email + type: view_function + send_thank_you_email: + description: 'Send a thank-you email to the client for booking an appointment. + + + :param ar: The appointment request associated with the booking. + + :param user: The user who booked the appointment. + + :param email: The email address of the client. + + :param appointment_details: Additional details about the appointment (default + None). + + :param account_details: Additional details about the account (default None). + + :param request: The request object. + + :return: None' + source: appointment.views.send_thank_you_email + type: view_function + verify_user_and_login: + description: 'This function verifies the user''s email and logs the user in. + + + :param request: The request instance. + + :param user: The User instance. + + :param code: The verification code.' + source: appointment.views.verify_user_and_login + type: view_function + import_name: + description: import module given by str or pass the module if it is not str + source: plans.views.import_name + type: view_function + plan_validation: + description: 'Validates validator that represents quotas in a given system + + :param user: + + :param plan: + + :return:' + source: plans.views.plan_validation + type: view_function + Site: + description: Site(id, domain, name) + source: sites.models.Site + type: model_class + LogEntry: + description: LogEntry(id, action_time, user, content_type, object_id, object_repr, + action_flag, change_message) + source: admin.models.LogEntry + type: model_class + Permission: + description: "The permissions system provides a way to assign permissions to specific\n\ + users and groups of users.\n\nThe permission system is used by the Django admin\ + \ site, but may also be\nuseful in your own code. The Django admin site uses\ + \ permissions as follows:\n\n - The \"add\" permission limits the user's\ + \ ability to view the \"add\" form\n and add an object.\n - The \"change\"\ + \ permission limits a user's ability to view the change\n list, view the\ + \ \"change\" form and change an object.\n - The \"delete\" permission limits\ + \ the ability to delete an object.\n - The \"view\" permission limits the\ + \ ability to view an object.\n\nPermissions are set globally per type of object,\ + \ not per specific object\ninstance. It is possible to say \"Mary may change\ + \ news stories,\" but it's\nnot currently possible to say \"Mary may change\ + \ news stories, but only the\nones she created herself\" or \"Mary may only\ + \ change news stories that have a\ncertain status or publication date.\"\n\n\ + The permissions listed above are automatically created for each model." + source: auth.models.Permission + type: model_class + Group: + description: 'Groups are a generic way of categorizing users to apply permissions, + or + + some other label, to those users. A user can belong to any number of + + groups. + + + A user in a group automatically has all the permissions granted to that + + group. For example, if the group ''Site editors'' has the permission + + can_edit_home_page, any user in that group will have that permission. + + + Beyond permissions, groups are a convenient way to categorize users to + + apply some label, or extended functionality, to them. For example, you + + could create a group ''Special users'', and you could write code that would + + do special things to those users -- such as giving them access to a + + members-only portion of your site, or sending them members-only email + + messages.' + source: auth.models.Group + type: model_class + User: + description: 'Users within the Django authentication system are represented by + this + + model. + + + Username and password are required. Other fields are optional.' + source: auth.models.User + type: model_class + ContentType: + description: ContentType(id, app_label, model) + source: contenttypes.models.ContentType + type: model_class + Session: + description: 'Django provides full support for anonymous sessions. The session + + framework lets you store and retrieve arbitrary data on a + + per-site-visitor basis. It stores data on the server side and + + abstracts the sending and receiving of cookies. Cookies contain a + + session ID -- not the data itself. + + + The Django sessions framework is entirely cookie-based. It does + + not fall back to putting session IDs in URLs. This is an intentional + + design decision. Not only does that behavior make URLs ugly, it makes + + your site vulnerable to session-ID theft via the "Referer" header. + + + For complete documentation on using Sessions in your code, consult + + the sessions documentation that is shipped with Django (also available + + on the Django web site).' + source: sessions.models.Session + type: model_class + DealersMake: + description: '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' + source: inventory.models.DealersMake + type: model_class + VatRate: + description: VatRate(id, rate, is_active, created_at) + source: inventory.models.VatRate + type: model_class + CarMake: + description: CarMake(id_car_make, name, slug, arabic_name, logo, is_sa_import, + car_type) + source: inventory.models.CarMake + type: model_class + CarModel: + description: CarModel(id_car_model, id_car_make, name, arabic_name, slug) + source: inventory.models.CarModel + type: model_class + CarSerie: + description: CarSerie(id_car_serie, id_car_model, name, arabic_name, year_begin, + year_end, generation_name, slug) + source: inventory.models.CarSerie + type: model_class + CarTrim: + description: CarTrim(id_car_trim, id_car_serie, name, arabic_name, start_production_year, + end_production_year, slug) + source: inventory.models.CarTrim + type: model_class + CarEquipment: + description: CarEquipment(id_car_equipment, id_car_trim, name, arabic_name, year_begin, + slug) + source: inventory.models.CarEquipment + type: model_class + CarSpecification: + description: CarSpecification(id_car_specification, name, arabic_name, id_parent, + slug) + source: inventory.models.CarSpecification + type: model_class + CarSpecificationValue: + description: CarSpecificationValue(id_car_specification_value, id_car_trim, id_car_specification, + value, unit) + source: inventory.models.CarSpecificationValue + type: model_class + CarOption: + description: CarOption(id_car_option, name, arabic_name, id_parent, slug) + source: inventory.models.CarOption + type: model_class + CarOptionValue: + description: CarOptionValue(id_car_option_value, id_car_option, id_car_equipment, + value, unit, is_base) + source: inventory.models.CarOptionValue + type: model_class + AdditionalServices: + description: AdditionalServices(id, name, arabic_name, description, price, taxable, + uom, dealer, item) + source: inventory.models.AdditionalServices + type: model_class + Car: + description: Car(id, slug, created_at, updated_at, item_model, vin, dealer, vendor, + id_car_make, id_car_model, year, id_car_serie, id_car_trim, status, stock_type, + remarks, mileage, receiving_date, hash) + source: inventory.models.Car + type: model_class + CarTransfer: + description: CarTransfer(id, car, from_dealer, to_dealer, transfer_date, quantity, + remarks, status, is_approved, active, created_at, updated_at) + source: inventory.models.CarTransfer + type: model_class + CarReservation: + description: CarReservation(id, car, reserved_by, reserved_at, reserved_until) + source: inventory.models.CarReservation + type: model_class + CarFinance: + description: CarFinance(id, car, cost_price, selling_price, discount_amount, is_sold) + source: inventory.models.CarFinance + type: model_class + ExteriorColors: + description: ExteriorColors(id, name, arabic_name, rgb) + source: inventory.models.ExteriorColors + type: model_class + InteriorColors: + description: InteriorColors(id, name, arabic_name, rgb) + source: inventory.models.InteriorColors + type: model_class + CarColors: + description: CarColors(id, car, exterior, interior) + source: inventory.models.CarColors + type: model_class + CustomCard: + description: CustomCard(id, car, custom_number, custom_date) + source: inventory.models.CustomCard + type: model_class + CarLocation: + description: CarLocation(id, car, owner, showroom, description, created_at, updated_at) + source: inventory.models.CarLocation + type: model_class + CarRegistration: + description: CarRegistration(id, car, plate_number, text1, text2, text3, registration_date) + source: inventory.models.CarRegistration + type: model_class + Dealer: + description: Dealer(id, user, crn, vrn, arabic_name, name, phone_number, address, + logo, entity, joined_at, updated_at, slug) + source: inventory.models.Dealer + type: model_class + Staff: + description: Staff(id, staff_member, dealer, name, arabic_name, phone_number, + staff_type, active, created, updated, slug) + source: inventory.models.Staff + type: model_class + Customer: + description: Customer(id, dealer, customer_model, user, title, first_name, last_name, + gender, dob, email, national_id, phone_number, address, active, image, created, + updated, slug) + source: inventory.models.Customer + type: model_class + Organization: + description: Organization(id, dealer, customer_model, user, name, arabic_name, + crn, vrn, email, phone_number, address, logo, active, created, updated, slug) + source: inventory.models.Organization + type: model_class + Representative: + description: Representative(id, dealer, name, arabic_name, id_number, phone_number, + email, address) + source: inventory.models.Representative + type: model_class + Lead: + description: Lead(id, dealer, first_name, last_name, email, phone_number, address, + lead_type, customer, organization, id_car_make, id_car_model, source, channel, + staff, status, next_action, next_action_date, is_converted, converted_at, created, + updated, slug) + source: inventory.models.Lead + type: model_class + Schedule: + description: Schedule(id, name, func, hook, args, kwargs, schedule_type, minutes, + repeats, next_run, cron, task, cluster, intended_date_kwarg) + source: django_q.models.Schedule + type: model_class + LeadStatusHistory: + description: LeadStatusHistory(id, lead, old_status, new_status, changed_by, changed_at) + source: inventory.models.LeadStatusHistory + type: model_class + Opportunity: + description: Opportunity(id, dealer, customer, organization, car, crn, vrn, salary, + priority, stage, staff, lead, probability, amount, expected_revenue, vehicle_of_interest_make, + vehicle_of_interest_model, expected_close_date, created, updated, estimate, + slug, loss_reason) + source: inventory.models.Opportunity + type: model_class + Notes: + description: Notes(id, dealer, content_type, object_id, note, created_by, created, + updated) + source: inventory.models.Notes + type: model_class + Tasks: + description: Tasks(id, dealer, content_type, object_id, title, description, due_date, + completed, assigned_to, created_by, created, updated) + source: inventory.models.Tasks + type: model_class + Email: + description: Email(id, content_type, object_id, from_email, to_email, subject, + message, status, created_by, created, updated) + source: inventory.models.Email + type: model_class + Activity: + description: Activity(id, dealer, content_type, object_id, activity_type, notes, + created_by, created, updated) + source: inventory.models.Activity + type: model_class + Notification: + description: Notification(id, user, message, is_read, created) + source: inventory.models.Notification + type: model_class + Vendor: + description: Vendor(id, dealer, crn, vrn, vendor_model, arabic_name, name, contact_person, + phone_number, email, address, logo, active, created_at, slug) + source: inventory.models.Vendor + type: model_class + Payment: + description: Payment(id, amount, payment_method, reference_number, payment_date) + source: inventory.models.Payment + type: model_class + Refund: + description: Refund(id, payment, amount, reason, refund_date) + source: inventory.models.Refund + type: model_class + UserActivityLog: + description: UserActivityLog(id, user, action, timestamp) + source: inventory.models.UserActivityLog + type: model_class + SaleOrder: + description: SaleOrder(id, estimate, invoice, payment_method, comments, formatted_order_id, + opportunity, customer, car, agreed_price, down_payment_amount, trade_in_value, + trade_in_vehicle, loan_amount, total_paid_amount, remaining_balance, status, + order_date, expected_delivery_date, actual_delivery_date, cancelled_date, cancellation_reason, + created_at, updated_at, created_by, last_modified_by) + source: inventory.models.SaleOrder + type: model_class + CustomGroup: + description: CustomGroup(id, name, dealer, group) + source: inventory.models.CustomGroup + type: model_class + DealerSettings: + description: DealerSettings(id, dealer, invoice_cash_account, invoice_prepaid_account, + invoice_unearned_account, bill_cash_account, bill_prepaid_account, bill_unearned_account, + additional_info) + source: inventory.models.DealerSettings + type: model_class + PaymentHistory: + description: PaymentHistory(id, user, user_data, amount, currency, payment_date, + status, payment_method, transaction_id, invoice_number, order_reference, gateway_response, + gateway_name, description, is_recurring, billing_email, billing_address, created_at, + updated_at) + source: inventory.models.PaymentHistory + type: model_class + CarVIN: + description: CarVIN(id, vin, created) + source: api.models.CarVIN + type: model_class + EmailAddress: + description: EmailAddress(id, user, email, verified, primary) + source: account.models.EmailAddress + type: model_class + EmailConfirmation: + description: EmailConfirmation(id, email_address, created, sent, key) + source: account.models.EmailConfirmation + type: model_class + SocialApp: + description: SocialApp(id, provider, provider_id, name, client_id, secret, key, + settings) + source: socialaccount.models.SocialApp + type: model_class + SocialAccount: + description: SocialAccount(id, user, provider, uid, last_login, date_joined, extra_data) + source: socialaccount.models.SocialAccount + type: model_class + SocialToken: + description: SocialToken(id, app, account, token, token_secret, expires_at) + source: socialaccount.models.SocialToken + type: model_class + Request: + description: Request(id, path, query_params, raw_body, body, method, start_time, + view_name, end_time, time_taken, encoded_headers, meta_time, meta_num_queries, + meta_time_spent_queries, pyprofile, prof_file, num_sql_queries) + source: silk.models.Request + type: model_class + Response: + description: Response(id, request, status_code, raw_body, body, encoded_headers) + source: silk.models.Response + type: model_class + SQLQuery: + description: SQLQuery(id, query, start_time, end_time, time_taken, identifier, + request, traceback, analysis) + source: silk.models.SQLQuery + type: model_class + Profile: + description: Profile(id, name, start_time, end_time, request, time_taken, file_path, + line_num, end_line_num, func_name, exception_raised, dynamic) + source: silk.models.Profile + type: model_class + Token: + description: The default authorization token model. + source: authtoken.models.Token + type: model_class + TokenProxy: + description: Proxy mapping pk to user pk for use in admin. + source: authtoken.models.TokenProxy + type: model_class + BankAccountModel: + description: Base Bank Account Model Implementation + source: django_ledger.models.BankAccountModel + type: model_class + AccountModel: + description: Base Account Model from Account Model Abstract Class + source: django_ledger.models.AccountModel + type: model_class + ChartOfAccountModel: + description: Base ChartOfAccounts Model + source: django_ledger.models.ChartOfAccountModel + type: model_class + CustomerModel: + description: Base Customer Model Implementation + source: django_ledger.models.CustomerModel + type: model_class + UnitOfMeasureModel: + description: Base UnitOfMeasureModel from Abstract. + source: django_ledger.models.UnitOfMeasureModel + type: model_class + ItemTransactionModel: + description: Base ItemTransactionModel from Abstract. + source: django_ledger.models.ItemTransactionModel + type: model_class + ItemModel: + description: Base ItemModel from Abstract. + source: django_ledger.models.ItemModel + type: model_class + LedgerModel: + description: Base LedgerModel from Abstract. + source: django_ledger.models.LedgerModel + type: model_class + EntityUnitModel: + description: Base Model Class for EntityUnitModel + source: django_ledger.models.EntityUnitModel + type: model_class + VendorModel: + description: Base Vendor Model Implementation + source: django_ledger.models.VendorModel + type: model_class + EntityModel: + description: Entity Model Base Class From Abstract + source: django_ledger.models.EntityModel + type: model_class + EntityStateModel: + description: Entity State Model Base Class from Abstract. + source: django_ledger.models.EntityStateModel + type: model_class + EntityManagementModel: + description: EntityManagement Model Base Class From Abstract + source: django_ledger.models.EntityManagementModel + type: model_class + BillModel: + description: Base BillModel from Abstract. + source: django_ledger.models.BillModel + type: model_class + InvoiceModel: + description: Base Invoice Model from Abstract. + source: django_ledger.models.InvoiceModel + type: model_class + TransactionModel: + description: Base Transaction Model From Abstract. + source: django_ledger.models.TransactionModel + type: model_class + JournalEntryModel: + description: Journal Entry Model Base Class From Abstract + source: django_ledger.models.JournalEntryModel + type: model_class + PurchaseOrderModel: + description: Purchase Order Base Model + source: django_ledger.models.PurchaseOrderModel + type: model_class + EstimateModel: + description: Base EstimateModel Class. + source: django_ledger.models.EstimateModel + type: model_class + ClosingEntryModel: + description: ClosingEntryModel(created, updated, markdown_notes, uuid, entity_model, + ledger_model, closing_date, posted) + source: django_ledger.models.ClosingEntryModel + type: model_class + ClosingEntryTransactionModel: + description: Base ClosingEntryModel Class + source: django_ledger.models.ClosingEntryTransactionModel + type: model_class + ImportJobModel: + description: Transaction Import Job Model Base Class. + source: django_ledger.models.ImportJobModel + type: model_class + StagedTransactionModel: + description: Staged Transaction Model Base Class. + source: django_ledger.models.StagedTransactionModel + type: model_class + ChatLog: + description: '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' + source: haikalbot.models.ChatLog + type: model_class + AnalysisCache: + description: 'Model to cache analysis results for performance optimization. + + + This model stores cached results of model analysis operations to improve + + performance for repeated queries. It includes a hash of the prompt, user + + information, dealer ID, timestamps, and the cached result in JSON format. + + + :ivar prompt_hash: MD5 hash of the prompt + dealer_id + language + + :type prompt_hash: str + + :ivar user: The user who made the request (optional) + + :type user: User + + :ivar dealer_id: ID of the dealer associated with this cache entry + + :type dealer_id: int + + :ivar created_at: When the cache entry was created + + :type created_at: datetime + + :ivar updated_at: When the cache entry was last updated + + :type updated_at: datetime + + :ivar expires_at: When the cache entry expires + + :type expires_at: datetime + + :ivar result: The cached analysis result + + :type result: dict' + source: haikalbot.models.AnalysisCache + type: model_class + Service: + description: 'Represents a service provided by the appointment system. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.Service + type: model_class + StaffMember: + description: StaffMember(id, user, slot_duration, lead_time, finish_time, appointment_buffer_time, + work_on_saturday, work_on_sunday, created_at, updated_at) + source: appointment.models.StaffMember + type: model_class + AppointmentRequest: + description: 'Represents an appointment request made by a client. + + + Author: Adams Pierre David + + Since: 1.0.0' + source: appointment.models.AppointmentRequest + type: model_class + AppointmentRescheduleHistory: + description: AppointmentRescheduleHistory(id, appointment_request, date, start_time, + end_time, staff_member, reason_for_rescheduling, reschedule_status, id_request, + created_at, updated_at) + source: appointment.models.AppointmentRescheduleHistory + type: model_class + Appointment: + description: 'Represents an appointment made by a client. It is created when the + client confirms the appointment request. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.Appointment + type: model_class + Config: + description: 'Represents configuration settings for the appointment system. There + can only be one Config object in the database. + + If you want to change the settings, you must edit the existing Config object. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.1.0' + source: appointment.models.Config + type: model_class + PaymentInfo: + description: 'Represents payment information for an appointment. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.PaymentInfo + type: model_class + EmailVerificationCode: + description: 'Represents an email verification code for a user when the email + already exists in the database. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.1.0' + source: appointment.models.EmailVerificationCode + type: model_class + PasswordResetToken: + description: 'Represents a password reset token for users. + + + Author: Adams Pierre David + + Version: 3.x.x + + Since: 3.x.x' + source: appointment.models.PasswordResetToken + type: model_class + DayOff: + description: DayOff(id, staff_member, start_date, end_date, description, created_at, + updated_at) + source: appointment.models.DayOff + type: model_class + WorkingHours: + description: WorkingHours(id, staff_member, day_of_week, start_time, end_time, + created_at, updated_at) + source: appointment.models.WorkingHours + type: model_class + Task: + description: Task(id, task_name, task_params, task_hash, verbose_name, priority, + run_at, repeat, repeat_until, queue, attempts, failed_at, last_error, locked_by, + locked_at, creator_content_type, creator_object_id) + source: background_task.models.Task + type: model_class + Success: + description: Success(id, name, func, hook, args, kwargs, result, group, cluster, + started, stopped, success, attempt_count) + source: django_q.models.Success + type: model_class + Failure: + description: Failure(id, name, func, hook, args, kwargs, result, group, cluster, + started, stopped, success, attempt_count) + source: django_q.models.Failure + type: model_class + OrmQ: + description: OrmQ(id, key, payload, lock) + source: django_q.models.OrmQ + type: model_class + Plan: + description: Plan(id, order, created, updated_at, name, description, default, + available, visible, customized, url) + source: plans.models.Plan + type: model_class + BillingInfo: + description: BillingInfo(id, created, updated_at, user, tax_number, name, street, + zipcode, city, country, shipping_name, shipping_street, shipping_zipcode, shipping_city) + source: plans.models.BillingInfo + type: model_class + UserPlan: + description: UserPlan(id, created, updated_at, user, plan, expire, active) + source: plans.models.UserPlan + type: model_class + Pricing: + description: Pricing(id, created, updated_at, name, period, url) + source: plans.models.Pricing + type: model_class + PlanPricing: + description: PlanPricing(id, created, updated_at, plan, pricing, price, order, + has_automatic_renewal, visible) + source: plans.models.PlanPricing + type: model_class + Quota: + description: Quota(id, order, created, updated_at, codename, name, unit, description, + is_boolean, url) + source: plans.models.Quota + type: model_class + PlanQuota: + description: PlanQuota(id, created, updated_at, plan, quota, value) + source: plans.models.PlanQuota + type: model_class + Order: + description: Order(id, created, updated_at, user, flat_name, plan, pricing, completed, + plan_extended_from, plan_extended_until, amount, tax, currency, status) + source: plans.models.Order + type: model_class + Invoice: + description: Invoice(id, created, updated_at, user, order, number, full_number, + type, issued, issued_duplicate, selling_date, payment_date, unit_price_net, + quantity, total_net, total, tax_total, tax, rebate, currency, item_description, + buyer_name, buyer_street, buyer_zipcode, buyer_city, buyer_country, buyer_tax_number, + shipping_name, shipping_street, shipping_zipcode, shipping_city, shipping_country, + require_shipment, issuer_name, issuer_street, issuer_zipcode, issuer_city, issuer_country, + issuer_tax_number) + source: plans.models.Invoice + type: model_class + RecurringUserPlan: + description: RecurringUserPlan(id, created, updated_at, user_plan, token, payment_provider, + pricing, amount, tax, currency, renewal_triggered_by, _has_automatic_renewal_backup_deprecated, + token_verified, card_expire_year, card_expire_month, card_masked_number) + source: plans.models.RecurringUserPlan + type: model_class + Sequence: + description: Sequence(name, last) + source: sequences.models.Sequence + type: model_class + ExportPDFSettings: + description: ExportPDFSettings(id, created, modified, title, active, page_size, + items_per_page, page_margin_mm, font_name, header_font_size, body_font_size, + logo, header_background_color, grid_line_color, grid_line_width, show_header, + show_logo, show_export_time, show_page_numbers, rtl_support, content_alignment, + header_alignment, title_alignment, table_spacing, max_chars_per_line) + source: django_pdf_actions.models.ExportPDFSettings + type: model_class + CompletedTask: + description: CompletedTask(id, task_name, task_params, task_hash, verbose_name, + priority, run_at, repeat, repeat_until, queue, attempts, failed_at, last_error, + locked_by, locked_at, creator_content_type, creator_object_id) + source: background_task.models.CompletedTask + type: model_class +user_workflows: + Add New Car: + description: How to add a new car to the inventory + steps: + - Navigate to the Inventory section by clicking 'Inventory' in the main menu + - Click the 'Add Car' button in the top right corner + - Enter the VIN number or scan it using the barcode scanner + - Select the car make from the dropdown menu + - Select the car series from the available options + - Select the trim level for the car + - Fill in additional details like color, mileage, and price + - Click 'Save' to add the car to inventory, or 'Save & Add Another' to continue + adding cars + source: manual_documentation + Create New Invoice: + description: How to create a new invoice + steps: + - Navigate to the Finance section by clicking 'Finance' in the main menu + - Click the 'Invoices' tab + - Click the 'Create New Invoice' button + - Select a customer from the dropdown or click 'Add New Customer' + - Select the car(s) to include in the invoice + - Add any additional services or parts by clicking 'Add Item' + - Set the payment terms and due date + - Click 'Save Draft' to save without finalizing, or 'Finalize Invoice' to complete + source: manual_documentation +templates: {} +glossary: {} diff --git a/haikalbot/ai_agent.py b/haikalbot/ai_agent.py index 331c8016..083adb7a 100644 --- a/haikalbot/ai_agent.py +++ b/haikalbot/ai_agent.py @@ -20,7 +20,7 @@ from sqlalchemy.orm import relationship logger = logging.getLogger(__name__) # Configuration settings -LLM_MODEL = getattr(settings, 'MODEL_ANALYZER_LLM_MODEL', 'qwen:7b-chat') +LLM_MODEL = getattr(settings, 'MODEL_ANALYZER_LLM_MODEL', 'qwen3:8b') LLM_TEMPERATURE = getattr(settings, 'MODEL_ANALYZER_LLM_TEMPERATURE', 0.3) LLM_MAX_TOKENS = getattr(settings, 'MODEL_ANALYZER_LLM_MAX_TOKENS', 2048) CACHE_TIMEOUT = getattr(settings, 'MODEL_ANALYZER_CACHE_TIMEOUT', 3600) @@ -753,12 +753,14 @@ def analyze_prompt(prompt: str) -> Dict[str, Any]: """ # Detect language language = "ar" if bool(re.search(r'[\u0600-\u06FF]', prompt)) else "en" - filtered_apps = ['inventory', 'django_ledger', 'appointments', 'plans'] + filtered_apps = ['inventory'] try: analyzer = DjangoModelAnalyzer() model_structure = get_all_model_structures(filtered_apps=filtered_apps) - + print(model_structure) analysis = analyzer.analyze_prompt(prompt, model_structure) + print(analysis) + if not analysis or not analysis.app_label or not analysis.model_name: return { diff --git a/haikalbot/haikal_agent.py b/haikalbot/haikal_agent.py new file mode 100644 index 00000000..f09c9e52 --- /dev/null +++ b/haikalbot/haikal_agent.py @@ -0,0 +1,801 @@ +import asyncio +import sqlite3 +import json +import re +import logging +from typing import List, Dict, Any, Optional, Union +from dataclasses import dataclass, asdict +from enum import Enum +import os +from functools import reduce +import operator + +# Pydantic and AI imports +from pydantic import BaseModel, Field +from pydantic_ai import Agent, RunContext +from pydantic_ai.models.openai import OpenAIModel +from pydantic_ai.providers.openai import OpenAIProvider + +# Optional Django imports (if available) +try: + from django.apps import apps + from django.db import models, connection + from django.db.models import QuerySet, Q, F, Sum, Avg, Count, Max, Min + from django.core.exceptions import FieldDoesNotExist + from django.conf import settings + + DJANGO_AVAILABLE = True +except ImportError: + DJANGO_AVAILABLE = False + +# Optional database drivers +try: + import psycopg2 + + POSTGRESQL_AVAILABLE = True +except ImportError: + POSTGRESQL_AVAILABLE = False + +try: + import pymysql + + MYSQL_AVAILABLE = True +except ImportError: + MYSQL_AVAILABLE = False + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +# Configuration +class DatabaseConfig: + LLM_MODEL = settings.MODEL_ANALYZER_LLM_MODEL + LLM_BASE_URL = "http://localhost:11434/v1" + LLM_TEMPERATURE = 0.3 + MAX_RESULTS = 1000 + SUPPORTED_CHART_TYPES = ["bar", "line", "pie", "doughnut", "radar", "scatter"] + + +class DatabaseType(Enum): + SQLITE = "sqlite" + POSTGRESQL = "postgresql" + MYSQL = "mysql" + + + +@dataclass +class DatabaseConnection: + db_type: DatabaseType + connection_string: str + database_name: Optional[str] = None + host: Optional[str] = None + port: Optional[int] = None + user: Optional[str] = None + password: Optional[str] = None + schema_info: Optional[Dict] = None + + +@dataclass +class QueryResult: + status: str + data: Union[List[Dict], Dict] + metadata: Dict[str, Any] + chart_data: Optional[Dict] = None + language: str = "en" + error: Optional[str] = None + + def to_dict(self): + """Convert to dictionary for JSON serialization.""" + return asdict(self) + + +class DatabaseSchema(BaseModel): + tables: Dict[str, List[Dict[str, Any]]] = Field( + description="Database schema with table names as keys and column info as values" + ) + relationships: Optional[List[Dict[str, Any]]] = Field( + default=None, + description="Foreign key relationships between tables" + ) + + +class InsightRequest(BaseModel): + prompt: str = Field(description="Natural language query from user") + database_path: Optional[str] = Field(default=None, description="Path to database file (for SQLite)") + chart_type: Optional[str] = Field(default=None, description="Preferred chart type") + limit: Optional[int] = Field(default=1000, description="Maximum number of results") + language: Optional[str] = Field(default="auto", description="Response language preference") + use_django: Optional[bool] = Field(default=True, description="Use Django database if available") + + +class DatabaseInsightSystem: + def __init__(self, config: DatabaseConfig = None): + self.config = config or DatabaseConfig() + self.model = OpenAIModel( + model_name=self.config.LLM_MODEL, + provider=OpenAIProvider(base_url=self.config.LLM_BASE_URL) + ) + self.db_connection = None + self._setup_agents() + + def _setup_agents(self): + """Initialize the AI agents for schema analysis and query generation.""" + + # Query generation and execution agent + self.query_agent = Agent( + self.model, + deps_type=DatabaseSchema, + output_type=str, + system_prompt="""You are an intelligent database query generator and analyst. + Given a natural language prompt and database schema, you must: + + 1. ANALYZE the user's request in English or Arabic + 2. IDENTIFY relevant tables and columns from the schema + 3. GENERATE appropriate SQL query or analysis approach + 4. DETERMINE if aggregation, grouping, or joins are needed + 5. SUGGEST appropriate visualization type + 6. EXECUTE the query and provide insights + + Response format should be JSON: + { + "analysis": "Brief analysis of the request", + "query_type": "select|aggregate|join|complex", + "sql_query": "Generated SQL query", + "chart_suggestion": "bar|line|pie|etc", + "expected_fields": ["field1", "field2"], + "language": "en|ar" + } + + Handle both English and Arabic prompts. For Arabic text, respond in Arabic. + Focus on providing actionable insights, not just raw data.""" + ) + + def _get_django_database_config(self) -> Optional[DatabaseConnection]: + """Extract database configuration from Django settings.""" + if not DJANGO_AVAILABLE: + return None + + try: + # Get default database configuration + db_config = settings.DATABASES.get('default', {}) + if not db_config: + logger.warning("No default database configuration found in Django settings") + return None + + engine = db_config.get('ENGINE', '') + db_name = db_config.get('NAME', '') + host = db_config.get('HOST', 'localhost') + port = db_config.get('PORT', None) + user = db_config.get('USER', '') + password = db_config.get('PASSWORD', '') + + # Determine database type from engine + if 'sqlite' in engine.lower(): + db_type = DatabaseType.SQLITE + connection_string = db_name # For SQLite, NAME is the file path + elif 'postgresql' in engine.lower(): + db_type = DatabaseType.POSTGRESQL + port = port or 5432 + connection_string = f"postgresql://{user}:{password}@{host}:{port}/{db_name}" + elif 'mysql' in engine.lower(): + db_type = DatabaseType.MYSQL + port = port or 3306 + connection_string = f"mysql://{user}:{password}@{host}:{port}/{db_name}" + else: + logger.warning(f"Unsupported database engine: {engine}") + return None + + return DatabaseConnection( + db_type=db_type, + connection_string=connection_string, + database_name=db_name, + host=host, + port=port, + user=user, + password=password + ) + + except Exception as e: + logger.error(f"Failed to get Django database config: {e}") + return None + + def analyze_database_schema_sync(self, request: InsightRequest) -> DatabaseSchema: + """Synchronous wrapper for schema analysis.""" + return asyncio.run(self.analyze_database_schema(request)) + + async def analyze_database_schema(self, request: InsightRequest) -> DatabaseSchema: + """Extract and analyze database schema.""" + try: + # Try Django first if available and requested + if request.use_django and DJANGO_AVAILABLE: + django_config = self._get_django_database_config() + if django_config: + self.db_connection = django_config + return await self._analyze_django_schema() + + # Fallback to direct database connection + if request.database_path: + # Assume SQLite for direct file path + self.db_connection = DatabaseConnection( + db_type=DatabaseType.SQLITE, + connection_string=request.database_path + ) + return await self._analyze_sqlite_schema(request.database_path) + + raise ValueError("No database configuration available") + + except Exception as e: + logger.error(f"Schema analysis failed: {e}") + raise + + async def _analyze_sqlite_schema(self, db_path: str) -> DatabaseSchema: + """Analyze SQLite database schema.""" + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Get table names + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = [row[0] for row in cursor.fetchall()] + + schema_data = {} + relationships = [] + + for table in tables: + # Get column information + cursor.execute(f"PRAGMA table_info({table})") + columns = [] + for col in cursor.fetchall(): + columns.append({ + "name": col[1], + "type": col[2], + "notnull": bool(col[3]), + "default_value": col[4], + "primary_key": bool(col[5]) + }) + schema_data[table] = columns + + # Get foreign key relationships + cursor.execute(f"PRAGMA foreign_key_list({table})") + for fk in cursor.fetchall(): + relationships.append({ + "from_table": table, + "from_column": fk[3], + "to_table": fk[2], + "to_column": fk[4] + }) + + conn.close() + return DatabaseSchema(tables=schema_data, relationships=relationships) + + except Exception as e: + logger.error(f"SQLite schema analysis failed: {e}") + raise + + async def _analyze_django_schema(self) -> DatabaseSchema: + """Analyze Django models schema.""" + if not DJANGO_AVAILABLE: + raise ImportError("Django is not available") + + schema_data = {} + relationships = [] + + for model in apps.get_models(): + table_name = model._meta.db_table + columns = [] + + for field in model._meta.get_fields(): + if not field.is_relation: + columns.append({ + "name": field.name, + "type": field.get_internal_type(), + "notnull": not getattr(field, 'null', True), + "primary_key": getattr(field, 'primary_key', False) + }) + else: + # Handle relationships + if hasattr(field, 'related_model') and field.related_model: + relationships.append({ + "from_table": table_name, + "from_column": field.name, + "to_table": field.related_model._meta.db_table, + "relationship_type": field.get_internal_type() + }) + + schema_data[table_name] = columns + + return DatabaseSchema(tables=schema_data, relationships=relationships) + + async def _analyze_postgresql_schema(self, connection_string: str) -> DatabaseSchema: + """Analyze PostgreSQL database schema.""" + if not POSTGRESQL_AVAILABLE: + raise ImportError("psycopg2 is not available") + + try: + import psycopg2 + from psycopg2.extras import RealDictCursor + + conn = psycopg2.connect(connection_string) + cursor = conn.cursor(cursor_factory=RealDictCursor) + + # Get table names + cursor.execute(""" + SELECT table_name + FROM information_schema.tables + WHERE table_schema = 'public' + """) + tables = [row['table_name'] for row in cursor.fetchall()] + + schema_data = {} + relationships = [] + + for table in tables: + # Get column information + cursor.execute(""" + SELECT column_name, data_type, is_nullable, column_default + FROM information_schema.columns + WHERE table_name = %s + ORDER BY ordinal_position + """, (table,)) + + columns = [] + for col in cursor.fetchall(): + columns.append({ + "name": col['column_name'], + "type": col['data_type'], + "notnull": col['is_nullable'] == 'NO', + "default_value": col['column_default'], + "primary_key": False # Will be updated below + }) + + # Get primary key information + cursor.execute(""" + SELECT column_name + FROM information_schema.key_column_usage + WHERE table_name = %s + AND constraint_name LIKE '%_pkey' + """, (table,)) + + pk_columns = [row['column_name'] for row in cursor.fetchall()] + for col in columns: + if col['name'] in pk_columns: + col['primary_key'] = True + + schema_data[table] = columns + + # Get foreign key relationships + cursor.execute(""" + SELECT kcu.column_name, + ccu.table_name AS foreign_table_name, + ccu.column_name AS foreign_column_name + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + WHERE tc.constraint_type = 'FOREIGN KEY' + AND tc.table_name = %s + """, (table,)) + + for fk in cursor.fetchall(): + relationships.append({ + "from_table": table, + "from_column": fk['column_name'], + "to_table": fk['foreign_table_name'], + "to_column": fk['foreign_column_name'] + }) + + conn.close() + return DatabaseSchema(tables=schema_data, relationships=relationships) + + except Exception as e: + logger.error(f"PostgreSQL schema analysis failed: {e}") + raise + + async def _analyze_mysql_schema(self, connection_string: str) -> DatabaseSchema: + """Analyze MySQL database schema.""" + if not MYSQL_AVAILABLE: + raise ImportError("pymysql is not available") + + try: + import pymysql + + # Parse connection string to get connection parameters + # Format: mysql://user:password@host:port/database + import urllib.parse + parsed = urllib.parse.urlparse(connection_string) + + conn = pymysql.connect( + host=parsed.hostname, + port=parsed.port or 3306, + user=parsed.username, + password=parsed.password, + database=parsed.path[1:], # Remove leading slash + cursorclass=pymysql.cursors.DictCursor + ) + + cursor = conn.cursor() + + # Get table names + cursor.execute("SHOW TABLES") + tables = [list(row.values())[0] for row in cursor.fetchall()] + + schema_data = {} + relationships = [] + + for table in tables: + # Get column information + cursor.execute(f"DESCRIBE {table}") + columns = [] + for col in cursor.fetchall(): + columns.append({ + "name": col['Field'], + "type": col['Type'], + "notnull": col['Null'] == 'NO', + "default_value": col['Default'], + "primary_key": col['Key'] == 'PRI' + }) + + schema_data[table] = columns + + # Get foreign key relationships + cursor.execute(f""" + SELECT + COLUMN_NAME, + REFERENCED_TABLE_NAME, + REFERENCED_COLUMN_NAME + FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE + WHERE TABLE_NAME = '{table}' + AND REFERENCED_TABLE_NAME IS NOT NULL + """) + + for fk in cursor.fetchall(): + relationships.append({ + "from_table": table, + "from_column": fk['COLUMN_NAME'], + "to_table": fk['REFERENCED_TABLE_NAME'], + "to_column": fk['REFERENCED_COLUMN_NAME'] + }) + + conn.close() + return DatabaseSchema(tables=schema_data, relationships=relationships) + + except Exception as e: + logger.error(f"MySQL schema analysis failed: {e}") + raise + + def _detect_language(self, text: str) -> str: + """Detect if text is Arabic or English.""" + arabic_chars = re.findall(r'[\u0600-\u06FF]', text) + return "ar" if len(arabic_chars) > len(text) * 0.3 else "en" + + def _execute_query_sync(self, query: str) -> List[Dict]: + """Synchronous wrapper for query execution.""" + return asyncio.run(self._execute_query(query)) + + async def _execute_query(self, query: str) -> List[Dict]: + """Execute query based on the current database connection.""" + if not self.db_connection: + raise ValueError("No database connection established") + + if self.db_connection.db_type == DatabaseType.SQLITE: + return await self._execute_sqlite_query(self.db_connection.connection_string, query) + # elif self.db_connection.db_type == DatabaseType.DJANGO and DJANGO_AVAILABLE: + # return await self._execute_django_query(query) + elif self.db_connection.db_type == DatabaseType.POSTGRESQL: + return await self._execute_postgresql_query(self.db_connection.connection_string, query) + elif self.db_connection.db_type == DatabaseType.MYSQL: + return await self._execute_mysql_query(self.db_connection.connection_string, query) + else: + raise ValueError(f"Unsupported database type: {self.db_connection.db_type}") + + async def _execute_sqlite_query(self, db_path: str, query: str) -> List[Dict]: + """Execute SQL query on SQLite database.""" + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + cursor.execute(query) + + # Get column names + columns = [description[0] for description in cursor.description] + + # Fetch results and convert to dictionaries + results = cursor.fetchall() + data = [dict(zip(columns, row)) for row in results] + + conn.close() + return data + + except Exception as e: + logger.error(f"SQLite query execution failed: {e}") + raise + + async def _execute_django_query(self, query: str) -> List[Dict]: + """Execute raw SQL query using Django's database connection.""" + try: + from django.db import connection + + with connection.cursor() as cursor: + cursor.execute(query) + columns = [col[0] for col in cursor.description] + results = cursor.fetchall() + data = [dict(zip(columns, row)) for row in results] + + return data + + except Exception as e: + logger.error(f"Django query execution failed: {e}") + raise + + async def _execute_postgresql_query(self, connection_string: str, query: str) -> List[Dict]: + """Execute SQL query on PostgreSQL database.""" + try: + import psycopg2 + from psycopg2.extras import RealDictCursor + + conn = psycopg2.connect(connection_string) + cursor = conn.cursor(cursor_factory=RealDictCursor) + cursor.execute(query) + + results = cursor.fetchall() + data = [dict(row) for row in results] + + conn.close() + return data + + except Exception as e: + logger.error(f"PostgreSQL query execution failed: {e}") + raise + + async def _execute_mysql_query(self, connection_string: str, query: str) -> List[Dict]: + """Execute SQL query on MySQL database.""" + try: + import pymysql + import urllib.parse + + parsed = urllib.parse.urlparse(connection_string) + + conn = pymysql.connect( + host=parsed.hostname, + port=parsed.port or 3306, + user=parsed.username, + password=parsed.password, + database=parsed.path[1:], + cursorclass=pymysql.cursors.DictCursor + ) + + cursor = conn.cursor() + cursor.execute(query) + results = cursor.fetchall() + + conn.close() + return results + + except Exception as e: + logger.error(f"MySQL query execution failed: {e}") + raise + + def _prepare_chart_data(self, data: List[Dict], chart_type: str, fields: List[str]) -> Optional[Dict]: + """Prepare data for chart visualization.""" + if not data or not fields: + return None + + chart_type = chart_type.lower() + if chart_type not in self.config.SUPPORTED_CHART_TYPES: + chart_type = "bar" + + try: + # Extract labels and values + labels = [] + datasets = [] + + if len(fields) >= 1: + labels = [str(item.get(fields[0], "")) for item in data] + + if chart_type in ["pie", "doughnut"]: + # Single dataset for pie charts + values = [] + for item in data: + if len(fields) > 1: + try: + value = float(item.get(fields[1], 0) or 0) + except (ValueError, TypeError): + value = 1 + values.append(value) + else: + values.append(1) + + return { + "type": chart_type, + "labels": labels, + "data": values, + "backgroundColor": [ + f"rgba({50 + i * 30}, {100 + i * 25}, {200 + i * 20}, 0.7)" + for i in range(len(values)) + ] + } + else: + # Multiple datasets for other chart types + for i, field in enumerate(fields[1:], 1): + try: + dataset_values = [] + for item in data: + try: + value = float(item.get(field, 0) or 0) + except (ValueError, TypeError): + value = 0 + dataset_values.append(value) + + datasets.append({ + "label": field, + "data": dataset_values, + "backgroundColor": f"rgba({50 + i * 40}, {100 + i * 30}, 235, 0.6)", + "borderColor": f"rgba({50 + i * 40}, {100 + i * 30}, 235, 1.0)", + "borderWidth": 2 + }) + except Exception as e: + logger.warning(f"Error processing field {field}: {e}") + + return { + "type": chart_type, + "labels": labels, + "datasets": datasets + } + + except Exception as e: + logger.error(f"Chart preparation failed: {e}") + return None + + def get_insights_sync(self, request: InsightRequest) -> Dict[str, Any]: + """Synchronous wrapper for get_insights - for Django views.""" + try: + result = asyncio.run(self.get_insights(request)) + return result.to_dict() + except Exception as e: + logger.error(f"Synchronous insight generation failed: {e}") + return { + "status": "error", + "data": [], + "metadata": {}, + "error": str(e), + "language": "en" + } + + async def get_insights(self, request: InsightRequest) -> QueryResult: + """Main method to get database insights from natural language prompt.""" + try: + # Detect language + language = self._detect_language(request.prompt) if request.language == "auto" else request.language + + # Analyze database schema + schema = await self.analyze_database_schema(request) + + # Generate query plan using AI + query_response = await self.query_agent.run( + f"User prompt: {request.prompt}\nLanguage: {language}", + database_schema=schema + ) + + # Parse AI response + try: + query_plan = json.loads(query_response.output) + except json.JSONDecodeError: + # Fallback: extract SQL from response + sql_match = re.search(r'SELECT.*?;', query_response.output, re.IGNORECASE | re.DOTALL) + if sql_match: + query_plan = { + "sql_query": sql_match.group(0), + "chart_suggestion": "bar", + "expected_fields": [], + "language": language + } + else: + raise ValueError("Could not parse AI response") + + # Execute query + sql_query = query_plan.get("sql_query", "") + if not sql_query: + raise ValueError("No SQL query generated") + + data = await self._execute_query(sql_query) + + # Prepare chart data + chart_data = None + chart_type = request.chart_type or query_plan.get("chart_suggestion", "bar") + expected_fields = query_plan.get("expected_fields", []) + + if data and expected_fields: + chart_data = self._prepare_chart_data(data, chart_type, expected_fields) + elif data: + # Use first few fields if no specific fields suggested + available_fields = list(data[0].keys()) if data else [] + chart_data = self._prepare_chart_data(data, chart_type, available_fields[:3]) + + # Prepare result + return QueryResult( + status="success", + data=data[:request.limit] if data else [], + metadata={ + "total_count": len(data) if data else 0, + "query": sql_query, + "analysis": query_plan.get("analysis", ""), + "fields": expected_fields or (list(data[0].keys()) if data else []), + "database_type": self.db_connection.db_type.value if self.db_connection else "unknown" + }, + chart_data=chart_data, + language=language + ) + + except Exception as e: + logger.error(f"Insight generation failed: {e}") + return QueryResult( + status="error", + data=[], + metadata={}, + error=str(e), + language=language if 'language' in locals() else "en" + ) + + # # Static method for Django view compatibility + # @staticmethod + # def get_insights(django_request, prompt: str, **kwargs) -> Dict[str, Any]: + # """ + # Static method compatible with your Django view. + # This method signature matches what your view is calling. + # + # Args: + # django_request: Django HttpRequest object (not used but kept for compatibility) + # prompt: Natural language query string + # **kwargs: Additional parameters + # + # Returns: + # Dictionary with query results + # """ + # try: + # # Create system instance + # system = DatabaseInsightSystem() + # + # # Extract language from Django request if available + # language = "auto" + # if hasattr(django_request, 'LANGUAGE_CODE'): + # language = django_request.LANGUAGE_CODE + # + # # Create insight request + # insight_request = InsightRequest( + # prompt=prompt, + # language=language, + # use_django=True, + # **kwargs + # ) + # + # # Get insights synchronously + # return system.get_insights_sync(insight_request) + # + # except Exception as e: + # logger.error(f"Static get_insights failed: {e}") + # return { + # "status": "error", + # "data": [], + # "metadata": {}, + # "error": str(e), + # "language": language if 'language' in locals() else "en" + # } + + +# Convenience function for Django views (alternative approach) +def analyze_prompt_sync(prompt: str, **kwargs) -> Dict[str, Any]: + """ + Synchronous function to analyze a prompt and return insights. + Perfect for Django views. + + Args: + prompt: Natural language query + **kwargs: Additional parameters for InsightRequest + + Returns: + Dictionary with query results + """ + system = DatabaseInsightSystem() + request = InsightRequest(prompt=prompt, **kwargs) + return system.get_insights_sync(request) \ No newline at end of file diff --git a/haikalbot/haikal_kb.yaml b/haikalbot/haikal_kb.yaml index 00b23b7a..e5eef292 100644 --- a/haikalbot/haikal_kb.yaml +++ b/haikalbot/haikal_kb.yaml @@ -1,38 +1,2923 @@ metadata: system_name: Haikal - version: 1.0 - language: bilingual - roles: - - admin - - dealer - - branch - - supplier - + version: '1.0' + generated_from: Django features: - add_car: - description: Add a new car to inventory - steps: - - Navigate to the "Inventory" section - - Click "Add New Car" - - Enter required fields: VIN, Make, Model, Year - - Optional: Upload custom card, add warranty or insurance - - Click "Save" - permissions: ["admin", "dealer"] - related_terms: ["chassis", "هيكل", "السيارة"] + auth_login: + description: 'Persist a user id and a backend in the request. This way a user + doesn''t - create_invoice: - description: Create a sale or purchase invoice - steps: - - Go to the "Invoices" page - - Click "New Invoice" - - Choose Type: Sale or Purchase - - Select invoice_from and invoice_to - - Link existing order(s) - - Confirm and save - permissions: ["admin", "dealer"] - notes: Use sale for customer transactions, purchase for supplier buys + have to reauthenticate on every request. Note that data set during -glossary: - VIN: Vehicle Identification Number or chassis number (هيكل السيارة) - custom_card: Official car registration document (استمارة) - adjustment: Any cost added to or subtracted from an order \ No newline at end of file + the anonymous session is retained when the user logs in.' + source: django.contrib.auth.views.auth_login + type: view_function + auth_logout: + description: 'Remove the authenticated user''s ID from the request and flush their + session + + data.' + source: django.contrib.auth.views.auth_logout + type: view_function + csrf_protect: + description: 'This decorator adds CSRF protection in exactly the same way as + + CsrfViewMiddleware, but it can be used on a per view basis. Using both, or + + using the decorator multiple times, is harmless and efficient.' + source: django.contrib.auth.views.csrf_protect + type: view_function + get_current_site: + description: 'Check if contrib.sites is installed and return either the current + + ``Site`` object or a ``RequestSite`` object based on the request.' + source: allauth.socialaccount.views.get_current_site + type: view_function + get_user_model: + description: Return the User model that is active in this project. + source: appointment.views.get_user_model + type: view_function + login_not_required: + description: Decorator for views that allows access to unauthenticated requests. + source: debug_toolbar.views.login_not_required + type: view_function + login_required: + description: 'Decorator for views that checks that the user is logged in, redirecting + + to the log-in page if necessary.' + source: allauth.socialaccount.views.login_required + type: view_function + logout_then_login: + description: Log out the user if they are logged in. Then redirect to the login + page. + source: django.contrib.auth.views.logout_then_login + type: view_function + method_decorator: + description: Convert a function decorator into a method decorator + source: allauth.socialaccount.providers.google.views.method_decorator + type: view_function + never_cache: + description: Decorator that adds headers to a response so that it will never be + cached. + source: allauth.account.views.never_cache + type: view_function + redirect_to_login: + description: Redirect the user to the login page, passing the given 'next' page. + source: django.contrib.auth.views.redirect_to_login + type: view_function + resolve_url: + description: "Return a URL appropriate for the arguments passed.\n\nThe arguments\ + \ could be:\n\n * A model: the model's `get_absolute_url()` function will\ + \ be called.\n\n * A view name, possibly with arguments: `urls.reverse()`\ + \ will be used\n to reverse-resolve the name.\n\n * A URL, which will\ + \ be returned as-is." + source: django.contrib.auth.views.resolve_url + type: view_function + sensitive_post_parameters: + description: "Indicate which POST parameters used in the decorated view are sensitive,\n\ + so that those parameters can later be treated in a special way, for example\n\ + by hiding them when logging unhandled exceptions.\n\nAccept two forms:\n\n*\ + \ with specified parameters:\n\n @sensitive_post_parameters('password', 'credit_card')\n\ + \ def my_view(request):\n pw = request.POST['password']\n cc\ + \ = request.POST['credit_card']\n ...\n\n* without any specified parameters,\ + \ in which case consider all\n variables are sensitive:\n\n @sensitive_post_parameters()\n\ + \ def my_view(request)\n ..." + source: allauth.account.views.sensitive_post_parameters + type: view_function + update_session_auth_hash: + description: 'Updating a user''s password logs out all sessions for the user. + + + Take the current request and the updated user object from which the new + + session hash will be derived and update the session hash appropriately to + + prevent a password change from logging out the session from which the + + password was changed.' + source: django.contrib.auth.views.update_session_auth_hash + type: view_function + url_has_allowed_host_and_scheme: + description: 'Return ``True`` if the url uses an allowed host and a safe scheme. + + + Always return ``False`` on an empty url. + + + If ``require_https`` is ``True``, only ''https'' will be considered a valid + + scheme, as opposed to ''http'' and ''https'' with the default, ``False``. + + + Note: "True" doesn''t entail that a URL is "safe". It may still be e.g. + + quoted incorrectly. Ensure to also use django.utils.encoding.iri_to_uri() + + on the path component of untrusted URLs.' + source: django.contrib.auth.views.url_has_allowed_host_and_scheme + type: view_function + urlsafe_base64_decode: + description: 'Decode a base64 encoded string. Add back any trailing equal signs + that + + might have been stripped.' + source: appointment.views.urlsafe_base64_decode + type: view_function + urlunsplit: + description: 'Combine the elements of a tuple as returned by urlsplit() into a + + complete URL as a string. The data argument can be any five-item iterable. + + This may result in a slightly different, but equivalent URL, if the URL that + + was parsed originally had unnecessary delimiters (for example, a ? with an + + empty query; the RFC states that these are equivalent).' + source: django.contrib.auth.views.urlunsplit + type: view_function + shortcut: + description: Redirect to an object's page based on a content-type ID and an object + ID. + source: django.contrib.contenttypes.views.shortcut + type: view_function + serve: + description: "Serve static files below a given point in the directory structure\ + \ or\nfrom locations inferred from the staticfiles finders.\n\nTo use, put a\ + \ URL pattern such as::\n\n from django.contrib.staticfiles import views\n\ + \n path('', views.serve)\n\nin your URLconf.\n\nIt uses the django.views.static.serve()\ + \ view to serve the found files." + source: django.contrib.staticfiles.views.serve + type: view_function + BillDeleteView: + description: 'Deletes a specific BillModel instance based on the primary key (pk). + + This view requires the user to be logged in and have the appropriate + + permission to delete a bill. After the delete operation is successful, + + the user is redirected to the bill list view. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param pk: Primary key of the BillModel instance to be deleted. + + :type pk: int + + :return: Redirect to the bill list view after successful deletion. + + :rtype: HttpResponseRedirect' + source: inventory.views.BillDeleteView + type: view_function + CarTransferPreviewView: + description: "Handles the preview of car transfer details and ensures that a user\ + \ has appropriate\npermissions to view the transfer based on their associated\ + \ dealer.\n\nThis view checks if the car transfer's destination dealer matches\ + \ the current user's\nassociated dealer type. If not, the user is redirected\ + \ to the car detail page. Otherwise,\nit renders the transfer preview page with\ + \ the relevant transfer details.\n\n:param request: The HTTP request object\n\ + :type request: django.http.HttpRequest\n:param car_pk: The primary key of the\ + \ car related to the transfer\n:type car_pk: int\n:param transfer_pk: The primary\ + \ key of the car transfer to preview\n:type transfer_pk: int\n:return: An HTTP\ + \ response rendering the transfer preview page or redirecting\n to the\ + \ car detail page\n:rtype: django.http.HttpResponse" + source: inventory.views.CarTransferPreviewView + type: view_function + DealerSettingsView: + description: "Handles dealer settings view where dealers can update their financial\ + \ and\npayment account settings. This view ensures validation and reassigns\ + \ form\nfields dynamically based on the dealer's account roles.\n\n:param request:\ + \ The HTTP request object received from the client. This parameter\n contains\ + \ data including HTTP headers, session, and POST data if applicable.\n:type\ + \ request: HttpRequest\n:param pk: Primary key representing the dealer for whom\ + \ the settings are being\n retrieved or modified. This identifier is used\ + \ to fetch or update dealer-\n specific settings from the database.\n:type\ + \ pk: int\n:return: An HTTP response rendering the dealer settings form or redirecting\n\ + \ to the dealer detail view after successful form submission.\n:rtype: HttpResponse" + source: inventory.views.DealerSettingsView + type: view_function + GroupDeleteview: + description: "Handles the deletion of a specific group instance. This view ensures\ + \ that only\nauthenticated users can perform the deletion. Upon successful deletion,\ + \ a\nsuccess message is displayed, and the user is redirected to the group list\ + \ page.\n\n:param request: The HTTP request object that contains metadata about\ + \ the\n request context and user information. Must be an authenticated user.\n\ + :param pk: The primary key of the group instance to be deleted.\n It specifies\ + \ which group to retrieve and delete.\n:return: The HTTP response that redirects\ + \ the user to the group list page\n after the group is successfully deleted." + source: inventory.views.GroupDeleteview + type: view_function + GroupPermissionView: + description: "Handles the view for adding or modifying permissions of a specific\ + \ group. This view\nfetches the group based on the primary key passed as a parameter,\ + \ and either displays\na form for editing permissions or processes the submitted\ + \ permissions.\n\nIf the request method is POST, the permissions of the group\ + \ are cleared and updated\nbased on the submitted data. A success message is\ + \ displayed upon completion, and\nthe user is redirected to the group's detail\ + \ page.\n\nIn case of a GET request, the view renders the form pre-filled with\ + \ the group's\ncurrent permissions.\n\n:param request: The HTTP request object.\n\ + :type request: HttpRequest\n:param pk: The primary key of the group whose permissions\ + \ are being modified.\n:type pk: int\n:return: The HTTP response depending on\ + \ the request type. For GET requests, renders\n the permission form for the\ + \ specified group. For POST requests, clears and updates\n the group's permissions\ + \ and redirects to the group's detail page.\n:rtype: HttpResponse" + source: inventory.views.GroupPermissionView + type: view_function + JournalEntryDeleteView: + description: "Handles the deletion of a specific journal entry. This view facilitates\n\ + the deletion of a journal entry identified by its primary key (pk). If the\n\ + deletion is successful, the user is redirected to the list of journal entries\n\ + for the associated ledger. If the deletion cannot proceed, an error message\n\ + is displayed, and the user is redirected back to the journal entry list.\n\n\ + :param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key (pk) of the journal entry to be deleted.\n:type pk: int\n\ + :return: A rendered HTML response for GET requests or a redirect upon\n \ + \ successful/failed deletion.\n:rtype: HttpResponse" + source: inventory.views.JournalEntryDeleteView + type: view_function + JournalEntryTransactionsView: + description: "Handles the retrieval and display of journal entry transactions\ + \ for a specific journal\nentry instance. It retrieves the journal entry and\ + \ its associated transactions, ordering\nthe transactions by account code. The\ + \ data is then rendered using the specified template.\n\n:param request: The\ + \ HTTP request object.\n:type request: django.http.HttpRequest\n:param pk: The\ + \ primary key of the journal entry to be retrieved.\n:type pk: int\n:return:\ + \ An HTTP response with the rendered template, including the journal entry and\n\ + \ its transactions.\n:rtype: django.http.HttpResponse" + source: inventory.views.JournalEntryTransactionsView + type: view_function + LeadDeleteView: + description: 'Handles the deletion of a Lead along with its associated customer + and potentially + + a related user account in the system. Ensures proper permissions and login + + are required before the operation is performed. Provides a success message + + after the deletion is complete. + + + :param request: The HTTP request object specific to the current user. + + :param pk: The primary key identifier of the Lead to be deleted. + + :return: An HTTP redirect response to the lead list page.' + source: inventory.views.LeadDeleteView + type: view_function + OrganizationDeleteView: + description: 'Handles the deletion of an organization based on the provided primary + key (pk). Looks up + + the organization and its corresponding user by email, attempts to delete both, + and provides + + appropriate success or error feedback to the user. In case of failure, an error + message is shown, + + while successful deletion redirects to the organization list. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the organization to be deleted. + + :type pk: int + + :return: An HTTP response redirecting to the organization list view. + + :rtype: HttpResponseRedirect' + source: inventory.views.OrganizationDeleteView + type: view_function + PaymentCreateView: + description: "Handles the creation of a payment entry associated with an invoice\ + \ or bill. Validates\nthe payment data against the model's current state and\ + \ reflects the changes in\ninvoice or bill records. Provides appropriate error\ + \ messages for invalid conditions\nsuch as exceeding payable amounts or attempting\ + \ payment for already fully paid models.\n\nIf successfully processed, the payment\ + \ details are saved, and the model is updated\naccordingly. This view regulates\ + \ payment for dealer-associated entities while\nensuring the model consistency.\n\ + \nThe view renders a form to submit payment details, and pre-populates the form\ + \ fields\nwith default data for the associated model if necessary.\n\n:param\ + \ request: The HTTP request object containing user request data and session\n\ + \ information. This is required to handle the request and apply the appropriate\n\ + \ processing rules.\n:param pk: The primary key of the invoice or bill being\ + \ processed. It is used to\n load the appropriate model instance for payment\ + \ processing.\n:return: An HTTP response object. Depending on the circumstances,\ + \ the response may\n redirect to the detail view of the processed invoice\ + \ or bill, re-render the\n payment form with error messages or indicate success\ + \ in payment creation." + source: inventory.views.PaymentCreateView + type: view_function + PaymentDetailView: + description: "This function handles the detail view for a payment by fetching\ + \ a journal entry\nand its associated transactions. It ensures that the request\ + \ is authenticated\nand the user has permission to view the journal entry model.\n\ + \n:param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key of the journal entry for which details are to be fetched.\n\ + :type pk: int\n:return: An HTTP response rendering the payment details template\ + \ with the journal\n entry and its associated transactions.\n:rtype:\ + \ HttpResponse" + source: inventory.views.PaymentDetailView + type: view_function + PaymentListView: + description: 'Handles the view for listing payment information associated with + the journals of a specific + + entity. This view is protected to ensure only authenticated and authorized users + can + + access it. + + + The function retrieves the related dealer object based on the current user session, + extracts + + the associated entity, and fetches all journal entries linked to the entity. + This data is + + then passed into the template for rendering. + + + :param request: The HTTP request object containing user context. + + :type request: HttpRequest + + + :return: The rendered HTML response displaying the list of payments. + + :rtype: HttpResponse' + source: inventory.views.PaymentListView + type: view_function + UserDeleteview: + description: 'Deletes a user and its associated staff member from the database + and redirects + + to the user list page. Displays a success message upon successful deletion + + of the user. + + + :param request: The HTTP request object representing the incoming request. + + :param pk: The primary key (ID) of the staff member to be deleted. + + :return: An HTTP redirect to the user list page.' + source: inventory.views.UserDeleteview + type: view_function + UserGroupView: + description: "Handles the assignment of user groups to a specific staff member.\ + \ This view\nallows updating the groups a staff member belongs to via a form\ + \ submission.\nIt processes both GET and POST requests, ensuring appropriate\ + \ group\nassignments are managed and feedback is provided to the user via messages.\n\ + \n:param request: HttpRequest object representing the HTTP request.\n:type request:\ + \ HttpRequest\n:param pk: Primary key of the staff member whose groups are being\ + \ updated.\n:type pk: int\n\n:return: Renders the user group form for GET requests\ + \ or redirects to the\n user detail page after successful submission for\ + \ POST requests.\n:rtype: HttpResponse or HttpResponseRedirect" + source: inventory.views.UserGroupView + type: view_function + account_delete: + description: 'Handles the deletion of an account object identified by its primary + key (pk). Ensures + + that the user has the necessary permissions to perform the deletion. Successfully + + deletes the account and redirects to the account list view with a success message. + + + :param request: The HTTP request object representing the current user and request + data. + + :type request: HttpRequest + + :param pk: The primary key of the account to be deleted. + + :type pk: int + + :return: An HTTP redirect response to the account list page. + + :rtype: HttpResponse' + source: inventory.views.account_delete + type: view_function + accruable_net_summary: + description: 'A convenience function that computes current net summary of accruable + models. + + "net_30" group indicates the total amount is due in 30 days or less. + + "net_0" group indicates total past due amount. + + + :param queryset: Accruable Objects Queryset. + + :return: A dictionary summarizing current net summary 0,30,60,90,90+ bill open + amounts.' + source: django_ledger.views.accruable_net_summary + type: view_function + add_activity_to_customer: + description: "Adds an activity to a specific customer.\n\nThis function allows\ + \ adding a new activity to a customer identified by their\nprimary key (`pk`).\ + \ It retrieves the customer object, processes the form for\nactivity creation,\ + \ and saves it. If the request method is POST, it validates\nthe form and associates\ + \ the activity with the respective customer. Upon\nsuccessful save, it redirects\ + \ to the customer detail view. If the request\nmethod is GET, it renders a form\ + \ for activity submission.\n\n:param request: The HTTP request object containing\ + \ metadata about the request.\n:type request: HttpRequest\n:param pk: The primary\ + \ key of the customer to which the activity will be added.\n:type pk: int\n\ + :return: An HTTP response rendered with the activity form in the context of\n\ + \ the customer, or a redirect response to the customer detail view upon\n\ + \ successful activity creation.\n:rtype: HttpResponse" + source: inventory.views.add_activity_to_customer + type: view_function + add_activity_to_lead: + description: 'Handles the process of adding a new activity to a specific lead. + This includes + + rendering a form for user input, validating the form submission, and saving + the + + new activity if the input is valid. If the method is GET, it will simply + + render the form. If the method is POST, it checks the form validity, creates + + the activity, associates it with the lead, and saves it to the database. + + + :param request: The HTTP request object containing metadata about the request + made + + :param pk: The primary key of the lead to which the activity is to be added + + :return: An HTTP response that either renders the form or redirects to the lead + detail page' + source: inventory.views.add_activity_to_lead + type: view_function + add_note_to_customer: + description: "This function allows authenticated users to add a note to a specific\ + \ customer. The\nnote creation is handled by a form, which is validated after\ + \ submission. If the form\nis valid, the note is saved and associated with the\ + \ specified customer. On successful\nsubmission, the user is redirected to the\ + \ customer detail page. If the request method\nis not POST, an empty form is\ + \ rendered.\n\n:param request: The HTTP request object containing metadata and\ + \ the method type\n (e.g., GET, POST). Should be an HttpRequest\ + \ instance.\n:param customer_id: The unique identifier (UUID) of the customer\ + \ to whom the note\n is to be added.\n:return: An HTTP response.\ + \ In the case of a successful POST request, the function\n returns a\ + \ redirect response to the customer detail page. For a GET or invalid\n \ + \ POST request, it renders the note form template with context including\n\ + \ the form and customer." + source: inventory.views.add_note_to_customer + type: view_function + add_note_to_lead: + description: "Adds a note to a specific lead. This view is accessible only to\ + \ authenticated\nusers. The function handles the POST request to create a new\ + \ note associated\nwith a lead. Upon successful submission, the note is linked\ + \ to the provided lead,\nand the user is redirected to the lead's detail page.\ + \ If the request method is\nnot POST, it initializes an empty form to add a\ + \ note.\n\n:param request: The HTTP request object\n:type request: HttpRequest\n\ + :param pk: The primary key of the lead to which the note will be added\n:type\ + \ pk: int\n:return: HTTP response object. Redirects to the lead detail page\ + \ on successful\n note creation or renders the note form template for GET\ + \ or invalid POST requests.\n:rtype: HttpResponse" + source: inventory.views.add_note_to_lead + type: view_function + add_note_to_opportunity: + description: 'Add a note to a specific opportunity identified by its primary key. + + + This function handles the addition of a note to an existing opportunity + + by processing a POST request that includes the note content. If the note + + content is missing, an error message will be displayed. If the operation + + is successful, the note is saved, and a success message is returned. + + + :param request: The HTTP request object representing the client''s request. + + :param pk: The primary key of the Opportunity to which the note is to be added. + + :type pk: int + + :return: A redirect response to the detailed view of the opportunity.' + source: inventory.views.add_note_to_opportunity + type: view_function + apply_search_filters: + description: "Apply search filters to a queryset based on a query string.\n\n\ + This function filters the provided queryset by applying a Q object for all\n\ + CharField, TextField, or EmailField fields in the model. It checks if the\n\ + query exists within these fields using case-insensitive containment (icontains).\n\ + If the query string is empty or None, the original queryset is returned\nwithout\ + \ any modifications.\n\n:param queryset: The initial queryset to apply the search\ + \ filters on.\n:param query: The search string to match against the model fields.\ + \ If None\n or an empty string, no filtering is applied.\n:return: A filtered\ + \ queryset that satisfies the search condition." + source: inventory.views.apply_search_filters + type: view_function + assign_car_makes: + description: "Assigns car makes to a dealer.\n\nThis function handles both the\ + \ display and processing of a form that allows\na dealer to assign or modify\ + \ their associated car makes. If the request\nmethod is POST, it validates and\ + \ saves the submitted form data. If the\nmethod is not POST, it displays a form\ + \ prefilled with the existing car makes\nassociated with the dealer.\n\n:param\ + \ request: The HTTP request object containing information about the\n current\ + \ request.\n:type request: HttpRequest\n:return: A rendered HTML response for\ + \ GET requests, or a redirect to the\n dealer detail page after successful\ + \ form submission.\n:rtype: HttpResponse" + source: inventory.views.assign_car_makes + type: view_function + bank_account_delete: + description: "Delete a bank account entry from the database.\n\nThis view handles\ + \ the deletion of a bank account record specified by its\nprimary key (pk).\ + \ It renders a deletion confirmation page and processes the\ndeletion if the\ + \ request method is POST. Upon successful deletion, the user is\nredirected\ + \ to the list of bank accounts and a success message is displayed.\n\n:param\ + \ request: The HTTP request object representing the client's request.\n It\ + \ contains data such as request type (GET or POST) and session\n information.\n\ + :type request: HttpRequest\n:param pk: The primary key of the bank account model\ + \ instance to be deleted.\n:type pk: int\n:return: Returns an HttpResponse object.\ + \ This can be an HTTP redirect to the\n bank account list page upon successful\ + \ deletion, or an HTML response\n rendering the confirmation template if\ + \ accessed via GET.\n:rtype: HttpResponse" + source: inventory.views.bank_account_delete + type: view_function + bill_create: + description: "Handles creation of a bill in the system, including the validation\ + \ of input data,\ncreation of transactions associated with the bill, and rendering\ + \ of the appropriate\nresponse or form. Ensures the user creating the bill has\ + \ the necessary permissions and\ncorrect input parameters for successful bill\ + \ creation and itemization.\n\n:param request: Django HttpRequest object containing\ + \ metadata and data of the HTTP request.\n:type request: HttpRequest\n:return:\ + \ JsonResponse with success/error information if the request is processed,\n\ + \ or HttpResponse rendering the form for bill creation.\n:rtype: JsonResponse\ + \ or HttpResponse" + source: inventory.views.bill_create + type: view_function + bill_mark_as_approved: + description: "Marks a bill as approved for the given bill ID (primary key) if\ + \ it is not\nalready approved. This action can only be completed by an authorized\ + \ user\nwith the corresponding permissions. Once the bill is approved, it is\ + \ saved\nand a success message is displayed. If the bill is already approved,\ + \ an\nerror message is shown instead.\n\n:param request: HttpRequest object\ + \ representing the current request.\n:param pk: Primary key of the bill to be\ + \ marked as approved.\n:return: HttpResponseRedirect to the bill detail page\ + \ after the operation is\n completed or an error/success message is\ + \ set." + source: inventory.views.bill_mark_as_approved + type: view_function + bill_mark_as_paid: + description: 'Marks a bill as paid if certain conditions are met and updates the + ledger accordingly. + + + This function is used to mark a specific bill as paid. It verifies whether the + bill + + is already paid or if the amount paid matches the amount due. If the conditions + are + + met, it updates the bill''s status, locks the journal entries in the associated + ledger, + + posts them, and saves the changes. Appropriate success or error messages are + displayed + + to the user, and the user is redirected to the bill details page. + + + :param request: The HTTP request object containing details about the request + made by the user. + + :type request: HttpRequest + + :param pk: The primary key of the bill to be marked as paid. + + :type pk: int + + :return: A redirect response to the bill details page. + + :rtype: HttpResponseRedirect' + source: inventory.views.bill_mark_as_paid + type: view_function + car_history: + description: "Fetch and display the history of activities related to a specific\ + \ car.\n\nThis view retrieves a car object based on its primary key (pk) and\ + \ gathers\nall related activity records where the content type corresponds to\ + \ the car\nmodel. The retrieved data is then rendered into a specified HTML\ + \ template\nfor presentation.\n\n:param request: The HTTP request object that\ + \ contains metadata about the\n request made by the client.\n:type request:\ + \ HttpRequest\n:param pk: The primary key of the car object to retrieve.\n:type\ + \ pk: int\n:return: An HTTP response with the rendered car history HTML template,\n\ + \ including the car and its associated activities as context data.\n:rtype:\ + \ HttpResponse" + source: inventory.views.car_history + type: view_function + car_transfer_accept_reject: + description: "Handles the acceptance or rejection of a car transfer request. Based\ + \ on the\n`status` parameter obtained from the query string, the function updates\ + \ the\ntransfer status to either 'accept' or 'reject'. If the transfer is accepted,\ + \ it\ninitiates the car transfer process. Appropriate notifications are sent,\ + \ and\nactivity records are created for both acceptance and rejection actions.\n\ + \n:param request: The HTTP request object which contains metadata about\n \ + \ the request made by the user, including session and user information.\n:param\ + \ car_pk: The primary key of the car to be transferred.\n:param transfer_pk:\ + \ The primary key of the car transfer request to be processed.\n:return: An\ + \ HTTP redirect response to the 'inventory_stats' view." + source: inventory.views.car_transfer_accept_reject + type: view_function + car_transfer_approve: + description: 'Approves or cancels a car transfer request based on the action parameter. + This view + + handles the workflow of updating the transfer status and notifying the involved + parties + + accordingly. If the transfer is canceled, it reverts the car status to "available" + and + + deactivates the transfer record. If approved, it notifies the recipient dealer + and allows + + the request to proceed for further actions. + + + :param request: The HTTP request object containing metadata and the action parameter. + + :param car_pk: Primary key of the car involved in the transfer. + + :param transfer_pk: Primary key of the transfer request to approve or cancel. + + :return: An HTTP response redirecting to the car detail page of the specified + car.' + source: inventory.views.car_transfer_approve + type: view_function + create_estimate: + description: "Creates a new estimate based on the provided data and saves it.\ + \ This function processes\na POST request and expects a JSON payload containing\ + \ details of the estimate such as\ntitle, customer, terms, items, and quantities.\ + \ It validates the input data, ensures\navailability of stocks, and updates\ + \ or creates the corresponding estimate in the database.\n\nIf `pk` is provided,\ + \ it links the created estimate with an existing opportunity. It handles\nthe\ + \ reservation of cars and updates the stock information accordingly.\n\n:param\ + \ request: The HttpRequest object containing user-specific data and state.\n\ + :type request: HttpRequest\n:param pk: An optional primary key of the existing\ + \ opportunity to associate with\n the created estimate.\n:type pk:\ + \ int, optional\n:return: A JsonResponse object with status and either the created\ + \ quotation URL\n or an error message. If the request method is not\ + \ POST, it renders the\n estimate creation form.\n:rtype: JsonResponse\ + \ or HttpResponse" + source: inventory.views.create_estimate + type: view_function + create_sale_order: + description: "Creates a sale order for a given estimate and updates associated\ + \ item and car data.\n\nThis view is responsible for handling the submission\ + \ of a sale order form linked to\na specific estimate. It ensures that the estimate\ + \ is approved if not already, updates\nthe status of the related car items as\ + \ sold, and redirects to the estimate's detailed\nview upon successful creation\ + \ of the sale order. If the request method is not POST, it\nrenders the form\ + \ for the user to input sale order details, along with other contextual\ninformation\ + \ like estimate data and car finance details.\n\n:param request: HTTP request\ + \ object.\n:type request: HttpRequest\n:param pk: Primary key of the estimate\ + \ to create a sale order for.\n:type pk: int\n:return: An HTTP response rendering\ + \ the sale order form if the method is GET or invalid\n POST data, or redirects\ + \ to the estimate detail view upon successful creation.\n:rtype: HttpResponse" + source: inventory.views.create_sale_order + type: view_function + csrf_exempt: + description: Mark a view function as being exempt from the CSRF view protection. + source: rest_framework.views.csrf_exempt + type: view_function + custom_bad_request_view: + description: 'Handles custom bad request responses by rendering a specified HTML + + template for 400 status errors. + + + :return: Rendered HTTP response rendering the error page. + + :rtype: HttpResponse' + source: inventory.views.custom_bad_request_view + type: view_function + custom_error_view: + description: 'Handles rendering the custom error page for HTTP 500 errors. + + + This function is called when an unhandled exception occurs in the application. + It renders + + a predefined template for server errors, providing a consistent error page layout + + to the users. + + + :param request: The HTTP request instance which triggered the error. + + :type request: HttpRequest + + :param exception: The exception that caused the error to trigger. Defaults to + None. + + :type exception: Exception, optional + + :return: An HttpResponse object representing the rendered error page. + + :rtype: HttpResponse' + source: inventory.views.custom_error_view + type: view_function + custom_page_not_found_view: + description: 'Custom handler for 404 errors that renders a custom HTML page + + upon encountering a Page Not Found error. + + + :param request: The HttpRequest object associated with the request. + + :type request: HttpRequest + + :param exception: The exception that triggered the 404 error, if any. + + :type exception: Exception, optional + + :return: An HttpResponse object rendering the "errors/404.html" template. + + :rtype: HttpResponse' + source: inventory.views.custom_page_not_found_view + type: view_function + custom_permission_denied_view: + description: "Handles the custom view for 403 Forbidden permission denied errors.\ + \ This\nfunction renders a custom template for the error page when users are\ + \ denied\npermission to access a particular resource or view.\n\n:param request:\ + \ Django HttpRequest object containing metadata about the request.\n:type request:\ + \ HttpRequest\n:param exception: Optional exception that caused the 403 error.\n\ + \ Defaults to None.\n:type exception: Exception | None\n:return:\ + \ HttpResponse object rendering the 403.html error page.\n:rtype: HttpResponse" + source: inventory.views.custom_permission_denied_view + type: view_function + dealer_signup: + description: "Handles the dealer signup wizard process, including forms validation,\ + \ user and group\ncreation, permissions assignment, and dealer data storage.\ + \ This view supports GET\nrequests for rendering the signup wizard page, and\ + \ POST requests for processing\nsubmitted data. The function also differentiates\ + \ between requests sent with the\n\"Hx-Request\" header for partial form validations\ + \ in the wizard.\n\n:param request: The HTTP request object representing the\ + \ client request. It contains\n metadata about the request and the POST data\ + \ for creating the dealer.\n:type request: django.http.HttpRequest\n:param args:\ + \ Optional positional arguments passed to the view during the call.\n:type args:\ + \ tuple\n:param kwargs: Optional keyword arguments passed to the view during\ + \ the call.\n:type kwargs: dict\n:return: A rendered signup wizard page or a\ + \ JSON response indicating operation success\n or failure.\n:rtype: Union[django.http.HttpResponse,\ + \ django.http.JsonResponse]" + source: inventory.views.dealer_signup + type: view_function + decode: + description: "Decodes datamatrix barcodes in `image`.\n\nArgs:\n image: `numpy.ndarray`,\ + \ `PIL.Image` or tuple (pixels, width, height)\n symbols: iter(ZBarSymbol)\ + \ the symbol types to decode; if `None`, uses\n `zbar`'s default behaviour,\ + \ which is to decode all symbol types.\n\nReturns:\n :obj:`list` of :obj:`Decoded`:\ + \ The values decoded from barcodes." + source: inventory.views.decode + type: view_function + decodevin: + description: "Decodes a Vehicle Identification Number (VIN) using multiple decoding\ + \ functions\nand returns the decoded result. This function attempts to decode\ + \ the VIN using\nthree different functions in sequence and returns the first\ + \ successful result.\nIf none of the decoding functions produce a valid result,\ + \ the function returns None.\n\n:param vin: The Vehicle Identification Number\ + \ (VIN) to be decoded.\n:type vin: str\n:return: The decoded result if any decoding\ + \ function is successful, or None if\n all decoding attempts fail.\n\ + :rtype: dict | None" + source: api.views.decodevin + type: view_function + delete_customer: + description: 'Deletes a customer from the system and deactivates the corresponding + user account. + + + This function retrieves a customer object based on the primary key (pk), + + sets their active status to False, and deactivates the linked user account + + (using the email associated with the customer). After saving these changes, + + it displays a success message to the user and redirects to the customer list + page. + + + :param request: A HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: Primary key of the customer to be deleted. + + :type pk: int + + :return: A redirect response to the customer list page. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_customer + type: view_function + delete_note: + description: 'Deletes a specific note created by the currently logged-in user + and redirects + + to the lead detail page. If the note does not exist or the user is not the creator, + + a 404 error will be raised. A success message is displayed upon successful deletion + + of the note. + + + :param request: The HTTP request object associated with the current request. + + :type request: HttpRequest + + :param pk: The primary key of the note to be deleted. + + :type pk: int + + :return: An HTTP redirection to the lead detail page of the corresponding note''s + lead. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_note + type: view_function + delete_opportunity: + description: 'Deletes an opportunity object from the database and redirects to + the opportunity + + list view. If the opportunity with the specified primary key is not found, a + 404 + + error will be raised. Displays a success message after deletion. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the opportunity object to be deleted. + + :type pk: int + + :return: An HTTP response redirecting to the opportunity list view. + + :rtype: HttpResponse' + source: inventory.views.delete_opportunity + type: view_function + delete_vendor: + description: 'Deletes an existing vendor record from the database. + + + This function allows users with valid authentication to delete a specified + + vendor object by its primary key. Upon successful deletion, a success message + + is displayed, and the user is redirected to the vendor list page. + + + :param request: HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: Primary key of the vendor object to be deleted. + + :type pk: int + + :return: HttpResponseRedirect object for redirecting to the vendor list page. + + :rtype: HttpResponseRedirect' + source: inventory.views.delete_vendor + type: view_function + estimate_mark_as: + description: 'Marks an estimate with a specified status based on the requested + action and + + permissions. The marking possibilities include review, approval, rejection, + + completion, and cancellation. The function validates whether the estimate + + can transition to the desired status before updating it. It also handles + + notifications and updates related entities if required, such as car status + + changes upon cancellation. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the estimate to be marked. + + :type pk: int + + :return: A redirect response to the estimate detail view. + + :rtype: HttpResponseRedirect' + source: inventory.views.estimate_mark_as + type: view_function + get_car_finance_data: + description: "Fetches car finance data from the provided model instance and calculates\n\ + various related details including total prices, VAT, discounts, and\nadditional\ + \ services information.\n\n:param model: The model instance that contains car\ + \ and finance-related\n transaction data.\n:type model: Model\n:return: A\ + \ dictionary containing detailed information about the car finance\n transactions,\ + \ including individual car details, total quantity, calculated\n totals for\ + \ prices, VAT, discounts, additional services, and the VAT rate.\n:rtype: dict" + source: inventory.views.get_car_finance_data + type: view_function + get_item_transactions: + description: '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' + source: inventory.views.get_item_transactions + type: view_function + get_localdate: + description: "Fetches the current local date, optionally considering time zone\ + \ settings.\n\nThis function retrieves the current local date. If the global\ + \ settings indicate\nthe use of time zones (`USE_TZ` is True), the date is determined\ + \ based on the\nlocal time zone. Otherwise, the date is based on the system's\ + \ local time without\nany time zone consideration.\n\nReturns\n-------\ndate\n\ + \ The current local date, adjusted for the time zone setting if applicable." + source: django_ledger.views.get_localdate + type: view_function + get_make: + description: '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' + source: inventory.views.get_make + type: view_function + get_model: + description: "Searches for a car model associated with a specific make by performing\ + \ an\nexact case-insensitive match. If no match is found, it attempts to match\n\ + based on individual words split from the input item.\n\n:param item: A string\ + \ representing the name of the car model to search for.\n:param make: An object\ + \ representing the car manufacturer, which contains the\n associated car\ + \ models.\n:return: Returns the first car model object that matches the search\ + \ criteria,\n or None if no match is found." + source: inventory.views.get_model + type: view_function + get_object_or_404: + description: 'Use get() to return an object, or raise an Http404 exception if + the object + + does not exist. + + + klass may be a Model, Manager, or QuerySet object. All other passed + + arguments and keyword arguments are used in the get() query. + + + Like with QuerySet.get(), MultipleObjectsReturned is raised if more than + + one object is found.' + source: plans.views.get_object_or_404 + type: view_function + get_user_type: + description: "Determine the type of user based on the given request object.\n\n\ + This function identifies the type of user from the provided request. It\nchecks\ + \ if the user is a dealer, staff member, or neither based on the\nattributes\ + \ of the request object, returning the appropriate associated\nuser type or\ + \ `None` if the determination cannot be made.\n\n:param request: The HTTP request\ + \ object containing user and role\n information.\n:type request: Any\n:return:\ + \ A dealer object if the user is a dealer, a dealer object\n associated with\ + \ the staff member if the user is a staff member, or\n None if the user type\ + \ cannot be identified.\n:rtype: Optional[Any]" + source: api.views.get_user_type + type: view_function + inventory_stats_view: + description: "Handle the inventory stats view for a dealer, displaying detailed\ + \ information\nabout the cars, including counts grouped by make, model, and\ + \ trim.\n\nThe function fetches all cars associated with the authenticated dealer,\ + \ calculates\nthe inventory statistics (e.g., total cars, reserved cars, and\ + \ cars categorized\nby make, model, and trim levels), and prepares the data\ + \ to be rendered in a\ntemplate.\n\n:param request: The HTTP request object\ + \ from the client.\n:type request: HttpRequest\n:return: An HTTP response containing\ + \ structured inventory data rendered in the\n \"inventory/inventory_stats.html\"\ + \ template.\n:rtype: HttpResponse" + source: inventory.views.inventory_stats_view + type: view_function + invoice_create: + description: "Handles the creation of a new invoice associated with a given estimate.\ + \ It validates\nthe submitted data through a form, processes the invoice, updates\ + \ related models, and\nfinalizes the estimate. If successful, redirects to the\ + \ detailed view of the created\ninvoice. If the submitted data is invalid or\ + \ the request is not a POST request, renders\nthe invoice creation form.\n\n\ + :param request: The HTTP request object.\n:type request: HttpRequest\n:param\ + \ pk: The primary key of the estimate associated with the invoice.\n:type pk:\ + \ int\n:return: An HTTP response. Redirects to the \"invoice_detail\" view upon\ + \ successful invoice\n creation or renders the invoice creation form template\ + \ otherwise.\n:rtype: HttpResponse" + source: inventory.views.invoice_create + type: view_function + invoice_mark_as: + description: 'Marks an invoice as approved if it meets the required conditions. + + + This view is responsible for marking an invoice as approved based on the provided + + `mark` parameter. If the `mark` parameter is specified as "accept" and the invoice + + is eligible for approval, it gets approved and saved. Otherwise, an error message + + is displayed. The function requires the user to be logged in and to have the + + appropriate permission to change the InvoiceModel. + + + :param request: The HTTP request object containing metadata about the request. + + :type request: django.http.HttpRequest + + :param pk: The primary key of the invoice to be processed. + + :type pk: int + + :return: An HTTP redirect response to the invoice detail page after processing. + + :rtype: django.http.HttpResponse' + source: inventory.views.invoice_mark_as + type: view_function + lead_convert: + description: 'Converts a lead into a customer and creates a corresponding opportunity. + + + The function ensures that leads are not converted to customers more than once. + + If the lead has already been converted, an error is displayed. Otherwise, + + the lead is converted into a customer and a new opportunity is created. + + Upon successful conversion, the user is redirected to the lead list view + + and a success message is displayed. + + + :param request: The HTTP request object representing the user''s request. + + :type request: HttpRequest + + :param pk: The primary key of the lead to be converted. + + :type pk: int + + :return: An HTTP response redirecting to the lead list view. + + :rtype: HttpResponse' + source: inventory.views.lead_convert + type: view_function + lead_create: + description: 'Handles the creation of a new lead in the inventory system. + + + This function manages the rendering and processing of a form for creating a + new + + lead. It filters options for car models in the form based on the selected car + + make. For POST requests, it validates and processes the submitted form data + + and creates the lead if valid. It also creates a corresponding customer in the + + ledger system if one does not exist for the provided email. + + + :param request: The HTTP request object containing request data. + + :type request: HttpRequest + + + :return: An HTTP response object rendering the lead creation form or redirecting + to the lead list page upon success. + + :rtype: HttpResponse' + source: inventory.views.lead_create + type: view_function + lead_transfer: + description: 'Handles the transfer of a lead to a different staff member. This + view is accessible + + only to authenticated users with the ''inventory.change_lead'' permission. If + the + + request method is POST and the form data is valid, the lead''s staff is updated + + accordingly, saved, and a success message is displayed. Otherwise, an error + message + + is shown. In both cases, the user is redirected to the lead listing page. + + + :param request: The HTTP request object. + + :param pk: The primary key of the lead to be transferred. + + :return: An HTTP redirect response to the lead list view.' + source: inventory.views.lead_transfer + type: view_function + ledger_lock_all_journals: + description: 'Locks all journals associated with a specific ledger. If the ledger + is already locked, + + it will notify the user through an error message. Otherwise, it initiates the + locking of + + related journal entries, locks the ledger itself, and saves the changes to the + database. + + After the operation, it redirects the user to the journal entry list associated + with the + + ledger. + + + :param request: HttpRequest object representing the current request. + + :type request: HttpRequest + + :param entity_slug: The slug identifier of the entity. + + :type entity_slug: str + + :param pk: The primary key of the ledger to be locked. + + :type pk: int + + :return: HttpResponse redirecting to the journal entry list page of the locked + ledger. + + :rtype: HttpResponse' + source: inventory.views.ledger_lock_all_journals + type: view_function + ledger_post_all_journals: + description: 'Posts all journal entries associated with a ledger. This function + updates the ledger''s + + state to reflect that its journal entries have been posted. If the ledger is + already + + posted, an error message is displayed and the user is redirected. + + + :param request: The HTTP request object used for processing the action. + + :type request: HttpRequest + + :param entity_slug: A string representing the specific entity slug for the ledger + context. + + :type entity_slug: str + + :param pk: The primary key of the ledger to be posted. + + :type pk: int + + :return: A redirect to the journal entry list view for the specified ledger. + + :rtype: HttpResponseRedirect' + source: inventory.views.ledger_post_all_journals + type: view_function + ledger_unlock_all_journals: + description: 'Unlocks all journal entries associated with a specific ledger. This + function first checks if the + + ledger is locked. If it is already unlocked, it shows an error message and redirects + the user + + to the journal entry list page. If the ledger is locked, it unlocks the ledger, + saves changes, + + and iterates through all the locked journal entries within the ledger to unlock + them as well. + + Afterward, it redirects the user to the journal entry list page. + + + :param request: The HTTP request object containing user session and request + metadata. + + :type request: HttpRequest + + :param entity_slug: A unique string slug representing the specific entity or + organization context. + + :type entity_slug: str + + :param pk: The primary key of the ledger record to be unlocked. + + :type pk: int + + :return: A redirection to the journal entry list page for the specified ledger. + + :rtype: HttpResponseRedirect' + source: inventory.views.ledger_unlock_all_journals + type: view_function + ledger_unpost_all_journals: + description: "Unposts all journal entries for a specified ledger and marks the\ + \ ledger as unposted.\n\nThis function identifies a ledger by its primary key\ + \ (pk) and checks if it is\nalready posted. If the ledger is not posted, an\ + \ error message is displayed.\nIf it is posted, the function iterates through\ + \ its posted journal entries,\nmarks them as unposted, and saves the changes.\ + \ Finally, it marks the ledger itself\nas unposted and saves it.\n\n:param request:\ + \ The HTTP request object from the client.\n:type request: HttpRequest\n:param\ + \ entity_slug: A slug identifying the entity associated with the ledger.\n:type\ + \ entity_slug: str\n:param pk: The primary key of the ledger whose journal entries\ + \ are being unposted.\n:type pk: int\n:return: An HTTP redirect response object\ + \ directing the client to the journal entry list\n page for the specified\ + \ ledger.\n:rtype: HttpResponseRedirect" + source: inventory.views.ledger_unpost_all_journals + type: view_function + manage_reservation: + description: "Handles the management of a car reservation, providing options to\ + \ renew or\ncancel an existing reservation associated with the logged-in user.\n\ + \nRenewing a reservation extends the reservation period by an additional\n24\ + \ hours. Canceling a reservation deletes it and updates the car's status\nto\ + \ AVAILABLE. All actions require a valid reservation and are performed\nbased\ + \ on the current user's authentication and request type.\n\n:param request:\ + \ Django HttpRequest object representing the client's request.\n:type request:\ + \ HttpRequest\n:param reservation_id: The unique identifier of the car reservation\ + \ to manage.\n:type reservation_id: int\n:return: On POST requests, returns\ + \ an HTTP redirect or JSON response\n based on the action performed. On other\ + \ request methods,\n returns a JSON response with an error message.\n:rtype:\ + \ JsonResponse or HttpResponseRedirect" + source: inventory.views.manage_reservation + type: view_function + opportunity_update_status: + description: "Update the status and/or stage of a specific Opportunity instance.\ + \ This is a\nview function, which is generally tied to a URL endpoint in a Django\ + \ application.\nThe function is accessible only to authenticated users due to\ + \ the\n`@login_required` decorator.\n\nThe function retrieves the `Opportunity`\ + \ instance based on the primary key\nin the URL, updates the status or stage\ + \ of the instance based on query\nparameters in the request, saves the changes,\ + \ and then redirects to the\ndetail view of the `Opportunity`. Additionally,\ + \ a success message is displayed,\nand a custom header (`HX-Refresh`) is added\ + \ to the response.\n\n:param request: The HTTP request object containing details\ + \ of the user's\n request, such as query parameters for status and stage.\ + \ This is a\n mandatory parameter provided by Django's view function framework.\n\ + :type request: HttpRequest\n:param pk: The primary key of the `Opportunity`\ + \ instance to be updated.\n:type pk: int\n\n:return: An HTTP response object\ + \ that redirects to the updated Opportunity's\n detail page, with a success\ + \ message and the \"HX-Refresh\" header to trigger\n frontend behavior.\n\ + :rtype: HttpResponse" + source: inventory.views.opportunity_update_status + type: view_function + payment_mark_as_paid: + description: "Marks an invoice as paid if it meets the conditions of being fully\ + \ paid and eligible\nfor payment. Also ensures that related ledger journal entries\ + \ are locked and posted\nwhen the payment is marked successfully.\n\nThis function\ + \ is protected with both `login_required` and\n`permission_required` decorators,\ + \ ensuring that only logged-in users with\nappropriate permissions can execute\ + \ it.\n\n:param request: HttpRequest object containing metadata about the request.\n\ + :type request: HttpRequest\n:param pk: Primary key of the invoice to mark as\ + \ paid.\n:type pk: int\n:return: Redirect response to the invoice detail page.\n\ + :rtype: HttpResponseRedirect\n:raises: In case of an exception during the process,\ + \ an error message is\n displayed to the user through Django's messaging\ + \ framework." + source: inventory.views.payment_mark_as_paid + type: view_function + permission_required: + description: 'Decorator for views that checks whether a user has a particular + permission + + enabled, redirecting to the log-in page if necessary. + + If the raise_exception parameter is given the PermissionDenied exception + + is raised.' + source: inventory.views.permission_required + type: view_function + preview_sale_order: + description: 'Handles rendering of the sale order preview page for a specific + estimate. + + + This view retrieves an `EstimateModel` object based on the provided primary + + key (`pk`), fetches related car finance data, and renders the preview of the + + sale order associated with the given estimate. + + + :param request: The HTTP request object + + :type request: HttpRequest + + :param pk: The primary key of the `EstimateModel` to retrieve + + :type pk: int + + :return: HTTP response containing the rendered sale order preview page + + :rtype: HttpResponse' + source: inventory.views.preview_sale_order + type: view_function + redirect: + description: "Return an HttpResponseRedirect to the appropriate URL for the arguments\n\ + passed.\n\nThe arguments could be:\n\n * A model: the model's `get_absolute_url()`\ + \ function will be called.\n\n * A view name, possibly with arguments: `urls.reverse()`\ + \ will be used\n to reverse-resolve the name.\n\n * A URL, which will\ + \ be used as-is for the redirect location.\n\nIssues a temporary redirect by\ + \ default. Set permanent=True to issue a\npermanent redirect. Set preserve_request=True\ + \ to instruct the user agent\nto preserve the original HTTP method and body\ + \ when following the redirect." + source: appointment.views.redirect + type: view_function + render: + description: 'Return an HttpResponse whose content is filled with the result of + calling + + django.template.loader.render_to_string() with the passed arguments.' + source: django_pdf_actions.views.render + type: view_function + reserve_car: + description: '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.' + source: inventory.views.reserve_car + type: view_function + reserve_car_view: + description: 'Handles car reservation requests. This view requires the user to + be logged in + + and processes only POST requests. When invoked, it checks if the specified car + + is already reserved. If not, it proceeds to reserve the car for the user and + + sends an appropriate response. If the car is already reserved or if the request + + method is invalid, it provides corresponding error messages or responses. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param car_id: The unique identifier of the car to be reserved. + + :type car_id: int + + :return: A response indicating the result of the reservation process. + + :rtype: HttpResponse or JsonResponse' + source: inventory.views.reserve_car_view + type: view_function + sales_list_view: + description: "Handles the retrieval and presentation of a paginated list of item\ + \ transactions for\nsales, specific to the logged-in user's entity. Requires\ + \ the user to have appropriate\npermissions to view the list.\n\n:param request:\ + \ The HTTP request object containing metadata about the request,\n such as\ + \ HTTP method, user credentials, and sent data.\n:type request: HttpRequest\n\ + \n:return: An HTTP response with the rendered sales list page containing the\ + \ paginated\n item transactions specific to the user's entity.\n:rtype: HttpResponse" + source: inventory.views.sales_list_view + type: view_function + schedule_cancel: + description: 'Cancel a schedule by updating its status to "Canceled". The function + is protected + + by a login requirement, ensuring only authenticated users can execute it. It + + retrieves the schedule object by its primary key, updates its status, saves + the + + changes, and returns an HTTP response with status code 200. + + + :param request: The HTTP request object representing the user''s request. + + :type request: HttpRequest + + :param pk: The primary key of the schedule to be canceled. + + :type pk: int + + :return: An HTTP response object with a 200 status code upon successful execution. + + :rtype: HttpResponse' + source: inventory.views.schedule_cancel + type: view_function + schedule_lead: + description: "Handles the scheduling of a lead for an appointment.\n\nThis function\ + \ ensures that only staff members with the appropriate permissions\ncan schedule\ + \ leads. If the user is not a staff member or does not have the\nrequired inventory\ + \ permissions, they are redirected with an appropriate error\nmessage. The function\ + \ creates an appointment request and an associated appointment\nrecord upon\ + \ successful submission of the scheduling form.\n\n:param request: The HTTP\ + \ request object containing metadata about the request.\n:type request: HttpRequest\n\ + :param pk: The primary key of the lead to be scheduled.\n:type pk: int\n:return:\ + \ A rendered template or a redirection to another view based on the request\n\ + \ method and validity of the form submission.\n:rtype: HttpResponse" + source: inventory.views.schedule_lead + type: view_function + send_email_view: + description: 'View function to send an email for an estimate. This function allows + authenticated and + + authorized users to send an email containing the estimate details to the customer. + + The email includes a link to preview the estimate and a message template in + multiple + + languages. If the estimate does not have any associated items, the user will + receive + + an error message. Upon successfully sending the email, the estimate is marked + as reviewed. + + + :param request: The HttpRequest object containing metadata about the request. + + :type request: HttpRequest + + :param pk: The primary key of the estimate to be sent via email. + + :type pk: int + + :return: An HttpResponseRedirect to the estimate detail view. + + :rtype: HttpResponseRedirect + + :raises Http404: If the estimate with the given primary key does not exist.' + source: inventory.views.send_email_view + type: view_function + send_lead_email: + description: "Handles sending emails related to a lead. Supports creating drafts,\ + \ sending emails, and rendering\nan email composition page. Changes on the lead\ + \ or email objects, such as marking a lead as contacted\nor an email as sent,\ + \ are recorded in associated activity logs.\n\n:param request: The HTTP request\ + \ object. This contains user information, method type, and data such as\n \ + \ GET or POST payload used to draft or send the email appropriately.\n\ + \ Type: HttpRequest\n:param pk: The primary key of the lead to\ + \ which the email action is associated. It's used to retrieve\n the\ + \ lead object from the database.\n Type: int\n:param email_pk: Optional\ + \ parameter representing the primary key of an email template. When provided,\n\ + \ the respective email content is pre-populated into the email\ + \ composition form.\n Defaults to None.\n Type:\ + \ Optional[int]\n:return: When successfully sending an email, redirects the\ + \ user to the lead list page. On draft mode\n or email composition rendering,\ + \ a response object is returned to render the respective page.\n Type:\ + \ HttpResponse" + source: inventory.views.send_lead_email + type: view_function + set_bill_payment: + description: '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' + source: inventory.views.set_bill_payment + type: view_function + set_invoice_payment: + description: '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' + source: inventory.views.set_invoice_payment + type: view_function + switch_language: + description: "Switches the current language context for the user based on a request\ + \ parameter, modifies the URL path\naccordingly, and updates session and cookies\ + \ with the new language preference.\n\n:param request: The HTTP request object\ + \ containing information about the user request, including\n \ + \ the desired language to switch to and the referring URL.\n \ + \ - \"GET\" dictionary is accessed to retrieve the desired language parameter.\n\ + \ - \"META\" dictionary is used to extract the referring URL\ + \ via \"HTTP_REFERER\".\n\n:return: A redirect response object pointing to the\ + \ modified URL with the updated language\n preference, if the requested\ + \ language is valid. Otherwise, redirects to the default URL." + source: inventory.views.switch_language + type: view_function + urlparse: + description: 'Parse a URL into 6 components: + + :///;?# + + + The result is a named 6-tuple with fields corresponding to the + + above. It is either a ParseResult or ParseResultBytes object, + + depending on the type of the url parameter. + + + The username, password, hostname, and port sub-components of netloc + + can also be accessed as attributes of the returned object. + + + The scheme argument provides the default value of the scheme + + component when no scheme is found in url. + + + If allow_fragments is False, no attempt is made to separate the + + fragment component from the previous component, which can be either + + path or query. + + + Note that % escapes are not expanded.' + source: inventory.views.urlparse + type: view_function + urlunparse: + description: 'Put a parsed URL back together again. This may result in a + + slightly different, but equivalent URL, if the URL that was parsed + + originally had redundant delimiters, e.g. a ? with an empty query + + (the draft states that these are equivalent).' + source: inventory.views.urlunparse + type: view_function + vendorDetailView: + description: 'Fetches and renders the detail view for a specific vendor. + + + This function retrieves a vendor object based on the primary key (pk) + + provided in the URL, ensures the user is logged in to access the + + view, and renders the vendor detail template with the vendor''s context. + + + :param request: The HTTP request object. + + :type request: HttpRequest + + :param pk: The primary key of the vendor to retrieve. + + :type pk: int + + :return: An HttpResponse object containing the rendered vendor detail page. + + :rtype: HttpResponse' + source: inventory.views.vendorDetailView + type: view_function + sync_user_email_addresses: + description: 'Keep user.email in sync with user.emailaddress_set. + + + Under some circumstances the user.email may not have ended up as + + an EmailAddress record, e.g. in the case of manually created admin + + users.' + source: allauth.account.views.sync_user_email_addresses + type: view_function + escape: + description: 'Return the given text with ampersands, quotes and angle brackets + encoded + + for use in HTML. + + + Always escape input, even if it''s already escaped and marked as such. + + This may result in double-escaping. If this is a concern, use + + conditional_escape() instead.' + source: debug_toolbar.views.escape + type: view_function + render_panel: + description: Render the contents of a panel + source: debug_toolbar.views.render_panel + type: view_function + render_with_toolbar_language: + description: Force any rendering within the view to use the toolbar's language. + source: debug_toolbar.views.render_with_toolbar_language + type: view_function + require_show_toolbar: + description: 'Async compatible decorator to restrict access to a view + + based on the Debug Toolbar''s visibility settings.' + source: debug_toolbar.views.require_show_toolbar + type: view_function + exception_handler: + description: 'Returns the response that should be used for any given exception. + + + By default we handle the REST framework `APIException`, and also + + Django''s built-in `Http404` and `PermissionDenied` exceptions. + + + Any unhandled exceptions may return `None`, which will cause a 500 error + + to be raised.' + source: rest_framework.views.exception_handler + type: view_function + get_view_description: + description: 'Given a view instance, return a textual description to represent + the view. + + This name is used in the browsable API, and in OPTIONS responses. + + + This function is the default for the `VIEW_DESCRIPTION_FUNCTION` setting.' + source: rest_framework.views.get_view_description + type: view_function + get_view_name: + description: 'Given a view instance, return a textual name to represent the view. + + This name is used in the browsable API, and in OPTIONS responses. + + + This function is the default for the `VIEW_NAME_FUNCTION` setting.' + source: rest_framework.views.get_view_name + type: view_function + patch_vary_headers: + description: 'Add (or update) the "Vary" header in the given HttpResponse object. + + newheaders is a list of header names that should be in "Vary". If headers + + contains an asterisk, then "Vary" header will consist of a single asterisk + + ''*''. Otherwise, existing headers in "Vary" aren''t removed.' + source: rest_framework.views.patch_vary_headers + type: view_function + smart_str: + description: 'Return a string representing ''s''. Treat bytestrings using the + ''encoding'' + + codec. + + + If strings_only is True, don''t convert (some) non-string-like objects.' + source: rest_framework.views.smart_str + type: view_function + add_message: + description: Attempt to add a message to the request using the 'messages' app. + source: django_ledger.views.add_message + type: view_function + format_html: + description: 'Similar to str.format, but pass all arguments through conditional_escape(), + + and call mark_safe() on the result. This function should be used instead + + of str.format or % interpolation to build up small HTML fragments.' + source: django_ledger.views.format_html + type: view_function + get_localtime: + description: "Retrieve the local time based on the specified timezone.\n\nDetermines\ + \ the local time depending on whether timezone support (``USE_TZ``) is\nenabled\ + \ in global settings. If timezone support is enabled, it uses the\n`localtime`\ + \ function to obtain the local time according to the provided\ntimezone. If\ + \ timezone support is disabled, it defaults to the current time\nwith respect\ + \ to the given timezone.\n\nParameters\n----------\ntz : timezone or None, optional\n\ + \ The timezone to determine the local time. If `None`, defaults to the system\n\ + \ timezone.\n\nReturns\n-------\ndatetime\n A datetime object representing\ + \ the calculated local time." + source: django_ledger.views.get_localtime + type: view_function + make_aware: + description: Make a naive datetime.datetime in a given time zone aware. + source: django_ledger.views.make_aware + type: view_function + analyze_prompt_sync: + description: "Synchronous function to analyze a prompt and return insights.\n\ + Perfect for Django views.\n\nArgs:\n prompt: Natural language query\n \ + \ **kwargs: Additional parameters for InsightRequest\n\nReturns:\n Dictionary\ + \ with query results" + source: haikalbot.views.analyze_prompt_sync + type: view_function + export_to_csv: + description: "Export data to CSV format.\n\nArgs:\n data: Data to export\n\ + \ filename: Base filename without extension\n\nReturns:\n HttpResponse:\ + \ Response with CSV file" + source: haikalbot.views.export_to_csv + type: view_function + export_to_excel: + description: "Export data to Excel format.\n\nArgs:\n data: Data to export\n\ + \ filename: Base filename without extension\n\nReturns:\n HttpResponse:\ + \ Response with Excel file" + source: haikalbot.views.export_to_excel + type: view_function + appointment_client_information: + description: 'This view function handles client information submission for an + appointment. + + + :param request: The request instance. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID of the appointment request. + + :return: The rendered HTML page.' + source: appointment.views.appointment_client_information + type: view_function + appointment_request: + description: 'This view function handles requests to book an appointment for a + service. + + + :param request: The request instance. + + :param service_id: The ID of the service. + + :param staff_member_id: The ID of the staff member. + + :return: The rendered HTML page.' + source: appointment.views.appointment_request + type: view_function + appointment_request_submit: + description: 'This view function handles the submission of the appointment request + form. + + + :param request: The request instance. + + :return: The rendered HTML page.' + source: appointment.views.appointment_request_submit + type: view_function + check_day_off_for_staff: + description: 'Check if the given staff member is off on the given date. + + :param staff_member: The staff member to check. + + :param date: The date to check.' + source: appointment.views.check_day_off_for_staff + type: view_function + check_q_cluster: + description: 'Checks if Django Q is properly installed and configured in the Django + settings. + + If ''django_q'' is not in INSTALLED_APPS, it warns about both ''django_q'' not + being installed + + and ''Q_CLUSTER'' likely not being configured. + + If ''django_q'' is installed but ''Q_CLUSTER'' is not configured, it only warns + about ''Q_CLUSTER''. + + Returns True if configurations are correct, otherwise False.' + source: appointment.views.check_q_cluster + type: view_function + convert_str_to_date: + description: "Convert a date string to a datetime date object.\n\n:param date_str:\ + \ The date string.\n Supported formats include `%Y-%m-%d` (like\ + \ \"2023-12-31\") and `%Y/%m/%d` (like \"2023/12/31\").\n:return: The converted\ + \ `datetime.date`'s object." + source: appointment.views.convert_str_to_date + type: view_function + create_and_save_appointment: + description: 'Create and save a new appointment based on the provided appointment + request and client data. + + + :param ar: The appointment request associated with the new appointment. + + :param client_data: The data of the client making the appointment. + + :param appointment_data: Additional data for the appointment, including phone + number, address, etc. + + :param request: The request object. + + :return: The newly created appointment.' + source: appointment.views.create_and_save_appointment + type: view_function + create_appointment: + description: 'This function creates a new appointment and redirects to the payment + page or the thank-you page. + + + :param request: The request instance. + + :param appointment_request_obj: The AppointmentRequest instance. + + :param client_data: The client data. + + :param appointment_data: The appointment data. + + :return: The redirect response.' + source: appointment.views.create_appointment + type: view_function + create_payment_info_and_get_url: + description: 'Create a new payment information entry for the appointment and return + the payment URL. + + + :param appointment: The appointment to create the payment information for. + + :return: The payment URL for the appointment.' + source: appointment.views.create_payment_info_and_get_url + type: view_function + default_thank_you: + description: 'This view function handles the default thank you page. + + + :param request: The request instance. + + :param appointment_id: The ID of the appointment. + + :return: The rendered HTML page.' + source: appointment.views.default_thank_you + type: view_function + enter_verification_code: + description: 'This view function handles the submission of the email verification + code. + + + :param request: The request instance. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID of the appointment request. + + :return: The rendered HTML page.' + source: appointment.views.enter_verification_code + type: view_function + force_str: + description: 'Similar to smart_str(), except that lazy instances are resolved + to + + strings, rather than kept as lazy objects. + + + If strings_only is True, don''t convert (some) non-string-like objects.' + source: appointment.views.force_str + type: view_function + get_appointment_data_from_session: + description: 'Get the appointment data from the session variables. + + Retrieves the phone, want_reminder, address, and additional_info stored in the + session. + + + :param request: The Django HttpRequest object. + + :return: The appointment data retrieved from the session.' + source: appointment.views.get_appointment_data_from_session + type: view_function + get_appointments_and_slots: + description: "Get appointments and available slots for a given date and service.\n\ + \nIf a service is provided, the function retrieves appointments for that service\ + \ on the given date.\nOtherwise, it retrieves all appointments for the given\ + \ date.\n\n:param date_: datetime.date, the date for which to retrieve appointments\ + \ and available slots\n:param service: Service, the service for which to retrieve\ + \ appointments\n:return: tuple, a tuple containing two elements:\n - A queryset\ + \ of appointments for the given date and service (if provided).\n - A list\ + \ of available time slots on the given date, excluding booked appointments." + source: appointment.views.get_appointments_and_slots + type: view_function + get_available_slots_ajax: + description: 'This view function handles AJAX requests to get available slots + for a selected date. + + + :param request: The request instance. + + :return: A JSON response containing available slots, selected date, an error + flag, and an optional error message.' + source: appointment.views.get_available_slots_ajax + type: view_function + get_available_slots_for_staff: + description: 'Calculate the available time slots for a given date and a staff + member. + + + :param date: The date for which to calculate the available slots + + :param staff_member: The staff member for which to calculate the available slots + + :return: A list of available time slots as strings in the format ''%I:%M %p'' + like [''10:00 AM'', ''10:30 AM'']' + source: appointment.views.get_available_slots_for_staff + type: view_function + get_current_timezone_name: + description: Return the name of the currently active time zone. + source: appointment.views.get_current_timezone_name + type: view_function + get_generic_context_with_extra: + description: Get the generic context for the admin pages with extra context. + source: appointment.views.get_generic_context_with_extra + type: view_function + get_locale: + description: 'Get the current locale based on the user''s language settings, without + the country code. + + Used in the JavaScript files. + + Can''t use the lang_country format because it is not supported. + + + :return: The current locale as a string (language code only)' + source: appointment.views.get_locale + type: view_function + get_next_available_date_ajax: + description: 'This view function handles AJAX requests to get the next available + date for a service. + + + :param request: The request instance. + + :param service_id: The ID of the service. + + :return: A JSON response containing the next available date.' + source: appointment.views.get_next_available_date_ajax + type: view_function + get_non_working_days_for_staff: + description: Return the non-working days for the given staff member or an empty + list if the staff member does not exist. + source: appointment.views.get_non_working_days_for_staff + type: view_function + get_user_by_email: + description: 'Get a user by their email address. + + + :param email: The email address of the user. + + :return: The user with the specified email address, if found; otherwise, None.' + source: appointment.views.get_user_by_email + type: view_function + get_website_name: + description: 'Get the website name from the configuration file. + + + :return: The website name' + source: appointment.views.get_website_name + type: view_function + get_weekday_num_from_date: + description: Get the number of the weekday from the given date. + source: appointment.views.get_weekday_num_from_date + type: view_function + handle_existing_email: + description: 'Handle the case where the email already exists in the database. + + + Sends a verification email to the existing user and redirects the client to + enter the verification code. + + + If the email is already in the session variables, clean the session variables + for email, phone, want_reminder, + + address, and additional_info. Then, store the current email, phone, want_reminder, + address, and additional_info + + in the session. + + + :param request: The Django HttpRequest object. + + :param client_data: The data of the client for the appointment. + + :param appointment_data: The data of the appointment. + + :param appointment_request_id: The ID of the appointment request. + + :param id_request: The unique ID for the appointment request. + + :return: The redirect response to enter the verification code.' + source: appointment.views.handle_existing_email + type: view_function + has_required_email_settings: + description: Check if all required email settings are configured and warn if any + are missing. + source: appointment.views.has_required_email_settings + type: view_function + is_working_day: + description: Check if the given day is a working day for the staff member. + source: appointment.views.is_working_day + type: view_function + json_response: + description: Return a generic JSON response. + source: appointment.views.json_response + type: view_function + login: + description: 'Persist a user id and a backend in the request. This way a user + doesn''t + + have to reauthenticate on every request. Note that data set during + + the anonymous session is retained when the user logs in.' + source: appointment.views.login + type: view_function + notify_admin_about_appointment: + description: Notify the admin and the staff member about a new appointment request. + source: appointment.views.notify_admin_about_appointment + type: view_function + notify_admin_about_reschedule: + description: Notify the admin and the staff member about a rescheduled appointment + request. + source: appointment.views.notify_admin_about_reschedule + type: view_function + redirect_to_payment_or_thank_you_page: + description: 'This function redirects to the payment page or the thank-you page + based on the configuration. + + + :param appointment: The Appointment instance. + + :return: The redirect response.' + source: appointment.views.redirect_to_payment_or_thank_you_page + type: view_function + require_ajax: + description: 'Decorator to require a request to be AJAX. + + Usage: @require_ajax' + source: appointment.views.require_ajax + type: view_function + send_reschedule_confirmation_email: + description: Send a rescheduling confirmation email to the client. + source: appointment.views.send_reschedule_confirmation_email + type: view_function + send_thank_you_email: + description: 'Send a thank-you email to the client for booking an appointment. + + + :param ar: The appointment request associated with the booking. + + :param user: The user who booked the appointment. + + :param email: The email address of the client. + + :param appointment_details: Additional details about the appointment (default + None). + + :param account_details: Additional details about the account (default None). + + :param request: The request object. + + :return: None' + source: appointment.views.send_thank_you_email + type: view_function + verify_user_and_login: + description: 'This function verifies the user''s email and logs the user in. + + + :param request: The request instance. + + :param user: The User instance. + + :param code: The verification code.' + source: appointment.views.verify_user_and_login + type: view_function + import_name: + description: import module given by str or pass the module if it is not str + source: plans.views.import_name + type: view_function + plan_validation: + description: 'Validates validator that represents quotas in a given system + + :param user: + + :param plan: + + :return:' + source: plans.views.plan_validation + type: view_function + Site: + description: Site(id, domain, name) + source: sites.models.Site + type: model_class + LogEntry: + description: LogEntry(id, action_time, user, content_type, object_id, object_repr, + action_flag, change_message) + source: admin.models.LogEntry + type: model_class + Permission: + description: "The permissions system provides a way to assign permissions to specific\n\ + users and groups of users.\n\nThe permission system is used by the Django admin\ + \ site, but may also be\nuseful in your own code. The Django admin site uses\ + \ permissions as follows:\n\n - The \"add\" permission limits the user's\ + \ ability to view the \"add\" form\n and add an object.\n - The \"change\"\ + \ permission limits a user's ability to view the change\n list, view the\ + \ \"change\" form and change an object.\n - The \"delete\" permission limits\ + \ the ability to delete an object.\n - The \"view\" permission limits the\ + \ ability to view an object.\n\nPermissions are set globally per type of object,\ + \ not per specific object\ninstance. It is possible to say \"Mary may change\ + \ news stories,\" but it's\nnot currently possible to say \"Mary may change\ + \ news stories, but only the\nones she created herself\" or \"Mary may only\ + \ change news stories that have a\ncertain status or publication date.\"\n\n\ + The permissions listed above are automatically created for each model." + source: auth.models.Permission + type: model_class + Group: + description: 'Groups are a generic way of categorizing users to apply permissions, + or + + some other label, to those users. A user can belong to any number of + + groups. + + + A user in a group automatically has all the permissions granted to that + + group. For example, if the group ''Site editors'' has the permission + + can_edit_home_page, any user in that group will have that permission. + + + Beyond permissions, groups are a convenient way to categorize users to + + apply some label, or extended functionality, to them. For example, you + + could create a group ''Special users'', and you could write code that would + + do special things to those users -- such as giving them access to a + + members-only portion of your site, or sending them members-only email + + messages.' + source: auth.models.Group + type: model_class + User: + description: 'Users within the Django authentication system are represented by + this + + model. + + + Username and password are required. Other fields are optional.' + source: auth.models.User + type: model_class + ContentType: + description: ContentType(id, app_label, model) + source: contenttypes.models.ContentType + type: model_class + Session: + description: 'Django provides full support for anonymous sessions. The session + + framework lets you store and retrieve arbitrary data on a + + per-site-visitor basis. It stores data on the server side and + + abstracts the sending and receiving of cookies. Cookies contain a + + session ID -- not the data itself. + + + The Django sessions framework is entirely cookie-based. It does + + not fall back to putting session IDs in URLs. This is an intentional + + design decision. Not only does that behavior make URLs ugly, it makes + + your site vulnerable to session-ID theft via the "Referer" header. + + + For complete documentation on using Sessions in your code, consult + + the sessions documentation that is shipped with Django (also available + + on the Django web site).' + source: sessions.models.Session + type: model_class + DealersMake: + description: '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' + source: inventory.models.DealersMake + type: model_class + VatRate: + description: VatRate(id, rate, is_active, created_at) + source: inventory.models.VatRate + type: model_class + CarMake: + description: CarMake(id_car_make, name, slug, arabic_name, logo, is_sa_import, + car_type) + source: inventory.models.CarMake + type: model_class + CarModel: + description: CarModel(id_car_model, id_car_make, name, arabic_name, slug) + source: inventory.models.CarModel + type: model_class + CarSerie: + description: CarSerie(id_car_serie, id_car_model, name, arabic_name, year_begin, + year_end, generation_name, slug) + source: inventory.models.CarSerie + type: model_class + CarTrim: + description: CarTrim(id_car_trim, id_car_serie, name, arabic_name, start_production_year, + end_production_year, slug) + source: inventory.models.CarTrim + type: model_class + CarEquipment: + description: CarEquipment(id_car_equipment, id_car_trim, name, arabic_name, year_begin, + slug) + source: inventory.models.CarEquipment + type: model_class + CarSpecification: + description: CarSpecification(id_car_specification, name, arabic_name, id_parent, + slug) + source: inventory.models.CarSpecification + type: model_class + CarSpecificationValue: + description: CarSpecificationValue(id_car_specification_value, id_car_trim, id_car_specification, + value, unit) + source: inventory.models.CarSpecificationValue + type: model_class + CarOption: + description: CarOption(id_car_option, name, arabic_name, id_parent, slug) + source: inventory.models.CarOption + type: model_class + CarOptionValue: + description: CarOptionValue(id_car_option_value, id_car_option, id_car_equipment, + value, unit, is_base) + source: inventory.models.CarOptionValue + type: model_class + AdditionalServices: + description: AdditionalServices(id, name, arabic_name, description, price, taxable, + uom, dealer, item) + source: inventory.models.AdditionalServices + type: model_class + Car: + description: Car(id, slug, created_at, updated_at, item_model, vin, dealer, vendor, + id_car_make, id_car_model, year, id_car_serie, id_car_trim, status, stock_type, + remarks, mileage, receiving_date, hash) + source: inventory.models.Car + type: model_class + CarTransfer: + description: CarTransfer(id, car, from_dealer, to_dealer, transfer_date, quantity, + remarks, status, is_approved, active, created_at, updated_at) + source: inventory.models.CarTransfer + type: model_class + CarReservation: + description: CarReservation(id, car, reserved_by, reserved_at, reserved_until) + source: inventory.models.CarReservation + type: model_class + CarFinance: + description: CarFinance(id, car, cost_price, selling_price, discount_amount, is_sold) + source: inventory.models.CarFinance + type: model_class + ExteriorColors: + description: ExteriorColors(id, name, arabic_name, rgb) + source: inventory.models.ExteriorColors + type: model_class + InteriorColors: + description: InteriorColors(id, name, arabic_name, rgb) + source: inventory.models.InteriorColors + type: model_class + CarColors: + description: CarColors(id, car, exterior, interior) + source: inventory.models.CarColors + type: model_class + CustomCard: + description: CustomCard(id, car, custom_number, custom_date) + source: inventory.models.CustomCard + type: model_class + CarLocation: + description: CarLocation(id, car, owner, showroom, description, created_at, updated_at) + source: inventory.models.CarLocation + type: model_class + CarRegistration: + description: CarRegistration(id, car, plate_number, text1, text2, text3, registration_date) + source: inventory.models.CarRegistration + type: model_class + Dealer: + description: Dealer(id, user, crn, vrn, arabic_name, name, phone_number, address, + logo, entity, joined_at, updated_at, slug) + source: inventory.models.Dealer + type: model_class + Staff: + description: Staff(id, staff_member, dealer, name, arabic_name, phone_number, + staff_type, active, created, updated, slug) + source: inventory.models.Staff + type: model_class + Customer: + description: Customer(id, dealer, customer_model, user, title, first_name, last_name, + gender, dob, email, national_id, phone_number, address, active, image, created, + updated, slug) + source: inventory.models.Customer + type: model_class + Organization: + description: Organization(id, dealer, customer_model, user, name, arabic_name, + crn, vrn, email, phone_number, address, logo, active, created, updated, slug) + source: inventory.models.Organization + type: model_class + Representative: + description: Representative(id, dealer, name, arabic_name, id_number, phone_number, + email, address) + source: inventory.models.Representative + type: model_class + Lead: + description: Lead(id, dealer, first_name, last_name, email, phone_number, address, + lead_type, customer, organization, id_car_make, id_car_model, source, channel, + staff, status, next_action, next_action_date, is_converted, converted_at, created, + updated, slug) + source: inventory.models.Lead + type: model_class + Schedule: + description: Schedule(id, name, func, hook, args, kwargs, schedule_type, minutes, + repeats, next_run, cron, task, cluster, intended_date_kwarg) + source: django_q.models.Schedule + type: model_class + LeadStatusHistory: + description: LeadStatusHistory(id, lead, old_status, new_status, changed_by, changed_at) + source: inventory.models.LeadStatusHistory + type: model_class + Opportunity: + description: Opportunity(id, dealer, customer, organization, car, crn, vrn, salary, + priority, stage, staff, lead, probability, amount, expected_revenue, vehicle_of_interest_make, + vehicle_of_interest_model, expected_close_date, created, updated, estimate, + slug, loss_reason) + source: inventory.models.Opportunity + type: model_class + Notes: + description: Notes(id, dealer, content_type, object_id, note, created_by, created, + updated) + source: inventory.models.Notes + type: model_class + Tasks: + description: Tasks(id, dealer, content_type, object_id, title, description, due_date, + completed, assigned_to, created_by, created, updated) + source: inventory.models.Tasks + type: model_class + Email: + description: Email(id, content_type, object_id, from_email, to_email, subject, + message, status, created_by, created, updated) + source: inventory.models.Email + type: model_class + Activity: + description: Activity(id, dealer, content_type, object_id, activity_type, notes, + created_by, created, updated) + source: inventory.models.Activity + type: model_class + Notification: + description: Notification(id, user, message, is_read, created) + source: inventory.models.Notification + type: model_class + Vendor: + description: Vendor(id, dealer, crn, vrn, vendor_model, arabic_name, name, contact_person, + phone_number, email, address, logo, active, created_at, slug) + source: inventory.models.Vendor + type: model_class + Payment: + description: Payment(id, amount, payment_method, reference_number, payment_date) + source: inventory.models.Payment + type: model_class + Refund: + description: Refund(id, payment, amount, reason, refund_date) + source: inventory.models.Refund + type: model_class + UserActivityLog: + description: UserActivityLog(id, user, action, timestamp) + source: inventory.models.UserActivityLog + type: model_class + SaleOrder: + description: SaleOrder(id, estimate, invoice, payment_method, comments, formatted_order_id, + opportunity, customer, car, agreed_price, down_payment_amount, trade_in_value, + trade_in_vehicle, loan_amount, total_paid_amount, remaining_balance, status, + order_date, expected_delivery_date, actual_delivery_date, cancelled_date, cancellation_reason, + created_at, updated_at, created_by, last_modified_by) + source: inventory.models.SaleOrder + type: model_class + CustomGroup: + description: CustomGroup(id, name, dealer, group) + source: inventory.models.CustomGroup + type: model_class + DealerSettings: + description: DealerSettings(id, dealer, invoice_cash_account, invoice_prepaid_account, + invoice_unearned_account, bill_cash_account, bill_prepaid_account, bill_unearned_account, + additional_info) + source: inventory.models.DealerSettings + type: model_class + PaymentHistory: + description: PaymentHistory(id, user, user_data, amount, currency, payment_date, + status, payment_method, transaction_id, invoice_number, order_reference, gateway_response, + gateway_name, description, is_recurring, billing_email, billing_address, created_at, + updated_at) + source: inventory.models.PaymentHistory + type: model_class + CarVIN: + description: CarVIN(id, vin, created) + source: api.models.CarVIN + type: model_class + EmailAddress: + description: EmailAddress(id, user, email, verified, primary) + source: account.models.EmailAddress + type: model_class + EmailConfirmation: + description: EmailConfirmation(id, email_address, created, sent, key) + source: account.models.EmailConfirmation + type: model_class + SocialApp: + description: SocialApp(id, provider, provider_id, name, client_id, secret, key, + settings) + source: socialaccount.models.SocialApp + type: model_class + SocialAccount: + description: SocialAccount(id, user, provider, uid, last_login, date_joined, extra_data) + source: socialaccount.models.SocialAccount + type: model_class + SocialToken: + description: SocialToken(id, app, account, token, token_secret, expires_at) + source: socialaccount.models.SocialToken + type: model_class + Request: + description: Request(id, path, query_params, raw_body, body, method, start_time, + view_name, end_time, time_taken, encoded_headers, meta_time, meta_num_queries, + meta_time_spent_queries, pyprofile, prof_file, num_sql_queries) + source: silk.models.Request + type: model_class + Response: + description: Response(id, request, status_code, raw_body, body, encoded_headers) + source: silk.models.Response + type: model_class + SQLQuery: + description: SQLQuery(id, query, start_time, end_time, time_taken, identifier, + request, traceback, analysis) + source: silk.models.SQLQuery + type: model_class + Profile: + description: Profile(id, name, start_time, end_time, request, time_taken, file_path, + line_num, end_line_num, func_name, exception_raised, dynamic) + source: silk.models.Profile + type: model_class + Token: + description: The default authorization token model. + source: authtoken.models.Token + type: model_class + TokenProxy: + description: Proxy mapping pk to user pk for use in admin. + source: authtoken.models.TokenProxy + type: model_class + BankAccountModel: + description: Base Bank Account Model Implementation + source: django_ledger.models.BankAccountModel + type: model_class + AccountModel: + description: Base Account Model from Account Model Abstract Class + source: django_ledger.models.AccountModel + type: model_class + ChartOfAccountModel: + description: Base ChartOfAccounts Model + source: django_ledger.models.ChartOfAccountModel + type: model_class + CustomerModel: + description: Base Customer Model Implementation + source: django_ledger.models.CustomerModel + type: model_class + UnitOfMeasureModel: + description: Base UnitOfMeasureModel from Abstract. + source: django_ledger.models.UnitOfMeasureModel + type: model_class + ItemTransactionModel: + description: Base ItemTransactionModel from Abstract. + source: django_ledger.models.ItemTransactionModel + type: model_class + ItemModel: + description: Base ItemModel from Abstract. + source: django_ledger.models.ItemModel + type: model_class + LedgerModel: + description: Base LedgerModel from Abstract. + source: django_ledger.models.LedgerModel + type: model_class + EntityUnitModel: + description: Base Model Class for EntityUnitModel + source: django_ledger.models.EntityUnitModel + type: model_class + VendorModel: + description: Base Vendor Model Implementation + source: django_ledger.models.VendorModel + type: model_class + EntityModel: + description: Entity Model Base Class From Abstract + source: django_ledger.models.EntityModel + type: model_class + EntityStateModel: + description: Entity State Model Base Class from Abstract. + source: django_ledger.models.EntityStateModel + type: model_class + EntityManagementModel: + description: EntityManagement Model Base Class From Abstract + source: django_ledger.models.EntityManagementModel + type: model_class + BillModel: + description: Base BillModel from Abstract. + source: django_ledger.models.BillModel + type: model_class + InvoiceModel: + description: Base Invoice Model from Abstract. + source: django_ledger.models.InvoiceModel + type: model_class + TransactionModel: + description: Base Transaction Model From Abstract. + source: django_ledger.models.TransactionModel + type: model_class + JournalEntryModel: + description: Journal Entry Model Base Class From Abstract + source: django_ledger.models.JournalEntryModel + type: model_class + PurchaseOrderModel: + description: Purchase Order Base Model + source: django_ledger.models.PurchaseOrderModel + type: model_class + EstimateModel: + description: Base EstimateModel Class. + source: django_ledger.models.EstimateModel + type: model_class + ClosingEntryModel: + description: ClosingEntryModel(created, updated, markdown_notes, uuid, entity_model, + ledger_model, closing_date, posted) + source: django_ledger.models.ClosingEntryModel + type: model_class + ClosingEntryTransactionModel: + description: Base ClosingEntryModel Class + source: django_ledger.models.ClosingEntryTransactionModel + type: model_class + ImportJobModel: + description: Transaction Import Job Model Base Class. + source: django_ledger.models.ImportJobModel + type: model_class + StagedTransactionModel: + description: Staged Transaction Model Base Class. + source: django_ledger.models.StagedTransactionModel + type: model_class + ChatLog: + description: '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' + source: haikalbot.models.ChatLog + type: model_class + AnalysisCache: + description: 'Model to cache analysis results for performance optimization. + + + This model stores cached results of model analysis operations to improve + + performance for repeated queries. It includes a hash of the prompt, user + + information, dealer ID, timestamps, and the cached result in JSON format. + + + :ivar prompt_hash: MD5 hash of the prompt + dealer_id + language + + :type prompt_hash: str + + :ivar user: The user who made the request (optional) + + :type user: User + + :ivar dealer_id: ID of the dealer associated with this cache entry + + :type dealer_id: int + + :ivar created_at: When the cache entry was created + + :type created_at: datetime + + :ivar updated_at: When the cache entry was last updated + + :type updated_at: datetime + + :ivar expires_at: When the cache entry expires + + :type expires_at: datetime + + :ivar result: The cached analysis result + + :type result: dict' + source: haikalbot.models.AnalysisCache + type: model_class + Service: + description: 'Represents a service provided by the appointment system. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.Service + type: model_class + StaffMember: + description: StaffMember(id, user, slot_duration, lead_time, finish_time, appointment_buffer_time, + work_on_saturday, work_on_sunday, created_at, updated_at) + source: appointment.models.StaffMember + type: model_class + AppointmentRequest: + description: 'Represents an appointment request made by a client. + + + Author: Adams Pierre David + + Since: 1.0.0' + source: appointment.models.AppointmentRequest + type: model_class + AppointmentRescheduleHistory: + description: AppointmentRescheduleHistory(id, appointment_request, date, start_time, + end_time, staff_member, reason_for_rescheduling, reschedule_status, id_request, + created_at, updated_at) + source: appointment.models.AppointmentRescheduleHistory + type: model_class + Appointment: + description: 'Represents an appointment made by a client. It is created when the + client confirms the appointment request. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.Appointment + type: model_class + Config: + description: 'Represents configuration settings for the appointment system. There + can only be one Config object in the database. + + If you want to change the settings, you must edit the existing Config object. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.1.0' + source: appointment.models.Config + type: model_class + PaymentInfo: + description: 'Represents payment information for an appointment. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.0.0' + source: appointment.models.PaymentInfo + type: model_class + EmailVerificationCode: + description: 'Represents an email verification code for a user when the email + already exists in the database. + + + Author: Adams Pierre David + + Version: 1.1.0 + + Since: 1.1.0' + source: appointment.models.EmailVerificationCode + type: model_class + PasswordResetToken: + description: 'Represents a password reset token for users. + + + Author: Adams Pierre David + + Version: 3.x.x + + Since: 3.x.x' + source: appointment.models.PasswordResetToken + type: model_class + DayOff: + description: DayOff(id, staff_member, start_date, end_date, description, created_at, + updated_at) + source: appointment.models.DayOff + type: model_class + WorkingHours: + description: WorkingHours(id, staff_member, day_of_week, start_time, end_time, + created_at, updated_at) + source: appointment.models.WorkingHours + type: model_class + Task: + description: Task(id, task_name, task_params, task_hash, verbose_name, priority, + run_at, repeat, repeat_until, queue, attempts, failed_at, last_error, locked_by, + locked_at, creator_content_type, creator_object_id) + source: background_task.models.Task + type: model_class + Success: + description: Success(id, name, func, hook, args, kwargs, result, group, cluster, + started, stopped, success, attempt_count) + source: django_q.models.Success + type: model_class + Failure: + description: Failure(id, name, func, hook, args, kwargs, result, group, cluster, + started, stopped, success, attempt_count) + source: django_q.models.Failure + type: model_class + OrmQ: + description: OrmQ(id, key, payload, lock) + source: django_q.models.OrmQ + type: model_class + Plan: + description: Plan(id, order, created, updated_at, name, description, default, + available, visible, customized, url) + source: plans.models.Plan + type: model_class + BillingInfo: + description: BillingInfo(id, created, updated_at, user, tax_number, name, street, + zipcode, city, country, shipping_name, shipping_street, shipping_zipcode, shipping_city) + source: plans.models.BillingInfo + type: model_class + UserPlan: + description: UserPlan(id, created, updated_at, user, plan, expire, active) + source: plans.models.UserPlan + type: model_class + Pricing: + description: Pricing(id, created, updated_at, name, period, url) + source: plans.models.Pricing + type: model_class + PlanPricing: + description: PlanPricing(id, created, updated_at, plan, pricing, price, order, + has_automatic_renewal, visible) + source: plans.models.PlanPricing + type: model_class + Quota: + description: Quota(id, order, created, updated_at, codename, name, unit, description, + is_boolean, url) + source: plans.models.Quota + type: model_class + PlanQuota: + description: PlanQuota(id, created, updated_at, plan, quota, value) + source: plans.models.PlanQuota + type: model_class + Order: + description: Order(id, created, updated_at, user, flat_name, plan, pricing, completed, + plan_extended_from, plan_extended_until, amount, tax, currency, status) + source: plans.models.Order + type: model_class + Invoice: + description: Invoice(id, created, updated_at, user, order, number, full_number, + type, issued, issued_duplicate, selling_date, payment_date, unit_price_net, + quantity, total_net, total, tax_total, tax, rebate, currency, item_description, + buyer_name, buyer_street, buyer_zipcode, buyer_city, buyer_country, buyer_tax_number, + shipping_name, shipping_street, shipping_zipcode, shipping_city, shipping_country, + require_shipment, issuer_name, issuer_street, issuer_zipcode, issuer_city, issuer_country, + issuer_tax_number) + source: plans.models.Invoice + type: model_class + RecurringUserPlan: + description: RecurringUserPlan(id, created, updated_at, user_plan, token, payment_provider, + pricing, amount, tax, currency, renewal_triggered_by, _has_automatic_renewal_backup_deprecated, + token_verified, card_expire_year, card_expire_month, card_masked_number) + source: plans.models.RecurringUserPlan + type: model_class + Sequence: + description: Sequence(name, last) + source: sequences.models.Sequence + type: model_class + ExportPDFSettings: + description: ExportPDFSettings(id, created, modified, title, active, page_size, + items_per_page, page_margin_mm, font_name, header_font_size, body_font_size, + logo, header_background_color, grid_line_color, grid_line_width, show_header, + show_logo, show_export_time, show_page_numbers, rtl_support, content_alignment, + header_alignment, title_alignment, table_spacing, max_chars_per_line) + source: django_pdf_actions.models.ExportPDFSettings + type: model_class + CompletedTask: + description: CompletedTask(id, task_name, task_params, task_hash, verbose_name, + priority, run_at, repeat, repeat_until, queue, attempts, failed_at, last_error, + locked_by, locked_at, creator_content_type, creator_object_id) + source: background_task.models.CompletedTask + type: model_class +glossary: {} diff --git a/haikalbot/management/commands/generate_support_yaml.py b/haikalbot/management/commands/generate_support_yaml.py index 37cc89e0..cfdee27e 100644 --- a/haikalbot/management/commands/generate_support_yaml.py +++ b/haikalbot/management/commands/generate_support_yaml.py @@ -5,9 +5,11 @@ import importlib import yaml import os from django.conf import settings +from django.template.loaders.app_directories import get_app_template_dirs + class Command(BaseCommand): - help = "Generate YAML support knowledge base from Django views and models" + help = "Generate YAML support knowledge base from Django views, models, and templates" def handle(self, *args, **kwargs): output_file = "haikal_kb.yaml" @@ -18,6 +20,8 @@ class Command(BaseCommand): "generated_from": "Django", }, "features": {}, + "user_workflows": {}, # New section for step-by-step instructions + "templates": {}, "glossary": {} } @@ -41,6 +45,49 @@ class Command(BaseCommand): all_models.append((model._meta.app_label, model.__name__, extract_doc(model))) return all_models + def get_all_templates(): + template_dirs = get_app_template_dirs('templates') + templates = [] + + for template_dir in template_dirs: + app_name = os.path.basename(os.path.dirname(os.path.dirname(template_dir))) + for root, dirs, files in os.walk(template_dir): + for file in files: + if file.endswith(('.html', '.htm', '.txt')): + rel_path = os.path.relpath(os.path.join(root, file), template_dir) + with open(os.path.join(root, file), 'r', encoding='utf-8', errors='ignore') as f: + try: + content = f.read() + # Extract template comment documentation if it exists + doc = "" + if '{# DOC:' in content and '#}' in content: + doc_parts = content.split('{# DOC:') + for part in doc_parts[1:]: + if '#}' in part: + doc += part.split('#}')[0].strip() + "\n" + except Exception as e: + self.stdout.write(self.style.WARNING(f"Error reading {rel_path}: {e}")) + continue + + templates.append((app_name, rel_path, doc.strip())) + return templates + + # Look for workflow documentation files + def get_workflow_docs(): + workflows = {} + workflow_dir = os.path.join(settings.BASE_DIR, 'docs', 'workflows') + if os.path.exists(workflow_dir): + for file in os.listdir(workflow_dir): + if file.endswith('.yaml') or file.endswith('.yml'): + try: + with open(os.path.join(workflow_dir, file), 'r') as f: + workflow_data = yaml.safe_load(f) + for workflow_name, workflow_info in workflow_data.items(): + workflows[workflow_name] = workflow_info + except Exception as e: + self.stdout.write(self.style.WARNING(f"Error reading workflow file {file}: {e}")) + return workflows + # Extract views for app, mod in get_all_views_modules(): for name, obj in inspect.getmembers(mod, inspect.isfunction): @@ -52,6 +99,25 @@ class Command(BaseCommand): "type": "view_function" } + # Look for @workflow decorator or WORKFLOW tag in docstring + if hasattr(obj, 'workflow_steps') or 'WORKFLOW:' in doc: + workflow_name = name.replace('_', ' ').title() + steps = [] + + if hasattr(obj, 'workflow_steps'): + steps = obj.workflow_steps + elif 'WORKFLOW:' in doc: + workflow_section = doc.split('WORKFLOW:')[1].strip() + steps_text = workflow_section.split('\n') + steps = [step.strip() for step in steps_text if step.strip()] + + if steps: + kb["user_workflows"][workflow_name] = { + "description": f"How to {name.replace('_', ' ')}", + "steps": steps, + "source": f"{app}.views.{name}" + } + # Extract models for app, name, doc in get_all_model_classes(): if doc: @@ -61,6 +127,52 @@ class Command(BaseCommand): "type": "model_class" } + # Extract templates + for app, template_path, doc in get_all_templates(): + template_id = f"{app}:{template_path}" + if doc: # Only include templates with documentation + kb["templates"][template_id] = { + "description": doc, + "path": template_path, + "app": app + } + + # Add workflow documentation + kb["user_workflows"].update(get_workflow_docs()) + + # Add manual workflow examples if no workflows were found + if not kb["user_workflows"]: + kb["user_workflows"] = { + "Add New Car": { + "description": "How to add a new car to the inventory", + "steps": [ + "Navigate to the Inventory section by clicking 'Inventory' in the main menu", + "Click the 'Add Car' button in the top right corner", + "Enter the VIN number or scan it using the barcode scanner", + "Select the car make from the dropdown menu", + "Select the car series from the available options", + "Select the trim level for the car", + "Fill in additional details like color, mileage, and price", + "Click 'Save' to add the car to inventory, or 'Save & Add Another' to continue adding cars" + ], + "source": "manual_documentation" + }, + "Create New Invoice": { + "description": "How to create a new invoice", + "steps": [ + "Navigate to the Finance section by clicking 'Finance' in the main menu", + "Click the 'Invoices' tab", + "Click the 'Create New Invoice' button", + "Select a customer from the dropdown or click 'Add New Customer'", + "Select the car(s) to include in the invoice", + "Add any additional services or parts by clicking 'Add Item'", + "Set the payment terms and due date", + "Click 'Save Draft' to save without finalizing, or 'Finalize Invoice' to complete" + ], + "source": "manual_documentation" + } + } + with open(output_file, "w", encoding="utf-8") as f: yaml.dump(kb, f, allow_unicode=True, sort_keys=False) diff --git a/haikalbot/migrations/0001_initial.py b/haikalbot/migrations/0001_initial.py new file mode 100644 index 00000000..944b6da5 --- /dev/null +++ b/haikalbot/migrations/0001_initial.py @@ -0,0 +1,50 @@ +# Generated by Django 5.2.1 on 2025-06-12 16:25 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('inventory', '__first__'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AnalysisCache', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('prompt_hash', models.CharField(db_index=True, max_length=64)), + ('dealer_id', models.IntegerField(blank=True, db_index=True, null=True)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('expires_at', models.DateTimeField(db_index=True)), + ('result', models.JSONField()), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name_plural': 'Analysis caches', + 'indexes': [models.Index(fields=['prompt_hash', 'dealer_id'], name='haikalbot_a_prompt__b98e1e_idx'), models.Index(fields=['expires_at'], name='haikalbot_a_expires_e790cd_idx')], + }, + ), + migrations.CreateModel( + name='ChatLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user_message', models.TextField()), + ('chatbot_response', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True, db_index=True)), + ('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer')), + ], + options={ + 'ordering': ['-timestamp'], + 'indexes': [models.Index(fields=['dealer', 'timestamp'], name='haikalbot_c_dealer__6f8d63_idx')], + }, + ), + ] diff --git a/haikalbot/model_analyzer_refactored.zip b/haikalbot/model_analyzer_refactored.zip deleted file mode 100644 index 46ea217c..00000000 Binary files a/haikalbot/model_analyzer_refactored.zip and /dev/null differ diff --git a/haikalbot/run_haikal_qa.py b/haikalbot/run_haikal_qa.py deleted file mode 100644 index cd026642..00000000 --- a/haikalbot/run_haikal_qa.py +++ /dev/null @@ -1,19 +0,0 @@ -from langchain.document_loaders import TextLoader -from langchain.indexes import VectorstoreIndexCreator -from langchain.chat_models import ChatOpenAI -from langchain.chains import RetrievalQA - -# Load YAML doc -loader = TextLoader("haikal_kb.yaml") -index = VectorstoreIndexCreator().from_loaders([loader]) - -# Setup QA chain -qa = RetrievalQA.from_chain_type( - llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0), - retriever=index.vectorstore.as_retriever() -) - -# Ask a question -query = "How do I add a new invoice?" -response = qa.run(query) -print("Answer:", response) \ No newline at end of file diff --git a/haikalbot/utils/ask_haikalbot.py b/haikalbot/utils/ask_haikalbot.py new file mode 100644 index 00000000..bcf11aea --- /dev/null +++ b/haikalbot/utils/ask_haikalbot.py @@ -0,0 +1,77 @@ +from langchain_community.document_loaders import TextLoader +from langchain.indexes import VectorstoreIndexCreator +from langchain_community.llms import Ollama +from langchain.chains import RetrievalQA +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain.prompts import PromptTemplate +# from django.conf import settings + + +# Load YAML doc +loader = TextLoader("haikal_kb.yaml") + +# Create embeddings model +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +# Create an instance of VectorstoreIndexCreator with the embeddings +index_creator = VectorstoreIndexCreator(embedding=embeddings) + +# Then call the from_loaders method on the instance +index = index_creator.from_loaders([loader]) + +# Create LLM instance +llm = Ollama(model="qwen3:8b", temperature=0.3) + +# Define a custom prompt template for instructional responses +template = """ +You are Haikal, an assistant for the car inventory management system. +Your goal is to provide clear step-by-step instructions for users to complete tasks. + +Use the following pieces of context to answer the question at the end. +If you don't know the answer, just say you don't know. Don't try to make up an answer. + +Context: +{context} + +Question: {question} + +Provide a clear step-by-step guide with numbered instructions. Include: +1. Where to click in the interface +2. What to enter or select +3. Any buttons to press to complete the action +4. Any alternatives or shortcuts if available + +Helpful Step-by-Step Instructions:""" + +PROMPT = PromptTemplate( + template=template, + input_variables=["context", "question"] +) + +# Setup QA chain +qa = RetrievalQA.from_chain_type( + llm=llm, + chain_type="stuff", + retriever=index.vectorstore.as_retriever(), + return_source_documents=True, + chain_type_kwargs={"prompt": PROMPT} +) + +# Function to run a query +def ask_haikal(query): + response = qa.invoke({"query": query}) + print("\n" + "="*50) + print(f"Question: {query}") + print("="*50) + print("\nAnswer:") + print(response["result"]) + print("\nSources:") + for doc in response["source_documents"]: + print(f"- {doc.metadata.get('source', 'Unknown source')}") + print("="*50) + return response["result"] + +# # Example query +# if __name__ == "__main__": +# query = "How do I add a new car to the inventory? answer in Arabic" +# ask_haikal(query) diff --git a/haikalbot/views.py b/haikalbot/views.py index 2bebda15..9467391d 100644 --- a/haikalbot/views.py +++ b/haikalbot/views.py @@ -4,12 +4,12 @@ from django.shortcuts import render from django.utils.translation import gettext as _ from django.views import View import logging - from .ai_agent import analyze_prompt +# from .haikal_agent import DatabaseInsightSystem, analyze_prompt_sync from .utils.export import export_to_excel, export_to_csv logger = logging.getLogger(__name__) - +# analyze_prompt_ai = DatabaseInsightSystem class HaikalBot(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): @@ -33,11 +33,9 @@ class HaikalBot(LoginRequiredMixin, View): if not prompt: error_msg = _("Prompt is required.") if language != "ar" else "الاستعلام مطلوب." return JsonResponse({"status": "error", "error": error_msg}, status=400) - try: result = analyze_prompt(prompt) - # Handle export requests if data is available if export and result.get("status") == "success" and result.get("data"): try: if export == "excel": diff --git a/locale/ar/LC_MESSAGES/django.mo b/locale/ar/LC_MESSAGES/django.mo index 2bad53ac..57675332 100644 Binary files a/locale/ar/LC_MESSAGES/django.mo and b/locale/ar/LC_MESSAGES/django.mo differ diff --git a/locale/ar/LC_MESSAGES/django.po b/locale/ar/LC_MESSAGES/django.po index 4d8c3f73..f69e8c22 100644 --- a/locale/ar/LC_MESSAGES/django.po +++ b/locale/ar/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-05-29 17:51+0300\n" +"POT-Creation-Date: 2025-06-13 02:11+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,8 +19,9 @@ msgstr "" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" -#: api/models.py:6 inventory/models.py:468 inventory/tables.py:51 -#: templates/inventory/car_detail.html:77 templates/inventory/car_form.html:49 +#: api/models.py:6 inventory/models.py:536 inventory/tables.py:51 +#: templates/inventory/car_detail.html:87 templates/inventory/car_form.html:45 +#: templates/inventory/car_form.html:51 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:30 #: templates/inventory/car_inventory.html:65 #: templates/inventory/car_list.html:72 templates/inventory/car_list.html:78 @@ -35,7 +36,7 @@ msgstr "" msgid "VIN" msgstr "رقم الهيكل" -#: api/views.py:146 inventory/views.py:654 +#: api/views.py:146 inventory/views.py:681 msgid "Invalid VIN number provided" msgstr "تم تقديم رقم تعريف مركبة (VIN) غير صالح" @@ -43,20 +44,20 @@ msgstr "تم تقديم رقم تعريف مركبة (VIN) غير صالح" msgid "VIN not found in any source" msgstr "لم يتم العثور على رقم الهيكل (VIN) في أي مصدر" -#: car_inventory/settings.py:170 car_inventory/settings.py:334 +#: car_inventory/settings.py:174 msgid "SAR" msgstr "ريال" -#: car_inventory/settings.py:266 +#: car_inventory/settings.py:270 #: venv/lib/python3.11/site-packages/appointments/settings.py:136 msgid "English" msgstr "الإنجليزية" -#: car_inventory/settings.py:267 +#: car_inventory/settings.py:271 msgid "Arabic" msgstr "العربية" -#: car_inventory/settings.py:356 templates/header.html:358 +#: car_inventory/settings.py:360 templates/header.html:358 #: templates/welcome-temp.html:57 templates/welcome_header.html:7 msgid "Haikal" msgstr "هيكل" @@ -66,21 +67,26 @@ msgstr "هيكل" msgid "Ask me anything..." msgstr "اسألني عن أي شيء..." +#: haikalbot/temp_files_not_included/ai_agent_complete/templates/chat.html:33 +#: haikalbot/temp_files_not_included/ai_agent_full_export/templates/chat.html:33 msgid "Chart" msgstr "رسم بياني" +#: haikalbot/views.py:21 msgid "AI Assistant" msgstr "المساعد الذكي" +#: haikalbot/views.py:34 msgid "Prompt is required." msgstr "الإدخال مطلوب." +#: haikalbot/views.py:53 msgid "An error occurred while processing your request." msgstr "حدث خطأ أثناء معالجة طلبك." -#: inventory/forms.py:105 inventory/forms.py:1646 inventory/models.py:1108 -#: inventory/models.py:1137 inventory/models.py:1198 inventory/models.py:1324 -#: inventory/models.py:1453 inventory/models.py:1646 inventory/models.py:1809 +#: inventory/forms.py:114 inventory/forms.py:1783 inventory/models.py:1229 +#: inventory/models.py:1257 inventory/models.py:1322 inventory/models.py:1465 +#: inventory/models.py:1608 inventory/models.py:1816 inventory/models.py:2088 #: templates/account/login.html:29 templates/account/login.html:31 #: templates/admin_management/user_management.html:21 #: templates/admin_management/user_management.html:85 @@ -92,10 +98,9 @@ msgstr "حدث خطأ أثناء معالجة طلبك." #: templates/administration/user_profile.html:25 #: templates/appointment/appointment_client_information.html:45 #: templates/components/activity_modal.html:18 -#: templates/crm/leads/lead_detail.html:72 -#: templates/crm/leads/lead_detail.html:163 -#: templates/crm/leads/lead_list.html:39 -#: templates/crm/opportunities/opportunity_detail.html:202 +#: templates/crm/leads/lead_detail.html:124 +#: templates/crm/leads/partials/update_action.html:32 +#: templates/crm/opportunities/opportunity_detail.html:243 #: templates/customers/view_customer.html:78 #: templates/dealers/dealer_detail.html:87 #: templates/groups/group_detail.html:61 templates/pricing_page.html:187 @@ -111,19 +116,19 @@ msgstr "حدث خطأ أثناء معالجة طلبك." msgid "Email" msgstr "البريد الإلكتروني" -#: inventory/forms.py:110 +#: inventory/forms.py:119 msgid "Services Offered" msgstr "الخدمات المقدمة" -#: inventory/forms.py:118 inventory/forms.py:121 inventory/forms.py:153 -#: inventory/forms.py:168 inventory/forms.py:267 inventory/forms.py:515 -#: inventory/forms.py:602 inventory/forms.py:822 inventory/forms.py:1019 -#: inventory/forms.py:1652 inventory/models.py:928 inventory/models.py:1015 -#: inventory/models.py:1203 inventory/models.py:1325 inventory/models.py:1434 -#: inventory/models.py:1454 inventory/models.py:1878 +#: inventory/forms.py:129 inventory/forms.py:133 inventory/forms.py:167 +#: inventory/forms.py:183 inventory/forms.py:295 inventory/forms.py:561 +#: inventory/forms.py:650 inventory/forms.py:872 inventory/forms.py:1075 +#: inventory/forms.py:1788 inventory/models.py:1028 inventory/models.py:1118 +#: inventory/models.py:1327 inventory/models.py:1466 inventory/models.py:1589 +#: inventory/models.py:1609 inventory/models.py:2163 #: templates/administration/staff_index.html:123 -#: templates/crm/leads/lead_list.html:103 -#: templates/crm/opportunities/opportunity_detail.html:192 +#: templates/crm/leads/lead_list.html:50 +#: templates/crm/opportunities/opportunity_detail.html:233 #: templates/customers/customer_list.html:41 #: templates/customers/view_customer.html:80 templates/pricing_page.html:114 #: templates/pricing_page.html:117 templates/users/user_detail.html:20 @@ -133,77 +138,77 @@ msgstr "الخدمات المقدمة" msgid "Phone Number" msgstr "رقم الهاتف" -#: inventory/forms.py:466 inventory/models.py:834 -#: templates/inventory/car_detail.html:144 +#: inventory/forms.py:510 inventory/models.py:930 +#: templates/inventory/car_detail.html:154 msgid "Custom Date" msgstr "تاريخ البطاقة الجمركية" -#: inventory/forms.py:516 inventory/models.py:1877 +#: inventory/forms.py:562 inventory/models.py:2162 #: templates/vendors/view_vendor.html:17 msgid "Contact Person" msgstr "الشخص المسؤول" -#: inventory/forms.py:581 +#: inventory/forms.py:628 msgid "Both exterior and interior colors must be selected." msgstr "يجب اختيار اللونين الخارجي والداخلي." -#: inventory/forms.py:677 inventory/forms.py:1649 inventory/models.py:1435 -#: inventory/models.py:1879 templates/account/email_change.html:5 +#: inventory/forms.py:727 inventory/forms.py:1785 inventory/models.py:1590 +#: inventory/models.py:2164 templates/account/email_change.html:5 #: templates/account/email_change.html:9 templates/pricing_page.html:107 msgid "Email Address" msgstr "عنوان البريد الإلكتروني" -#: inventory/forms.py:681 +#: inventory/forms.py:731 #: venv/lib/python3.11/site-packages/appointment/views.py:424 #: venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py:1920 msgid "Email address" msgstr "عنوان البريد الإلكتروني" -#: inventory/forms.py:682 templates/crm/leads/lead_list.html:97 +#: inventory/forms.py:732 templates/crm/leads/lead_list.html:44 #: templates/customers/customer_list.html:36 templates/users/user_list.html:33 #: templates/vendors/vendors_list.html:35 msgid "email" msgstr "البريد الإلكتروني" -#: inventory/forms.py:688 +#: inventory/forms.py:738 msgid "You must add an email." msgstr "يجب إضافة بريد إلكتروني." -#: inventory/forms.py:693 inventory/forms.py:697 +#: inventory/forms.py:743 inventory/forms.py:747 #: templates/account/login.html:36 templates/account/login.html:38 #: venv/lib/python3.11/site-packages/django_ledger/forms/auth.py:15 msgid "Password" msgstr "كلمة المرور" -#: inventory/forms.py:704 inventory/forms.py:721 inventory/forms.py:857 -#: inventory/forms.py:875 inventory/forms.py:890 +#: inventory/forms.py:754 inventory/forms.py:771 inventory/forms.py:908 +#: inventory/forms.py:926 inventory/forms.py:941 #: venv/lib/python3.11/site-packages/django/forms/fields.py:95 msgid "This field is required." msgstr "هذا الحقل مطلوب." -#: inventory/forms.py:710 inventory/forms.py:714 +#: inventory/forms.py:760 inventory/forms.py:764 msgid "Confirm Password" msgstr "تأكيد كلمة المرور" -#: inventory/forms.py:727 +#: inventory/forms.py:777 msgid "I accept the Terms and Privacy Policy" msgstr "أوافق على الشروط وسياسة الخصوصية" -#: inventory/forms.py:736 +#: inventory/forms.py:786 msgid "You must accept the terms and privacy policy." msgstr "يجب أن تقبل الشروط وسياسة الخصوصية." -#: inventory/forms.py:746 +#: inventory/forms.py:795 msgid "An account with this email already exists." msgstr "يوجد بالفعل حساب بهذا البريد الإلكتروني." -#: inventory/forms.py:754 +#: inventory/forms.py:803 msgid "Passwords do not match." msgstr "كلمات المرور غير متطابقة." -#: inventory/forms.py:781 inventory/models.py:416 inventory/models.py:783 -#: inventory/models.py:796 inventory/models.py:1013 inventory/models.py:1318 -#: inventory/models.py:1429 templates/admin_management/user_management.html:83 +#: inventory/forms.py:831 inventory/models.py:479 inventory/models.py:879 +#: inventory/models.py:892 inventory/models.py:1116 inventory/models.py:1459 +#: inventory/models.py:1584 templates/admin_management/user_management.html:83 #: templates/admin_management/user_management.html:147 #: templates/admin_management/user_management.html:211 #: templates/administration/manage_service.html:22 @@ -229,59 +234,61 @@ msgstr "كلمات المرور غير متطابقة." msgid "Name" msgstr "الاسم" -#: inventory/forms.py:785 inventory/models.py:927 inventory/models.py:1876 +#: inventory/forms.py:835 inventory/models.py:1027 inventory/models.py:2161 msgid "English Name" msgstr "الاسم بالإنجليزية" -#: inventory/forms.py:790 +#: inventory/forms.py:840 msgid "Please enter an English Name." msgstr "يرجى إدخال اسم باللغة الإنجليزية." -#: inventory/forms.py:795 inventory/forms.py:799 inventory/models.py:417 -#: inventory/models.py:784 inventory/models.py:797 inventory/models.py:926 -#: inventory/models.py:1014 inventory/models.py:1319 inventory/models.py:1430 -#: inventory/models.py:1875 templates/admin_management/user_management.html:84 +#: inventory/forms.py:845 inventory/forms.py:849 inventory/models.py:480 +#: inventory/models.py:880 inventory/models.py:893 inventory/models.py:1026 +#: inventory/models.py:1117 inventory/models.py:1460 inventory/models.py:1585 +#: inventory/models.py:2160 templates/admin_management/user_management.html:84 #: templates/admin_management/user_management.html:148 #: templates/admin_management/user_management.html:212 #: templates/users/user_detail.html:17 msgid "Arabic Name" msgstr "الاسم بالعربية" -#: inventory/forms.py:804 +#: inventory/forms.py:854 msgid "Please enter an Arabic name." msgstr "يرجى إدخال اسم باللغة العربية." -#: inventory/forms.py:846 templates/organizations/organization_detail.html:8 +#: inventory/forms.py:897 inventory/models.py:1907 +#: templates/organizations/organization_detail.html:8 #: templates/organizations/organization_list.html:50 msgid "CRN" msgstr "رقم السجل التجاري" -#: inventory/forms.py:850 inventory/models.py:919 inventory/models.py:1321 -#: inventory/models.py:1490 inventory/models.py:1867 +#: inventory/forms.py:901 inventory/models.py:1019 inventory/models.py:1462 +#: inventory/models.py:2148 msgid "Commercial Registration Number" msgstr "رقم السجل التجاري" -#: inventory/forms.py:858 +#: inventory/forms.py:909 msgid "Commercial Registration Number must be 10 characters" msgstr "رقم السجل التجاري يجب أن يتكون من 10 أرقام" -#: inventory/forms.py:864 templates/organizations/organization_detail.html:9 +#: inventory/forms.py:915 inventory/models.py:1908 +#: templates/organizations/organization_detail.html:9 #: templates/organizations/organization_list.html:57 msgid "VRN" msgstr "الرقم الضريبي" -#: inventory/forms.py:868 inventory/models.py:924 inventory/models.py:1323 -#: inventory/models.py:1493 inventory/models.py:1870 +#: inventory/forms.py:919 inventory/models.py:1024 inventory/models.py:1464 +#: inventory/models.py:2151 msgid "VAT Registration Number" msgstr "رقم التسجيل في ضريبة القيمة المضافة" -#: inventory/forms.py:876 +#: inventory/forms.py:927 msgid "VAT Registration Number must be 15 characters." msgstr "يجب أن يكون رقم التسجيل الضريبي مكونًا من 15 حرفًا." -#: inventory/forms.py:881 inventory/models.py:930 inventory/models.py:1206 -#: inventory/models.py:1327 inventory/models.py:1437 inventory/models.py:1881 -#: templates/crm/leads/lead_detail.html:199 +#: inventory/forms.py:932 inventory/models.py:1030 inventory/models.py:1330 +#: inventory/models.py:1468 inventory/models.py:1592 inventory/models.py:1611 +#: inventory/models.py:2165 templates/crm/leads/lead_detail.html:154 #: templates/customers/customer_list.html:51 #: templates/customers/view_customer.html:75 #: templates/dealers/dealer_detail.html:77 @@ -295,10 +302,15 @@ msgstr "يجب أن يكون رقم التسجيل الضريبي مكونًا msgid "Address" msgstr "العنوان" -#: inventory/forms.py:911 inventory/models.py:434 +#: inventory/forms.py:964 inventory/models.py:497 +#: templates/bill/bill_detail.html:140 +#: templates/bill/tags/bill_item_formset.html:34 #: templates/inventory/transfer_preview.html:285 #: templates/ledger/bills/bill_detail.html:213 #: templates/ledger/ledger/ledger_detail.html:81 +#: templates/purchase_orders/includes/po_item_formset.html:19 +#: templates/purchase_orders/po_update.html:53 +#: templates/purchase_orders/tags/po_item_table.html:8 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:94 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:18 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_item_table.html:8 @@ -315,11 +327,15 @@ msgstr "العنوان" msgid "Item" msgstr "العنصر" -#: inventory/forms.py:915 inventory/models.py:644 +#: inventory/forms.py:968 inventory/models.py:739 +#: templates/bill/bill_detail.html:143 +#: templates/bill/tags/bill_item_formset.html:37 #: templates/inventory/transfer_preview.html:286 #: templates/ledger/bills/bill_detail.html:214 #: templates/ledger/ledger/ledger_detail.html:83 #: templates/plans/invoices/layout.html:104 +#: templates/purchase_orders/includes/po_item_formset.html:21 +#: templates/purchase_orders/po_update.html:54 #: templates/sales/estimates/estimate_detail.html:195 #: templates/sales/estimates/sale_order_preview.html:182 #: templates/sales/invoices/invoice_detail.html:242 @@ -335,12 +351,14 @@ msgstr "العنصر" msgid "Quantity" msgstr "الكمية" -#: inventory/forms.py:940 inventory/models.py:2035 +#: inventory/forms.py:994 inventory/models.py:2352 +#: templates/crm/opportunities/opportunity_detail.html:114 #: templates/customers/view_customer.html:154 #: templates/ledger/journal_entry/includes/card_invoice.html:10 #: templates/plans/create_order.html:29 templates/plans/invoices/layout.html:11 #: templates/sales/invoices/invoice_create.html:5 #: templates/sales/invoices/invoice_detail.html:69 +#: templates/sales/orders/order_list.html:17 #: templates/sales/payments/payment_list.html:21 #: templates/sales/sales_list.html:119 #: venv/lib/python3.11/site-packages/django_ledger/models/entity.py:3172 @@ -349,7 +367,9 @@ msgstr "الكمية" msgid "Invoice" msgstr "فاتورة" -#: inventory/forms.py:944 templates/ledger/bills/bill_detail.html:61 +#: inventory/forms.py:998 templates/bill/includes/card_bill.html:11 +#: templates/bill/includes/card_bill.html:94 +#: templates/ledger/bills/bill_detail.html:61 #: templates/ledger/bills/bill_update_form.html:4 #: templates/ledger/bills/bill_update_form.html:7 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:392 @@ -359,63 +379,66 @@ msgstr "فاتورة" msgid "Bill" msgstr "الفاتورة" -#: inventory/forms.py:946 +#: inventory/forms.py:1000 inventory/models.py:1934 +#: templates/crm/opportunities/opportunity_detail.html:170 #: templates/ledger/bank_accounts/bank_account_detail.html:50 +#: templates/purchase_orders/includes/po_item_formset.html:23 +#: templates/purchase_orders/tags/po_item_table.html:11 #: venv/lib/python3.11/site-packages/django_ledger/models/transactions.py:471 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:22 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:11 msgid "Amount" msgstr "المبلغ" -#: inventory/forms.py:949 inventory/models.py:1966 +#: inventory/forms.py:1003 inventory/models.py:2272 msgid "cash" msgstr "نقداً" -#: inventory/forms.py:950 inventory/models.py:1967 +#: inventory/forms.py:1004 inventory/models.py:2273 msgid "credit" msgstr "دائن" -#: inventory/forms.py:951 inventory/models.py:1968 -#: templates/inventory/car_detail.html:192 +#: inventory/forms.py:1005 inventory/models.py:2274 +#: templates/inventory/car_detail.html:202 #: templates/inventory/transfer_car.html:18 msgid "transfer" msgstr "نقل" -#: inventory/forms.py:952 inventory/models.py:1969 +#: inventory/forms.py:1006 inventory/models.py:2275 msgid "debit" msgstr "مدين" -#: inventory/forms.py:953 inventory/models.py:1970 inventory/models.py:2045 +#: inventory/forms.py:1007 inventory/models.py:2276 inventory/models.py:2364 msgid "SADAD" msgstr "سداد" -#: inventory/forms.py:955 templates/sales/estimates/sale_order_form.html:177 +#: inventory/forms.py:1009 templates/sales/estimates/sale_order_form.html:177 msgid "Payment Method" msgstr "طريقة الدفع" -#: inventory/forms.py:959 +#: inventory/forms.py:1013 msgid "Payment Date" msgstr "تاريخ الدفع" -#: inventory/forms.py:968 inventory/forms.py:974 +#: inventory/forms.py:1022 inventory/forms.py:1028 msgid "Payment amount is greater than amount due" msgstr "مبلغ الدفع أكبر من المبلغ المستحق" -#: inventory/forms.py:970 +#: inventory/forms.py:1024 msgid "Payment amount must be greater than 0" msgstr "يجب أن يكون مبلغ الدفع أكبر من 0" -#: inventory/forms.py:972 +#: inventory/forms.py:1026 msgid "Invoice is already paid" msgstr "تم دفع الفاتورة بالفعل" -#: inventory/forms.py:1000 templates/inventory/transfer_details.html:79 +#: inventory/forms.py:1055 templates/inventory/transfer_details.html:79 #: templates/inventory/transfer_preview.html:277 msgid "To" msgstr "إلى" -#: inventory/forms.py:1037 inventory/models.py:203 inventory/models.py:485 -#: inventory/models.py:1471 inventory/tables.py:52 +#: inventory/forms.py:1093 inventory/forms.py:1913 inventory/models.py:238 +#: inventory/models.py:553 inventory/models.py:1638 inventory/tables.py:52 #: templates/inventory/car_list_view.html:104 #: templates/inventory/car_list_view.html:164 #: templates/inventory/cars_list_api.html:33 @@ -427,8 +450,9 @@ msgstr "إلى" msgid "Make" msgstr "الصانع" -#: inventory/forms.py:1054 inventory/models.py:226 inventory/models.py:493 -#: inventory/models.py:1478 inventory/tables.py:53 +#: inventory/forms.py:1110 inventory/forms.py:1918 inventory/models.py:267 +#: inventory/models.py:561 inventory/models.py:1645 inventory/tables.py:53 +#: templates/admin_management/model_logs.html:33 #: templates/inventory/car_list_view.html:118 #: templates/inventory/car_list_view.html:165 #: templates/inventory/cars_list_api.html:34 @@ -440,31 +464,36 @@ msgstr "الصانع" msgid "Model" msgstr "الموديل" -#: inventory/forms.py:1168 +#: inventory/forms.py:1238 +#: templates/crm/opportunities/opportunity_detail.html:315 msgid "Expected Closing Date" msgstr "تاريخ الإغلاق المتوقع" -#: inventory/forms.py:1173 +#: inventory/forms.py:1242 msgid "Probability (%)" msgstr "الاحتمالية (%)" -#: inventory/forms.py:1362 inventory/models.py:516 inventory/models.py:1513 -#: inventory/models.py:1801 inventory/tables.py:62 +#: inventory/forms.py:1462 inventory/models.py:584 inventory/models.py:1665 +#: inventory/models.py:2078 inventory/tables.py:62 #: templates/admin_management/user_management.html:22 #: templates/admin_management/user_management.html:86 #: templates/admin_management/user_management.html:150 #: templates/admin_management/user_management.html:214 -#: templates/crm/leads/lead_detail.html:130 -#: templates/inventory/car_detail.html:101 -#: templates/inventory/car_detail.html:418 +#: templates/bill/tags/bill_table.html:10 +#: templates/crm/leads/lead_detail.html:77 +#: templates/inventory/car_detail.html:111 +#: templates/inventory/car_detail.html:423 #: templates/inventory/car_inventory.html:78 #: templates/inventory/car_list.html:173 #: templates/inventory/car_list_view.html:170 #: templates/inventory/cars_list_api.html:19 #: templates/inventory/cars_list_api.html:35 templates/plans/current.html:24 +#: templates/purchase_orders/includes/po_item_formset.html:24 +#: templates/purchase_orders/tags/po_item_table.html:12 #: templates/sales/estimates/estimate_list.html:16 #: templates/sales/invoices/invoice_list.html:17 #: templates/sales/journals/journal_list.html:17 +#: templates/sales/orders/order_list.html:18 #: templates/sales/sales_list.html:120 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:10 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:12 @@ -475,195 +504,200 @@ msgstr "الاحتمالية (%)" msgid "Status" msgstr "الحالة" -#: inventory/forms.py:1378 inventory/models.py:1717 +#: inventory/forms.py:1478 inventory/models.py:1916 msgid "Stage" msgstr "المرحلة" -#: inventory/forms.py:1507 +#: inventory/forms.py:1631 msgid "Select Car Makes" msgstr "اختر ماركات السيارات" -#: inventory/forms.py:1567 +#: inventory/forms.py:1693 msgid "Please enter a valid credit card number" msgstr "يرجى إدخال رقم بطاقة ائتمان صالح" -#: inventory/forms.py:1597 +#: inventory/forms.py:1725 msgid "Please enter a valid month (01-12)" msgstr "يرجى إدخال شهر صالح (01-12)" -#: inventory/forms.py:1604 +#: inventory/forms.py:1734 msgid "This card appears to be expired" msgstr "يبدو أن هذه البطاقة منتهية الصلاحية" -#: inventory/forms.py:1607 +#: inventory/forms.py:1738 msgid "Please enter a valid expiry date in MM/YY format" msgstr "يرجى إدخال تاريخ انتهاء صلاحية صحيح بصيغة MM/YY" -#: inventory/forms.py:1616 +#: inventory/forms.py:1749 msgid "CVV must contain only digits" msgstr "يجب أن يحتوي رمز التحقق (CVV) على أرقام فقط" -#: inventory/forms.py:1618 +#: inventory/forms.py:1751 msgid "CVV must be 3 or 4 digits" msgstr "يجب أن يكون رمز التحقق (CVV) مكونًا من 3 أو 4 أرقام" -#: inventory/forms.py:1627 inventory/forms.py:1630 inventory/models.py:1187 -#: inventory/models.py:1451 templates/admin_management/user_management.html:19 +#: inventory/forms.py:1762 inventory/forms.py:1766 inventory/models.py:1311 +#: inventory/models.py:1606 templates/admin_management/user_management.html:19 #: templates/administration/manage_staff_personal_info.html:18 #: templates/pricing_page.html:93 templates/pricing_page.html:96 msgid "First Name" msgstr "الاسم الأول" -#: inventory/forms.py:1637 inventory/forms.py:1640 inventory/models.py:1191 -#: inventory/models.py:1452 templates/admin_management/user_management.html:20 +#: inventory/forms.py:1774 inventory/forms.py:1778 inventory/models.py:1315 +#: inventory/models.py:1607 templates/admin_management/user_management.html:20 #: templates/administration/manage_staff_personal_info.html:24 #: templates/pricing_page.html:100 templates/pricing_page.html:103 msgid "Last Name" msgstr "اسم العائلة" -#: inventory/forms.py:1663 templates/pricing_page.html:143 +#: inventory/forms.py:1800 templates/pricing_page.html:143 #: templates/pricing_page.html:146 templates/pricing_page.html:193 msgid "Card Number" msgstr "رقم البطاقة" -#: inventory/forms.py:1674 +#: inventory/forms.py:1812 msgid "Expiration Date" msgstr "تاريخ الانتهاء" -#: inventory/forms.py:1685 +#: inventory/forms.py:1824 msgid "Security Code (CVV)" msgstr "رمز الأمان (CVV)" -#: inventory/forms.py:1697 +#: inventory/forms.py:1837 msgid "Name on Card" msgstr "الاسم على البطاقة" -#: inventory/forms.py:1707 +#: inventory/forms.py:1844 msgid "I agree to the Terms and Conditions" msgstr "أوافق على الشروط وسياسة الخصوصية" -#: inventory/forms.py:1709 +#: inventory/forms.py:1845 msgid "You must accept the terms and conditions" msgstr "يجب أن تقبل الشروط وسياسة الخصوصية." -#: inventory/models.py:36 -msgid "Primary Key" -msgstr "المفتاح الأساسي" - -#: inventory/models.py:37 inventory/models.py:1735 inventory/models.py:1888 -msgid "Slug" -msgstr "المُعرّف الفريد (Slug)" - -#: inventory/models.py:38 -msgid "" -"Slug for the object. If not provided, it will be generated automatically." -msgstr "المُعرّف الفريد للكائن. إذا لم يتم توفيره، فسيتم إنشاؤه تلقائيًا." - -#: inventory/models.py:39 inventory/models.py:653 inventory/models.py:868 -#: inventory/models.py:1887 -msgid "Created At" -msgstr "تاريخ الإنشاء" - -#: inventory/models.py:40 inventory/models.py:654 inventory/models.py:939 -msgid "Updated At" -msgstr "تم التحديث" - -#: inventory/models.py:165 inventory/models.py:536 inventory/models.py:627 -#: inventory/models.py:672 inventory/models.py:831 inventory/models.py:846 -#: inventory/models.py:890 inventory/models.py:1714 -#: templates/crm/leads/lead_list.html:91 templates/dashboards/manager.html:52 -#: templates/inventory/transfer_details.html:88 -msgid "Car" -msgstr "سيارة" - -#: inventory/models.py:166 -msgid "Light Commercial" -msgstr "مركبات تجارية خفيفة" - -#: inventory/models.py:167 -msgid "Heavy-Duty Tractors" -msgstr "جرارات ثقيلة" - -#: inventory/models.py:168 -msgid "Trailers" -msgstr "مقطورات" - -#: inventory/models.py:169 -msgid "Medium Trucks" -msgstr "شاحنات متوسطة" - -#: inventory/models.py:170 -msgid "Buses" -msgstr "حافلات" - -#: inventory/models.py:171 -msgid "Motorcycles" -msgstr "دراجات نارية" - -#: inventory/models.py:172 -msgid "Buggy" -msgstr "باجي" - -#: inventory/models.py:173 -msgid "Moto ATV" -msgstr "موتو ATV" - -#: inventory/models.py:174 -msgid "Scooters" -msgstr "دراجات سكوتر" - -#: inventory/models.py:175 -msgid "Karting" -msgstr "كارتينج" - -#: inventory/models.py:176 -msgid "ATV" -msgstr "مركبات ATV" - -#: inventory/models.py:177 -msgid "Snowmobiles" -msgstr "دراجات الثلج" - -#: inventory/models.py:185 -msgid "logo" -msgstr "الشعار" - -#: inventory/models.py:255 inventory/models.py:502 inventory/tables.py:55 -#: templates/inventory/car_form.html:83 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:100 -msgid "Series" +#: inventory/forms.py:1923 +msgid "Serie" msgstr "السلسلة" -#: inventory/models.py:283 inventory/models.py:510 inventory/tables.py:56 -#: templates/inventory/car_list_view.html:167 +#: inventory/forms.py:1928 inventory/models.py:334 inventory/models.py:578 +#: inventory/tables.py:56 templates/inventory/car_list_view.html:167 #: templates/sales/sales_list.html:116 msgid "Trim" msgstr "الفئة" -#: inventory/models.py:302 +#: inventory/models.py:49 +msgid "Primary Key" +msgstr "المفتاح الأساسي" + +#: inventory/models.py:55 inventory/models.py:1955 inventory/models.py:2172 +msgid "Slug" +msgstr "المُعرّف الفريد (Slug)" + +#: inventory/models.py:57 +msgid "" +"Slug for the object. If not provided, it will be generated automatically." +msgstr "المُعرّف الفريد للكائن. إذا لم يتم توفيره، فسيتم إنشاؤه تلقائيًا." + +#: inventory/models.py:60 inventory/models.py:748 inventory/models.py:964 +#: inventory/models.py:2170 +msgid "Created At" +msgstr "تاريخ الإنشاء" + +#: inventory/models.py:61 inventory/models.py:749 inventory/models.py:1039 +msgid "Updated At" +msgstr "تم التحديث" + +#: inventory/models.py:195 inventory/models.py:606 inventory/models.py:722 +#: inventory/models.py:768 inventory/models.py:927 inventory/models.py:942 +#: inventory/models.py:986 inventory/models.py:1905 +#: templates/crm/leads/lead_detail.html:263 +#: templates/crm/leads/lead_list.html:38 templates/dashboards/manager.html:52 +#: templates/inventory/transfer_details.html:88 +msgid "Car" +msgstr "سيارة" + +#: inventory/models.py:196 +msgid "Light Commercial" +msgstr "مركبات تجارية خفيفة" + +#: inventory/models.py:197 +msgid "Heavy-Duty Tractors" +msgstr "جرارات ثقيلة" + +#: inventory/models.py:198 +msgid "Trailers" +msgstr "مقطورات" + +#: inventory/models.py:199 +msgid "Medium Trucks" +msgstr "شاحنات متوسطة" + +#: inventory/models.py:200 +msgid "Buses" +msgstr "حافلات" + +#: inventory/models.py:201 +msgid "Motorcycles" +msgstr "دراجات نارية" + +#: inventory/models.py:202 +msgid "Buggy" +msgstr "باجي" + +#: inventory/models.py:203 +msgid "Moto ATV" +msgstr "موتو ATV" + +#: inventory/models.py:204 +msgid "Scooters" +msgstr "دراجات سكوتر" + +#: inventory/models.py:205 +msgid "Karting" +msgstr "كارتينج" + +#: inventory/models.py:206 +msgid "ATV" +msgstr "مركبات ATV" + +#: inventory/models.py:207 +msgid "Snowmobiles" +msgstr "دراجات الثلج" + +#: inventory/models.py:215 +msgid "logo" +msgstr "الشعار" + +#: inventory/models.py:301 inventory/models.py:570 inventory/tables.py:55 +#: templates/inventory/car_form.html:111 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:100 +msgid "Series" +msgstr "السلسلة" + +#: inventory/models.py:354 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:455 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:541 #: venv/lib/python3.11/site-packages/django_ledger/models/items.py:509 msgid "Equipment" msgstr "المعدات" -#: inventory/models.py:328 +#: inventory/models.py:385 msgid "Specification" msgstr "المواصفة" -#: inventory/models.py:344 +#: inventory/models.py:401 msgid "Specification Value" msgstr "قيمة المواصفة" -#: inventory/models.py:370 +#: inventory/models.py:432 msgid "Option" msgstr "الخيار" -#: inventory/models.py:389 +#: inventory/models.py:451 msgid "Option Value" msgstr "قيمة الخيار" -#: inventory/models.py:393 templates/ledger/bills/bill_detail.html:191 +#: inventory/models.py:455 templates/ledger/bills/bill_detail.html:191 #: templates/sales/estimates/estimate_detail.html:82 #: templates/sales/estimates/estimate_detail.html:169 #: templates/sales/estimates/estimate_list.html:29 @@ -677,7 +711,7 @@ msgstr "قيمة الخيار" msgid "Draft" msgstr "مسودة" -#: inventory/models.py:394 templates/ledger/bills/bill_detail.html:195 +#: inventory/models.py:456 templates/ledger/bills/bill_detail.html:195 #: templates/sales/estimates/estimate_detail.html:86 #: templates/sales/estimates/estimate_detail.html:173 #: templates/sales/estimates/estimate_list.html:33 @@ -692,28 +726,29 @@ msgstr "مسودة" msgid "Approved" msgstr "تمت الموافقة" -#: inventory/models.py:395 templates/crm/leads/lead_list.html:167 test.txt:46 +#: inventory/models.py:457 templates/crm/leads/lead_list.html:114 test.txt:46 msgid "Pending" msgstr "قيد الانتظار" -#: inventory/models.py:396 +#: inventory/models.py:458 msgid "Accepted" msgstr "تم القبول" -#: inventory/models.py:397 templates/administration/staff_index.html:83 +#: inventory/models.py:459 templates/administration/staff_index.html:83 +#: templates/payment_success.html:14 #: venv/lib/python3.11/site-packages/appointment/templates/administration/staff_index.html:329 msgid "Success" msgstr "ناجحة" -#: inventory/models.py:398 +#: inventory/models.py:460 msgid "Reject" msgstr "رفض" -#: inventory/models.py:399 +#: inventory/models.py:461 msgid "Cancelled" msgstr "ملغى" -#: inventory/models.py:403 templates/dashboards/manager.html:103 +#: inventory/models.py:465 templates/dashboards/manager.html:103 #: templates/dashboards/manager.html:235 templates/dashboards/sales.html:20 #: templates/dashboards/sales.html:332 #: templates/inventory/car_inventory.html:131 @@ -725,7 +760,7 @@ msgstr "ملغى" msgid "Available" msgstr "متاح" -#: inventory/models.py:404 templates/dashboards/manager.html:109 +#: inventory/models.py:466 templates/dashboards/manager.html:109 #: templates/dashboards/manager.html:236 templates/dashboards/sales.html:26 #: templates/dashboards/sales.html:333 #: templates/inventory/car_inventory.html:133 @@ -736,14 +771,14 @@ msgstr "متاح" msgid "Sold" msgstr "تم البيع" -#: inventory/models.py:405 templates/dashboards/manager.html:127 +#: inventory/models.py:467 templates/dashboards/manager.html:127 #: templates/dashboards/manager.html:239 templates/dashboards/sales.html:44 #: templates/dashboards/sales.html:336 #: templates/inventory/car_inventory.html:135 msgid "Hold" msgstr "في الانتظار" -#: inventory/models.py:406 templates/dashboards/manager.html:133 +#: inventory/models.py:468 templates/dashboards/manager.html:133 #: templates/dashboards/manager.html:240 templates/dashboards/sales.html:50 #: templates/dashboards/sales.html:337 #: templates/inventory/car_inventory.html:142 @@ -751,7 +786,7 @@ msgstr "في الانتظار" msgid "Damaged" msgstr "تالف" -#: inventory/models.py:407 templates/dashboards/manager.html:115 +#: inventory/models.py:469 templates/dashboards/manager.html:115 #: templates/dashboards/manager.html:237 templates/dashboards/sales.html:32 #: templates/dashboards/sales.html:334 #: templates/inventory/car_inventory.html:140 @@ -762,7 +797,7 @@ msgstr "تالف" msgid "Reserved" msgstr "محجوزة" -#: inventory/models.py:408 inventory/models.py:1147 +#: inventory/models.py:470 inventory/models.py:1267 #: templates/dashboards/manager.html:121 templates/dashboards/manager.html:238 #: templates/dashboards/sales.html:38 templates/dashboards/sales.html:335 #: templates/inventory/car_list_view.html:54 @@ -773,18 +808,19 @@ msgstr "محجوزة" msgid "Transfer" msgstr "نقل" -#: inventory/models.py:411 inventory/models.py:1113 -#: templates/crm/leads/lead_detail.html:132 -#: templates/crm/leads/lead_list.html:165 +#: inventory/models.py:474 inventory/models.py:1234 +#: templates/crm/leads/lead_detail.html:79 +#: templates/crm/leads/lead_list.html:112 +#: templates/crm/leads/partials/update_action.html:17 #: templates/inventory/car_inventory.html:90 test.txt:33 msgid "New" msgstr "جديد" -#: inventory/models.py:412 templates/inventory/car_inventory.html:92 +#: inventory/models.py:475 templates/inventory/car_inventory.html:92 msgid "Used" msgstr "مستعمل" -#: inventory/models.py:418 inventory/models.py:865 inventory/models.py:1774 +#: inventory/models.py:481 inventory/models.py:961 inventory/models.py:2043 #: templates/administration/manage_day_off.html:63 #: templates/administration/manage_service.html:33 #: templates/administration/user_profile.html:93 @@ -813,7 +849,7 @@ msgstr "مستعمل" msgid "Description" msgstr "الوصف" -#: inventory/models.py:420 inventory/tables.py:58 +#: inventory/models.py:483 inventory/tables.py:58 #: templates/administration/manage_service.html:55 #: templates/administration/service_list.html:25 #: templates/administration/user_profile.html:245 @@ -824,35 +860,36 @@ msgstr "الوصف" msgid "Price" msgstr "السعر" -#: inventory/models.py:422 +#: inventory/models.py:485 msgid "taxable" msgstr "خاضع للضريبة" -#: inventory/models.py:426 +#: inventory/models.py:489 msgid "Unit of Measurement" msgstr "وحدة القياس" -#: inventory/models.py:429 inventory/models.py:470 inventory/models.py:990 +#: inventory/models.py:492 inventory/models.py:538 inventory/models.py:1091 msgid "Dealer" msgstr "المعرض" -#: inventory/models.py:453 inventory/models.py:454 +#: inventory/models.py:521 inventory/models.py:522 #: templates/sales/estimates/estimate_detail.html:227 #: templates/sales/estimates/sale_order_preview.html:206 #: templates/sales/invoices/invoice_detail.html:273 msgid "Additional Services" msgstr "الخدمات الإضافية" -#: inventory/models.py:464 +#: inventory/models.py:532 #: venv/lib/python3.11/site-packages/django_ledger/models/items.py:1053 msgid "Item Model" msgstr "نموذج العنصر" -#: inventory/models.py:477 inventory/models.py:1901 -#: templates/inventory/car_detail.html:118 -#: templates/inventory/car_form.html:148 +#: inventory/models.py:545 inventory/models.py:2191 +#: templates/bill/tags/bill_table.html:12 +#: templates/inventory/car_detail.html:128 +#: templates/inventory/car_form.html:155 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:136 -#: templates/ledger/bills/bill_list.html:52 +#: templates/ledger/bills/bill_list.html:50 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:364 #: venv/lib/python3.11/site-packages/django_ledger/models/vendor.py:191 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:12 @@ -860,8 +897,8 @@ msgstr "نموذج العنصر" msgid "Vendor" msgstr "المورد" -#: inventory/models.py:495 inventory/models.py:1481 inventory/tables.py:54 -#: templates/inventory/car_form.html:73 +#: inventory/models.py:563 inventory/tables.py:54 +#: templates/inventory/car_form.html:77 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:55 #: templates/inventory/car_inventory.html:67 #: templates/inventory/car_list_view.html:124 @@ -874,205 +911,206 @@ msgstr "المورد" msgid "Year" msgstr "السنة" -#: inventory/models.py:522 inventory/tables.py:50 -#: templates/inventory/car_detail.html:105 -#: templates/inventory/car_form.html:159 +#: inventory/models.py:590 inventory/tables.py:50 +#: templates/inventory/car_detail.html:115 +#: templates/inventory/car_form.html:166 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:147 #: templates/inventory/car_list.html:185 msgid "Stock Type" msgstr "نوع المخزون" -#: inventory/models.py:524 inventory/models.py:645 -#: templates/inventory/car_detail.html:123 -#: templates/inventory/car_form.html:192 +#: inventory/models.py:592 inventory/models.py:740 +#: templates/inventory/car_detail.html:133 +#: templates/inventory/car_form.html:199 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:181 #: templates/inventory/car_list.html:211 msgid "Remarks" msgstr "ملاحظات" -#: inventory/models.py:525 inventory/tables.py:57 -#: templates/inventory/car_detail.html:109 -#: templates/inventory/car_form.html:170 +#: inventory/models.py:593 inventory/tables.py:57 +#: templates/inventory/car_detail.html:119 +#: templates/inventory/car_form.html:177 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:157 #: templates/inventory/car_list.html:197 templates/inventory/car_list.html:203 msgid "Mileage" msgstr "عدد الكيلومترات" -#: inventory/models.py:526 templates/inventory/car_detail.html:113 -#: templates/inventory/car_form.html:181 +#: inventory/models.py:594 templates/inventory/car_detail.html:123 +#: templates/inventory/car_form.html:188 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:168 msgid "Receiving Date" msgstr "تاريخ الاستلام" -#: inventory/models.py:527 +#: inventory/models.py:596 msgid "Hash" msgstr "رمز" -#: inventory/models.py:537 templates/header.html:36 +#: inventory/models.py:607 templates/header.html:36 #: templates/sales/estimates/estimate_form.html:38 msgid "Cars" msgstr "السيارات" -#: inventory/models.py:633 +#: inventory/models.py:728 msgid "From Dealer" msgstr "من معرض" -#: inventory/models.py:639 +#: inventory/models.py:734 msgid "To Dealer" msgstr "الى معرض" -#: inventory/models.py:642 +#: inventory/models.py:737 msgid "Transfer Date" msgstr "تاريخ النقل" -#: inventory/models.py:660 +#: inventory/models.py:756 msgid "Car Transfer Log" msgstr "سجل نقل السيارة" -#: inventory/models.py:661 +#: inventory/models.py:757 msgid "Car Transfer Logs" msgstr "سجلات نقل السيارات" -#: inventory/models.py:678 templates/inventory/car_detail.html:353 +#: inventory/models.py:774 templates/inventory/car_detail.html:358 msgid "Reserved By" msgstr "محجوز بواسطة" -#: inventory/models.py:686 +#: inventory/models.py:782 msgid "Reserved At" msgstr "تاريخ الحجز" -#: inventory/models.py:687 +#: inventory/models.py:783 msgid "Reserved Until" msgstr "محجوز حتى" -#: inventory/models.py:697 templates/inventory/car_detail.html:518 +#: inventory/models.py:792 templates/inventory/car_detail.html:523 msgid "Car Reservation" msgstr "حجز السيارة" -#: inventory/models.py:698 +#: inventory/models.py:793 msgid "Car Reservations" msgstr "حجوزات السيارات" -#: inventory/models.py:708 templates/inventory/car_detail.html:230 +#: inventory/models.py:803 templates/inventory/car_detail.html:240 msgid "Cost Price" msgstr "سعر التكلفة" -#: inventory/models.py:711 templates/inventory/car_detail.html:235 +#: inventory/models.py:806 templates/inventory/car_detail.html:245 msgid "Selling Price" msgstr "سعر البيع" -#: inventory/models.py:716 templates/inventory/car_detail.html:239 +#: inventory/models.py:811 templates/inventory/car_detail.html:249 #: templates/sales/estimates/estimate_detail.html:221 #: templates/sales/invoices/invoice_detail.html:261 msgid "Discount Amount" msgstr "مبلغ الخصم" -#: inventory/models.py:778 inventory/models.py:779 +#: inventory/models.py:874 inventory/models.py:875 msgid "Car Financial Details" msgstr "تفاصيل المالية للسيارة" -#: inventory/models.py:785 inventory/models.py:798 +#: inventory/models.py:881 inventory/models.py:894 msgid "RGB" msgstr "آر جي بي" -#: inventory/models.py:788 inventory/models.py:789 -#: templates/inventory/add_colors.html:13 +#: inventory/models.py:884 inventory/models.py:885 +#: templates/inventory/add_colors.html:14 msgid "Exterior Colors" msgstr "الألوان الخارجية" -#: inventory/models.py:801 inventory/models.py:802 -#: templates/inventory/add_colors.html:33 +#: inventory/models.py:897 inventory/models.py:898 +#: templates/inventory/add_colors.html:35 msgid "Interior Colors" msgstr "الألوان الداخلية" -#: inventory/models.py:818 templates/inventory/car_list_view.html:168 +#: inventory/models.py:914 templates/inventory/car_list_view.html:168 msgid "Color" msgstr "اللون" -#: inventory/models.py:819 +#: inventory/models.py:915 msgid "Colors" msgstr "الألوان" -#: inventory/models.py:833 templates/inventory/car_detail.html:140 +#: inventory/models.py:929 templates/inventory/car_detail.html:150 msgid "Custom Number" msgstr "رقم البطاقة الجمركية" -#: inventory/models.py:837 templates/inventory/car_detail.html:149 -#: templates/inventory/car_detail.html:476 +#: inventory/models.py:933 templates/inventory/car_detail.html:159 +#: templates/inventory/car_detail.html:481 msgid "Custom Card" msgstr "البطاقة الجمركية" -#: inventory/models.py:838 +#: inventory/models.py:934 msgid "Custom Cards" msgstr "البطاقات الجمركية" -#: inventory/models.py:852 inventory/models.py:1724 +#: inventory/models.py:948 inventory/models.py:1923 msgid "Owner" msgstr "المالك" -#: inventory/models.py:853 +#: inventory/models.py:949 msgid "Dealer who owns the car." msgstr "التاجر الذي يمتلك السيارة." -#: inventory/models.py:859 inventory/models.py:1093 +#: inventory/models.py:955 inventory/models.py:1214 msgid "Showroom" msgstr "صالة العرض" -#: inventory/models.py:860 +#: inventory/models.py:956 msgid "Dealer where the car is displayed (can be the owner)." msgstr "التاجر الذي تُعرض السيارة في صالته (يمكن أن يكون المالك)." -#: inventory/models.py:866 +#: inventory/models.py:962 msgid "Optional description about the showroom placement." msgstr "وصف اختياري حول وضع السيارة في صالة العرض." -#: inventory/models.py:869 +#: inventory/models.py:965 +#: templates/crm/opportunities/opportunity_detail.html:139 msgid "Last Updated" msgstr "آخر تحديث" -#: inventory/models.py:872 +#: inventory/models.py:968 msgid "Car Location" msgstr "موقع السيارة" -#: inventory/models.py:873 +#: inventory/models.py:969 msgid "Car Locations" msgstr "مواقف السيارات" -#: inventory/models.py:892 +#: inventory/models.py:988 msgid "Plate Number" msgstr "رقم اللوحة" -#: inventory/models.py:893 +#: inventory/models.py:989 msgid "Text 1" msgstr "النص 1" -#: inventory/models.py:894 +#: inventory/models.py:991 msgid "Text 2" msgstr "النص 2" -#: inventory/models.py:895 +#: inventory/models.py:994 msgid "Text 3" msgstr "النص 3" -#: inventory/models.py:896 templates/inventory/car_detail.html:166 +#: inventory/models.py:996 templates/inventory/car_detail.html:176 msgid "Registration Date" msgstr "تاريخ التسجيل" -#: inventory/models.py:899 templates/inventory/car_detail.html:160 -#: templates/inventory/car_detail.html:171 -#: templates/inventory/car_detail.html:497 +#: inventory/models.py:999 templates/inventory/car_detail.html:170 +#: templates/inventory/car_detail.html:181 +#: templates/inventory/car_detail.html:502 msgid "Registration" msgstr "التسجيل" -#: inventory/models.py:900 +#: inventory/models.py:1000 msgid "Registrations" msgstr "تسجيل السيارات" -#: inventory/models.py:908 inventory/models.py:1018 inventory/models.py:1212 -#: inventory/models.py:1333 inventory/models.py:1532 inventory/models.py:1732 -#: inventory/models.py:1758 inventory/models.py:1783 inventory/models.py:1805 -#: inventory/models.py:1828 inventory/models.py:1845 -#: templates/crm/leads/lead_detail.html:181 +#: inventory/models.py:1008 inventory/models.py:1123 inventory/models.py:1336 +#: inventory/models.py:1474 inventory/models.py:1679 inventory/models.py:1942 +#: inventory/models.py:2026 inventory/models.py:2056 inventory/models.py:2084 +#: inventory/models.py:2109 inventory/models.py:2126 +#: templates/crm/leads/lead_detail.html:136 #: templates/sales/estimates/estimate_list.html:18 #: templates/sales/invoices/invoice_list.html:19 #: templates/sales/journals/journal_list.html:19 @@ -1082,27 +1120,27 @@ msgstr "تسجيل السيارات" msgid "Created" msgstr "تاريخ الإنشاء" -#: inventory/models.py:909 inventory/models.py:1019 inventory/models.py:1213 -#: inventory/models.py:1334 inventory/models.py:1534 inventory/models.py:1733 -#: inventory/models.py:1759 inventory/models.py:1784 inventory/models.py:1806 -#: inventory/models.py:1829 +#: inventory/models.py:1009 inventory/models.py:1124 inventory/models.py:1337 +#: inventory/models.py:1475 inventory/models.py:1681 inventory/models.py:1943 +#: inventory/models.py:2027 inventory/models.py:2057 inventory/models.py:2085 +#: inventory/models.py:2110 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:41 msgid "Updated" msgstr "تم التحديث" -#: inventory/models.py:933 inventory/models.py:1330 inventory/models.py:1884 +#: inventory/models.py:1033 inventory/models.py:1471 inventory/models.py:2167 msgid "Logo" msgstr "الشعار" -#: inventory/models.py:938 +#: inventory/models.py:1038 msgid "Joined At" msgstr "انضم في" -#: inventory/models.py:991 +#: inventory/models.py:1092 msgid "Dealers" msgstr "المعارض" -#: inventory/models.py:1002 inventory/tasks.py:62 templates/header.html:17 +#: inventory/models.py:1103 inventory/tasks.py:806 templates/header.html:17 #: templates/header.html:22 templates/welcome.html:27 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:440 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:526 @@ -1111,28 +1149,28 @@ msgstr "المعارض" msgid "Inventory" msgstr "المخزن" -#: inventory/models.py:1003 +#: inventory/models.py:1104 msgid "Accountant" msgstr "محاسب" -#: inventory/models.py:1004 templates/header.html:110 +#: inventory/models.py:1105 templates/header.html:110 #: templates/sales/sales_list.html:4 msgid "Sales" msgstr "المبيعات" -#: inventory/models.py:1016 +#: inventory/models.py:1120 msgid "Staff Type" msgstr "نوع الموظف" -#: inventory/models.py:1017 inventory/models.py:1208 inventory/models.py:1332 -#: inventory/models.py:1886 templates/admin_management/user_management.html:35 +#: inventory/models.py:1122 inventory/models.py:1332 inventory/models.py:1473 +#: inventory/models.py:2169 templates/admin_management/user_management.html:35 #: templates/admin_management/user_management.html:99 #: templates/admin_management/user_management.html:163 #: templates/admin_management/user_management.html:227 #: templates/customers/customer_list.html:56 #: templates/dealers/dealer_detail.html:114 #: templates/ledger/coa_accounts/account_detail.html:55 -#: templates/ledger/coa_accounts/account_list.html:28 +#: templates/ledger/coa_accounts/partials/account_table.html:10 #: templates/plans/current.html:26 #: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:433 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:27 @@ -1142,286 +1180,299 @@ msgstr "نوع الموظف" msgid "Active" msgstr "نشط" -#: inventory/models.py:1082 inventory/models.py:1083 +#: inventory/models.py:1203 inventory/models.py:1204 #: templates/admin_management/user_management.html:206 -#: templates/crm/opportunities/opportunity_detail.html:233 #: templates/dashboards/manager.html:16 msgid "Staff" msgstr "الموظفون" -#: inventory/models.py:1091 +#: inventory/models.py:1212 msgid "Referrals" msgstr "إحالات" -#: inventory/models.py:1092 inventory/models.py:1139 +#: inventory/models.py:1213 inventory/models.py:1259 msgid "WhatsApp" msgstr "واتساب" -#: inventory/models.py:1094 +#: inventory/models.py:1215 msgid "TikTok" msgstr "تيك توك" -#: inventory/models.py:1095 +#: inventory/models.py:1216 msgid "Instagram" msgstr "إنستغرام" -#: inventory/models.py:1096 +#: inventory/models.py:1217 msgid "X" msgstr "إكس" -#: inventory/models.py:1097 +#: inventory/models.py:1218 msgid "Facebook" msgstr "فيسبوك" -#: inventory/models.py:1098 +#: inventory/models.py:1219 msgid "Motory" msgstr "موتري" -#: inventory/models.py:1099 +#: inventory/models.py:1220 msgid "Influencers" msgstr "المؤثرون" -#: inventory/models.py:1100 +#: inventory/models.py:1221 msgid "Youtube" msgstr "يوتيوب" -#: inventory/models.py:1101 +#: inventory/models.py:1222 msgid "Campaign" msgstr "حملة" -#: inventory/models.py:1105 +#: inventory/models.py:1226 msgid "Walk In" msgstr "زيارة مباشرة" -#: inventory/models.py:1106 +#: inventory/models.py:1227 msgid "Toll Free" msgstr "رقم مجاني" -#: inventory/models.py:1107 +#: inventory/models.py:1228 #: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:113 msgid "Website" msgstr "الموقع الإلكتروني" -#: inventory/models.py:1109 +#: inventory/models.py:1230 msgid "Form" msgstr "نموذج" -#: inventory/models.py:1114 -msgid "Follow-up" -msgstr "متابعة" +#: inventory/models.py:1235 templates/crm/leads/lead_detail.html:81 +#: templates/crm/leads/lead_list.html:120 +#: templates/crm/leads/partials/update_action.html:18 +msgid "Contacted" +msgstr "تم الاتصال" -#: inventory/models.py:1115 inventory/models.py:1141 inventory/models.py:1164 -#: templates/crm/leads/lead_detail.html:58 -#: templates/crm/leads/lead_detail.html:136 -#: templates/crm/leads/lead_list.html:28 -#: templates/crm/leads/lead_tracking.html:104 -msgid "Negotiation" -msgstr "مفاوضات" +#: inventory/models.py:1236 templates/crm/leads/lead_detail.html:83 +#: templates/crm/leads/lead_list.html:118 +#: templates/crm/leads/partials/update_action.html:19 +msgid "Qualified" +msgstr "مؤهل" -#: inventory/models.py:1116 inventory/models.py:1143 -#: templates/crm/leads/lead_detail.html:59 -#: templates/crm/leads/lead_detail.html:138 -#: templates/crm/leads/lead_tracking.html:120 -msgid "Won" -msgstr "تم الفوز" +#: inventory/models.py:1237 templates/crm/leads/lead_detail.html:85 +#: templates/crm/leads/partials/update_action.html:20 +msgid "Unqualified" +msgstr "غير مؤهل" -#: inventory/models.py:1117 inventory/models.py:1144 -#: templates/crm/leads/lead_detail.html:60 -#: templates/crm/leads/lead_detail.html:140 -#: templates/crm/leads/lead_tracking.html:136 -msgid "Lost" -msgstr "تم الفقد" +#: inventory/models.py:1238 inventory/models.py:1266 +#: templates/crm/leads/lead_detail.html:87 +#: templates/crm/leads/partials/update_action.html:21 +msgid "Converted" +msgstr "تم التحويل" -#: inventory/models.py:1118 inventory/models.py:1145 -#: templates/crm/leads/lead_detail.html:61 -#: templates/crm/leads/lead_detail.html:142 -#: templates/crm/leads/lead_list.html:29 -msgid "Closed" -msgstr "مغلقة" - -#: inventory/models.py:1122 +#: inventory/models.py:1242 msgid "Mr" msgstr "السيد" -#: inventory/models.py:1123 +#: inventory/models.py:1243 msgid "Mrs" msgstr "السيدة" -#: inventory/models.py:1124 +#: inventory/models.py:1244 msgid "Ms" msgstr "الآنسة" -#: inventory/models.py:1125 +#: inventory/models.py:1245 msgid "Miss" msgstr "الآنسة" -#: inventory/models.py:1126 +#: inventory/models.py:1246 msgid "Dr" msgstr "الدكتور" -#: inventory/models.py:1127 +#: inventory/models.py:1247 msgid "Prof" msgstr "الأستاذ" -#: inventory/models.py:1128 +#: inventory/models.py:1248 msgid "Prince" msgstr "الأمير" -#: inventory/models.py:1129 +#: inventory/models.py:1249 msgid "Princess" msgstr "الأميرة" -#: inventory/models.py:1130 templates/pricing_page.html:121 +#: inventory/models.py:1250 templates/pricing_page.html:121 #: templates/pricing_page.html:124 templates/pricing_page.html:188 msgid "Company" msgstr "الشركة" -#: inventory/models.py:1131 +#: inventory/models.py:1251 msgid "N/A" msgstr "غير متوفر" -#: inventory/models.py:1135 inventory/models.py:1644 +#: inventory/models.py:1255 inventory/models.py:1814 #: templates/components/activity_modal.html:17 -#: templates/crm/leads/lead_detail.html:70 -#: templates/crm/leads/lead_list.html:37 +#: templates/crm/leads/partials/update_action.html:30 msgid "Call" msgstr "مكالمة" -#: inventory/models.py:1136 +#: inventory/models.py:1256 msgid "SMS" msgstr "رسالة نصية" -#: inventory/models.py:1138 inventory/models.py:1645 +#: inventory/models.py:1258 inventory/models.py:1815 #: templates/components/activity_modal.html:19 -#: templates/crm/leads/lead_detail.html:71 -#: templates/crm/leads/lead_list.html:38 +#: templates/crm/leads/partials/update_action.html:31 msgid "Meeting" msgstr "اجتماع" -#: inventory/models.py:1140 +#: inventory/models.py:1260 msgid "Visit" msgstr "زيارة" -#: inventory/models.py:1142 templates/crm/leads/lead_detail.html:57 -#: templates/crm/leads/lead_detail.html:134 -#: templates/crm/leads/lead_list.html:26 templates/crm/leads/lead_list.html:41 +#: inventory/models.py:1261 inventory/models.py:1285 +msgid "Negotiation" +msgstr "مفاوضات" + +#: inventory/models.py:1262 msgid "Follow Up" msgstr "متابعة" -#: inventory/models.py:1146 -msgid "Converted" -msgstr "تم التحويل" +#: inventory/models.py:1263 templates/crm/leads/lead_tracking.html:126 +msgid "Won" +msgstr "تم الفوز" -#: inventory/models.py:1148 templates/inventory/car_form.html:38 +#: inventory/models.py:1264 templates/crm/leads/lead_tracking.html:142 +msgid "Lost" +msgstr "تم الفقد" + +#: inventory/models.py:1265 +msgid "Closed" +msgstr "مغلقة" + +#: inventory/models.py:1268 templates/inventory/car_form.html:38 #: templates/sales/estimates/estimate_form.html:20 msgid "Add Car" msgstr "إضافة سيارة" -#: inventory/models.py:1149 +#: inventory/models.py:1269 msgid "Sale Car" msgstr "بيع سيارة" -#: inventory/models.py:1150 templates/inventory/reserve_car.html:5 +#: inventory/models.py:1270 templates/inventory/reserve_car.html:5 #: templates/inventory/reserve_car.html:8 msgid "Reserve Car" msgstr "حجز السيارة" -#: inventory/models.py:1151 templates/inventory/transfer_car.html:4 +#: inventory/models.py:1271 templates/inventory/transfer_car.html:4 msgid "Transfer Car" msgstr "نقل السيارة" -#: inventory/models.py:1152 +#: inventory/models.py:1272 msgid "Remove Car" msgstr "إزالة السيارة" -#: inventory/models.py:1153 +#: inventory/models.py:1273 #: templates/crm/opportunities/opportunity_detail.html:18 #: templates/sales/estimates/estimate_form.html:5 #: templates/sales/estimates/estimate_form.html:32 msgid "Create Quotation" msgstr "إنشاء عرض" -#: inventory/models.py:1154 +#: inventory/models.py:1274 msgid "Cancel Quotation" msgstr "إلغاء العرض" -#: inventory/models.py:1155 +#: inventory/models.py:1275 msgid "Create Order" msgstr "إنشاء طلب" -#: inventory/models.py:1156 +#: inventory/models.py:1276 msgid "Cancel Order" msgstr "إلغاء الطلب" -#: inventory/models.py:1157 templates/sales/estimates/estimate_detail.html:108 +#: inventory/models.py:1277 templates/sales/estimates/estimate_detail.html:108 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_create.html:24 #: venv/lib/python3.11/site-packages/django_ledger/views/invoice.py:68 msgid "Create Invoice" msgstr "إنشاء فاتورة" -#: inventory/models.py:1158 +#: inventory/models.py:1278 msgid "Cancel Invoice" msgstr "إلغاء الفاتورة" -#: inventory/models.py:1162 -msgid "Discovery" -msgstr "الاكتشاف" +#: inventory/models.py:1282 +msgid "Qualification" +msgstr "التأهيل" -#: inventory/models.py:1163 -msgid "Proposal" -msgstr "عرض" +msgid "Test Drive" +msgstr "تجربة القيادة" -#: inventory/models.py:1165 +#: inventory/models.py:1284 templates/customers/view_customer.html:132 +#: templates/sales/estimates/estimate_detail.html:79 +#: templates/sales/estimates/estimate_send.html:5 +#: templates/sales/estimates/sale_order_form.html:171 +#: templates/sales/sales_list.html:118 +msgid "Quotation" +msgstr "عرض سعر" + +#: inventory/models.py:1286 +#: venv/lib/python3.11/site-packages/django_ledger/models/journal_entry.py:356 +msgid "Financing" +msgstr "تمويل" + +#: inventory/models.py:1287 msgid "Closed Won" msgstr "مغلقة - ناجحة" -#: inventory/models.py:1166 +#: inventory/models.py:1288 msgid "Closed Lost" msgstr "مغلقة - خسارة" -#: inventory/models.py:1170 +#: inventory/models.py:1289 +msgid "On Hold" +msgstr "في الانتظار" + +#: inventory/models.py:1293 msgid "Low" msgstr "منخفض" -#: inventory/models.py:1171 +#: inventory/models.py:1294 msgid "Medium" msgstr "متوسط" -#: inventory/models.py:1172 +#: inventory/models.py:1295 msgid "High" msgstr "مرتفع" -#: inventory/models.py:1185 inventory/models.py:1773 +#: inventory/models.py:1309 inventory/models.py:2042 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_table.html:11 msgid "Title" msgstr "العنوان" -#: inventory/models.py:1193 +#: inventory/models.py:1317 msgid "Male" msgstr "ذكر" -#: inventory/models.py:1193 +#: inventory/models.py:1317 msgid "Female" msgstr "أنثى" -#: inventory/models.py:1195 +#: inventory/models.py:1319 msgid "Gender" msgstr "الجنس" -#: inventory/models.py:1197 +#: inventory/models.py:1321 msgid "Date of Birth" msgstr "تاريخ الميلاد" -#: inventory/models.py:1200 templates/customers/customer_list.html:46 +#: inventory/models.py:1324 templates/customers/customer_list.html:46 msgid "National ID" msgstr "رقم الهوية الوطنية" -#: inventory/models.py:1210 templates/administration/manage_service.html:76 +#: inventory/models.py:1334 templates/administration/manage_service.html:76 #: venv/lib/python3.11/site-packages/django/db/models/fields/files.py:420 msgid "Image" msgstr "الصورة" -#: inventory/models.py:1228 inventory/models.py:1456 +#: inventory/models.py:1358 inventory/models.py:1615 #: templates/sales/estimates/estimate_detail.html:154 #: templates/sales/estimates/estimate_list.html:15 #: templates/sales/estimates/sale_order_preview.html:167 @@ -1436,7 +1487,7 @@ msgstr "الصورة" msgid "Customer" msgstr "العميل" -#: inventory/models.py:1229 templates/admin_management/user_management.html:14 +#: inventory/models.py:1359 templates/admin_management/user_management.html:14 #: templates/customers/customer_list.html:4 #: templates/customers/customer_list.html:5 #: templates/customers/customer_list.html:9 @@ -1444,113 +1495,99 @@ msgstr "العميل" msgid "Customers" msgstr "العملاء" -#: inventory/models.py:1349 inventory/models.py:1456 +#: inventory/models.py:1496 inventory/models.py:1615 inventory/models.py:1902 msgid "Organization" msgstr "شركة" -#: inventory/models.py:1350 templates/admin_management/user_management.html:78 +#: inventory/models.py:1497 templates/admin_management/user_management.html:78 #: templates/header.html:165 templates/organizations/organization_list.html:5 #: templates/organizations/organization_list.html:8 #: templates/organizations/organization_list.html:14 msgid "Organizations" msgstr "الشركات" -#: inventory/models.py:1432 +#: inventory/models.py:1587 #: templates/representatives/representative_detail.html:8 #: templates/representatives/representative_list.html:18 msgid "ID Number" msgstr "رقم الهوية" -#: inventory/models.py:1442 +#: inventory/models.py:1597 msgid "Representative" msgstr "ممثل شركة" -#: inventory/models.py:1443 +#: inventory/models.py:1598 #: templates/representatives/representative_list.html:3 #: templates/representatives/representative_list.html:6 msgid "Representatives" msgstr "ممثلي الشركات" -#: inventory/models.py:1456 +#: inventory/models.py:1616 msgid "Lead Type" msgstr "نوع العميل المتوقع" -#: inventory/models.py:1484 +#: inventory/models.py:1649 msgid "Source" msgstr "المصدر" -#: inventory/models.py:1487 +#: inventory/models.py:1652 msgid "Channel" msgstr "القناة" -#: inventory/models.py:1495 -msgid "address" -msgstr "العنوان" - -#: inventory/models.py:1502 +#: inventory/models.py:1660 msgid "Assigned" msgstr "مُعين" -#: inventory/models.py:1508 -msgid "Priority" -msgstr "الأولوية" - -#: inventory/models.py:1519 templates/crm/leads/lead_detail.html:66 -#: templates/crm/leads/lead_detail.html:218 -#: templates/crm/leads/lead_list.html:34 +#: inventory/models.py:1670 templates/crm/leads/lead_detail.html:167 +#: templates/crm/leads/partials/update_action.html:26 msgid "Next Action" msgstr "الإجراء التالي" -#: inventory/models.py:1524 templates/crm/leads/lead_detail.html:77 -#: templates/crm/leads/lead_list.html:46 +#: inventory/models.py:1673 templates/crm/leads/partials/update_action.html:37 msgid "Next Action Date" msgstr "تاريخ الإجراء التالي" -#: inventory/models.py:1530 templates/crm/leads/lead_detail.html:175 -msgid "Salary" -msgstr "الراتب" - -#: inventory/models.py:1538 +#: inventory/models.py:1685 msgid "Lead" msgstr "فرصة" -#: inventory/models.py:1539 templates/crm/leads/lead_list.html:3 +#: inventory/models.py:1686 templates/crm/leads/lead_list.html:3 #: templates/crm/leads/lead_list.html:7 templates/crm/leads/lead_send.html:5 #: templates/dashboards/manager.html:21 test.txt:21 msgid "Leads" msgstr "الفرص" -#: inventory/models.py:1636 +#: inventory/models.py:1806 msgid "Product Demo" msgstr "عرض توضيحي للمنتج" -#: inventory/models.py:1637 +#: inventory/models.py:1807 msgid "Follow-Up Call" msgstr "مكالمة متابعة" -#: inventory/models.py:1638 +#: inventory/models.py:1808 msgid "Contract Discussion" msgstr "مناقشة العقد" -#: inventory/models.py:1639 +#: inventory/models.py:1809 msgid "Sales Meeting" msgstr "اجتماع مبيعات" -#: inventory/models.py:1640 +#: inventory/models.py:1810 msgid "Support Call" msgstr "مكالمة دعم" -#: inventory/models.py:1641 +#: inventory/models.py:1811 #: venv/lib/python3.11/site-packages/django_ledger/models/estimate.py:240 #: venv/lib/python3.11/site-packages/django_ledger/models/items.py:511 msgid "Other" msgstr "أخرى" -#: inventory/models.py:1649 +#: inventory/models.py:1819 msgid "Scheduled" msgstr "مجدول" -#: inventory/models.py:1650 inventory/models.py:1776 +#: inventory/models.py:1820 inventory/models.py:2045 #: templates/sales/estimates/estimate_detail.html:88 #: templates/sales/estimates/estimate_detail.html:175 #: templates/sales/estimates/estimate_list.html:39 @@ -1558,7 +1595,7 @@ msgstr "مجدول" msgid "Completed" msgstr "مكتمل" -#: inventory/models.py:1651 templates/crm/leads/lead_list.html:175 +#: inventory/models.py:1821 templates/crm/leads/lead_list.html:122 #: templates/sales/estimates/estimate_detail.html:90 #: templates/sales/estimates/estimate_detail.html:177 #: templates/sales/estimates/estimate_list.html:37 @@ -1571,73 +1608,76 @@ msgstr "مكتمل" msgid "Canceled" msgstr "ملغى" -#: inventory/models.py:1683 +#: inventory/models.py:1863 msgid "Old Status" msgstr "الحالة القديمة" -#: inventory/models.py:1686 +#: inventory/models.py:1866 msgid "New Status" msgstr "الحالة الجديدة" -#: inventory/models.py:1691 +#: inventory/models.py:1871 msgid "Changed At" msgstr "تم التغيير في" -#: inventory/models.py:1694 +#: inventory/models.py:1874 msgid "Lead Status History" msgstr "تاريخ حالة العميل المحتمل" -#: inventory/models.py:1695 +#: inventory/models.py:1875 msgid "Lead Status Histories" msgstr "تواريخ حالات العملاء المحتملين" -#: inventory/models.py:1703 +#: inventory/models.py:1883 msgid "Probability must be between 0 and 100." msgstr "يجب أن تكون الاحتمالية بين 0 و 100." -#: inventory/models.py:1729 +#: inventory/models.py:1910 +msgid "Salary" +msgstr "الراتب" + +#: inventory/models.py:1913 templates/crm/leads/lead_detail.html:265 +msgid "Priority" +msgstr "الأولوية" + +#: inventory/models.py:1937 +#: templates/crm/opportunities/opportunity_detail.html:179 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:78 -#: templates/crm/opportunities/partials/opportunity_grid.html:60 +#: templates/crm/opportunities/partials/opportunity_grid.html:81 msgid "Expected Revenue" msgstr "الإيرادات المتوقعة" -#: inventory/models.py:1731 -#: templates/crm/opportunities/opportunity_detail.html:266 -#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:100 -#: templates/crm/opportunities/partials/opportunity_grid.html:72 -#: venv/lib/python3.11/site-packages/django_ledger/models/closing_entry.py:75 -msgid "Closing Date" -msgstr "تاريخ الإغلاق" - -#: inventory/models.py:1736 +#: inventory/models.py:1956 msgid "Unique slug for the opportunity." msgstr "المُعرّف الفريد للفرصة (slug)." -#: inventory/models.py:1742 templates/crm/leads/lead_list.html:128 -#: templates/header.html:148 +#: inventory/models.py:2008 templates/crm/leads/lead_detail.html:110 +#: templates/crm/leads/lead_list.html:75 templates/header.html:148 msgid "Opportunity" msgstr "فرصة" -#: inventory/models.py:1743 +#: inventory/models.py:2009 templates/crm/leads/lead_detail.html:170 +#: templates/crm/leads/lead_detail.html:254 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:8 #: templates/crm/opportunities/opportunity_list.html:4 #: templates/crm/opportunities/opportunity_list.html:8 msgid "Opportunities" msgstr "الفرص" -#: inventory/models.py:1754 inventory/models.py:1762 +#: inventory/models.py:2022 inventory/models.py:2030 #: templates/account/snippets/already_logged_in.html:8 -#: templates/crm/leads/lead_detail.html:314 -#: templates/crm/leads/lead_detail.html:592 +#: templates/crm/leads/lead_detail.html:295 +#: templates/crm/leads/lead_detail.html:554 #: templates/customers/view_customer.html:95 msgid "Note" msgstr "ملاحظة" -#: inventory/models.py:1763 inventory/models.py:1824 -#: templates/crm/leads/lead_detail.html:82 -#: templates/crm/leads/lead_detail.html:222 -#: templates/crm/leads/lead_detail.html:305 -#: templates/crm/leads/lead_list.html:51 +#: inventory/models.py:2031 inventory/models.py:2105 +#: templates/bill/includes/card_markdown.html:9 +#: templates/crm/leads/lead_detail.html:172 +#: templates/crm/leads/lead_detail.html:286 +#: templates/crm/leads/partials/update_action.html:42 +#: templates/crm/opportunities/opportunity_detail.html:329 #: templates/customers/view_customer.html:192 #: templates/plans/invoices/layout.html:175 #: venv/lib/python3.11/site-packages/django_ledger/forms/bill.py:154 @@ -1645,7 +1685,9 @@ msgstr "ملاحظة" msgid "Notes" msgstr "ملاحظات" -#: inventory/models.py:1775 +#: inventory/models.py:2044 templates/bill/includes/card_bill.html:107 +#: templates/bill/includes/card_bill.html:127 +#: templates/bill/includes/card_bill.html:150 #: templates/ledger/journal_entry/includes/card_invoice.html:52 #: templates/ledger/journal_entry/includes/card_invoice.html:63 #: templates/ledger/journal_entry/includes/card_invoice.html:77 @@ -1660,42 +1702,47 @@ msgstr "ملاحظات" msgid "Due Date" msgstr "تاريخ الاستحقاق" -#: inventory/models.py:1787 templates/crm/leads/lead_detail.html:572 +#: inventory/models.py:2060 templates/components/task_modal.html:7 +#: templates/crm/leads/lead_detail.html:534 msgid "Task" msgstr "مهمة" -#: inventory/models.py:1788 templates/crm/leads/lead_detail.html:224 -#: templates/crm/leads/lead_detail.html:485 +#: inventory/models.py:2061 templates/crm/leads/lead_detail.html:174 +#: templates/crm/leads/lead_detail.html:465 +#: templates/crm/opportunities/opportunity_detail.html:335 +#: templates/crm/opportunities/opportunity_detail.html:584 msgid "Tasks" msgstr "مهام" -#: inventory/models.py:1797 +#: inventory/models.py:2071 msgid "From Email" msgstr "من البريد الإلكتروني" -#: inventory/models.py:1798 +#: inventory/models.py:2072 msgid "To Email" msgstr "إلى البريد الإلكتروني" -#: inventory/models.py:1799 +#: inventory/models.py:2073 msgid "Subject" msgstr "الموضوع" -#: inventory/models.py:1800 inventory/models.py:1843 +#: inventory/models.py:2074 inventory/models.py:2124 msgid "Message" msgstr "رسالة" -#: inventory/models.py:1810 templates/crm/leads/lead_detail.html:223 -#: templates/crm/leads/lead_detail.html:362 +#: inventory/models.py:2089 templates/crm/leads/lead_detail.html:173 +#: templates/crm/leads/lead_detail.html:342 +#: templates/crm/opportunities/opportunity_detail.html:334 msgid "Emails" msgstr "رسائل البريد الإلكتروني" -#: inventory/models.py:1822 +#: inventory/models.py:2103 msgid "Activity Type" msgstr "نوع النشاط" -#: inventory/models.py:1832 templates/components/activity_modal.html:7 -#: templates/crm/leads/lead_detail.html:221 +#: inventory/models.py:2113 templates/components/activity_modal.html:7 +#: templates/crm/leads/lead_detail.html:171 +#: templates/crm/opportunities/opportunity_detail.html:328 #: templates/dealers/activity_log.html:3 templates/dealers/activity_log.html:12 #: templates/ledger/journal_entry/includes/card_journal_entry.html:32 #: templates/ledger/journal_entry/journal_entry_list.html:50 @@ -1707,121 +1754,122 @@ msgstr "نوع النشاط" msgid "Activity" msgstr "النشاط" -#: inventory/models.py:1833 templates/crm/leads/lead_detail.html:257 +#: inventory/models.py:2114 templates/crm/leads/lead_detail.html:206 #: templates/header.html:434 msgid "Activities" msgstr "الأنشطة" -#: inventory/models.py:1844 +#: inventory/models.py:2125 msgid "Is Read" msgstr "تمت قراءته" -#: inventory/models.py:1848 +#: inventory/models.py:2129 msgid "Notification" msgstr "إشعار" -#: inventory/models.py:1849 templates/crm/notifications_history.html:6 +#: inventory/models.py:2130 templates/crm/notifications_history.html:6 #: templates/notifications-copy.html:13 templates/notifications.html:23 msgid "Notifications" msgstr "الإشعارات" -#: inventory/models.py:1873 +#: inventory/models.py:2156 msgid "Vendor Model" msgstr "نموذج المورد" -#: inventory/models.py:1902 templates/admin_management/user_management.html:142 +#: inventory/models.py:2192 templates/admin_management/user_management.html:142 #: templates/vendors/vendors_list.html:5 templates/vendors/vendors_list.html:7 #: templates/vendors/vendors_list.html:12 msgid "Vendors" msgstr "الموردين" -#: inventory/models.py:1974 inventory/models.py:1998 +#: inventory/models.py:2280 inventory/models.py:2303 msgid "amount" msgstr "المبلغ" -#: inventory/models.py:1977 +#: inventory/models.py:2283 msgid "method" msgstr "طريقة" -#: inventory/models.py:1980 +#: inventory/models.py:2286 msgid "reference number" msgstr "رقم المرجع" -#: inventory/models.py:1982 +#: inventory/models.py:2288 msgid "date" msgstr "التاريخ" -#: inventory/models.py:1986 +#: inventory/models.py:2291 msgid "payment" msgstr "الدفعة" -#: inventory/models.py:1987 templates/header.html:102 +#: inventory/models.py:2292 templates/header.html:102 msgid "payments" msgstr "المدفوعات" -#: inventory/models.py:2000 +#: inventory/models.py:2305 msgid "reason" msgstr "السبب" -#: inventory/models.py:2001 +#: inventory/models.py:2306 msgid "refund date" msgstr "تاريخ الاسترداد" -#: inventory/models.py:2004 +#: inventory/models.py:2309 msgid "refund" msgstr "استرداد" -#: inventory/models.py:2005 +#: inventory/models.py:2310 msgid "refunds" msgstr "استردادات" -#: inventory/models.py:2017 +#: inventory/models.py:2322 msgid "User Activity Log" msgstr "سجل نشاط المستخدم" -#: inventory/models.py:2018 +#: inventory/models.py:2323 msgid "User Activity Logs" msgstr "سجلات نشاط المستخدم" -#: inventory/models.py:2029 +#: inventory/models.py:2346 +#: templates/crm/opportunities/opportunity_detail.html:104 #: venv/lib/python3.11/site-packages/django_ledger/models/entity.py:3173 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:9 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_table.html:9 msgid "Estimate" msgstr "تقدير" -#: inventory/models.py:2040 inventory/tasks.py:38 +#: inventory/models.py:2359 inventory/tasks.py:782 #: templates/ledger/reports/dashboard.html:32 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:14 msgid "Cash" msgstr "نقداً" -#: inventory/models.py:2041 +#: inventory/models.py:2360 msgid "Finance" msgstr "تمويل" -#: inventory/models.py:2042 +#: inventory/models.py:2361 msgid "Lease" msgstr "تأجير" -#: inventory/models.py:2043 +#: inventory/models.py:2362 #: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:1139 msgid "Credit Card" msgstr "بطاقة ائتمان" -#: inventory/models.py:2044 +#: inventory/models.py:2363 msgid "Bank Transfer" msgstr "تحويل بنكي" -#: inventory/models.py:2088 templates/users/user_group_form.html:4 +#: inventory/models.py:2538 templates/users/user_group_form.html:4 msgid "Group" msgstr "مجموعة" -#: inventory/models.py:2255 +#: inventory/models.py:2843 msgid "Payment History" msgstr "سجل الدفع" -#: inventory/models.py:2256 +#: inventory/models.py:2844 msgid "Payment Histories" msgstr "سجلات الدفع" @@ -1837,262 +1885,262 @@ msgstr "اللون الداخلي" msgid "Age" msgstr "العمر" -#: inventory/tasks.py:50 templates/ledger/ledger/ledger_detail.html:38 +#: inventory/tasks.py:794 templates/ledger/ledger/ledger_detail.html:38 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:41 msgid "Accounts Receivable" msgstr "الحسابات المدينة" -#: inventory/tasks.py:75 +#: inventory/tasks.py:819 msgid "Prepaid Expenses" msgstr "المصروفات المدفوعة مقدمًا" -#: inventory/tasks.py:87 +#: inventory/tasks.py:831 msgid "Employee Advance" msgstr "سلفة الموظف" -#: inventory/tasks.py:98 +#: inventory/tasks.py:842 msgid "VAT Receivable" msgstr "ضريبة القيمة المضافة المستحقة" -#: inventory/tasks.py:108 +#: inventory/tasks.py:852 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:452 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:538 msgid "Buildings - Accum. Depreciation" msgstr "المباني - الإهلاك المتراكم" -#: inventory/tasks.py:120 +#: inventory/tasks.py:864 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:459 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:545 msgid "Intangible Assets" msgstr "الأصول غير الملموسة" -#: inventory/tasks.py:132 +#: inventory/tasks.py:876 msgid "Investments" msgstr "الاستثمارات" -#: inventory/tasks.py:169 +#: inventory/tasks.py:913 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:451 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:537 msgid "Buildings" msgstr "المباني" -#: inventory/tasks.py:183 +#: inventory/tasks.py:927 templates/bill/bill_detail.html:89 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:466 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:552 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:52 msgid "Accounts Payable" msgstr "الحسابات الدائنة" -#: inventory/tasks.py:195 templates/ledger/ledger/ledger_detail.html:46 +#: inventory/tasks.py:939 templates/ledger/ledger/ledger_detail.html:46 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:472 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:558 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:51 msgid "Deferred Revenue" msgstr "الإيرادات المؤجلة" -#: inventory/tasks.py:207 +#: inventory/tasks.py:951 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:467 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:553 msgid "Wages Payable" msgstr "الأجور المستحقة الدفع" -#: inventory/tasks.py:219 +#: inventory/tasks.py:963 msgid "Long-Term Notes Payable" msgstr "أوراق الدفع طويلة الأجل" -#: inventory/tasks.py:231 +#: inventory/tasks.py:975 msgid "VAT Payable" msgstr "ضريبة القيمة المضافة المستحقة الدفع" -#: inventory/tasks.py:241 +#: inventory/tasks.py:985 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:469 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:555 msgid "Taxes Payable" msgstr "الضرائب المستحقة الدفع" -#: inventory/tasks.py:251 +#: inventory/tasks.py:995 msgid "Social Insurance Payable" msgstr "التأمينات الاجتماعية المستحقة الدفع" -#: inventory/tasks.py:257 +#: inventory/tasks.py:1001 msgid "End of Service Benefits" msgstr "مكافأة نهاية الخدمة" -#: inventory/tasks.py:264 +#: inventory/tasks.py:1008 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:478 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:564 msgid "Mortgage Payable" msgstr "الرهن المستحق الدفع" -#: inventory/tasks.py:272 +#: inventory/tasks.py:1016 msgid "Registered Capital" msgstr "رأس المال المسجل" -#: inventory/tasks.py:275 +#: inventory/tasks.py:1019 msgid "Additional Paid-In Capital" msgstr "رأس المال المدفوع الإضافي" -#: inventory/tasks.py:278 +#: inventory/tasks.py:1022 msgid "Opening Balances" msgstr "الأرصدة الافتتاحية" -#: inventory/tasks.py:283 +#: inventory/tasks.py:1027 msgid "Statutory Reserve" msgstr "الاحتياطي النظامي" -#: inventory/tasks.py:286 +#: inventory/tasks.py:1030 msgid "Foreign Currency Translation Reserve" msgstr "احتياطي تحويل العملات الأجنبية" -#: inventory/tasks.py:293 +#: inventory/tasks.py:1037 msgid "Operating Profits and Losses" msgstr "الأرباح والخسائر التشغيلية" -#: inventory/tasks.py:304 +#: inventory/tasks.py:1048 msgid "Retained Earnings (or Losses)" msgstr "الأرباح المحتجزة (أو الخسائر)" -#: inventory/tasks.py:314 +#: inventory/tasks.py:1058 msgid "Sales Revenue" msgstr "إيرادات المبيعات" -#: inventory/tasks.py:326 +#: inventory/tasks.py:1070 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:492 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:580 msgid "Interest Income" msgstr "دخل الفائدة" -#: inventory/tasks.py:338 +#: inventory/tasks.py:1082 msgid "Unearned Income" msgstr "الدخل غير المكتسب" -#: inventory/tasks.py:344 +#: inventory/tasks.py:1088 msgid "Sales/Service Revenue" msgstr "إيرادات المبيعات/الخدمات" -#: inventory/tasks.py:347 +#: inventory/tasks.py:1091 msgid "Non-Operating Revenues" msgstr "الإيرادات غير التشغيلية" -#: inventory/tasks.py:355 inventory/tasks.py:536 +#: inventory/tasks.py:1099 inventory/tasks.py:1280 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:497 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:587 msgid "Cost of Goods Sold" msgstr "تكلفة البضائع المباعة" -#: inventory/tasks.py:368 +#: inventory/tasks.py:1112 msgid "Accrued Expenses" msgstr "المصروفات المستحقة" -#: inventory/tasks.py:378 +#: inventory/tasks.py:1122 msgid "Accrued Salaries" msgstr "الرواتب المستحقة" -#: inventory/tasks.py:388 +#: inventory/tasks.py:1132 msgid "Rent Expense" msgstr "مصروف الإيجار" -#: inventory/tasks.py:400 +#: inventory/tasks.py:1144 msgid "Salaries and Administrative Fees" msgstr "الرواتب والرسوم الإدارية" -#: inventory/tasks.py:410 +#: inventory/tasks.py:1154 msgid "Medical Insurance" msgstr "التأمين الطبي" -#: inventory/tasks.py:420 +#: inventory/tasks.py:1164 msgid "Marketing and Advertising Expenses" msgstr "مصروفات التسويق والإعلان" -#: inventory/tasks.py:430 +#: inventory/tasks.py:1174 msgid "Commissions and Incentives" msgstr "العمولات والحوافز" -#: inventory/tasks.py:440 +#: inventory/tasks.py:1184 msgid "Travel Tickets" msgstr "تذاكر السفر" -#: inventory/tasks.py:450 +#: inventory/tasks.py:1194 msgid "Social Insurance" msgstr "التأمينات الاجتماعية" -#: inventory/tasks.py:460 +#: inventory/tasks.py:1204 msgid "Government Fees" msgstr "الرسوم الحكومية" -#: inventory/tasks.py:470 +#: inventory/tasks.py:1214 msgid "Fees and Subscriptions" msgstr "الرسوم والاشتراكات" -#: inventory/tasks.py:480 +#: inventory/tasks.py:1224 msgid "Office Services Expenses" msgstr "مصروفات خدمات المكتب" -#: inventory/tasks.py:490 +#: inventory/tasks.py:1234 msgid "Office Supplies and Printing" msgstr "اللوازم المكتبية والطباعة" -#: inventory/tasks.py:500 +#: inventory/tasks.py:1244 msgid "Hospitality Expenses" msgstr "مصروفات الضيافة" -#: inventory/tasks.py:510 +#: inventory/tasks.py:1254 msgid "Bank Commissions" msgstr "عمولات البنوك" -#: inventory/tasks.py:520 +#: inventory/tasks.py:1264 #: templates/ledger/reports/tags/income_statement.html:223 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html:291 msgid "Other Expenses" msgstr "مصروفات أخرى" -#: inventory/tasks.py:530 +#: inventory/tasks.py:1274 msgid "Transportation Expenses" msgstr "مصروفات النقل" -#: inventory/tasks.py:537 +#: inventory/tasks.py:1281 msgid "Salaries and Wages" msgstr "الرواتب والأجور" -#: inventory/tasks.py:538 +#: inventory/tasks.py:1282 msgid "Sales Commissions" msgstr "عمولات المبيعات" -#: inventory/tasks.py:539 +#: inventory/tasks.py:1283 msgid "Shipping and Customs Clearance" msgstr "الشحن والتخليص الجمركي" -#: inventory/tasks.py:542 +#: inventory/tasks.py:1286 msgid "Zakat" msgstr "الزكاة" -#: inventory/tasks.py:543 +#: inventory/tasks.py:1287 msgid "Taxes" msgstr "الضرائب" -#: inventory/tasks.py:544 +#: inventory/tasks.py:1288 msgid "Foreign Currency Translation" msgstr "تحويل العملات الأجنبية" -#: inventory/tasks.py:545 +#: inventory/tasks.py:1289 msgid "Interest Expenses" msgstr "مصروفات الفائدة" -#: inventory/utils.py:74 +#: inventory/utils.py:79 msgid "success" msgstr "ناجحة" -#: inventory/utils.py:75 templates/inventory/car_form.html:387 +#: inventory/utils.py:80 templates/inventory/car_form.html:397 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:381 msgid "error" msgstr "خطأ" -#: inventory/utils.py:76 templates/account/login.html:48 +#: inventory/utils.py:81 templates/account/login.html:48 #: templates/account/password_change.html:28 msgid "Forgot Password?" msgstr "نسيت كلمة المرور؟" -#: inventory/utils.py:212 +#: inventory/utils.py:217 msgid "Car reserved successfully." msgstr "تم حجز السيارة بنجاح." @@ -2100,480 +2148,488 @@ msgstr "تم حجز السيارة بنجاح." msgid "Enter a valid Saudi phone number (05XXXXXXXX or +9665XXXXXXXX)" msgstr "أدخل رقم جوال سعودي صحيح 05XXXXXXXX" -#: inventory/views.py:270 +#: inventory/views.py:297 msgid "Passwords do not match" msgstr "كلمات المرور غير متطابقة." -#: inventory/views.py:275 inventory/views.py:2672 +#: inventory/views.py:302 inventory/views.py:2712 msgid "User created successfully" msgstr "تم إنشاء المستخدم بنجاح." -#: inventory/views.py:578 +#: inventory/views.py:605 msgid "Car saved successfully" msgstr "تم حفظ السيارة بنجاح" -#: inventory/views.py:650 +#: inventory/views.py:677 msgid "VIN number exists" msgstr "رقم الهيكل موجود مسبقاً" -#: inventory/views.py:674 +#: inventory/views.py:701 msgid "Manufacturer not found in the database" msgstr "لم يتم العثور على الشركة المصنعة في قاعدة البيانات" -#: inventory/views.py:691 +#: inventory/views.py:718 msgid "VIN not found in all sources" msgstr "لم يتم العثور على رقم التعريف (VIN) في جميع المصادر" -#: inventory/views.py:721 +#: inventory/views.py:748 msgid "Server error occurred" msgstr "حدث خطأ في الخادم" -#: inventory/views.py:819 +#: inventory/views.py:846 msgid "No image provided" msgstr "لم يتم تقديم صورة" -#: inventory/views.py:832 +#: inventory/views.py:859 msgid "No QR/Barcode detected" msgstr "لم يتم اكتشاف رمز QR أو الباركود" -#: inventory/views.py:878 templates/dashboards/manager.html:48 +#: inventory/views.py:905 templates/dashboards/manager.html:48 #: templates/dashboards/sales.html:112 templates/inventory/car_inventory.html:4 #: templates/inventory/inventory_stats.html:4 msgid "inventory" msgstr "المخزون" -#: inventory/views.py:952 inventory/views.py:1292 -msgid "Car finance details updated successfully" -msgstr "تم تحديث تفاصيل المالية للسيارة بنجاح." +#: inventory/views.py:981 +msgid "Car Colors details updated successfully" +msgstr "تم تحديث تفاصيل ألوان السيارة بنجاح" -#: inventory/views.py:1245 +msgid "Update Colors for %(car_name)s" +msgstr "تحديث الألوان لـ %(car_name)s" + +#: inventory/views.py:1285 msgid "Car finance details saved successfully" msgstr "تم حفظ تفاصيل المالية للسيارة بنجاح." -#: inventory/views.py:1345 +#: inventory/views.py:1332 +msgid "Car finance details updated successfully" +msgstr "تم تحديث تفاصيل المالية للسيارة بنجاح." + +#: inventory/views.py:1385 msgid "Car updated successfully" msgstr "تم تحديث السيارة بنجاح" -#: inventory/views.py:1385 +#: inventory/views.py:1425 msgid "Car deleted successfully" msgstr "تم حذف السيارة بنجاح." -#: inventory/views.py:1422 +#: inventory/views.py:1462 msgid "Location saved successfully" msgstr "تم حفظ يوم الإجازة بنجاح." -#: inventory/views.py:1461 +#: inventory/views.py:1501 msgid "Location updated successfully" msgstr "تم تحديث البريد الإلكتروني بنجاح!" -#: inventory/views.py:1568 +#: inventory/views.py:1608 msgid "Car transfer canceled successfully" msgstr "تم إلغاء نقل السيارة بنجاح." -#: inventory/views.py:1585 +#: inventory/views.py:1625 msgid "Car transfer approved successfully" msgstr "تمت الموافقة على نقل السيارة بنجاح." -#: inventory/views.py:1610 +#: inventory/views.py:1650 msgid "Car transfer rejected successfully" msgstr "تم رفض نقل السيارة بنجاح." -#: inventory/views.py:1622 +#: inventory/views.py:1662 msgid "Car Transfer Completed successfully." msgstr "تم إكمال نقل السيارة بنجاح." -#: inventory/views.py:1692 +#: inventory/views.py:1732 msgid "Custom Card added successfully" msgstr "تم إضافة البطاقة الجمركية بنجاح." -#: inventory/views.py:1734 +#: inventory/views.py:1774 msgid "Registration added successfully" msgstr "تم إلغاء الحجز بنجاح." -#: inventory/views.py:1757 +#: inventory/views.py:1797 msgid "This car is already reserved" msgstr "هذه السيارة محجوزة بالفعل." -#: inventory/views.py:1795 +#: inventory/views.py:1835 msgid "Reservation renewed successfully" msgstr "تم تجديد الحجز بنجاح" -#: inventory/views.py:1803 +#: inventory/views.py:1843 msgid "Reservation canceled successfully" msgstr "تم إلغاء الحجز بنجاح." -#: inventory/views.py:1808 +#: inventory/views.py:1848 msgid "Invalid action" msgstr "إجراء غير صالح." -#: inventory/views.py:1812 +#: inventory/views.py:1852 msgid "Invalid request method" msgstr "طريقة الطلب غير صالحة" -#: inventory/views.py:1888 +#: inventory/views.py:1928 msgid "Dealer updated successfully" msgstr "تم تحديث المعرض بنجاح." -#: inventory/views.py:1922 templates/header.html:157 +#: inventory/views.py:1962 templates/header.html:157 msgid "customers" msgstr "العملاء" -#: inventory/views.py:2083 +#: inventory/views.py:2123 msgid "Customer Account with this email is Deactivated,Please Contact Admin" msgstr "" "تم تعطيل حساب العميل المرتبط بهذا البريد الإلكتروني، يرجى التواصل مع المسؤول" -#: inventory/views.py:2088 +#: inventory/views.py:2128 msgid "Customer with this email already exists" msgstr "يوجد عميل مسجل مسبقًا بهذا البريد الإلكتروني" -#: inventory/views.py:2158 +#: inventory/views.py:2198 msgid "Customer deactivated successfully" msgstr "تم تعطيل حساب العميل بنجاح" -#: inventory/views.py:2253 +#: inventory/views.py:2293 msgid "Vendor created successfully" msgstr "تم إنشاء المورد بنجاح" -#: inventory/views.py:2261 +#: inventory/views.py:2301 msgid "Vendor Account with this email is Deactivated,Please Contact Admin" msgstr "" "تم تعطيل حساب المورد المرتبط بهذا البريد الإلكتروني، يرجى التواصل مع المسؤول" -#: inventory/views.py:2265 +#: inventory/views.py:2305 msgid "Vendor with this email already exists" msgstr "يوجد مورد مسجل مسبقًا بهذا البريد الإلكتروني" -#: inventory/views.py:2304 +#: inventory/views.py:2344 msgid "Vendor updated successfully" msgstr "تم تحديث المورد بنجاح" -#: inventory/views.py:2347 +#: inventory/views.py:2387 msgid "Vendor deleted successfully" msgstr "تم حذف المورد بنجاح." -#: inventory/views.py:2435 +#: inventory/views.py:2475 msgid "Group created successfully" msgstr "تم إنشاء المجموعة بنجاح." -#: inventory/views.py:2478 +#: inventory/views.py:2518 msgid "Group updated successfully" msgstr "تم تحديث المجموعة بنجاح." -#: inventory/views.py:2505 +#: inventory/views.py:2545 msgid "Group deleted successfully" msgstr "تم حذف المجموعة بنجاح." -#: inventory/views.py:2539 +#: inventory/views.py:2579 msgid "Permission added successfully" msgstr "تمت إضافة الإذن بنجاح." -#: inventory/views.py:2575 +#: inventory/views.py:2615 msgid "Group added successfully" msgstr "تمت إضافة المجموعة بنجاح." -#: inventory/views.py:2687 +#: inventory/views.py:2727 msgid "" "You have reached the maximum number of staff users allowed for your plan" msgstr "لقد وصلت إلى الحد الأقصى لعدد أعضاء الفريق المسموح به في خطتك." -#: inventory/views.py:2744 +#: inventory/views.py:2743 +msgid "A user with this email already exists. Please use a different email." +msgstr "يوجد مستخدم بهذا البريد الإلكتروني بالفعل. يرجى استخدام بريد إلكتروني مختلف." + +#: inventory/views.py:2790 msgid "User updated successfully" msgstr "تم تحديث المستخدم بنجاح" -#: inventory/views.py:2795 +#: inventory/views.py:2841 msgid "User deleted successfully" msgstr "تم حذف المستخدم بنجاح." -#: inventory/views.py:2887 +#: inventory/views.py:2933 msgid "" "Organization Account with this email is Deactivated,Please Contact Admin" msgstr "" "تم تعطيل حساب المؤسسة المرتبط بهذا البريد الإلكتروني، يرجى التواصل مع المسؤول" -#: inventory/views.py:2892 +#: inventory/views.py:2938 msgid "Organization with this email already exists" msgstr "يوجد مؤسسة مسجلة مسبقًا بهذا البريد الإلكتروني" -#: inventory/views.py:2953 +#: inventory/views.py:2999 msgid "Organization Deactivated successfully" msgstr "تم إلغاء تفعيل المؤسسة بنجاح" -#: inventory/views.py:3038 +#: inventory/views.py:3084 msgid "Representative created successfully" msgstr "تم إنشاء الخدمة بنجاح." -#: inventory/views.py:3081 +#: inventory/views.py:3127 msgid "Representative updated successfully" msgstr "تم تحديث الخدمة بنجاح." -#: inventory/views.py:3106 +#: inventory/views.py:3152 msgid "Representative deleted successfully" msgstr "تم حذف الخدمة بنجاح!" -#: inventory/views.py:3179 +#: inventory/views.py:3225 msgid "Bank account created successfully" msgstr "تم إنشاء المنظمة بنجاح." -#: inventory/views.py:3252 +#: inventory/views.py:3298 msgid "Bank account updated successfully" msgstr "تم تحديث المجموعة بنجاح." -#: inventory/views.py:3288 +#: inventory/views.py:3334 msgid "Bank account deleted successfully" msgstr "تم حذف الملاحظة بنجاح." -#: inventory/views.py:3376 +#: inventory/views.py:3422 msgid "Account created successfully" msgstr "تم إنشاء المجموعة بنجاح." -#: inventory/views.py:3490 +#: inventory/views.py:3536 msgid "Account updated successfully" msgstr "تم تحديث المجموعة بنجاح." -#: inventory/views.py:3518 +#: inventory/views.py:3564 msgid "Account deleted successfully" msgstr "تم حذف الملاحظة بنجاح." -#: inventory/views.py:3632 inventory/views.py:6210 +#: inventory/views.py:3678 msgid "Items and Quantities are required" msgstr "المنتجات والكميات مطلوبة" -#: inventory/views.py:3641 inventory/views.py:3649 inventory/views.py:6218 -#: inventory/views.py:6226 +#: inventory/views.py:3687 inventory/views.py:3695 msgid "Quantity must be greater than zero" msgstr "يجب أن تكون مدة الفاصل الزمني أكبر من 0." -#: inventory/views.py:3662 inventory/views.py:3675 +#: inventory/views.py:3708 inventory/views.py:3721 msgid "Quantity must be less than or equal to the number of cars in stock" msgstr "يجب أن تكون الكمية أقل من أو تساوي عدد السيارات المتوفرة في المخزون" -#: inventory/views.py:3791 +#: inventory/views.py:3837 msgid "Quotation created successfully" msgstr "تم إنشاء عرض السعر بنجاح" -#: inventory/views.py:4068 +#: inventory/views.py:4144 msgid "Quotation is not ready for review" msgstr "العرض غير جاهز للمراجعة." -#: inventory/views.py:4074 +#: inventory/views.py:4150 msgid "Quotation is not ready for approval" msgstr "العرض غير جاهز للموافقة." -#: inventory/views.py:4077 +#: inventory/views.py:4153 msgid "Quotation approved successfully" msgstr "تمت الموافقة على العرض بنجاح." -#: inventory/views.py:4080 +#: inventory/views.py:4156 msgid "Quotation is not ready for rejection" msgstr "العرض غير جاهز للرفض." -#: inventory/views.py:4083 inventory/views.py:4101 +#: inventory/views.py:4159 inventory/views.py:4177 msgid "Quotation canceled successfully" msgstr "تم إلغاء الحجز بنجاح." -#: inventory/views.py:4086 +#: inventory/views.py:4162 msgid "Quotation is not ready for completion" msgstr "العرض غير جاهز للإكمال." -#: inventory/views.py:4090 +#: inventory/views.py:4166 msgid "Quotation is not ready for cancellation" msgstr "العرض غير جاهز للإلغاء." -#: inventory/views.py:4103 +#: inventory/views.py:4179 msgid "Quotation marked as " msgstr "تم وضع علامة على عرض السعر كـ" -#: inventory/views.py:4523 +#: inventory/views.py:4602 msgid "fully paid" msgstr "مدفوع بالكامل" -#: inventory/views.py:4526 +#: inventory/views.py:4605 msgid "Amount exceeds due amount" msgstr "المبلغ يتجاوز المبلغ المستحق" -#: inventory/views.py:4534 inventory/views.py:4652 +#: inventory/views.py:4613 inventory/views.py:4731 msgid "Payment created successfully" msgstr "تم إنشاء الدفعة بنجاح" -#: inventory/views.py:4656 +#: inventory/views.py:4735 msgid "Invoice is not fully paid, Payment cannot be marked as paid" msgstr "لم يتم دفع الفاتورة بالكامل، لا يمكن وضع علامة مدفوعة على الدفعة" -#: inventory/views.py:4861 +#: inventory/views.py:4943 msgid "Lead created successfully" msgstr "تم إنشاء العميل المتوقع بنجاح" -#: inventory/views.py:5027 +#: inventory/views.py:5109 msgid "Lead deleted successfully" msgstr "تم حذف العميل المتوقع بنجاح" -#: inventory/views.py:5056 inventory/views.py:5087 inventory/views.py:8119 +#: inventory/views.py:5138 inventory/views.py:5171 inventory/views.py:8321 msgid "Note added successfully" msgstr "تمت إضافة الملاحظة بنجاح" -#: inventory/views.py:5082 +#: inventory/views.py:5165 msgid "Notes field is required" msgstr "حقل الملاحظات مطلوب" -#: inventory/views.py:5110 +#: inventory/views.py:5194 msgid "Note deleted successfully." msgstr "تم حذف الملاحظة بنجاح." -#: inventory/views.py:5136 +#: inventory/views.py:5220 msgid "Lead is already converted to customer" msgstr "تم تحويل العميل المتوقع بالفعل إلى عميل" -#: inventory/views.py:5147 +#: inventory/views.py:5231 msgid "Lead converted to customer successfully" msgstr "تم تحويل العميل المتوقع إلى عميل بنجاح" -#: inventory/views.py:5173 +#: inventory/views.py:5257 msgid "You do not have permission to schedule lead" msgstr "ليست لديك صلاحية جدولة هذا العميل المتوقع" -#: inventory/views.py:5217 -msgid "Lead scheduled and appointment created successfully" -msgstr "تمت جدولة العميل المتوقع وإنشاء الموعد بنجاح" +#: inventory/views.py:5295 +msgid "Appointment Created Successfully" +msgstr "تم إنشاء الموعد بنجاح" -#: inventory/views.py:5248 +#: inventory/views.py:5329 msgid "Lead transferred successfully" msgstr "تم نقل العميل المتوقع بنجاح" -#: inventory/views.py:5295 +#: inventory/views.py:5376 msgid "Email Draft successfully" msgstr "تم إنشاء مسودة البريد الإلكتروني بنجاح" -#: inventory/views.py:5330 inventory/views.py:6430 +#: inventory/views.py:5418 inventory/views.py:6637 msgid "Email sent successfully" msgstr "تم إرسال البريد الإلكتروني بنجاح!" -#: inventory/views.py:5579 +#: inventory/views.py:5704 msgid "Opportunity deleted successfully" msgstr "تم حذف الفرصة بنجاح." -#: inventory/views.py:5617 +#: inventory/views.py:5742 msgid "Opportunity status updated successfully" msgstr "تم تحديث حالة الفرصة بنجاح" -#: inventory/views.py:5733 +#: inventory/views.py:5858 msgid "Service created successfully" msgstr "تم إنشاء الخدمة بنجاح" -#: inventory/views.py:5778 +#: inventory/views.py:5903 msgid "Service updated successfully" msgstr "تم تحديث الخدمة بنجاح" -#: inventory/views.py:6041 inventory/views.py:6094 +#: inventory/views.py:6170 inventory/views.py:6223 msgid "Bill updated successfully" msgstr "تم تحديث الفاتورة بنجاح." -#: inventory/views.py:6135 +#: inventory/views.py:6264 msgid "Bill is already approved" msgstr "تمت الموافقة على الفاتورة مسبقًا." -#: inventory/views.py:6139 +#: inventory/views.py:6268 msgid "Bill marked as approved successfully" msgstr "تم تحديد الفاتورة كموافقة بنجاح." -#: inventory/views.py:6166 +#: inventory/views.py:6295 msgid "Bill is already paid" msgstr "تم دفع الفاتورة مسبقًا." -#: inventory/views.py:6175 +#: inventory/views.py:6304 msgid "Bill marked as paid successfully" msgstr "تم تحديد الفاتورة كمدفوعة بنجاح." -#: inventory/views.py:6177 +#: inventory/views.py:6306 msgid "Amount paid is not equal to amount due" msgstr "المبلغ المدفوع لا يساوي المبلغ المستحق." -#: inventory/views.py:6288 -msgid "Bill created successfully" -msgstr "تم تحديث الفاتورة بنجاح." - -#: inventory/views.py:6391 +#: inventory/views.py:6598 msgid "Quotation has no items" msgstr "عرض السعر لا يحتوي على أي عناصر" -#: inventory/views.py:6947 +#: inventory/views.py:7154 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:23 #: venv/lib/python3.11/site-packages/django_ledger/views/entity.py:210 msgid "Dashboard" msgstr "لوحة القيادة" -#: inventory/views.py:7102 inventory/views.py:7135 inventory/views.py:7194 +#: inventory/views.py:7309 inventory/views.py:7342 inventory/views.py:7401 msgid "Unauthorized" msgstr "غير مصرح" -#: inventory/views.py:7320 +#: inventory/views.py:7527 msgid "Settings updated" msgstr "تم تحديث الإعدادات" -#: inventory/views.py:7660 +#: inventory/views.py:7867 msgid "Journal Entry created" msgstr "تم إنشاء قيد اليومية" -#: inventory/views.py:7701 +#: inventory/views.py:7908 msgid "Journal Entry cannot be deleted" msgstr "لا يمكن حذف قيد اليومية" -#: inventory/views.py:7775 +#: inventory/views.py:7982 msgid "Ledger is already locked" msgstr "دفتر الأستاذ مقفل بالفعل" -#: inventory/views.py:7802 +#: inventory/views.py:8009 msgid "Ledger is already Unlocked" msgstr "دفتر الأستاذ غير مقفل بالفعل" -#: inventory/views.py:7831 +#: inventory/views.py:8038 msgid "Ledger is already posted" msgstr "دفتر الأستاذ تم ترحيله بالفعل" -#: inventory/views.py:7861 +#: inventory/views.py:8068 msgid "Ledger is already Unposted" msgstr "دفتر الأستاذ لم يتم ترحيله بعد" -#: inventory/views.py:8054 +#: inventory/views.py:8261 msgid "Activity added successfully" msgstr "تمت إضافة النشاط بنجاح" -#: inventory/views.py:8056 +#: inventory/views.py:8263 msgid "Activity form is not valid" msgstr "نموذج النشاط غير صالح" -#: inventory/views.py:8078 +#: inventory/views.py:8285 msgid "Task added successfully" msgstr "تمت إضافة المهمة بنجاح" -#: inventory/views.py:8081 inventory/views.py:8094 +#: inventory/views.py:8288 msgid "Task form is not valid" msgstr "نموذج المهمة غير صالح" -#: inventory/views.py:8092 -msgid "Task updated successfully" -msgstr "تم تحديث المهمة بنجاح" - -#: inventory/views.py:8122 inventory/views.py:8136 +#: inventory/views.py:8324 inventory/views.py:8338 msgid "Note form is not valid" msgstr "نموذج الملاحظة غير صالح" -#: inventory/views.py:8133 +#: inventory/views.py:8335 msgid "Note updated successfully" msgstr "تم تحديث الملاحظة بنجاح" -#: inventory/views.py:8169 +#: inventory/views.py:8488 msgid "Account activated successfully" msgstr "تم تفعيل الحساب بنجاح" -#: inventory/views.py:8186 +#: inventory/views.py:8505 msgid "Account Deleted successfully" msgstr "تم حذف الحساب بنجاح" -#: inventory/views.py:8190 +#: inventory/views.py:8509 msgid "You cannot delete this account,it is related to another account" msgstr "لا يمكنك حذف هذا الحساب، لأنه مرتبط بحساب آخر" +msgid "Purchase order created successfully" +msgstr "تم إنشاء أمر الشراء بنجاح" + +msgid "Inventory item created successfully" +msgstr "تم إنشاء عنصر المخزون بنجاح" + #: templates/account/account_inactive.html:5 #: templates/account/account_inactive.html:9 msgid "Account Inactive" @@ -2621,16 +2677,16 @@ msgstr "تأكيد" #: templates/account/confirm_email_verification_code.html:31 #: templates/account/confirm_email_verification_code.html:35 #: templates/account/confirm_login_code..html:38 +#: templates/bill/bill_create.html:43 templates/bill/includes/card_bill.html:80 #: templates/crm/leads/lead_form.html:40 #: templates/crm/leads/schedule_lead.html:18 -#: templates/crm/opportunities/opportunity_detail.html:59 #: templates/customers/customer_form.html:39 #: templates/dealers/dealer_form.html:21 templates/groups/group_form.html:42 #: templates/groups/group_permission_form.html:35 -#: templates/inventory/add_colors.html:74 +#: templates/inventory/add_colors.html:76 #: templates/inventory/add_custom_card.html:13 #: templates/inventory/car_confirm_delete.html:11 -#: templates/inventory/car_detail.html:378 +#: templates/inventory/car_detail.html:383 #: templates/inventory/car_finance_form.html:46 #: templates/inventory/car_registration_form.html:14 #: templates/inventory/color_palette.html:108 @@ -2640,7 +2696,8 @@ msgstr "تأكيد" #: templates/items/expenses/expense_create.html:22 #: templates/items/service/service_create.html:33 #: templates/ledger/bank_accounts/bank_account_form.html:42 -#: templates/ledger/bills/bill_form.html:43 +#: templates/ledger/bills/bill_form-copy.html:43 +#: templates/ledger/bills/bill_form.html:18 #: templates/ledger/bills/bill_update_form.html:18 #: templates/ledger/coa_accounts/account_form.html:43 #: templates/ledger/journal_entry/includes/card_invoice.html:134 @@ -2648,6 +2705,9 @@ msgstr "تأكيد" #: templates/ledger/ledger/ledger_form.html:23 #: templates/modal/event_details_modal.html:24 #: templates/organizations/organization_form.html:23 +#: templates/purchase_orders/includes/card_po.html:197 +#: templates/purchase_orders/includes/card_po.html:219 +#: templates/purchase_orders/po_form.html:46 #: templates/representatives/representative_form.html:12 #: templates/sales/estimates/estimate_detail.html:120 #: templates/sales/estimates/estimate_form.html:77 @@ -3261,13 +3321,19 @@ msgstr "في أي مكان" msgid "Submit" msgstr "إرسال" -#: templates/account/signup-wizard.html:74 templates/pricing_page.html:200 +#: templates/account/signup-wizard.html:74 +#: templates/partials/pagination_audit.html:7 +#: templates/partials/pagination_audit.html:9 +#: templates/partials/pagination_audit.html:14 templates/pricing_page.html:200 #: venv/lib/python3.11/site-packages/alabaster/relations.html:9 msgid "Previous" msgstr "السابق" #: templates/account/signup-wizard.html:76 -#: templates/appointment/appointments.html:86 templates/pricing_page.html:201 +#: templates/appointment/appointments.html:86 +#: templates/partials/pagination_audit.html:21 +#: templates/partials/pagination_audit.html:22 +#: templates/partials/pagination_audit.html:27 templates/pricing_page.html:201 #: templates/two_factor/_wizard_actions.html:14 #: venv/lib/python3.11/site-packages/alabaster/relations.html:13 #: venv/lib/python3.11/site-packages/appointment/templates/appointment/appointments.html:85 @@ -3284,13 +3350,13 @@ msgid "Password does not match" msgstr "كلمة المرور غير متطابقة" #: templates/account/signup-wizard.html:252 -#: templates/inventory/car_form.html:618 +#: templates/inventory/car_form.html:628 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:608 msgid "Please Wait" msgstr "الرجاء الإنتظار" #: templates/account/signup-wizard.html:253 -#: templates/inventory/car_form.html:619 +#: templates/inventory/car_form.html:629 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:609 msgid "Loading" msgstr "تحميل" @@ -3393,15 +3459,137 @@ msgstr "" "ملاحظة: لا يزال بإمكانك تغيير " "عنوان بريدك الإلكتروني." +#: templates/admin_management/auth_logs.html:4 +#: templates/admin_management/auth_logs.html:7 +#: templates/admin_management/model_logs.html:4 +#: templates/admin_management/model_logs.html:7 +#: templates/admin_management/request_logs.html:4 +#: templates/admin_management/request_logs.html:7 +#: templates/ledger/coa_accounts/account_list.html:3 +#: templates/ledger/coa_accounts/account_list.html:6 +#: templates/ledger/coa_accounts/account_list.html:13 +#: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:444 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:54 +msgid "Accounts" +msgstr "الحسابات" + +#: templates/admin_management/auth_logs.html:15 +#: templates/admin_management/model_logs.html:15 +#: templates/admin_management/request_logs.html:15 +msgid "Audit Log Dashboard" +msgstr "لوحة سجل التدقيق" + +#: templates/admin_management/auth_logs.html:30 +#: templates/admin_management/model_logs.html:30 +#: templates/admin_management/request_logs.html:29 +#: templates/ledger/journal_entry/journal_entry_list.html:49 +#: templates/ledger/journal_entry/journal_entry_transactions.html:18 +#: templates/sales/payments/payment_details.html:15 +#: templates/sales/payments/payment_list.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/models/journal_entry.py:373 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_txs_table.html:8 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/transactions/tags/txs_table.html:8 +msgid "Timestamp" +msgstr "الطابع الزمني" + +#: templates/admin_management/auth_logs.html:31 +#: templates/admin_management/model_logs.html:31 +#: templates/admin_management/request_logs.html:30 +msgid "User" +msgstr "المستخدم" + +msgid "Event Type" +msgstr "نوع الحدث" + +msgid "username" +msgstr "اسم المستخدم" + +msgid "IP Address" +msgstr "عنوان IP" + #: templates/admin_management/management.html:3 msgid "Admin Management" msgstr "إدارة المشرفين" +#: templates/admin_management/management.html:10 #: templates/admin_management/user_management.html:5 #: templates/admin_management/user_management.html:11 msgid "User Management" msgstr "إدارة المستخدمين" +#: templates/admin_management/management.html:20 +msgid "Audit Log Dashboard" +msgstr "لوحة سجل التدقيق" + +#: templates/admin_management/model_logs.html:32 +#: templates/administration/service_list.html:26 +#: templates/administration/user_profile.html:94 +#: templates/administration/user_profile.html:162 +#: templates/crm/leads/lead_list.html:62 templates/crm/leads/lead_list.html:79 +#: templates/groups/group_detail.html:83 +#: templates/inventory/car_detail.html:422 +#: templates/items/expenses/expenses_list.html:23 +#: templates/items/service/service_list.html:24 +#: templates/ledger/bank_accounts/bank_account_list.html:22 +#: templates/ledger/bills/bill_list.html:51 +#: templates/ledger/journal_entry/journal_entry_list.html:55 +#: templates/ledger/ledger/ledger_list.html:25 +#: templates/modal/confirm_modal.html:21 +#: venv/lib/python3.11/site-packages/appointment/templates/administration/service_list.html:31 +#: venv/lib/python3.11/site-packages/appointment/templates/administration/user_profile.html:106 +#: venv/lib/python3.11/site-packages/appointment/templates/administration/user_profile.html:172 +#: venv/lib/python3.11/site-packages/appointment/templates/modal/confirm_modal.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/inventory/tags/inventory_item_table.html:13 +msgid "Action" +msgstr "الإجراء" + +msgid "Object ID" +msgstr "معرّف الكائن" + +msgid "Object Representation" +msgstr "تمثيل الكائن" + +msgid "Field" +msgstr "الحقل" + +msgid "Old Value" +msgstr "القيمة القديمة" + +msgid "New Value" +msgstr "القيمة الجديدة" + +msgid "Object created." +msgstr "تم إنشاء الكائن." + +msgid "Object deleted." +msgstr "تم حذف الكائن." + +msgid "No specific field changes recorded." +msgstr "لم يتم تسجيل تغييرات محددة في الحقول." + +msgid "No model change audit events found." +msgstr "لم يتم العثور على أحداث تدقيق لتغييرات النماذج." + +msgid "User Actions" +msgstr "إجراءات المستخدم" + +msgid "User Login Events" +msgstr "أحداث تسجيل دخول المستخدم" + +msgid "User Page Requests" +msgstr "طلبات صفحات المستخدم" + +#: templates/admin_management/request_logs.html:31 +#: venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py:2642 +msgid "URL" +msgstr "رابط URL" + +#: templates/admin_management/request_logs.html:32 +#: templates/plans/invoices/layout.html:156 +msgid "Method" +msgstr "طريقة" + #: templates/admin_management/user_management.html:23 msgid "Created date" msgstr "تاريخ الإنشاء" @@ -3410,7 +3598,8 @@ msgstr "تاريخ الإنشاء" #: templates/admin_management/user_management.html:88 #: templates/admin_management/user_management.html:152 #: templates/admin_management/user_management.html:216 -#: templates/inventory/car_detail.html:355 +#: templates/bill/tags/bill_table.html:16 +#: templates/inventory/car_detail.html:360 #: templates/ledger/coa_accounts/account_detail.html:71 #: templates/representatives/representative_list.html:20 #: templates/sales/estimates/estimate_list.html:19 @@ -3494,7 +3683,7 @@ msgstr "تاريخ الإنشاء" #: templates/email_sender/reminder_email.html:80 #: templates/email_sender/reschedule_email.html:64 #: templates/email_sender/reschedule_email.html:69 -#: templates/inventory/car_detail.html:421 +#: templates/inventory/car_detail.html:426 #: templates/inventory/transfer_details.html:73 #: templates/inventory/transfer_preview.html:271 #: templates/ledger/coa_accounts/account_detail.html:67 @@ -3548,7 +3737,7 @@ msgstr "العميل" #: templates/administration/display_appointment.html:55 #: templates/appointment/appointment_client_information.html:57 -#: templates/crm/leads/lead_detail.html:169 +#: templates/crm/leads/lead_detail.html:130 #: templates/dealers/dealer_detail.html:93 #: templates/organizations/organization_detail.html:10 #: templates/organizations/organization_list.html:64 @@ -3589,7 +3778,7 @@ msgstr "معلومات إضافية" msgid "Is paid" msgstr "مدفوع" -#: templates/administration/display_appointment.html:85 +#: templates/administration/display_appointment.html:86 #: venv/lib/python3.11/site-packages/appointment/templates/administration/display_appointment.html:69 msgid "Service price" msgstr "سعر الخدمة" @@ -3618,7 +3807,7 @@ msgstr "لقد أرسلنا رمز التحقق إلى بريدك الإلكتر #: templates/administration/email_change_verification_code.html:22 #: templates/appointment/enter_verification_code.html:21 -#: templates/ledger/coa_accounts/account_list.html:26 +#: templates/ledger/coa_accounts/partials/account_table.html:8 #: venv/lib/python3.11/site-packages/appointment/templates/administration/email_change_verification_code.html:22 #: venv/lib/python3.11/site-packages/appointment/templates/appointment/enter_verification_code.html:21 msgid "Code" @@ -3666,14 +3855,14 @@ msgstr "تأكيد الحذف" #: templates/administration/service_list.html:13 #: templates/administration/staff_index.html:79 #: templates/administration/user_profile.html:18 -#: templates/crm/leads/lead_list.html:142 -#: templates/crm/leads/lead_list.html:279 +#: templates/bill/tags/bill_item_formset.html:41 +#: templates/crm/leads/lead_list.html:89 templates/crm/leads/lead_list.html:226 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:28 #: templates/customers/view_customer.html:23 #: templates/groups/group_detail.html:109 #: templates/ledger/bank_accounts/bank_account_detail.html:63 #: templates/ledger/coa_accounts/account_detail.html:144 -#: templates/ledger/coa_accounts/account_list.html:100 +#: templates/ledger/coa_accounts/partials/account_table.html:45 #: templates/ledger/journal_entry/journal_entry_delete.html:19 #: templates/ledger/journal_entry/journal_entry_list.html:102 #: templates/ledger/ledger/ledger_delete.html:19 @@ -3683,6 +3872,9 @@ msgstr "تأكيد الحذف" #: templates/organizations/organization_detail.html:19 #: templates/organizations/organization_list.html:123 #: templates/plans/billing_info_create_or_update.html:14 +#: templates/purchase_orders/includes/card_po.html:204 +#: templates/purchase_orders/includes/po_item_formset.html:26 +#: templates/purchase_orders/po_delete.html:23 #: templates/representatives/representative_detail.html:16 #: templates/sales/estimates/estimate_detail.html:29 #: templates/users/user_detail.html:60 templates/vendors/vendors_list.html:131 @@ -3771,16 +3963,16 @@ msgstr "" #: templates/administration/manage_staff_member.html:70 #: templates/components/activity_modal.html:25 -#: templates/crm/leads/lead_detail.html:581 -#: templates/crm/leads/lead_detail.html:601 +#: templates/components/task_modal.html:16 +#: templates/crm/leads/lead_detail.html:543 +#: templates/crm/leads/lead_detail.html:563 #: templates/crm/leads/lead_form.html:38 #: templates/crm/leads/schedule_lead.html:15 -#: templates/crm/opportunities/opportunity_detail.html:60 #: templates/customers/customer_form.html:37 #: templates/dealers/assign_car_makes.html:88 #: templates/dealers/dealer_form.html:19 templates/groups/group_form.html:45 #: templates/groups/group_permission_form.html:38 -#: templates/inventory/add_colors.html:72 +#: templates/inventory/add_colors.html:74 #: templates/inventory/add_custom_card.html:18 #: templates/inventory/car_edit.html:18 #: templates/inventory/car_finance_form.html:44 @@ -3792,7 +3984,8 @@ msgstr "" #: templates/items/expenses/expense_update.html:16 #: templates/items/service/service_create.html:32 #: templates/ledger/bank_accounts/bank_account_form.html:40 -#: templates/ledger/bills/bill_form.html:42 +#: templates/ledger/bills/bill_form-copy.html:42 +#: templates/ledger/bills/bill_form.html:17 #: templates/ledger/bills/bill_update_form.html:15 #: templates/ledger/coa_accounts/account_form.html:40 #: templates/ledger/journal_entry/journal_entry_form.html:16 @@ -3800,6 +3993,8 @@ msgstr "" #: templates/ledger/ledger/ledger_form.html:22 #: templates/organizations/organization_form.html:22 #: templates/plans/billing_info_create_or_update.html:17 +#: templates/purchase_orders/includes/po_item_formset.html:98 +#: templates/purchase_orders/po_form.html:44 #: templates/representatives/representative_form.html:11 #: templates/sales/estimates/estimate_form.html:74 #: templates/sales/estimates/sale_order_form.html:194 @@ -3848,27 +4043,6 @@ msgstr "يوم الأسبوع" msgid "Service List" msgstr "قائمة الخدمات" -#: templates/administration/service_list.html:26 -#: templates/administration/user_profile.html:94 -#: templates/administration/user_profile.html:162 -#: templates/crm/leads/lead_list.html:115 -#: templates/crm/leads/lead_list.html:132 templates/groups/group_detail.html:83 -#: templates/inventory/car_detail.html:417 -#: templates/items/expenses/expenses_list.html:23 -#: templates/items/service/service_list.html:24 -#: templates/ledger/bank_accounts/bank_account_list.html:22 -#: templates/ledger/bills/bill_list.html:53 -#: templates/ledger/journal_entry/journal_entry_list.html:55 -#: templates/ledger/ledger/ledger_list.html:25 -#: templates/modal/confirm_modal.html:21 -#: venv/lib/python3.11/site-packages/appointment/templates/administration/service_list.html:31 -#: venv/lib/python3.11/site-packages/appointment/templates/administration/user_profile.html:106 -#: venv/lib/python3.11/site-packages/appointment/templates/administration/user_profile.html:172 -#: venv/lib/python3.11/site-packages/appointment/templates/modal/confirm_modal.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/inventory/tags/inventory_item_table.html:13 -msgid "Action" -msgstr "الإجراء" - #: templates/administration/service_list.html:59 #: venv/lib/python3.11/site-packages/appointment/templates/administration/service_list.html:63 msgid "No service found" @@ -3972,17 +4146,17 @@ msgstr "أعضاء الفريق" #: templates/administration/staff_list.html:25 templates/crm/note_form.html:15 #: templates/customers/note_form.html:6 #: templates/customers/view_customer.html:88 -#: templates/inventory/car_detail.html:154 -#: templates/inventory/car_detail.html:176 -#: templates/inventory/car_detail.html:197 -#: templates/inventory/car_detail.html:274 +#: templates/inventory/car_detail.html:164 +#: templates/inventory/car_detail.html:186 +#: templates/inventory/car_detail.html:207 +#: templates/inventory/car_detail.html:284 #: venv/lib/python3.11/site-packages/appointment/services.py:170 msgid "Add" msgstr "إضافة" #: templates/administration/staff_list.html:36 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:71 -#: templates/inventory/car_form.html:229 +#: templates/inventory/car_form.html:246 #: templates/inventory/inventory_stats.html:63 #: venv/lib/python3.11/site-packages/appointment/templates/administration/staff_list.html:40 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/tags/closing_entry_table.html:43 @@ -4245,8 +4419,11 @@ msgid "Payment Details" msgstr "تفاصيل الدفع" #: templates/appointment/appointment_client_information.html:96 +#: templates/bill/bill_detail.html:144 templates/bill/bill_detail.html:192 +#: templates/bill/tags/bill_item_formset.html:40 +#: templates/bill/tags/bill_item_formset.html:124 #: templates/customers/view_customer.html:121 -#: templates/inventory/car_detail.html:259 +#: templates/inventory/car_detail.html:269 #: templates/inventory/inventory_stats.html:70 #: templates/inventory/transfer_details.html:91 #: templates/inventory/transfer_preview.html:288 @@ -4259,6 +4436,7 @@ msgstr "تفاصيل الدفع" #: templates/plans/invoices/layout.html:112 #: templates/plans/invoices/layout.html:133 #: templates/plans/order_detail_table.html:12 templates/pricing_page.html:183 +#: templates/purchase_orders/includes/po_item_formset.html:84 #: templates/sales/estimates/estimate_detail.html:197 #: templates/sales/estimates/sale_order_preview.html:184 #: templates/sales/invoices/invoice_detail.html:244 @@ -4427,135 +4605,292 @@ msgstr "إعادة تعيين كلمة المرور" msgid "HAIKAL" msgstr "هيكل" -#: templates/components/date_picker.html:5 -#: templates/ledger/reports/components/date_picker.html:5 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/components/date_picker.html:5 -msgid "Select Date" -msgstr "اختر التاريخ" +#: templates/bill/bill_create.html:12 +#: templates/ledger/bills/bill_form-copy.html:5 +#: templates/ledger/bills/bill_form-copy.html:9 +#: templates/ledger/bills/bill_form.html:5 +#: templates/ledger/bills/bill_form.html:9 +#: templates/purchase_orders/includes/po_item_formset.html:28 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:11 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:27 +#: venv/lib/python3.11/site-packages/django_ledger/views/bill.py:52 +msgid "Create Bill" +msgstr "إنشاء فاتورة" -#: templates/crm/leads/lead_detail.html:45 -#: templates/crm/leads/lead_list.html:13 -msgid "Update Lead Actions" -msgstr "تحديث إجراءات العميل المحتمل" +#: templates/bill/bill_create.html:20 templates/bill/bill_create.html:21 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:20 +msgid "Bill for" +msgstr "فاتورة لـ" -#: templates/crm/leads/lead_detail.html:54 -#: templates/crm/leads/lead_list.html:22 -msgid "Current Action" -msgstr "الإجراء الحالي" +#: templates/bill/bill_create.html:39 templates/crm/leads/lead_form.html:28 +#: templates/crm/leads/schedule_lead.html:5 +#: templates/crm/opportunities/opportunity_form.html:168 +#: venv/lib/python3.11/site-packages/appointment/views_admin.py:429 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bank_account/bank_account_create.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:33 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/estimate_create.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/expense/expense_create.html:23 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/inventory/inventory_item_create.html:23 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_create.html:38 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/product/product_create.html:24 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_create.html:27 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/service/service_create.html:24 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_create.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/uom/uom_create.html:24 +msgid "Create" +msgstr "إنشاء" -#: templates/crm/leads/lead_detail.html:56 -#: templates/crm/leads/lead_list.html:24 -msgid "Select Action" -msgstr "اختر إجراء" +#: templates/bill/bill_detail.html:44 templates/bill/bill_update.html:40 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:24 +#: venv/lib/python3.11/site-packages/django_ledger/views/bill.py:214 +msgid "Bill List" +msgstr "قائمة الفواتير" -#: templates/crm/leads/lead_detail.html:68 -#: templates/crm/leads/lead_list.html:36 -msgid "Select Next Action" -msgstr "اختر الإجراء التالي" +#: templates/bill/bill_detail.html:60 +#: templates/ledger/bank_accounts/bank_account_detail.html:47 +#: templates/ledger/ledger/ledger_detail.html:28 +#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:323 +#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:223 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:31 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:30 +msgid "Cash Account" +msgstr "حساب نقدي" -#: templates/crm/leads/lead_detail.html:69 -msgid "No Action" -msgstr "لا يوجد إجراء" +#: templates/bill/bill_detail.html:75 +#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:327 +#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:229 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:42 +msgid "Prepaid Account" +msgstr "حساب مسبق الدفع" -#: templates/crm/leads/lead_detail.html:87 -#: templates/crm/leads/lead_list.html:56 templates/inventory/car_form.html:240 -#: templates/inventory/car_form.html:259 templates/inventory/car_form.html:277 -#: templates/inventory/car_form.html:294 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:229 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:235 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:252 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:270 -#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:287 -#: templates/modal/confirm_modal.html:11 templates/modal/confirm_modal.html:20 -#: templates/modal/error_modal.html:17 -#: templates/modal/event_details_modal.html:21 -#: templates/partials/scanner_modal.html:6 -#: templates/partials/specifications_modal.html:8 -#: venv/lib/python3.11/site-packages/appointment/templates/modal/confirm_modal.html:18 -#: venv/lib/python3.11/site-packages/appointment/templates/modal/error_modal.html:17 -#: venv/lib/python3.11/site-packages/appointment/templates/modal/event_details_modal.html:19 -msgid "Close" -msgstr "إغلاق" +#: templates/bill/bill_detail.html:103 +#: templates/bill/includes/card_bill.html:29 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:63 +msgid "Accrued" +msgstr "متراكم" -#: templates/crm/leads/lead_detail.html:88 -#: templates/crm/leads/lead_list.html:57 -msgid "Save Changes" -msgstr "حفظ التغييرات" +#: templates/bill/bill_detail.html:114 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:71 +msgid "You Still Owe" +msgstr "ما زلت مديناً" -#: templates/crm/leads/lead_detail.html:97 -#: templates/crm/leads/lead_detail.html:114 -msgid "Lead Details" -msgstr "تفاصيل العميل المحتمل" +#: templates/bill/bill_detail.html:132 +#: templates/bill/tags/bill_item_formset.html:13 +#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:372 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:85 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:8 +msgid "Bill Items" +msgstr "بنود الفاتورة" -#: templates/crm/leads/lead_detail.html:123 -msgid "Assigned to" -msgstr "مُعين إلى" +#: templates/bill/bill_detail.html:141 +#: venv/lib/python3.11/site-packages/django_ledger/forms/journal_entry.py:64 +#: venv/lib/python3.11/site-packages/django_ledger/models/entity.py:3182 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:95 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_item_table.html:9 +msgid "Entity Unit" +msgstr "وحدة الكيان" -#: templates/crm/leads/lead_detail.html:125 -msgid "Not Assigned" -msgstr "غير معين" +#: templates/bill/bill_detail.html:142 +#: templates/bill/tags/bill_item_formset.html:38 +#: templates/ledger/ledger/ledger_detail.html:82 +#: templates/purchase_orders/includes/po_item_formset.html:20 +#: templates/purchase_orders/tags/po_item_table.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:96 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_item_table.html:11 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/tags/ce_item_formset.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:95 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:9 +msgid "Unit Cost" +msgstr "تكلفة الوحدة" -#: templates/crm/leads/lead_detail.html:153 -msgid "Car Requested" -msgstr "السيارة المطلوبة" +#: templates/bill/bill_detail.html:145 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:99 +msgid "PO" +msgstr "أمر الشراء" -#: templates/crm/leads/lead_detail.html:187 -msgid "Lead Source" -msgstr "مصدر العميل المحتمل" +#: templates/bill/bill_detail.html:182 +#: templates/bill/tags/bill_item_formset.html:76 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:115 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:45 +msgid "View PO" +msgstr "عرض أمر الشراء" -#: templates/crm/leads/lead_detail.html:193 -msgid "Lead Channel" -msgstr "قناة العميل المحتمل" +#: templates/bill/bill_detail.html:213 templates/header.html:319 +#: templates/ledger/ledger/ledger_detail.html:115 +#: templates/ledger/reports/balance_sheet.html:5 +#: templates/ledger/reports/balance_sheet.html:36 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:144 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:66 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/balance_sheet.html:30 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:131 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_update.html:65 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:49 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:25 +#: venv/lib/python3.11/site-packages/django_ledger/views/financial_statement.py:59 +msgid "Balance Sheet" +msgstr "الميزانية العمومية" -#: templates/crm/leads/lead_detail.html:205 -#: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:82 -#: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:159 -#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:108 -msgid "City" -msgstr "المدينة" +#: templates/bill/bill_detail.html:217 templates/header.html:308 +#: templates/ledger/ledger/ledger_detail.html:117 +#: templates/ledger/reports/income_statement.html:5 +#: templates/ledger/reports/income_statement.html:31 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:146 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:71 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/income_statement.html:31 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:133 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_update.html:70 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:52 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:27 +msgid "Income Statement" +msgstr "بيان الدخل" -#: templates/crm/leads/lead_detail.html:217 -msgid "Current Stage" -msgstr "المرحلة الحالية" +#: templates/bill/bill_detail.html:221 +#: templates/ledger/ledger/ledger_detail.html:119 +#: templates/ledger/reports/cash_flow_statement.html:5 +#: templates/ledger/reports/cash_flow_statement.html:31 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:148 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/cash_flow.html:31 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:135 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:55 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:29 +msgid "Cash Flow Statement" +msgstr "بيان التدفقات النقدية" -#: templates/crm/leads/lead_detail.html:230 -#: templates/crm/leads/lead_list.html:270 -msgid "Update Actions" -msgstr "تحديث الإجراءات" +#: templates/bill/bill_detail.html:231 +#: templates/ledger/ledger/ledger_detail.html:125 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:155 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:141 +msgid "Balance Sheet PDF" +msgstr "الميزانية العمومية PDF" -#: templates/crm/leads/lead_detail.html:258 -#: templates/crm/opportunities/opportunity_detail.html:303 -msgid "Add Activity" -msgstr "إضافة نشاط" +#: templates/bill/bill_detail.html:235 +#: templates/ledger/ledger/ledger_detail.html:128 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:158 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:144 +msgid "Income Statement PDF" +msgstr "بيان الدخل PDF" -#: templates/crm/leads/lead_detail.html:293 -msgid "created by" -msgstr "تم الإنشاء بواسطة" +#: templates/bill/bill_detail.html:239 +#: templates/ledger/ledger/ledger_detail.html:131 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:161 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:147 +msgid "Cash Flow Statement PDF" +msgstr "بيان التدفقات النقدية PDF" -#: templates/crm/leads/lead_detail.html:306 -#: templates/customers/view_customer.html:90 -msgid "Add Note" -msgstr "إضافة ملاحظة" +#: templates/bill/bill_detail.html:251 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:171 +msgid "Bill Transactions" +msgstr "معاملات الفاتورة" -#: templates/crm/leads/lead_detail.html:315 -msgid "Created By" -msgstr "تم الإنشاء بواسطة" +#: templates/bill/bill_detail.html:264 +msgid "Bill Notes" +msgstr "ملاحظات الفاتورة" -#: templates/crm/leads/lead_detail.html:316 -msgid "Created On" -msgstr "تم الإنشاء في" +#: templates/bill/bill_update.html:30 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:19 +msgid "Save Bill" +msgstr "حفظ الفاتورة" -#: templates/crm/leads/lead_detail.html:342 -#: templates/crm/leads/lead_detail.html:343 +#: templates/bill/bill_update.html:35 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:22 +msgid "Back to Bill Detail" +msgstr "العودة إلى تفاصيل الفاتورة" + +#: templates/bill/includes/card_bill.html:20 +#: templates/ledger/journal_entry/includes/card_invoice.html:15 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:16 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:14 +msgid "Due in" +msgstr "مستحق في" + +#: templates/bill/includes/card_bill.html:24 +#: templates/bill/tags/bill_table.html:15 +#: templates/sales/invoices/invoice_list.html:30 +#: templates/sales/sales_list.html:187 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:15 +msgid "Past Due" +msgstr "مستحق" + +#: templates/bill/includes/card_bill.html:24 +#: templates/dealers/dealer_detail.html:46 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:41 +msgid "ago" +msgstr "منذ" + +#: templates/bill/includes/card_bill.html:39 +#: templates/bill/includes/card_bill.html:103 +#: templates/bill/includes/card_bill.html:123 +#: templates/bill/includes/card_bill.html:146 +#: templates/bill/tags/bill_table.html:13 +#: templates/ledger/journal_entry/includes/card_invoice.html:51 +#: templates/ledger/journal_entry/includes/card_invoice.html:62 +#: templates/ledger/journal_entry/includes/card_invoice.html:76 +#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:178 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:67 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:84 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:105 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:13 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:58 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:75 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:96 +msgid "Amount Due" +msgstr "المبلغ المستحق" + +#: templates/bill/includes/card_bill.html:42 +#: templates/bill/includes/card_bill.html:154 +#: templates/bill/includes/card_bill.html:178 +#: templates/ledger/journal_entry/includes/card_invoice.html:85 +#: templates/ledger/journal_entry/includes/card_invoice.html:92 +#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:183 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:120 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:133 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:111 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:121 +msgid "Amount Paid" +msgstr "المبلغ المدفوع" + +#: templates/bill/includes/card_bill.html:45 +#: templates/bill/includes/card_bill.html:158 +msgid "Progress" +msgstr "التقدم" + +#: templates/bill/includes/card_bill.html:64 +#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:55 +#: templates/inventory/car_list_view.html:244 +#: templates/ledger/bills/bill_list.html:82 +#: templates/ledger/coa_accounts/partials/account_table.html:42 +#: templates/ledger/journal_entry/includes/card_invoice.html:33 +#: templates/ledger/journal_entry/journal_entry_list.html:99 +#: templates/sales/invoices/invoice_list.html:61 +#: templates/sales/sales_list.html:208 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:44 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/entity/entitiy_list.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:38 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:85 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_list.html:32 +msgid "View" +msgstr "عرض" + +#: templates/bill/includes/card_bill.html:68 +#: templates/bill/includes/card_bill.html:206 +#: templates/crm/leads/lead_detail.html:322 +#: templates/crm/leads/lead_detail.html:323 #: templates/crm/leads/lead_form.html:28 #: templates/crm/leads/schedule_lead.html:5 templates/crm/note_form.html:13 -#: templates/crm/opportunities/opportunity_form.html:149 -#: templates/crm/opportunities/partials/opportunity_grid.html:103 +#: templates/crm/opportunities/opportunity_form.html:166 +#: templates/crm/opportunities/partials/opportunity_grid.html:126 #: templates/customers/view_customer.html:30 #: templates/items/expenses/expenses_list.html:44 #: templates/items/service/service_list.html:51 #: templates/ledger/bank_accounts/bank_account_list.html:41 #: templates/ledger/journal_entry/includes/card_invoice.html:34 +#: templates/purchase_orders/includes/card_po.html:164 #: venv/lib/python3.11/site-packages/appointment/services.py:170 #: venv/lib/python3.11/site-packages/appointment/views_admin.py:374 #: venv/lib/python3.11/site-packages/appointment/views_admin.py:471 @@ -4596,12 +4931,284 @@ msgstr "تم الإنشاء في" msgid "Update" msgstr "تحديث" -#: templates/crm/leads/lead_detail.html:366 -#: templates/crm/leads/lead_list.html:272 +#: templates/bill/includes/card_bill.html:74 +#: templates/bill/includes/card_bill.html:233 +#: templates/ledger/bills/bill_detail.html:73 +#: templates/ledger/journal_entry/includes/card_invoice.html:36 +#: templates/ledger/journal_entry/includes/card_invoice.html:122 +#: templates/sales/invoices/invoice_detail.html:92 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:49 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:187 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:43 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:170 +msgid "Mark as Paid" +msgstr "وضع علامة مدفوعة" + +#: templates/bill/includes/card_bill.html:100 +#: templates/bill/includes/card_bill.html:120 +#: templates/bill/includes/card_bill.html:143 +#: templates/bill/includes/card_bill.html:175 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:66 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:83 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:104 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:132 +msgid "This bill is" +msgstr "هذه الفاتورة هي" + +#: templates/bill/includes/card_bill.html:111 +#: templates/bill/includes/card_bill.html:131 +#: templates/ledger/journal_entry/includes/card_invoice.html:53 +#: templates/ledger/journal_entry/includes/card_invoice.html:64 +#: templates/ledger/journal_entry/includes/card_invoice.html:78 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:75 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:92 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:113 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:66 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:83 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:104 +msgid "Is Accrued" +msgstr "مستحقة" + +#: templates/bill/includes/card_bill.html:140 +#: templates/bill/includes/card_bill.html:172 +#: templates/bill/includes/card_bill.html:187 +#: templates/ledger/journal_entry/includes/card_invoice.html:72 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:100 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:129 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:141 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:91 +msgid "External Ref" +msgstr "المرجع الخارجي" + +#: templates/bill/includes/card_bill.html:182 +#: templates/ledger/journal_entry/includes/card_invoice.html:93 +#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:383 +#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:352 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:138 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:126 +msgid "Paid Date" +msgstr "تاريخ الدفع" + +#: templates/bill/includes/card_bill.html:192 +msgid "Bill Amount" +msgstr "قيمة الفاتورة" + +#: templates/bill/includes/card_bill.html:212 +#: templates/ledger/journal_entry/includes/card_invoice.html:104 +#: templates/purchase_orders/includes/card_po.html:172 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:160 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:62 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:143 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:67 +msgid "Mark as Draft" +msgstr "وضع كمسودة" + +#: templates/bill/includes/card_bill.html:219 +#: templates/ledger/journal_entry/includes/card_invoice.html:110 +#: templates/purchase_orders/includes/card_po.html:179 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:169 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:71 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:152 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:76 +msgid "Mark as Review" +msgstr "وضع قيد المراجعة" + +#: templates/bill/includes/card_bill.html:226 +#: templates/ledger/bills/bill_detail.html:67 +#: templates/purchase_orders/includes/card_po.html:186 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:178 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:85 +msgid "Mark as Approved" +msgstr "وضع علامة معتمد" + +#: templates/bill/includes/card_bill.html:240 +msgid "Mark as Void" +msgstr "وضع كملغي" + +#: templates/bill/includes/card_bill.html:247 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:53 +msgid "Mark as Canceled" +msgstr "وضع علامة ملغاة" + +#: templates/bill/includes/card_bill.html:263 +#: templates/ledger/bills/bill_list.html:17 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:217 +msgid "New Bill" +msgstr "فاتورة جديدة" + +#: templates/bill/includes/card_markdown.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/card_markdown.html:20 +msgid "No available notes to display..." +msgstr "لا توجد ملاحظات متاحة للعرض..." + +#: templates/bill/includes/card_vendor.html:10 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/includes/card_vendor.html:9 +msgid "Vendor Info" +msgstr "معلومات المورد" + +#: templates/bill/tags/bill_item_formset.html:35 +#: templates/purchase_orders/tags/po_item_table.html:10 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:10 +msgid "PO Qty" +msgstr "كمية أمر الشراء" + +#: templates/bill/tags/bill_item_formset.html:36 +#: templates/purchase_orders/includes/card_po.html:119 +#: templates/purchase_orders/includes/card_po.html:146 +#: templates/purchase_orders/po_detail.html:36 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:31 +msgid "PO Amount" +msgstr "مبلغ أمر الشراء" + +#: templates/bill/tags/bill_item_formset.html:39 +#: templates/ledger/reports/balance_sheet.html:38 +#: templates/ledger/reports/cash_flow_statement.html:33 +#: templates/ledger/reports/income_statement.html:28 +#: templates/ledger/reports/tags/balance_sheet_statement.html:16 +#: templates/ledger/reports/tags/income_statement.html:11 +#: templates/plans/invoices/layout.html:105 +#: templates/purchase_orders/includes/po_item_formset.html:22 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:23 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/tags/closing_entry_txs_table.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/balance_sheet.html:32 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/cash_flow.html:33 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/income_statement.html:28 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html:23 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html:11 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:14 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_txs_table.html:11 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:21 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/transactions/tags/txs_table.html:11 +msgid "Unit" +msgstr "الوحدة" + +#: templates/bill/tags/bill_item_formset.html:148 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:79 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/tags/ce_item_formset.html:74 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:69 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:101 +msgid "New Item" +msgstr "عنصر جديد" + +#: templates/bill/tags/bill_item_formset.html:153 +#: templates/crm/leads/partials/update_action.html:48 +msgid "Save Changes" +msgstr "حفظ التغييرات" + +#: templates/bill/tags/bill_table.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:9 +msgid "Number" +msgstr "الرقم" + +#: templates/bill/tags/bill_table.html:11 +#: templates/sales/estimates/estimate_list.html:17 +#: templates/sales/invoices/invoice_list.html:18 +#: templates/sales/journals/journal_list.html:18 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:11 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_table.html:13 +msgid "Status Date" +msgstr "تاريخ الحالة" + +#: templates/bill/tags/bill_table.html:14 +#: templates/sales/payments/payment_list.html:4 +#: templates/sales/payments/payment_list.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:14 +msgid "Payments" +msgstr "المدفوعات" + +#: templates/components/date_picker.html:5 +#: templates/ledger/reports/components/date_picker.html:5 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/components/date_picker.html:5 +msgid "Select Date" +msgstr "اختر التاريخ" + +#: templates/crm/leads/lead_detail.html:44 +#: templates/crm/leads/lead_detail.html:61 +msgid "Lead Details" +msgstr "تفاصيل العميل المحتمل" + +#: templates/crm/leads/lead_detail.html:70 +msgid "Assigned to" +msgstr "مُعين إلى" + +#: templates/crm/leads/lead_detail.html:72 +msgid "Not Assigned" +msgstr "غير معين" + +#: templates/crm/leads/lead_detail.html:98 +msgid "Car Requested" +msgstr "السيارة المطلوبة" + +#: templates/crm/leads/lead_detail.html:109 +#: templates/crm/opportunities/opportunity_detail.html:99 +msgid "Related Records" +msgstr "السجلات المرتبطة" + +msgid "No Opportunity" +msgstr "لا توجد فرصة" + +#: templates/crm/leads/lead_detail.html:142 +msgid "Lead Source" +msgstr "مصدر العميل المحتمل" + +#: templates/crm/leads/lead_detail.html:148 +msgid "Lead Channel" +msgstr "قناة العميل المحتمل" + +#: templates/crm/leads/lead_detail.html:166 +#: templates/crm/leads/partials/update_action.html:14 +msgid "Current Stage" +msgstr "المرحلة الحالية" + +#: templates/crm/leads/lead_detail.html:179 +#: templates/crm/leads/lead_list.html:217 +msgid "Update Actions" +msgstr "تحديث الإجراءات" + +#: templates/crm/leads/lead_detail.html:207 +#: templates/crm/opportunities/opportunity_detail.html:354 +msgid "Add Activity" +msgstr "إضافة نشاط" + +#: templates/crm/leads/lead_detail.html:242 +msgid "created by" +msgstr "تم الإنشاء بواسطة" + +#: templates/crm/leads/lead_detail.html:255 +#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:11 +#: templates/crm/opportunities/opportunity_list.html:83 +msgid "Add Opportunity" +msgstr "إضافة فرصة" + +#: templates/crm/leads/lead_detail.html:264 +#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:110 +#: templates/crm/opportunities/partials/opportunity_grid.html:104 +msgid "Probability" +msgstr "الاحتمالية" + +#: templates/crm/leads/lead_detail.html:287 +#: templates/customers/view_customer.html:90 +msgid "Add Note" +msgstr "إضافة ملاحظة" + +#: templates/crm/leads/lead_detail.html:296 +msgid "Created By" +msgstr "تم الإنشاء بواسطة" + +#: templates/crm/leads/lead_detail.html:297 +msgid "Created On" +msgstr "تم الإنشاء في" + +#: templates/crm/leads/lead_detail.html:346 +#: templates/crm/leads/lead_list.html:219 +#: templates/crm/opportunities/opportunity_detail.html:512 msgid "Send Email" msgstr "إرسال البريد الإلكتروني" -#: templates/crm/leads/lead_detail.html:486 +#: templates/crm/leads/lead_detail.html:466 +#: templates/crm/opportunities/opportunity_detail.html:585 msgid "Add Task" msgstr "إضافة مهمة" @@ -4609,70 +5216,43 @@ msgstr "إضافة مهمة" msgid "Update Lead" msgstr "تحديث العميل المحتمل" +#: templates/crm/leads/lead_form.html:8 msgid "Add New Lead" msgstr "إضافة عميل محتمل جديد" -#: templates/crm/leads/lead_form.html:28 -#: templates/crm/leads/schedule_lead.html:5 -#: templates/crm/opportunities/opportunity_form.html:151 -#: venv/lib/python3.11/site-packages/appointment/views_admin.py:429 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bank_account/bank_account_create.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:33 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/estimate_create.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/expense/expense_create.html:23 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/inventory/inventory_item_create.html:23 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_create.html:38 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/product/product_create.html:24 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_create.html:27 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/service/service_create.html:24 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_create.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/uom/uom_create.html:24 -msgid "Create" -msgstr "إنشاء" - -#: templates/crm/leads/lead_list.html:25 templates/crm/leads/lead_list.html:173 -msgid "Contacted" -msgstr "تم الاتصال" - -#: templates/crm/leads/lead_list.html:27 -msgid "Proposal Sent" -msgstr "تم إرسال العرض" - -#: templates/crm/leads/lead_list.html:40 -msgid "Send Proposal" -msgstr "إرسال العرض" - -#: templates/crm/leads/lead_list.html:69 +#: templates/crm/leads/lead_list.html:16 msgid "Add Lead" msgstr "إضافة عميل محتمل" -#: templates/crm/leads/lead_list.html:87 +#: templates/crm/leads/lead_list.html:34 msgid "Lead Name" msgstr "اسم العميل المحتمل" -#: templates/crm/leads/lead_list.html:109 +#: templates/crm/leads/lead_list.html:56 msgid "Schedule" msgstr "الجدولة" -#: templates/crm/leads/lead_list.html:121 +#: templates/crm/leads/lead_list.html:68 +#: templates/crm/opportunities/opportunity_detail.html:278 +#: templates/crm/opportunities/partials/opportunity_grid.html:69 msgid "Assigned To" msgstr "مُعين إلى" -#: templates/crm/leads/lead_list.html:146 +#: templates/crm/leads/lead_list.html:93 msgid "Are you sure you want to delete this lead?" msgstr "هل أنت متأكد أنك تريد حذف هذا العميل المحتمل؟" -#: templates/crm/leads/lead_list.html:150 +#: templates/crm/leads/lead_list.html:97 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:158 #: templates/groups/group_detail.html:32 -#: templates/inventory/car_detail.html:538 +#: templates/inventory/car_detail.html:543 #: templates/inventory/transfer_details.html:62 #: templates/ledger/bank_accounts/bank_account_detail.html:31 #: templates/ledger/bills/bill_detail.html:24 #: templates/ledger/bills/bill_detail.html:49 #: templates/ledger/bills/bill_detail.html:121 #: templates/ledger/coa_accounts/account_detail.html:22 -#: templates/ledger/coa_accounts/account_list.html:60 +#: templates/ledger/coa_accounts/account_list.html:123 #: templates/ledger/journal_entry/journal_entry_list.html:25 #: templates/organizations/organization_list.html:96 #: templates/sales/estimates/estimate_detail.html:37 @@ -4685,20 +5265,17 @@ msgstr "هل أنت متأكد أنك تريد حذف هذا العميل الم msgid "Yes" msgstr "نعم" -#: templates/crm/leads/lead_list.html:169 +#: templates/crm/leads/lead_list.html:116 msgid "In Progress" msgstr "قيد التنفيذ" -#: templates/crm/leads/lead_list.html:171 -msgid "Qualified" -msgstr "مؤهل" - -#: templates/crm/leads/lead_list.html:267 +#: templates/crm/leads/lead_list.html:214 #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:27 #: templates/dealers/dealer_detail.html:22 #: templates/groups/group_detail.html:103 -#: templates/inventory/car_detail.html:208 -#: templates/inventory/car_detail.html:266 +#: templates/inventory/car_detail.html:218 +#: templates/inventory/car_detail.html:276 +#: templates/inventory/car_detail.html:326 #: templates/ledger/bank_accounts/bank_account_detail.html:57 #: templates/ledger/coa_accounts/account_detail.html:140 #: templates/modal/event_details_modal.html:27 @@ -4715,11 +5292,11 @@ msgstr "مؤهل" msgid "Edit" msgstr "تحديث" -#: templates/crm/leads/lead_list.html:273 +#: templates/crm/leads/lead_list.html:220 msgid "Schedule Event" msgstr "جدولة الحدث" -#: templates/crm/leads/lead_list.html:275 +#: templates/crm/leads/lead_list.html:222 msgid "Convert to Opportunity" msgstr "تحويل إلى فرصة" @@ -4727,18 +5304,55 @@ msgstr "تحويل إلى فرصة" msgid "Leads Tracking" msgstr "متابعة العملاء المحتملين" -#: templates/crm/leads/lead_tracking.html:65 +#: templates/crm/leads/lead_tracking.html:71 msgid "Lead Tracking" msgstr "تتبع العملاء المحتملين" -#: templates/crm/leads/lead_tracking.html:72 templates/dashboards/sales.html:91 +#: templates/crm/leads/lead_tracking.html:78 templates/dashboards/sales.html:91 msgid "New Leads" msgstr "عملاء محتملون جدد" -#: templates/crm/leads/lead_tracking.html:88 +#: templates/crm/leads/lead_tracking.html:94 msgid "Follow Ups" msgstr "متابعات" +#: templates/crm/leads/lead_tracking.html:110 +msgid "Negotiation Ups" +msgstr "مفاوضات إضافية" + +msgid "Update Lead Actions" +msgstr "تحديث إجراءات العميل المحتمل" + +msgid "Select Stage" +msgstr "اختر المرحلة" + +#: templates/crm/leads/partials/update_action.html:28 +msgid "Select Next Action" +msgstr "اختر الإجراء التالي" + +#: templates/crm/leads/partials/update_action.html:29 +msgid "No Action" +msgstr "لا يوجد إجراء" + +#: templates/crm/leads/partials/update_action.html:47 +#: templates/inventory/car_form.html:250 templates/inventory/car_form.html:269 +#: templates/inventory/car_form.html:287 templates/inventory/car_form.html:304 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:229 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:235 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:252 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:270 +#: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:287 +#: templates/modal/confirm_modal.html:11 templates/modal/confirm_modal.html:20 +#: templates/modal/error_modal.html:17 +#: templates/modal/event_details_modal.html:21 +#: templates/partials/scanner_modal.html:6 +#: templates/partials/specifications_modal.html:8 +#: venv/lib/python3.11/site-packages/appointment/templates/modal/confirm_modal.html:18 +#: venv/lib/python3.11/site-packages/appointment/templates/modal/error_modal.html:17 +#: venv/lib/python3.11/site-packages/appointment/templates/modal/event_details_modal.html:19 +msgid "Close" +msgstr "إغلاق" + #: templates/crm/notifications.html:16 #: templates/crm/notifications_history.html:14 msgid "System" @@ -4757,30 +5371,61 @@ msgid "Opportunity details" msgstr "تفاصيل الفرصة" #: templates/crm/opportunities/opportunity_detail.html:16 +#: templates/crm/opportunities/opportunity_detail.html:107 #: templates/sales/estimates/estimate_detail.html:4 msgid "View Quotation" msgstr "مشاهدة عرض السعر" -#: templates/crm/opportunities/opportunity_detail.html:116 +msgid "Upcoming Events" +msgstr "الأحداث القادمة" + +msgid "No upcoming events" +msgstr "لا توجد أحداث قادمة" + +msgid "No Estimate" +msgstr "لا يوجد تقدير" + +msgid "View Invoice" +msgstr "عرض الفاتورة" + +msgid "No Invoice" +msgstr "لا توجد فاتورة" + +msgid "System Information" +msgstr "معلومات النظام" + +msgid "Created " +msgstr "تم الإنشاء" + +#: templates/crm/opportunities/opportunity_detail.html:157 msgid "Quotation Amount" msgstr "مبلغ عرض السعر" -#: templates/crm/opportunities/opportunity_detail.html:171 +#: templates/crm/opportunities/opportunity_detail.html:212 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:14 msgid "Estimated Revenue" msgstr "الإيرادات المقدرة" -#: templates/crm/opportunities/opportunity_detail.html:221 +#: templates/crm/opportunities/opportunity_detail.html:262 msgid "Contact Name" msgstr "اسم جهة الاتصال" -#: templates/crm/opportunities/opportunity_detail.html:254 +#: templates/crm/opportunities/opportunity_detail.html:303 msgid "Create Date" msgstr "تاريخ الإنشاء" +#: templates/crm/opportunities/opportunity_detail.html:330 +msgid "Meetings" +msgstr "الاجتماعات" + +msgid "Calls" +msgstr "المكالمات" + +#: templates/crm/opportunities/opportunity_form.html:6 msgid "Update Opportunity" msgstr "تحديث الفرصة" +#: templates/crm/opportunities/opportunity_form.html:8 msgid "Add New Opportunity" msgstr "إضافة فرصة جديدة" @@ -4796,56 +5441,35 @@ msgstr "إنشاء فرصة جديدة" msgid "Back to list" msgstr "العودة إلى القائمة" -#: templates/crm/opportunities/opportunity_form.html:145 +#: templates/crm/opportunities/opportunity_form.html:162 msgid "Reset" msgstr "إعادة تعيين" -#: templates/crm/opportunities/opportunity_form.html:162 +#: templates/crm/opportunities/opportunity_form.html:179 msgid "Opportunity Guidelines" msgstr "إرشادات الفرص" -#: templates/crm/opportunities/opportunity_form.html:167 +#: templates/crm/opportunities/opportunity_form.html:184 msgid "Probability indicates conversion chance" msgstr "تشير النسبة المئوية إلى فرصة التحويل" -#: templates/crm/opportunities/opportunity_form.html:173 +#: templates/crm/opportunities/opportunity_form.html:190 msgid "Update stage as deal progresses" msgstr "تحديث المرحلة مع تقدم الصفقة" -#: templates/crm/opportunities/opportunity_form.html:179 +#: templates/crm/opportunities/opportunity_form.html:196 msgid "Set realistic closing dates" msgstr "تحديد تواريخ إغلاق واقعية" -#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:11 -#: templates/crm/opportunities/opportunity_list.html:83 -msgid "Add Opportunity" -msgstr "إضافة فرصة" - -#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:55 -#: templates/inventory/car_list_view.html:244 -#: templates/ledger/bills/bill_list.html:84 -#: templates/ledger/coa_accounts/account_list.html:98 -#: templates/ledger/journal_entry/includes/card_invoice.html:33 -#: templates/ledger/journal_entry/journal_entry_list.html:99 -#: templates/sales/invoices/invoice_list.html:61 -#: templates/sales/sales_list.html:208 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:44 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/entity/entitiy_list.html:20 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:38 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:85 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_list.html:32 -msgid "View" -msgstr "عرض" - #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:89 msgid "Contact" msgstr "جهة الاتصال" -#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:110 -#: templates/crm/opportunities/partials/opportunity_grid.html:81 -msgid "Probability" -msgstr "الاحتمالية" +#: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:100 +#: templates/crm/opportunities/partials/opportunity_grid.html:93 +#: venv/lib/python3.11/site-packages/django_ledger/models/closing_entry.py:75 +msgid "Closing Date" +msgstr "تاريخ الإغلاق" #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:145 msgid "Delete Opportunity" @@ -4857,7 +5481,7 @@ msgstr "هل أنت متأكد أنك تريد حذف هذه الفرصة؟" #: ⁨templates/crm/opportunities/opportunity_list copy.html⁩:155 #: templates/groups/group_detail.html:27 -#: templates/inventory/car_detail.html:533 +#: templates/inventory/car_detail.html:538 #: templates/inventory/transfer_details.html:29 #: templates/inventory/transfer_details.html:58 #: templates/ledger/bank_accounts/bank_account_detail.html:26 @@ -4865,7 +5489,7 @@ msgstr "هل أنت متأكد أنك تريد حذف هذه الفرصة؟" #: templates/ledger/bills/bill_detail.html:45 #: templates/ledger/bills/bill_detail.html:123 #: templates/ledger/coa_accounts/account_detail.html:18 -#: templates/ledger/coa_accounts/account_list.html:57 +#: templates/ledger/coa_accounts/account_list.html:120 #: templates/ledger/journal_entry/journal_entry_list.html:24 #: templates/organizations/organization_list.html:95 #: templates/sales/estimates/estimate_detail.html:63 @@ -4898,7 +5522,11 @@ msgstr "أعلى قيمة" msgid "Earliest Close Date" msgstr "أقرب تاريخ إغلاق" -#: templates/crm/opportunities/partials/opportunity_grid.html:100 +#: templates/crm/opportunities/partials/opportunity_grid.html:70 +msgid "You" +msgstr "أنت" + +#: templates/crm/opportunities/partials/opportunity_grid.html:123 msgid "View Details" msgstr "عرض التفاصيل" @@ -4964,7 +5592,6 @@ msgstr "مرتبط" #: templates/customers/view_customer.html:120 #: templates/ledger/bank_accounts/bank_account_list.html:21 -#: templates/ledger/coa_accounts/account_list.html:24 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/product/tags/product_table.html:8 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/service/tags/services_table.html:8 msgid "Type" @@ -4974,14 +5601,6 @@ msgstr "النوع" msgid "Payment Status" msgstr "حالة الدفع" -#: templates/customers/view_customer.html:132 -#: templates/sales/estimates/estimate_detail.html:79 -#: templates/sales/estimates/estimate_send.html:5 -#: templates/sales/estimates/sale_order_form.html:171 -#: templates/sales/sales_list.html:118 -msgid "Quotation" -msgstr "عرض سعر" - #: templates/customers/view_customer.html:160 #: templates/ledger/bills/bill_detail.html:199 #: templates/sales/invoices/invoice_detail.html:80 @@ -4993,7 +5612,7 @@ msgid "Paid" msgstr "مدفوع" #: templates/customers/view_customer.html:223 -#: templates/inventory/car_detail.html:607 +#: templates/inventory/car_detail.html:612 msgid "Error loading form. Please try again later" msgstr "حدث خطأ أثناء تحميل النموذج. يرجى المحاولة مرة أخرى لاحقًا." @@ -5002,6 +5621,7 @@ msgid "As of" msgstr "حتى" #: templates/dashboards/manager.html:41 +#: templates/purchase_orders/po_list.html:19 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/estimate_detail.html:69 msgid "Purchase Orders" msgstr "أوامر الشراء" @@ -5072,11 +5692,6 @@ msgstr "معلومات الفوترة" msgid "Joined" msgstr "انضم" -#: templates/dealers/dealer_detail.html:46 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:41 -msgid "ago" -msgstr "منذ" - #: templates/dealers/dealer_detail.html:53 msgid "last login" msgstr "آخر تسجيل دخول" @@ -5090,12 +5705,12 @@ msgid "Total cars" msgstr "إجمالي السيارات" #: templates/dealers/dealer_detail.html:116 -#: templates/inventory/car_detail.html:383 templates/plans/current.html:28 +#: templates/inventory/car_detail.html:388 templates/plans/current.html:28 msgid "Expired" msgstr "منتهي الصلاحية" #: templates/dealers/dealer_detail.html:117 -#: templates/inventory/car_detail.html:372 +#: templates/inventory/car_detail.html:377 msgid "Renew" msgstr "تجديد" @@ -5218,7 +5833,7 @@ msgid "This is a reminder for your upcoming appointment." msgstr "هذه تذكرة بموعدك القادم." #: templates/email_sender/reminder_email.html:83 -#: templates/inventory/car_detail.html:181 +#: templates/inventory/car_detail.html:191 #: venv/lib/python3.11/site-packages/appointment/templates/email_sender/reminder_email.html:142 msgid "Location" msgstr "الموقع" @@ -5464,6 +6079,7 @@ msgstr "طلب غير صالح" #: templates/errors/400.html:46 #: templates/ledger/journal_entry/journal_entry_delete.html:18 #: templates/ledger/ledger/ledger_delete.html:18 +#: templates/purchase_orders/po_delete.html:22 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_delete.html:27 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_void.html:24 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/closing_entry_delete.html:18 @@ -5528,18 +6144,23 @@ msgstr "الاسم" msgid "Back to List" msgstr "العودة إلى القائمة" +#: templates/groups/group_form.html:7 msgid "Update Group" msgstr "تحديث المجموعة" +#: templates/groups/group_form.html:9 msgid "Add New Group" msgstr "إضافة مجموعة جديدة" +#: templates/groups/group_form.html:23 msgid "Edit Group" msgstr "تعديل المجموعة" +#: templates/groups/group_form.html:25 templates/groups/group_list.html:14 msgid "Add Group" msgstr "إضافة مجموعة" +#: templates/groups/group_list.html:5 msgid "Groups" msgstr "المجموعات" @@ -5555,9 +6176,10 @@ msgstr "إجمالي الأذونات" msgid "actions" msgstr "الإجراءات" -#: templates/groups/group_list.html:40 templates/inventory/car_detail.html:134 +#: templates/groups/group_list.html:40 templates/inventory/car_detail.html:144 #: templates/inventory/car_inventory.html:150 #: templates/ledger/coa_accounts/account_detail.html:102 +#: templates/purchase_orders/po_list.html:54 #: templates/representatives/representative_list.html:30 #: templates/sales/estimates/estimate_list.html:50 #: templates/sales/journals/journal_list.html:34 @@ -5581,21 +6203,18 @@ msgstr "إضافة إذن" msgid "HaikalBot" msgstr "هيكل بوت" +#: templates/haikalbot/chat.html:16 msgid "Export CSV" msgstr "تصدير CSV" +#: templates/haikalbot/chat.html:24 msgid "Type your question..." msgstr "اكتب سؤالك..." +#: templates/haikalbot/chat.html:138 msgid "Chart displayed below." msgstr "تم عرض المخطط أدناه." -msgid "Here is the data table." -msgstr "إليك جدول البيانات." - -msgid "Here is your result." -msgstr "إليك النتيجة." - #: templates/haikalbot/chatbot.html:5 msgid "Haikalbot" msgstr "هيكل بوت" @@ -5686,6 +6305,7 @@ msgstr "الخدمات" #: templates/header.html:239 templates/items/expenses/expenses_list.html:4 #: templates/items/expenses/expenses_list.html:11 +#: templates/ledger/coa_accounts/account_list.html:42 #: templates/ledger/reports/dashboard.html:48 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_ic.html:8 msgid "Expenses" @@ -5709,33 +6329,6 @@ msgstr "التقارير" msgid "Cash Flow" msgstr "التدفق النقدي" -#: templates/header.html:308 templates/ledger/ledger/ledger_detail.html:117 -#: templates/ledger/reports/income_statement.html:5 -#: templates/ledger/reports/income_statement.html:31 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:146 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:71 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/income_statement.html:31 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:133 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_update.html:70 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:52 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:27 -msgid "Income Statement" -msgstr "بيان الدخل" - -#: templates/header.html:319 templates/ledger/ledger/ledger_detail.html:115 -#: templates/ledger/reports/balance_sheet.html:5 -#: templates/ledger/reports/balance_sheet.html:36 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:144 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:66 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/balance_sheet.html:30 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:131 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_update.html:65 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:49 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:25 -#: venv/lib/python3.11/site-packages/django_ledger/views/financial_statement.py:59 -msgid "Balance Sheet" -msgstr "الميزانية العمومية" - #: templates/header.html:367 templates/header.html:368 #: templates/welcome_header.html:13 templates/welcome_header.html:14 msgid "Switch theme" @@ -5757,74 +6350,100 @@ msgstr "الإعدادات" msgid "Admin Managemnet" msgstr "إدارة المشرفين" -#: templates/inventory/add_colors.html:5 +#: templates/inventory/add_colors.html:3 templates/inventory/add_colors.html:6 msgid "Add Colors" msgstr "إضافة لون" -#: templates/inventory/add_colors.html:7 +#: templates/inventory/add_colors.html:8 msgid "Select exterior and interior colors for" msgstr "اختر الألوان الخارجية والداخلية لـ" -#: templates/inventory/car_detail.html:3 templates/inventory/car_detail.html:72 +#: templates/inventory/car_detail.html:3 templates/inventory/car_detail.html:82 #: templates/inventory/car_history.html:3 msgid "Car Details" msgstr "تفاصيل السيارة" -#: templates/inventory/car_detail.html:25 +#: templates/inventory/car_detail.html:27 +#, fuzzy +#| msgid "" +#| "This car information is not complete , please add colors and finances " +#| "before making it ready for sale ." msgid "" -"This car information is not complete , please add colors and finances before " -"making it ready for sale ." +"This car information is not complete , please add colors and finances both " +"before making it ready for sale ." msgstr "" "معلومات هذه السيارة غير مكتملة، يرجى إضافة الألوان المعلومات المالية قبل " "تجهيزها للبيع." -#: templates/inventory/car_detail.html:26 -msgid "Add Color" -msgstr "إضافة لون" +#: templates/inventory/car_detail.html:31 +#, fuzzy +#| msgid "" +#| "This car information is not complete , please add colors and finances " +#| "before making it ready for sale ." +msgid "" +"This car information is not complete , please add colors before making it " +"ready for sale ." +msgstr "" +"معلومات هذه السيارة غير مكتملة، يرجى إضافة الألوان المعلومات المالية قبل " +"تجهيزها للبيع." -#: templates/inventory/car_detail.html:38 +#: templates/inventory/car_detail.html:35 +#, fuzzy +#| msgid "" +#| "This car information is not complete , please add colors and finances " +#| "before making it ready for sale ." +msgid "" +"This car information is not complete , please add finances before making it " +"ready for sale ." +msgstr "" +"معلومات هذه السيارة غير مكتملة، يرجى إضافة الألوان المعلومات المالية قبل " +"تجهيزها للبيع." + +#: templates/inventory/car_detail.html:48 msgid "Action Required , Please Approved The Tranfer Request Of This Car ." msgstr "الإجراء مطلوب، يرجى الموافقة على طلب نقل هذه السيارة." -#: templates/inventory/car_detail.html:49 +#: templates/inventory/car_detail.html:59 msgid "" "Car Is In Transfer Process To Another Dealer, Please Wait For The " "Acceptance ." msgstr "السيارة قيد عملية النقل إلى تاجر آخر، يرجى انتظار القبول." -#: templates/inventory/car_detail.html:60 +#: templates/inventory/car_detail.html:70 msgid "This car is reserved until " msgstr "هذه السيارة محجوزة حتى " -#: templates/inventory/car_detail.html:81 templates/inventory/car_list.html:129 +#: templates/inventory/car_detail.html:91 templates/inventory/car_list.html:129 msgid "year" msgstr "السنة" -#: templates/inventory/car_detail.html:85 templates/inventory/car_form.html:92 +#: templates/inventory/car_detail.html:95 templates/inventory/car_form.html:87 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:70 #: templates/inventory/car_list.html:89 msgid "make" msgstr "الصانع" -#: templates/inventory/car_detail.html:89 templates/inventory/car_form.html:115 +#: templates/inventory/car_detail.html:99 templates/inventory/car_form.html:98 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:83 #: templates/inventory/car_list.html:107 msgid "model" msgstr "الموديل" -#: templates/inventory/car_detail.html:93 templates/inventory/car_list.html:140 +#: templates/inventory/car_detail.html:103 +#: templates/inventory/car_list.html:140 msgid "series" msgstr "السلسلة" -#: templates/inventory/car_detail.html:97 templates/inventory/car_form.html:102 +#: templates/inventory/car_detail.html:107 +#: templates/inventory/car_form.html:121 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:117 #: templates/inventory/car_list.html:151 msgid "trim" msgstr "الفئة" -#: templates/inventory/car_detail.html:127 -#: templates/inventory/car_detail.html:555 -#: templates/inventory/car_form.html:126 templates/inventory/car_form.html:229 +#: templates/inventory/car_detail.html:137 +#: templates/inventory/car_detail.html:560 +#: templates/inventory/car_form.html:133 templates/inventory/car_form.html:238 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:196 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:225 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:248 @@ -5832,90 +6451,99 @@ msgstr "الفئة" msgid "specifications" msgstr "المواصفات" -#: templates/inventory/car_detail.html:186 +#: templates/inventory/car_detail.html:196 #: templates/inventory/car_inventory.html:124 msgid "Our Showroom" msgstr "معرضنا" -#: templates/inventory/car_detail.html:195 +#: templates/inventory/car_detail.html:205 msgid "No location available." msgstr "لا يوجد موقع متاح." -#: templates/inventory/car_detail.html:211 +#: templates/inventory/car_detail.html:221 msgid "Sell to another dealer" msgstr "بيع السيارة لمعرض آخر" -#: templates/inventory/car_detail.html:215 -#: templates/inventory/car_detail.html:268 +#: templates/inventory/car_detail.html:225 +#: templates/inventory/car_detail.html:278 +#: templates/inventory/car_detail.html:328 msgid "Cannot Edit, Car in Transfer." msgstr "لا يمكن التعديل، السيارة قيد النقل." -#: templates/inventory/car_detail.html:223 +#: templates/inventory/car_detail.html:233 msgid "Financial Details" msgstr "التفاصيل المالية" -#: templates/inventory/car_detail.html:243 +#: templates/inventory/car_detail.html:253 msgid "Additional Fee" msgstr "رسوم إضافية" -#: templates/inventory/car_detail.html:255 +#: templates/inventory/car_detail.html:265 #: templates/plans/invoices/layout.html:111 msgid "VAT Amount" msgstr "مبلغ ضريبة القيمة المضافة" -#: templates/inventory/car_detail.html:271 +#: templates/inventory/car_detail.html:281 msgid "No finance details available." msgstr "لا توجد تفاصيل مالية متاحة." -#: templates/inventory/car_detail.html:284 +#: templates/inventory/car_detail.html:294 msgid "Colors Details" msgstr "تفاصيل الألوان" -#: templates/inventory/car_detail.html:290 +#: templates/inventory/car_detail.html:302 msgid "Exterior" msgstr "الخارجي" -#: templates/inventory/car_detail.html:300 +#: templates/inventory/car_detail.html:312 msgid "Interior" msgstr "الداخلي" -#: templates/inventory/car_detail.html:346 +#: templates/inventory/car_detail.html:336 +msgid "No color details available." +msgstr "لا توجد تفاصيل ألوان متاحة." + +#: templates/inventory/car_detail.html:338 +msgid "Add Color" +msgstr "إضافة لون" + +#: templates/inventory/car_detail.html:351 msgid "Reservations Details" msgstr "تفاصيل الحجز" -#: templates/inventory/car_detail.html:354 +#: templates/inventory/car_detail.html:359 msgid "Expires At" msgstr "ينتهي في" -#: templates/inventory/car_detail.html:396 +#: templates/inventory/car_detail.html:401 #: templates/inventory/reserve_car.html:22 msgid "Reserve" msgstr "حجز" -#: templates/inventory/car_detail.html:411 +#: templates/inventory/car_detail.html:416 #: templates/inventory/transfer_details.html:70 msgid "Transfer Details" msgstr "تفاصيل النقل" -#: templates/inventory/car_detail.html:419 +#: templates/inventory/car_detail.html:424 msgid "From Showroom" msgstr "من صالة العرض" -#: templates/inventory/car_detail.html:420 +#: templates/inventory/car_detail.html:425 msgid "To Showroom" msgstr "إلى صالة العرض" -#: templates/inventory/car_detail.html:524 +#: templates/inventory/car_detail.html:529 msgid "Are you sure you want to reserve this car?" msgstr "هل أنت متأكد أنك تريد حجز هذه السيارة؟" -#: templates/inventory/car_detail.html:670 +#: templates/inventory/car_detail.html:675 #: templates/inventory/car_list.html:549 #: templates/partials/specifications_modal.html:11 msgid "No specifications available." msgstr "لا توجد مواصفات متاحة." -#: templates/inventory/car_detail.html:674 +#: templates/inventory/car_detail.html:679 #: templates/inventory/car_list.html:553 msgid "Error loading specifications." msgstr "حدث خطأ أثناء تحميل المواصفات." @@ -5969,11 +6597,17 @@ msgstr "يرجى إضافة مورد قبل إضافة السيارة." msgid "Add Vendor" msgstr "إضافة مورد" -#: templates/inventory/car_form.html:81 templates/inventory/car_form.html:100 -#: templates/inventory/car_form.html:113 templates/inventory/car_form.html:269 -#: templates/inventory/car_form.html:458 templates/inventory/car_form.html:475 -#: templates/inventory/car_form.html:476 templates/inventory/car_form.html:498 -#: templates/inventory/car_form.html:517 +msgid "Scan VIN" +msgstr "مسح رقم الهيكل" + +msgid "Decode VIN" +msgstr "تحليل رقم الهيكل" + +#: templates/inventory/car_form.html:96 templates/inventory/car_form.html:109 +#: templates/inventory/car_form.html:119 templates/inventory/car_form.html:279 +#: templates/inventory/car_form.html:468 templates/inventory/car_form.html:485 +#: templates/inventory/car_form.html:486 templates/inventory/car_form.html:508 +#: templates/inventory/car_form.html:527 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:88 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:104 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:121 @@ -5987,57 +6621,57 @@ msgstr "إضافة مورد" msgid "Select" msgstr "اختيار" -#: templates/inventory/car_form.html:132 +#: templates/inventory/car_form.html:139 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:202 #: templates/inventory/car_list.html:26 templates/inventory/car_list.html:229 msgid "options" msgstr "الخيارات" -#: templates/inventory/car_form.html:204 +#: templates/inventory/car_form.html:211 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:206 msgid "Save and Add Another" msgstr "حفظ وإضافة آخر" -#: templates/inventory/car_form.html:210 +#: templates/inventory/car_form.html:217 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:210 msgid "Save and Go to Inventory" msgstr "حفظ والانتقال إلى المخزون" -#: templates/inventory/car_form.html:255 +#: templates/inventory/car_form.html:265 #: venv/lib/python3.11/site-packages/click/core.py:1140 msgid "Options" msgstr "الخيارات" -#: templates/inventory/car_form.html:265 +#: templates/inventory/car_form.html:275 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:258 #: templates/inventory/car_list.html:162 msgid "equipment" msgstr "التجهيزات" -#: templates/inventory/car_form.html:290 +#: templates/inventory/car_form.html:300 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:283 msgid "scanner" msgstr "الماسح الضوئي" -#: templates/inventory/car_form.html:299 +#: templates/inventory/car_form.html:309 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:292 #: templates/partials/scanner_modal.html:10 msgid "VIN will appear here." msgstr "رقم الهيكل سيظهر هنا." -#: templates/inventory/car_form.html:300 +#: templates/inventory/car_form.html:310 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:293 #: templates/partials/scanner_modal.html:11 msgid "Use OCR Fallback" msgstr "التعرف الآلي على الحروف" -#: templates/inventory/car_form.html:369 templates/inventory/car_form.html:370 +#: templates/inventory/car_form.html:379 templates/inventory/car_form.html:380 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:363 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:364 msgid "Please enter a valid VIN." msgstr "الرجاء إدخال رقم هيكل صالح مكون من 17 حرفًا." -#: templates/inventory/car_form.html:392 +#: templates/inventory/car_form.html:402 #: ⁨templates/inventory/car_form_qabl alfalsafa.html⁩:386 msgid "An error occurred while decoding the VIN." msgstr "حدث خطأ أثناء فك تشفير الهيكل" @@ -6073,7 +6707,7 @@ msgid "Add a Car" msgstr "إضافة سيارة" #: templates/inventory/car_list.html:80 -#: templates/ledger/bills/bill_list.html:26 +#: templates/ledger/bills/bill_list.html:24 msgid "search" msgstr "بحث" @@ -6158,12 +6792,15 @@ msgstr "تصفية" msgid "Date Received" msgstr "تاريخ الاستلام" +#: templates/inventory/car_list_view.html:171 msgid "Inventory Ready" msgstr "جاهز للمخزون" +#: templates/inventory/car_list_view.html:227 msgid "NO" msgstr "لا" +#: templates/inventory/car_list_view.html:229 msgid "YES" msgstr "نعم" @@ -6391,7 +7028,7 @@ msgstr "وحدة القياس" #: templates/items/expenses/expenses_list.html:58 #: templates/items/service/service_list.html:59 #: templates/ledger/bank_accounts/bank_account_list.html:48 -#: templates/ledger/coa_accounts/account_list.html:107 +#: templates/ledger/coa_accounts/partials/account_table.html:52 #: templates/vendors/vendors_list.html:138 msgid "No Accounts Found" msgstr "لم يتم العثور على أي حسابات" @@ -6433,15 +7070,6 @@ msgstr "تفاصيل الحساب البنكي" msgid "Bank Account Name" msgstr "اسم الحساب البنكي" -#: templates/ledger/bank_accounts/bank_account_detail.html:47 -#: templates/ledger/ledger/ledger_detail.html:28 -#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:323 -#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:223 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:31 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:30 -msgid "Cash Account" -msgstr "حساب نقدي" - #: templates/ledger/bank_accounts/bank_account_form.html:7 #: venv/lib/python3.11/site-packages/django_ledger/views/bank_account.py:76 msgid "Update Bank Account" @@ -6469,6 +7097,7 @@ msgid "Account Number" msgstr "رقم الحساب" #: templates/ledger/bills/bill_detail.html:4 +#: templates/purchase_orders/includes/po_item_formset.html:62 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:61 msgid "View Bill" msgstr "عرض الفاتورة" @@ -6477,28 +7106,11 @@ msgstr "عرض الفاتورة" msgid "Review Bill" msgstr "مراجعة الفاتورة" -#: templates/ledger/bills/bill_detail.html:67 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:178 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:85 -msgid "Mark as Approved" -msgstr "وضع علامة معتمد" - #: templates/ledger/bills/bill_detail.html:70 #: templates/sales/invoices/invoice_detail.html:89 msgid "Record Payment" msgstr "تسجيل عملية دفع" -#: templates/ledger/bills/bill_detail.html:73 -#: templates/ledger/journal_entry/includes/card_invoice.html:36 -#: templates/ledger/journal_entry/includes/card_invoice.html:122 -#: templates/sales/invoices/invoice_detail.html:92 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:49 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:187 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:43 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:170 -msgid "Mark as Paid" -msgstr "وضع علامة مدفوعة" - #: templates/ledger/bills/bill_detail.html:86 #: templates/sales/invoices/invoice_detail.html:107 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:43 @@ -6533,7 +7145,7 @@ msgid "Due Amount" msgstr "المبلغ الكلي" #: templates/ledger/bills/bill_detail.html:158 -#: templates/ledger/bills/bill_list.html:50 +#: templates/ledger/bills/bill_list.html:48 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:356 msgid "Bill Number" msgstr "رقم الفاتورة" @@ -6584,14 +7196,6 @@ msgstr "مبلغ ضريبة القيمة المضافة" msgid "Grand Total" msgstr "الإجمالي" -#: templates/ledger/bills/bill_form.html:5 -#: templates/ledger/bills/bill_form.html:9 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:11 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:27 -#: venv/lib/python3.11/site-packages/django_ledger/views/bill.py:52 -msgid "Create Bill" -msgstr "إنشاء فاتورة" - #: templates/ledger/bills/bill_list.html:4 #: templates/ledger/bills/bill_list.html:8 #: templates/ledger/bills/bill_list.html:16 @@ -6600,29 +7204,24 @@ msgstr "إنشاء فاتورة" msgid "Bills" msgstr "الفواتير" -#: templates/ledger/bills/bill_list.html:17 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:217 -msgid "New Bill" -msgstr "فاتورة جديدة" - -#: templates/ledger/bills/bill_list.html:32 +#: templates/ledger/bills/bill_list.html:30 msgid "Search bills..." msgstr "ابحث عن الفواتير ..." -#: templates/ledger/bills/bill_list.html:51 +#: templates/ledger/bills/bill_list.html:49 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:360 msgid "Bill Status" msgstr "حالة الفاتورة" -#: templates/ledger/bills/bill_list.html:92 +#: templates/ledger/bills/bill_list.html:90 msgid "No bill found." msgstr "لم يتم العثور على فاتورة." -#: templates/ledger/bills/bill_list.html:99 +#: templates/ledger/bills/bill_list.html:97 msgid "to" msgstr "إلى" -#: templates/ledger/bills/bill_list.html:99 +#: templates/ledger/bills/bill_list.html:97 msgid "Items of" msgstr "عناصر" @@ -6635,7 +7234,7 @@ msgid "Are you sure you want to delete this account?" msgstr "هل أنت متأكد أنك تريد حذف هذا الحساب؟" #: templates/ledger/coa_accounts/account_detail.html:39 -#: templates/ledger/coa_accounts/account_list.html:25 +#: templates/ledger/coa_accounts/partials/account_table.html:7 #: templates/ledger/journal_entry/journal_entry_transactions.html:19 #: templates/ledger/reports/tags/balance_sheet_statement.html:14 #: templates/sales/payments/payment_details.html:16 @@ -6661,7 +7260,7 @@ msgstr "رمز الحساب" #: templates/ledger/coa_accounts/account_detail.html:48 #: templates/ledger/coa_accounts/account_detail.html:50 -#: templates/ledger/coa_accounts/account_list.html:27 +#: templates/ledger/coa_accounts/partials/account_table.html:9 #: templates/ledger/reports/tags/balance_sheet_statement.html:18 #: templates/ledger/reports/tags/income_statement.html:13 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/account/tags/accounts_table.html:26 @@ -6672,7 +7271,7 @@ msgstr "نوع الرصيد" #: templates/ledger/coa_accounts/account_detail.html:48 #: templates/ledger/coa_accounts/account_detail.html:68 -#: templates/ledger/coa_accounts/account_list.html:82 +#: templates/ledger/coa_accounts/partials/account_table.html:25 #: templates/ledger/journal_entry/journal_entry_transactions.html:21 #: templates/sales/payments/payment_details.html:18 #: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:423 @@ -6686,7 +7285,7 @@ msgstr "مدين" #: templates/ledger/coa_accounts/account_detail.html:50 #: templates/ledger/coa_accounts/account_detail.html:69 -#: templates/ledger/coa_accounts/account_list.html:84 +#: templates/ledger/coa_accounts/partials/account_table.html:27 #: templates/ledger/journal_entry/journal_entry_transactions.html:22 #: templates/sales/payments/payment_details.html:19 #: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:422 @@ -6720,31 +7319,43 @@ msgstr "تعديل الحساب" msgid "Add Account" msgstr "إضافة حساب" -#: templates/ledger/coa_accounts/account_list.html:3 -#: templates/ledger/coa_accounts/account_list.html:6 #: templates/ledger/coa_accounts/account_list.html:14 -#: venv/lib/python3.11/site-packages/django_ledger/models/accounts.py:444 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html:54 -msgid "Accounts" -msgstr "الحسابات" - -#: templates/ledger/coa_accounts/account_list.html:15 msgid "New Account" msgstr "حساب جديد" -#: templates/ledger/coa_accounts/account_list.html:46 +#: templates/ledger/coa_accounts/account_list.html:22 +#: templates/ledger/reports/dashboard.html:20 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:5 +msgid "Assets" +msgstr "الأصول" + +#: templates/ledger/coa_accounts/account_list.html:27 +msgid "COGS" +msgstr "تكلفة البضائع المباعة" + +msgid "Capital" +msgstr "رأس المال" + +msgid "Income" +msgstr "الإيرادات" + +#: templates/ledger/coa_accounts/account_list.html:47 +#: templates/ledger/reports/dashboard.html:24 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:8 +msgid "Liabilities" +msgstr "الالتزامات" + +#: templates/ledger/coa_accounts/account_list.html:109 msgid "Delete Account" msgstr "حذف الحساب" -#: templates/ledger/coa_accounts/account_list.html:53 +#: templates/ledger/coa_accounts/account_list.html:116 msgid "Are you sure you want to delete this Account?" msgstr "هل أنت متأكد أنك تريد حذف هذا الحساب؟" -#: templates/ledger/journal_entry/includes/card_invoice.html:15 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:16 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:14 -msgid "Due in" -msgstr "مستحق في" +#: templates/ledger/coa_accounts/partials/account_table.html:67 +msgid "No accounts found in this category." +msgstr "لم يتم العثور على أي حسابات في هذه الفئة." #: templates/ledger/journal_entry/includes/card_invoice.html:45 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:53 @@ -6762,81 +7373,14 @@ msgstr "معلومات الفاتورة" msgid "This invoice is" msgstr "هذه الفاتورة هي" -#: templates/ledger/journal_entry/includes/card_invoice.html:51 -#: templates/ledger/journal_entry/includes/card_invoice.html:62 -#: templates/ledger/journal_entry/includes/card_invoice.html:76 -#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:178 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:67 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:84 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:105 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:13 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:58 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:75 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:96 -msgid "Amount Due" -msgstr "المبلغ المستحق" - -#: templates/ledger/journal_entry/includes/card_invoice.html:53 -#: templates/ledger/journal_entry/includes/card_invoice.html:64 -#: templates/ledger/journal_entry/includes/card_invoice.html:78 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:75 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:92 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:113 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:66 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:83 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:104 -msgid "Is Accrued" -msgstr "مستحقة" - -#: templates/ledger/journal_entry/includes/card_invoice.html:72 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:100 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:129 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:141 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:91 -msgid "External Ref" -msgstr "المرجع الخارجي" - -#: templates/ledger/journal_entry/includes/card_invoice.html:85 -#: templates/ledger/journal_entry/includes/card_invoice.html:92 -#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:183 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:120 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:133 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:111 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:121 -msgid "Amount Paid" -msgstr "المبلغ المدفوع" - #: templates/ledger/journal_entry/includes/card_invoice.html:86 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:122 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:113 msgid "Progressed" msgstr "متقدم" -#: templates/ledger/journal_entry/includes/card_invoice.html:93 -#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:383 -#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:352 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:138 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:126 -msgid "Paid Date" -msgstr "تاريخ الدفع" - -#: templates/ledger/journal_entry/includes/card_invoice.html:104 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:160 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:62 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:143 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:67 -msgid "Mark as Draft" -msgstr "وضع كمسودة" - -#: templates/ledger/journal_entry/includes/card_invoice.html:110 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:169 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/card_estimate.html:71 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/includes/card_invoice.html:152 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:76 -msgid "Mark as Review" -msgstr "وضع قيد المراجعة" - #: templates/ledger/journal_entry/includes/card_invoice.html:128 +#: templates/purchase_orders/includes/card_po.html:211 #: templates/sales/estimates/estimate_list.html:41 #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:348 #: venv/lib/python3.11/site-packages/django_ledger/models/estimate.py:227 @@ -6959,17 +7503,6 @@ msgstr "إضافة قيد يومية" msgid "Document Number" msgstr "رقم المستند" -#: templates/ledger/journal_entry/journal_entry_list.html:49 -#: templates/ledger/journal_entry/journal_entry_transactions.html:18 -#: templates/sales/payments/payment_details.html:15 -#: templates/sales/payments/payment_list.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/models/journal_entry.py:373 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:9 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_txs_table.html:8 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/transactions/tags/txs_table.html:8 -msgid "Timestamp" -msgstr "الطابع الزمني" - #: templates/ledger/journal_entry/journal_entry_list.html:54 msgid "Transaction Count" msgstr "عدد المعاملات" @@ -7013,47 +7546,6 @@ msgstr "قائمة الفواتير" msgid "Invoice Items" msgstr "عناصر الفاتورة" -#: templates/ledger/ledger/ledger_detail.html:82 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:96 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:22 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_item_table.html:11 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/tags/ce_item_formset.html:20 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:95 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:20 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:9 -msgid "Unit Cost" -msgstr "تكلفة الوحدة" - -#: templates/ledger/ledger/ledger_detail.html:119 -#: templates/ledger/reports/cash_flow_statement.html:5 -#: templates/ledger/reports/cash_flow_statement.html:31 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:148 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/cash_flow.html:31 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:135 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/ledger/tags/ledgers_table.html:55 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_detail.html:29 -msgid "Cash Flow Statement" -msgstr "بيان التدفقات النقدية" - -#: templates/ledger/ledger/ledger_detail.html:125 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:155 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:141 -msgid "Balance Sheet PDF" -msgstr "الميزانية العمومية PDF" - -#: templates/ledger/ledger/ledger_detail.html:128 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:158 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:144 -msgid "Income Statement PDF" -msgstr "بيان الدخل PDF" - -#: templates/ledger/ledger/ledger_detail.html:131 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:161 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:147 -msgid "Cash Flow Statement PDF" -msgstr "بيان التدفقات النقدية PDF" - #: templates/ledger/ledger/ledger_detail.html:141 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_detail.html:157 msgid "Invoice Transactions" @@ -7098,26 +7590,6 @@ msgstr "إلغاء الإخفاء" msgid "No Entries found" msgstr "لم يتم العثور على أي مدخلات" -#: templates/ledger/reports/balance_sheet.html:38 -#: templates/ledger/reports/cash_flow_statement.html:33 -#: templates/ledger/reports/income_statement.html:28 -#: templates/ledger/reports/tags/balance_sheet_statement.html:16 -#: templates/ledger/reports/tags/income_statement.html:11 -#: templates/plans/invoices/layout.html:105 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:23 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/closing_entry/tags/closing_entry_txs_table.html:9 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/balance_sheet.html:32 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/cash_flow.html:33 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/income_statement.html:28 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html:23 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html:11 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_table.html:14 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/journal_entry/tags/je_txs_table.html:11 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:21 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/transactions/tags/txs_table.html:11 -msgid "Unit" -msgstr "الوحدة" - #: templates/ledger/reports/balance_sheet.html:43 #: templates/ledger/reports/cash_flow_statement.html:38 #: templates/ledger/reports/components/period_navigator.html:11 @@ -7168,16 +7640,6 @@ msgstr "المستحقات" msgid "Payables" msgstr "الحسابات الدائنة" -#: templates/ledger/reports/dashboard.html:20 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:5 -msgid "Assets" -msgstr "الأصول" - -#: templates/ledger/reports/dashboard.html:24 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:8 -msgid "Liabilities" -msgstr "الالتزامات" - #: templates/ledger/reports/dashboard.html:28 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/widget_bs.html:11 msgid "Equity" @@ -7532,9 +7994,11 @@ msgstr "وضع علامة مقروء على الكل" msgid "Organization Details" msgstr "تفاصيل الشركة" +#: templates/organizations/organization_form.html:7 msgid "Update Organization" msgstr "تحديث المؤسسة" +#: templates/organizations/organization_form.html:9 msgid "Add New Organization" msgstr "إضافة مؤسسة جديدة" @@ -7591,7 +8055,8 @@ msgstr "من" msgid "Payment Failed" msgstr "فشل الدفع" -#: templates/payment_failed.html:13 templates/welcome-temp.html:67 +#: templates/payment_failed.html:13 templates/payment_success.html:13 +#: templates/welcome-temp.html:67 msgid "Home" msgstr "الرئيسية" @@ -7603,7 +8068,7 @@ msgstr "فشل" msgid "We couldn't process your payment. Please try again" msgstr "تعذر معالجة دفعتك. يرجى المحاولة مرة أخرى" -#: templates/payment_failed.html:32 +#: templates/payment_failed.html:32 templates/payment_success.html:32 msgid "Back to Home" msgstr "العودة إلى الرئيسية" @@ -7611,6 +8076,16 @@ msgstr "العودة إلى الرئيسية" msgid "Payment Successful" msgstr "تم الدفع بنجاح" +#: templates/payment_success.html:25 +msgid "Thank You" +msgstr "شكرًا لك" + +msgid "Your payment was successful" +msgstr "تمت عملية الدفع بنجاح" + +msgid "Your order is being processed" +msgstr "يتم الآن معالجة طلبك" + #: templates/plans/account_activation.html:6 msgid "Activation successful" msgstr "تم التفعيل بنجاح" @@ -7815,8 +8290,10 @@ msgstr "نعم" msgid "no" msgstr "لا" -#: templates/plans/extend.html:40 -msgid "Pricings" +#: templates/plans/extend.html:40 templates/plans/plan_table.html:63 +#: templates/subscriptions/subscription_plan.html:7 templates/welcome.html:94 +#: templates/welcome_header.html:39 +msgid "Pricing" msgstr "السعر" #: templates/plans/extend.html:44 templates/plans/plan_table.html:95 @@ -7901,10 +8378,6 @@ msgstr "غير متوفر" msgid "Payment Information" msgstr "معلومات الدفع" -#: templates/plans/invoices/layout.html:156 -msgid "Method" -msgstr "طريقة" - #: templates/plans/invoices/layout.html:157 msgid "Electronic Payment" msgstr "دفع إلكتروني" @@ -8053,12 +8526,6 @@ msgstr "الخطة الحالية" msgid "No Limit" msgstr "لا يوجد حد" -#: templates/plans/plan_table.html:63 -#: templates/subscriptions/subscription_plan.html:7 templates/welcome.html:94 -#: templates/welcome_header.html:39 -msgid "Pricing" -msgstr "السعر" - #: templates/plans/plan_table.html:74 templates/plans/plan_table.html:122 #: venv/lib/python3.11/site-packages/django/forms/widgets.py:529 msgid "Change" @@ -8161,6 +8628,163 @@ msgstr "حامل البطاقة" msgid "Expiry" msgstr "الانتهاء" +#: templates/purchase_orders/includes/card_po.html:58 +#: templates/purchase_orders/po_update.html:45 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:19 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:42 +msgid "Contract" +msgstr "العقد" + +#: templates/purchase_orders/includes/card_po.html:63 +msgid "View Contract" +msgstr "عرض العقد" + +#: templates/purchase_orders/includes/card_po.html:73 +#: venv/lib/python3.11/site-packages/django_ledger/forms/bill.py:49 +#: venv/lib/python3.11/site-packages/django_ledger/forms/invoice.py:64 +#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:380 +#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:349 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:219 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:26 +msgid "Draft Date" +msgstr "تاريخ المسودة" + +#: templates/purchase_orders/includes/card_po.html:81 +#: templates/purchase_orders/includes/card_po.html:100 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:210 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:27 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:33 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:39 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:51 +msgid "Purchase Order Amount" +msgstr "مبلغ أمر الشراء" + +#: templates/purchase_orders/includes/card_po.html:92 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:32 +msgid "Review Date" +msgstr "تاريخ المراجعة" + +#: templates/purchase_orders/includes/card_po.html:111 +#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:382 +#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:351 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:221 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:38 +msgid "Approved Date" +msgstr "تاريخ الموافقة" + +#: templates/purchase_orders/includes/card_po.html:127 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:214 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:41 +msgid "Received Amount" +msgstr "المبلغ المستلم" + +#: templates/purchase_orders/includes/card_po.html:138 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:48 +msgid "Fulfilled Date" +msgstr "تاريخ التنفيذ" + +#: templates/purchase_orders/includes/card_po.html:150 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:195 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:53 +msgid "Fulfilled" +msgstr "تم التنفيذ" + +#: templates/purchase_orders/includes/card_po.html:193 +#: venv/lib/python3.11/site-packages/django_ledger/forms/purchase_order.py:67 +msgid "Mark as Fulfilled" +msgstr "تمييز كمنفذ" + +#: templates/purchase_orders/includes/card_po.html:233 +msgid "New Purchase Order" +msgstr "أمر شراء جديد" + +#: templates/purchase_orders/includes/po_item_formset.html:9 +#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:229 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:8 +msgid "Purchase Order Items" +msgstr "عناصر أمر الشراء" + +#: templates/purchase_orders/includes/po_item_formset.html:29 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:28 +msgid "Bill Paid?" +msgstr "هل تم دفع الفاتورة؟" + +#: templates/purchase_orders/includes/po_table.html:40 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_table.html:40 +msgid " Delete" +msgstr "حذف" + +#: templates/purchase_orders/po_detail.html:23 +#: templates/purchase_orders/po_update.html:33 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:16 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:27 +#: venv/lib/python3.11/site-packages/django_ledger/views/purchase_order.py:43 +msgid "PO List" +msgstr "قائمة أوامر الشراء" + +#: templates/purchase_orders/po_detail.html:44 +#: venv/lib/python3.11/site-packages/django_ledger/forms/invoice.py:119 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:38 +msgid "Amount Received" +msgstr "المبلغ المستلم" + +#: templates/purchase_orders/po_detail_backup.html:59 +#: templates/sales/estimates/estimate_detail.html:98 +msgid "View Purchase Order" +msgstr "عرض أمر الشراء" + +#: templates/purchase_orders/po_form.html:7 +#: templates/vendors/vendor_form.html:7 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/vendor_update.html:10 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/vendor_update.html:22 +msgid "Update Vendor" +msgstr "تحديث المورد" + +#: templates/purchase_orders/po_form.html:9 +#: templates/vendors/vendor_form.html:9 +msgid "Add New Vendor" +msgstr "مورد جديد" + +#: templates/purchase_orders/po_form.html:21 +msgid "Edit Purchase Order" +msgstr "تعديل أمر الشراء" + +msgid "Add New Purchase Order" +msgstr "إضافة أمر شراء جديد" + +msgid "Create New PO" +msgstr "إنشاء أمر شراء جديد" + +#: templates/purchase_orders/po_update.html:27 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:22 +msgid "Save PO" +msgstr "حفظ أمر الشراء" + +#: templates/purchase_orders/po_update.html:30 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:25 +msgid "Back to PO Detail" +msgstr "العودة إلى تفاصيل أمر الشراء" + +#: templates/purchase_orders/po_update.html:55 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:52 +msgid "Avg Unit Price" +msgstr "متوسط سعر الوحدة" + +#: templates/purchase_orders/po_update.html:56 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:53 +msgid "Total Contracted Cost" +msgstr "إجمالي التكلفة المتعاقد عليها" + +#: templates/purchase_orders/tags/po_item_table.html:13 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:13 +msgid "Billed" +msgstr "مفوترة" + +#: templates/purchase_orders/tags/po_item_table.html:41 +#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:41 +msgid "Total PO Amount" +msgstr "إجمالي مبلغ أمر الشراء" + #: templates/representatives/representative_detail.html:3 msgid "Representative Details" msgstr "تفاصيل ممثل الشركة" @@ -8179,15 +8803,6 @@ msgstr "لم يتم العثور على ممثلين للشركات." msgid "Are you sure you want to Cancel this Estimate?" msgstr "هل أنت متأكد أنك تريد إلغاء هذا التقدير؟" -#: templates/sales/estimates/estimate_detail.html:97 -#: templates/sales/invoices/invoice_detail.html:5 -msgid "View Invoice" -msgstr "عرض الفاتورة" - -#: templates/sales/estimates/estimate_detail.html:98 -msgid "View Purchase Order" -msgstr "عرض أمر الشراء" - #: templates/sales/estimates/estimate_detail.html:102 msgid "Send Quotation" msgstr "إرسال عرض السعر" @@ -8246,17 +8861,9 @@ msgstr "لم يتم العثور على سيارات" msgid "Add More" msgstr "إضافة المزيد" -#: templates/sales/estimates/estimate_list.html:17 -#: templates/sales/invoices/invoice_list.html:18 -#: templates/sales/journals/journal_list.html:18 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:11 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_table.html:13 -msgid "Status Date" -msgstr "تاريخ الحالة" - #: templates/sales/estimates/estimate_list.html:56 #: templates/sales/journals/journal_list.html:40 -#: templates/sales/orders/order_list.html:34 +#: templates/sales/orders/order_list.html:49 msgid "No Quotations Found" msgstr "لم يتم العثور على عروض" @@ -8265,6 +8872,7 @@ msgid "Send" msgstr "إرسال" #: templates/sales/estimates/sale_order_form.html:5 +#: templates/sales/estimates/sale_order_form1.html:5 #: templates/sales/estimates/sale_order_preview.html:159 msgid "Sale Order" msgstr "أمر بيع" @@ -8336,12 +8944,6 @@ msgstr "ايميل العميل" msgid "Invoice Status" msgstr "حالة الفاتورة" -#: templates/sales/invoices/invoice_list.html:30 -#: templates/sales/sales_list.html:187 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:15 -msgid "Past Due" -msgstr "مستحق" - #: templates/sales/invoices/invoice_list.html:68 msgid "No Invoice Found" msgstr "لم يتم العثور على فاتورة" @@ -8359,6 +8961,10 @@ msgstr "رقم الطلب" msgid "For Quotation" msgstr "لعرض سعر" +#: templates/sales/orders/order_list.html:19 +msgid "Expected Delivery" +msgstr "موعد التسليم المتوقع" + #: templates/sales/orders/purchase_order.html:37 msgid "Print" msgstr "طباعة" @@ -8383,12 +8989,6 @@ msgstr "إجراء الدفع" msgid "Payment Already Made" msgstr "تم الدفع بالفعل" -#: templates/sales/payments/payment_list.html:4 -#: templates/sales/payments/payment_list.html:9 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:14 -msgid "Payments" -msgstr "المدفوعات" - #: templates/sales/payments/payment_list.html:20 msgid "Payment Number" msgstr "رقم عملية الدفع" @@ -8781,16 +9381,6 @@ msgstr "رقم الهاتف" msgid "role" msgstr "الدور" -#: templates/vendors/vendor_form.html:7 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/vendor_update.html:10 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/vendor_update.html:22 -msgid "Update Vendor" -msgstr "تحديث المورد" - -#: templates/vendors/vendor_form.html:9 -msgid "Add New Vendor" -msgstr "مورد جديد" - #: templates/vendors/vendor_form.html:25 msgid "Edit Vendor" msgstr "تعديل مورد" @@ -9790,6 +10380,28 @@ msgstr "المستخدم هو مشرف عام." msgid "French" msgstr "الفرنسية" +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:140 +#, python-format +msgid "not allowed with argument %s" +msgstr "غير مسموح به مع الوسيط %s" + +msgid "ignored explicit argument %r" +msgstr "تم تجاهل الوسيط المحدد %r" + +msgid "too few arguments" +msgstr "عدد غير كافٍ من الوسائط" + +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:324 +#, fuzzy, python-format +#| msgid "Prompt is required." +msgid "argument %s is required" +msgstr "الإدخال مطلوب." + +#: venv/lib/python3.11/site-packages/argcomplete/packages/_argparse.py:338 +#, python-format +msgid "one of the arguments %s is required" +msgstr "أحد الوسائط %s مطلوب" + #: venv/lib/python3.11/site-packages/ckeditor_uploader/forms.py:6 msgid "Search files" msgstr "البحث في الملفات" @@ -10584,10 +11196,6 @@ msgstr "" "القيمة “%(value)s” تحتوي على التنسيق الصحيح (YYYY-MM-DD HH:MM[:ss[.uuuuuu]]" "[TZ]) لكنها تاريخ/وقت غير صالح." -#: venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py:2642 -msgid "URL" -msgstr "رابط URL" - #: venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py:2666 msgid "Raw binary data" msgstr "بيانات ثنائية خام" @@ -11458,15 +12066,6 @@ msgstr "رقم التوجيه" msgid "Make Active" msgstr "اجعل نشطاً" -#: venv/lib/python3.11/site-packages/django_ledger/forms/bill.py:49 -#: venv/lib/python3.11/site-packages/django_ledger/forms/invoice.py:64 -#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:380 -#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:349 -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:219 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:26 -msgid "Draft Date" -msgstr "تاريخ المسودة" - #: venv/lib/python3.11/site-packages/django_ledger/forms/bill.py:50 msgid "Payable Account" msgstr "حساب دائن" @@ -11570,6 +12169,12 @@ msgstr "العنوان سطر 1" msgid "Address line 2" msgstr "العنوان سطر 2" +#: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:82 +#: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:159 +#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:108 +msgid "City" +msgstr "المدينة" + #: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:86 #: venv/lib/python3.11/site-packages/django_ledger/forms/entity.py:164 msgid "State" @@ -11671,11 +12276,6 @@ msgstr "تاريخ الفاتورة (YYYY-MM-DD)..." msgid "Progress Amount 0.00 -> 1.00 (percent)" msgstr "مبلغ التقدم 0.00 -> 1.00 (النسبة)" -#: venv/lib/python3.11/site-packages/django_ledger/forms/invoice.py:119 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:38 -msgid "Amount Received" -msgstr "المبلغ المستلم" - #: venv/lib/python3.11/site-packages/django_ledger/forms/invoice.py:129 msgid "Paid Date (YYYY-MM-DD)..." msgstr "تاريخ الدفع (YYYY-MM-DD)..." @@ -11712,13 +12312,6 @@ msgstr "اسم المخزون" msgid "Cannot create new Journal Entries on a locked Ledger." msgstr "لا يمكن إنشاء إدخالات يومية جديدة على دفتر حسابات مقفل." -#: venv/lib/python3.11/site-packages/django_ledger/forms/journal_entry.py:64 -#: venv/lib/python3.11/site-packages/django_ledger/models/entity.py:3182 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:95 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/includes/estimate_item_table.html:9 -msgid "Entity Unit" -msgstr "وحدة الكيان" - #: venv/lib/python3.11/site-packages/django_ledger/forms/ledger.py:43 #: venv/lib/python3.11/site-packages/django_ledger/models/ledger.py:193 msgid "Ledger External ID" @@ -11736,10 +12329,6 @@ msgstr "تاريخ التنفيذ (YYYY-MM-DD)..." msgid "PO Status" msgstr "حالة طلب الشراء" -#: venv/lib/python3.11/site-packages/django_ledger/forms/purchase_order.py:67 -msgid "Mark as Fulfilled" -msgstr "تمييز كمنفذ" - #: venv/lib/python3.11/site-packages/django_ledger/forms/purchase_order.py:68 msgid "PO Notes" msgstr "ملاحظات طلب الشراء" @@ -11880,11 +12469,6 @@ msgstr "سندات الدفع طويلة الأجل" msgid "Bonds Payable" msgstr "السندات المستحقة الدفع" -#: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:483 -#: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:569 -msgid "Capital" -msgstr "رأس المال" - #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:484 #: venv/lib/python3.11/site-packages/django_ledger/io/roles.py:570 msgid "Common Stock" @@ -12026,12 +12610,6 @@ msgstr "رقم المرجع الخارجي" msgid "Bill Additional Info" msgstr "معلومات إضافية عن الفاتورة" -#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:372 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:85 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:8 -msgid "Bill Items" -msgstr "بنود الفاتورة" - #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:378 #: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:347 #: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:235 @@ -12044,13 +12622,6 @@ msgstr "الوظيفة/التقدير المرتبط بالعميل" msgid "In Review Date" msgstr "تاريخ المراجعة" -#: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:382 -#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:351 -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:221 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:38 -msgid "Approved Date" -msgstr "تاريخ الموافقة" - #: venv/lib/python3.11/site-packages/django_ledger/models/bill.py:384 #: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:353 #: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:222 @@ -12438,12 +13009,6 @@ msgstr "هل تريد إبطال التقدير %s؟" msgid "Cannot compute gross margin, total cost is zero." msgstr "لا يمكن حساب هامش الربح الإجمالي، التكلفة الإجمالية صفر." -#: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:327 -#: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:229 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:42 -msgid "Prepaid Account" -msgstr "حساب مسبق الدفع" - #: venv/lib/python3.11/site-packages/django_ledger/models/invoice.py:331 #: venv/lib/python3.11/site-packages/django_ledger/models/mixins.py:237 msgid "Unearned Account" @@ -12748,10 +13313,6 @@ msgstr "شراء/التخلص من الأوراق المالية" msgid "Investing Activity Other" msgstr "نشاط استثماري آخر" -#: venv/lib/python3.11/site-packages/django_ledger/models/journal_entry.py:356 -msgid "Financing" -msgstr "تمويل" - #: venv/lib/python3.11/site-packages/django_ledger/models/journal_entry.py:357 msgid "Payoff of Short Term Debt" msgstr "سداد الدين قصير الأجل" @@ -12873,11 +13434,6 @@ msgstr "رقم التسجيل الضريبي" msgid "Sales Tax Rate" msgstr "معدل ضريبة المبيعات" -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:195 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:53 -msgid "Fulfilled" -msgstr "تم التنفيذ" - #: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:201 msgid "Purchase Order Number" msgstr "رقم أمر الشراء" @@ -12890,28 +13446,10 @@ msgstr "عنوان أمر الشراء" msgid "PO Title must be greater than 5" msgstr "يجب أن يكون عنوان أمر الشراء أكثر من 5 أحرف" -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:210 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:27 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:33 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:39 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:51 -msgid "Purchase Order Amount" -msgstr "مبلغ أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:214 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:41 -msgid "Received Amount" -msgstr "المبلغ المستلم" - #: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:223 msgid "Fulfillment Date" msgstr "تاريخ التنفيذ" -#: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:229 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:8 -msgid "Purchase Order Items" -msgstr "عناصر أمر الشراء" - #: venv/lib/python3.11/site-packages/django_ledger/models/purchase_order.py:742 #, python-format msgid "Do you want to mark Purchase Order %s as Draft?" @@ -13069,38 +13607,6 @@ msgstr "ABA" msgid "Inactivate" msgstr "إلغاء التنشيط" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_create.html:20 -msgid "Bill for" -msgstr "فاتورة لـ" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:24 -#: venv/lib/python3.11/site-packages/django_ledger/views/bill.py:214 -msgid "Bill List" -msgstr "قائمة الفواتير" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:63 -msgid "Accrued" -msgstr "متراكم" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:71 -msgid "You Still Owe" -msgstr "ما زلت مديناً" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:99 -msgid "PO" -msgstr "أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:115 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:45 -msgid "View PO" -msgstr "عرض أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_detail.html:171 -msgid "Bill Transactions" -msgstr "معاملات الفاتورة" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_list.html:18 msgid "Latest Bills" msgstr "أحدث الفواتير" @@ -13123,14 +13629,6 @@ msgstr "الذهاب إلى الشهر:" msgid "Go to year:" msgstr "الذهاب إلى السنة:" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:19 -msgid "Save Bill" -msgstr "حفظ الفاتورة" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:22 -msgid "Back to Bill Detail" -msgstr "العودة إلى تفاصيل الفاتورة" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/bill_update.html:26 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/invoice_update.html:26 #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:20 @@ -13176,38 +13674,6 @@ msgstr "الهجرة القسرية" msgid "Bill Configuration" msgstr "تكوين الفاتورة" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:53 -msgid "Mark as Canceled" -msgstr "وضع علامة ملغاة" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:66 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:83 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:104 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/includes/card_bill.html:132 -msgid "This bill is" -msgstr "هذه الفاتورة هي" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:10 -msgid "PO Qty" -msgstr "كمية أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:20 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:31 -msgid "PO Amount" -msgstr "مبلغ أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_item_formset.html:79 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/estimate/tags/ce_item_formset.html:74 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/invoice/tags/invoice_item_formset.html:69 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:101 -msgid "New Item" -msgstr "عنصر جديد" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/bills/tags/bill_table.html:9 -msgid "Number" -msgstr "الرقم" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/chart_of_accounts/coa_create.html:10 #: venv/lib/python3.11/site-packages/django_ledger/views/chart_of_accounts.py:51 msgid "Create Chart of Accounts" @@ -13562,10 +14028,6 @@ msgstr "حسب الوحدة" msgid "Noncash Charges to Current Accounts" msgstr "تكاليف غير نقدية لحسابات جارية" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/card_markdown.html:20 -msgid "No available notes to display..." -msgstr "لا توجد ملاحظات متاحة للعرض..." - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/includes/nav.html:37 msgid "Logout" msgstr "تسجيل الخروج" @@ -13686,19 +14148,6 @@ msgstr "رمز المنتج (SKU)" msgid "UPC" msgstr "رمز المنتج العالمي (UPC)" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:19 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:42 -msgid "Contract" -msgstr "العقد" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:32 -msgid "Review Date" -msgstr "تاريخ المراجعة" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:48 -msgid "Fulfilled Date" -msgstr "تاريخ التنفيذ" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/card_po.html:94 msgid "Fulfill" msgstr "تنفيذ" @@ -13707,52 +14156,14 @@ msgstr "تنفيذ" msgid "New PO" msgstr "أمر شراء جديد" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_item_formset.html:28 -msgid "Bill Paid?" -msgstr "هل تم دفع الفاتورة؟" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/includes/po_table.html:40 -msgid " Delete" -msgstr "حذف" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_create.html:12 msgid "PO for Estimate" msgstr "أمر شراء للتقدير" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_detail.html:16 -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:27 -#: venv/lib/python3.11/site-packages/django_ledger/views/purchase_order.py:43 -msgid "PO List" -msgstr "قائمة أوامر الشراء" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_list.html:18 msgid "Latest Purchase Orders" msgstr "أحدث أوامر الشراء" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:22 -msgid "Save PO" -msgstr "حفظ أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:25 -msgid "Back to PO Detail" -msgstr "العودة إلى تفاصيل أمر الشراء" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:52 -msgid "Avg Unit Price" -msgstr "متوسط سعر الوحدة" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/po_update.html:53 -msgid "Total Contracted Cost" -msgstr "إجمالي التكلفة المتعاقد عليها" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:13 -msgid "Billed" -msgstr "مفوترة" - -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/purchase_order/tags/po_item_table.html:41 -msgid "Total PO Amount" -msgstr "إجمالي مبلغ أمر الشراء" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/unit/unit_create.html:12 msgid "Create Entity Unit" msgstr "إنشاء وحدة كيان" @@ -13778,10 +14189,6 @@ msgstr "الاختصار" msgid "Unit of Measures List" msgstr "قائمة وحدات القياس" -#: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/includes/card_vendor.html:9 -msgid "Vendor Info" -msgstr "معلومات المورد" - #: venv/lib/python3.11/site-packages/django_ledger/templates/django_ledger/vendor/tags/vendor_table.html:9 msgid "Vendor Number" msgstr "رقم المورد" diff --git a/requirements.txt b/requirements.txt index e39311be..958851d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,8 +6,10 @@ alabaster==1.0.0 albucore==0.0.24 albumentations==2.0.7 annotated-types==0.7.0 +anthropic==0.52.2 anyio==4.9.0 arabic-reshaper==3.0.0 +argcomplete==3.6.2 arrow==1.3.0 asgiref==3.8.1 astor==0.8.1 @@ -19,13 +21,17 @@ beautifulsoup4==4.13.4 bleach==6.2.0 blessed==1.21.0 blinker==1.9.0 +boto3==1.38.29 +botocore==1.38.29 Brotli==1.1.0 +cachetools==5.5.2 cattrs==24.1.3 certifi==2025.4.26 cffi==1.17.1 chardet==5.2.0 charset-normalizer==3.4.2 click==8.2.1 +cohere==5.15.0 colorama==0.4.6 commonmark==0.9.1 contourpy==1.3.2 @@ -55,6 +61,7 @@ django-cors-headers==4.7.0 django-countries==7.6.1 django-crispy-forms==2.4 django-debug-toolbar==5.2.0 +django-easy-audit==1.3.7 django-extensions==4.1 django-filter==25.1 django-formtools==2.5.1 @@ -94,7 +101,11 @@ docutils==0.21.2 easy-thumbnails==2.10 emoji==2.14.1 et_xmlfile==2.0.0 +eval_type_backport==0.2.2 +executing==2.2.0 Faker==37.3.0 +fasta2a==0.2.14 +fastavro==1.11.1 filelock==3.18.0 fire==0.7.0 fonttools==4.58.0 @@ -102,28 +113,37 @@ fpdf==1.7.2 fpdf2==2.8.3 frozenlist==1.6.0 fsspec==2025.5.1 +google-auth==2.40.2 +google-genai==1.18.0 +googleapis-common-protos==1.70.0 gprof2dot==2025.4.14 graphqlclient==0.2.4 greenlet==3.2.2 +griffe==1.7.3 +groq==0.26.0 h11==0.16.0 h2==4.2.0 +hf-xet==1.1.3 hpack==4.1.0 hstspreload==2025.1.1 httpcore==1.0.9 httpx==0.28.1 httpx-sse==0.4.0 +huggingface-hub==0.32.4 hyperframe==6.1.0 icalendar==6.3.1 idna==3.10 imageio==2.37.0 imagesize==1.4.1 imgaug==0.4.0 +importlib_metadata==8.7.0 iso4217==1.12.20240625 isodate==0.7.2 isort==6.0.1 itsdangerous==2.2.0 Jinja2==3.1.6 jiter==0.10.0 +jmespath==1.0.1 joblib==1.5.1 jsonpatch==1.33 jsonpointer==3.0.0 @@ -132,12 +152,15 @@ kiwisolver==1.4.8 langchain==0.3.25 langchain-community==0.3.24 langchain-core==0.3.61 +langchain-ollama==0.3.3 langchain-text-splitters==0.3.8 langsmith==0.3.42 lazy_loader==0.4 ledger==1.0.1 libretranslatepy==2.1.4 lmdb==1.6.2 +logfire==3.18.0 +logfire-api==3.17.0 luhnchecker==0.0.12 lxml==5.4.0 Markdown==3.8 @@ -146,7 +169,9 @@ MarkupSafe==3.0.2 marshmallow==3.26.1 matplotlib==3.10.3 mccabe==0.7.0 +mcp==1.9.2 mdurl==0.1.2 +mistralai==1.8.1 MouseInfo==0.1.3 mpmath==1.3.0 multidict==6.4.4 @@ -158,11 +183,19 @@ num2words==0.5.14 numpy==2.2.6 oauthlib==3.2.2 ofxtools==0.9.5 +ollama==0.4.8 openai==1.82.0 opencv-contrib-python==4.11.0.86 opencv-python==4.11.0.86 opencv-python-headless==4.11.0.86 openpyxl==3.1.5 +opentelemetry-api==1.34.0 +opentelemetry-exporter-otlp-proto-common==1.34.0 +opentelemetry-exporter-otlp-proto-http==1.34.0 +opentelemetry-instrumentation==0.55b0 +opentelemetry-proto==1.34.0 +opentelemetry-sdk==1.34.0 +opentelemetry-semantic-conventions==0.55b0 opt_einsum==3.4.0 orjson==3.10.18 outcome==1.3.0.post0 @@ -174,18 +207,25 @@ phonenumbers==8.13.42 pillow==10.4.0 platformdirs==4.3.8 prometheus_client==0.22.0 +prompt_toolkit==3.0.51 propcache==0.3.1 -protobuf==6.31.0 +protobuf==5.29.5 psycopg==3.2.9 psycopg-binary==3.2.9 psycopg-c==3.2.9 psycopg2-binary==2.9.10 py-moneyed==3.0 +pyasn1==0.6.1 +pyasn1_modules==0.4.2 PyAutoGUI==0.9.54 pyclipper==1.3.0.post6 pycodestyle==2.13.0 pycparser==2.22 pydantic==2.11.5 +pydantic-ai==0.2.14 +pydantic-ai-slim==0.2.14 +pydantic-evals==0.2.14 +pydantic-graph==0.2.14 pydantic-settings==2.9.1 pydantic_core==2.33.2 pydotplus==2.0.2 @@ -212,6 +252,7 @@ python-bidi==0.6.6 python-dateutil==2.9.0.post0 python-docx==1.1.2 python-dotenv==1.1.0 +python-multipart==0.0.20 python-openid==2.2.5 python-slugify==8.0.4 python-stdnum==2.1 @@ -234,12 +275,16 @@ requests-oauthlib==2.0.0 requests-toolbelt==1.0.0 rfc3986==2.0.0 rich==14.0.0 +rsa==4.9.1 rubicon-objc==0.5.0 +s3transfer==0.13.0 sacremoses==0.1.1 +safetensors==0.5.3 scikit-image==0.25.2 scikit-learn==1.6.1 scipy==1.15.3 selenium==4.33.0 +sentence-transformers==4.1.0 sentencepiece==0.2.0 shapely==2.1.1 simsimd==6.2.1 @@ -251,7 +296,9 @@ sortedcontainers==2.4.0 soupsieve==2.7 SQLAlchemy==2.0.41 sqlparse==0.5.3 +sse-starlette==2.3.6 stanza==1.10.1 +starlette==0.47.0 stringzilla==3.12.5 suds==1.2.0 swapper==1.3.0 @@ -264,14 +311,17 @@ threadpoolctl==3.6.0 tifffile==2025.5.24 tinycss2==1.4.0 tinyhtml5==2.0.0 +tokenizers==0.21.1 tomli==2.2.1 tomlkit==0.13.2 torch==2.7.0 tqdm==4.67.1 +transformers==4.52.4 trio==0.30.0 trio-websocket==0.12.2 twilio==9.6.1 types-python-dateutil==2.9.0.20250516 +types-requests==2.32.0.20250602 typing-inspect==0.9.0 typing-inspection==0.4.1 typing_extensions==4.13.2 @@ -279,6 +329,7 @@ tzdata==2025.2 Unidecode==1.4.0 upgrade-requirements==1.7.0 urllib3==2.4.0 +uvicorn==0.34.3 vin==0.6.2 vininfo==1.8.0 vishap==0.1.5 @@ -287,10 +338,13 @@ wcwidth==0.2.13 weasyprint==65.1 webencodings==0.5.1 websocket-client==1.8.0 +websockets==15.0.1 Werkzeug==3.1.3 wikipedia==1.4.0 +wrapt==1.17.2 wsproto==1.2.0 xmlsec==1.3.15 yarl==1.20.0 +zipp==3.22.0 zopfli==0.2.3.post1 zstandard==0.23.0 diff --git a/run_haikal_qa.py b/run_haikal_qa.py new file mode 100644 index 00000000..83b11ff7 --- /dev/null +++ b/run_haikal_qa.py @@ -0,0 +1,77 @@ +from langchain_community.document_loaders import TextLoader +from langchain.indexes import VectorstoreIndexCreator +from langchain_community.llms import Ollama +from langchain.chains import RetrievalQA +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain.prompts import PromptTemplate +# from django.conf import settings + + +# Load YAML doc +loader = TextLoader("haikal_kb.yaml") + +# Create embeddings model +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +# Create an instance of VectorstoreIndexCreator with the embeddings +index_creator = VectorstoreIndexCreator(embedding=embeddings) + +# Then call the from_loaders method on the instance +index = index_creator.from_loaders([loader]) + +# Create LLM instance +llm = Ollama(model="qwen3:8b", temperature=0.3) + +# Define a custom prompt template for instructional responses +template = """ +You are Haikal, an assistant for the car inventory management system. +Your goal is to provide clear step-by-step instructions for users to complete tasks. + +Use the following pieces of context to answer the question at the end. +If you don't know the answer, just say you don't know. Don't try to make up an answer. + +Context: +{context} + +Question: {question} + +Provide a clear step-by-step guide with numbered instructions. Include: +1. Where to click in the interface +2. What to enter or select +3. Any buttons to press to complete the action +4. Any alternatives or shortcuts if available + +Helpful Step-by-Step Instructions:""" + +PROMPT = PromptTemplate( + template=template, + input_variables=["context", "question"] +) + +# Setup QA chain +qa = RetrievalQA.from_chain_type( + llm=llm, + chain_type="stuff", + retriever=index.vectorstore.as_retriever(), + return_source_documents=True, + chain_type_kwargs={"prompt": PROMPT} +) + +# Function to run a query +def ask_haikal(query): + response = qa.invoke({"query": query}) + print("\n" + "="*50) + print(f"Question: {query}") + print("="*50) + print("\nAnswer:") + print(response["result"]) + print("\nSources:") + for doc in response["source_documents"]: + print(f"- {doc.metadata.get('source', 'Unknown source')}") + print("="*50) + return response["result"] + +# Example query +if __name__ == "__main__": + query = "How do I add a new car to the inventory? answer in Arabic" + ask_haikal(query) diff --git a/sql_agent.py b/sql_agent.py new file mode 100644 index 00000000..bb38f081 --- /dev/null +++ b/sql_agent.py @@ -0,0 +1,159 @@ +import asyncio +import sqlite3 +import json +from typing import List, Dict + +from pydantic import BaseModel, Field + +from pydantic_ai import Agent, RunContext +from pydantic_ai.models.openai import OpenAIModel +from pydantic_ai.providers.openai import OpenAIProvider +import os + +import logfire + +logfire.configure(send_to_logfire='if-token-present') +logfire.instrument_pydantic_ai() + +# Define the OpenAI model (replace with your actual model if needed) +model = OpenAIModel( + model_name="qwen2.5:14b", # Or your preferred model + provider=OpenAIProvider(base_url='http://localhost:11434/v1') # Or your provider +) + + +class DatabaseSchema(BaseModel): + tables: Dict[str, List[Dict[str, str]]] = Field( + description="A dictionary where keys are table names and values are lists of column dictionaries (name, type)") + + +# Agent to get the database schema +schema_agent = Agent( + model, + deps_type=str, + output_type=str, + system_prompt="""You are a helpful assistant that extracts the schema of a SQLite database. + When the user provides a database path, use the get_database_schema to retrieve the schema. + Your ONLY response should be the raw JSON string representing the database schema. Do not include any other text. + The JSON should be a dictionary where keys are table names, and values are lists of column dictionaries. + Each column dictionary should include 'name', 'type', 'notnull', 'dflt_value', and 'pk' keys. + If there is an error, return a JSON string containing an "error" key with a list of error messages.""" +) + + +@schema_agent.tool +async def get_database_schema(ctx: RunContext[str], db_path: str) -> str: + """Retrieves the schema of the SQLite database and returns it as a JSON string.""" + print(f"Database path: {db_path}") + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") + tables = [row[0] for row in cursor.fetchall()] + print(tables) + + schema = {} + for table in tables: + cursor.execute(f"PRAGMA table_info({table})") + columns = [ + { + "name": col[1], + "type": col[2], + "notnull": col[3], + "dflt_value": col[4], + "pk": col[5], + } + for col in cursor.fetchall() + ] + schema[table] = columns + print(schema) + conn.close() + return json.dumps(schema) + except sqlite3.Error as e: + error_json = json.dumps({"error": [str(e)]}) + return error_json + except Exception as e: + error_json = json.dumps({"error": [str(e)]}) + return error_json + + +# Agent to generate and execute SQL queries +sql_agent = Agent( + model, + deps_type=DatabaseSchema, + output_type=str, + system_prompt="""You are a highly precise SQL query generator for a SQLite database. +You are given the EXACT database schema, which is a dictionary where keys are table names and values are lists of column dictionaries (with 'name' and 'type'). +Your ABSOLUTE priority is to generate SQL queries that ONLY use the table and column names exactly as they appear in this schema to answer the user's question. + +Follow these strict steps: +1. **Analyze User Question:** Understand the user's request. +2. **Match Schema EXACTLY:** Identify the specific table(s) and column(s) in the provided schema whose names EXACTLY match the entities and information requested in the user's question. +3. **Generate STRICT SQL:** Construct a valid SQL query that selects the identified column(s) from the identified table(s). You MUST use the exact names from the schema. Do not use aliases or make any assumptions about naming conventions. Aim for the simplest possible query. +4. **Execute Query:** Use the execute_sql_query to run your generated SQL. +5. **Return interactive Answer as if you are a sports person:** Provide a direct and simple answer to the user's question based on the query results. +6. **No Results:** If the query returns empty list, respond with: 'No matching entries found.' +7. **Error Handling:** If there's any error in generating or executing the SQL, return a JSON string with an "error" key and a list of error messages. + + +""" +) +# Example: +# Schema: {'Country': [{'name': 'id', 'type': 'INTEGER'}, {'name': 'name', 'type': 'TEXT'}]} +# User Question: "What are the country names?" +# Generated SQL: SELECT name FROM Country; +# Expected Answer: The countries are Belgium, England, France, ... + +@sql_agent.tool +async def execute_sql_query(ctx: RunContext[DatabaseSchema], query: str) -> str: + """Executes the SQL query and returns a simple string answer.""" + db_path = os.path.join(os.getcwd(), 'db.sqlite3') + print(query) + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + cursor.execute(query) + results = cursor.fetchall() + columns = [description[0] for description in cursor.description] + rows = [dict(zip(columns, row)) for row in results] + conn.close() + print(rows) + return rows + except Exception as e: + print(e) + + +async def main(): + db_path = os.path.join(os.getcwd(), 'db.sqlite3') + print(f"Database path: {db_path}") + user_question = "how many cars do we have in the inventory" + + # 1. Get the database schema + schema_result = await schema_agent.run(db_path) + print("Schema Agent Response:", schema_result) + print("Schema Agent Output:", schema_result.output) + + if "error" in schema_result.output: + print(f"Error getting schema: {schema_result.output}") + return + + try: + schema_data = json.loads(schema_result.output) + database_schema = DatabaseSchema(tables=schema_data) + print("Parsed Database Schema:", database_schema) + + # 2. Use the schema to answer the user question + sql_response = await sql_agent.run(user_question, database_schema=database_schema.tables) + print("SQL Agent Response:", sql_response) + print("SQL Agent Output:", sql_response.output) + + if "error" in sql_response.output: + print(f"Error executing SQL: {sql_response.output}") + + except json.JSONDecodeError: + print(f"Error: Could not parse schema agent response as JSON: {schema_result.output}") + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/static/js/tours/add-new-car_tour.json b/static/js/tours/add-new-car_tour.json new file mode 100644 index 00000000..a319e178 --- /dev/null +++ b/static/js/tours/add-new-car_tour.json @@ -0,0 +1,61 @@ +{ + "name": "Add New Car", + "description": "How to add a new car to the inventory", + "steps": [ + { + "title": "Step 1", + "intro": "Navigate to the Inventory section by clicking 'Inventory' in the main menu", + "position": "bottom", + "element": "#inventory-nav", + "click": "#inventory-nav" + }, + { + "title": "Step 2", + "intro": "Click the 'Inventory' button in the top right corner", + "position": "bottom", + "element": ".parent-wrapper label-1" + }, + { + "title": "Step 3", + "intro": "Click the 'Add Car' button in the top right corner", + "position": "bottom", + "element": "#btn-add-car" + }, + { + "title": "Step 4", + "intro": "Enter the VIN number or scan it using the barcode scanner", + "position": "bottom", + "element": "#nv-inventory" + }, + { + "title": "Step 5", + "intro": "Select the car make from the dropdown menu", + "position": "bottom", + "element": "#make-select, select[name='make'], .make-field" + }, + { + "title": "Step 6", + "intro": "Select the car series from the available options", + "position": "bottom", + "element": "#series-select, select[name='series'], .series-field" + }, + { + "title": "Step 7", + "intro": "Select the trim level for the car", + "position": "bottom", + "element": "#trim-select, select[name='trim'], .trim-field" + }, + { + "title": "Step 8", + "intro": "Fill in additional details like color, mileage, and price", + "position": "bottom", + "element": "#price-input, input[name='price'], .price-field" + }, + { + "title": "Step 9", + "intro": "Click 'Save' to add the car to inventory, or 'Save & Add Another' to continue adding cars", + "position": "bottom", + "element": "#inventory-menu, .inventory-nav, nav .inventory" + } + ] +} \ No newline at end of file diff --git a/static/js/tours/create-new-invoice_tour.json b/static/js/tours/create-new-invoice_tour.json new file mode 100644 index 00000000..98862178 --- /dev/null +++ b/static/js/tours/create-new-invoice_tour.json @@ -0,0 +1,52 @@ +{ + "name": "Create New Invoice", + "description": "How to create a new invoice", + "steps": [ + { + "title": "Step 1", + "intro": "Navigate to the Finance section by clicking 'Finance' in the main menu", + "position": "bottom", + "element": "#finance-menu, .finance-nav, nav .finance" + }, + { + "title": "Step 2", + "intro": "Click the 'Invoices' tab", + "position": "bottom", + "element": "#invoice-section, .invoice-tab, #create-invoice" + }, + { + "title": "Step 3", + "intro": "Click the 'Create New Invoice' button", + "position": "bottom", + "element": "#invoice-section, .invoice-tab, #create-invoice" + }, + { + "title": "Step 4", + "intro": "Select a customer from the dropdown or click 'Add New Customer'", + "position": "bottom", + "element": "#customer-select, select[name='customer'], .customer-field" + }, + { + "title": "Step 5", + "intro": "Select the car(s) to include in the invoice", + "position": "bottom", + "element": "#invoice-section, .invoice-tab, #create-invoice" + }, + { + "title": "Step 6", + "intro": "Add any additional services or parts by clicking 'Add Item'", + "position": "bottom" + }, + { + "title": "Step 7", + "intro": "Set the payment terms and due date", + "position": "bottom" + }, + { + "title": "Step 8", + "intro": "Click 'Save Draft' to save without finalizing, or 'Finalize Invoice' to complete", + "position": "bottom", + "element": "button[type='submit'], .btn-save, #save-button" + } + ] +} \ No newline at end of file diff --git a/static/js/tours/help-button.js b/static/js/tours/help-button.js new file mode 100644 index 00000000..9081f7a7 --- /dev/null +++ b/static/js/tours/help-button.js @@ -0,0 +1,163 @@ +/** + * Help Button Component + * Provides context-aware help based on the current page + */ +class HelpButton { + constructor(options = {}) { + this.options = Object.assign({ + position: 'bottom-right', + icon: 'question-circle', + text: 'Help', + autoDetect: true + }, options); + + this.pageToTourMap = { + '/inventory/': 'inventory_overview', + '/inventory/add/': 'add_new_car', + '/inventory/edit/': 'edit_car', + '/finance/invoices/': 'manage_invoices', + '/finance/invoices/create/': 'create_new_invoice', + '/customers/': 'manage_customers', + '/customers/add/': 'add_new_customer' + }; + + this.render(); + this.attachEvents(); + } + + render() { + // Create the help button + const button = document.createElement('div'); + button.className = `help-button ${this.options.position}`; + button.innerHTML = ` + + `; + + // Add styles + const style = document.createElement('style'); + style.textContent = ` + .help-button { + position: fixed; + z-index: 1000; + } + .help-button.bottom-right { + bottom: 20px; + right: 20px; + } + .help-button.bottom-left { + bottom: 20px; + left: 20px; + } + .help-button.top-right { + top: 20px; + right: 20px; + } + .help-button.top-left { + top: 20px; + left: 20px; + } + `; + + document.head.appendChild(style); + document.body.appendChild(button); + } + + attachEvents() { + const helpButton = document.getElementById('context-help-btn'); + if (!helpButton) return; + + helpButton.addEventListener('click', () => { + this.showContextHelp(); + }); + + // Initialize tooltip + new bootstrap.Tooltip(helpButton); + } + + showContextHelp() { + // Detect current page and show appropriate tour + if (this.options.autoDetect) { + const currentPath = window.location.pathname; + let tourSlug = null; + + // Find the best match for the current path + for (const [path, slug] of Object.entries(this.pageToTourMap)) { + if (currentPath.includes(path)) { + tourSlug = slug; + break; + } + } + + if (tourSlug) { + window.tourManager.loadTour(tourSlug); + return; + } + } + + // If no specific tour found or autoDetect is off, show help menu + this.showHelpMenu(); + } + + showHelpMenu() { + // Create a modal with available help options + const modal = document.createElement('div'); + modal.className = 'modal fade'; + modal.id = 'helpModal'; + modal.setAttribute('tabindex', '-1'); + + modal.innerHTML = ` + + `; + + document.body.appendChild(modal); + + const modalInstance = new bootstrap.Modal(modal); + modalInstance.show(); + + // Remove modal from DOM after it's hidden + modal.addEventListener('hidden.bs.modal', () => { + modal.remove(); + }); + } +} + +// Initialize help button on all pages +document.addEventListener('DOMContentLoaded', () => { + window.helpButton = new HelpButton(); +}); + +// export { HelpButton }; diff --git a/static/js/tours/tour-manager.js b/static/js/tours/tour-manager.js new file mode 100644 index 00000000..ad0b910f --- /dev/null +++ b/static/js/tours/tour-manager.js @@ -0,0 +1,134 @@ +/** + * Tour Manager for Car Inventory System + * Uses IntroJS to provide guided tours of the application + */ + +function getCsrfToken(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== "") { + const cookies = document.cookie.split(";"); + for (let cookie of cookies) { + cookie = cookie.trim(); + if (cookie.substring(0, name.length + 1) === name + "=") { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + +class TourManager { + constructor() { + this.introJs = introJs(); + this.currentTour = null; + this.tourData = null; + this.tourSlug = null; + + // Configure IntroJS defaults + this.introJs.setOptions({ + showStepNumbers: true, + showBullets: true, + showProgress: true, + scrollToElement: true, + disableInteraction: false, + doneLabel: 'Finish', + nextLabel: 'Next →', + prevLabel: '← Back', + exitOnEsc: true, + exitOnOverlayClick: false + }); + + // Set up event listeners + this.introJs.oncomplete(() => this.onTourComplete()); + this.introJs.onexit(() => this.onTourExit()); + } + + /** + * Load and start a tour by its slug + * @param {string} slug - The tour slug + */ + async loadTour(slug) { + try { + this.tourSlug = slug; + const response = await fetch(`/tours/data/${slug}/`); + if (!response.ok) { + throw new Error('Failed to load tour data'); + } + + const data = await response.json(); + this.tourData = data.tour; + + // If user already completed this tour, ask if they want to repeat + if (data.completed && !confirm('You have already completed this guide. Would you like to view it again?')) { + return; + } + + this.startTour(); + } catch (error) { + console.error('Error loading tour:', error); + alert('Failed to load the interactive guide. Please try again later.'); + } + } + + /** + * Start the currently loaded tour + */ + startTour() { + if (!this.tourData) { + console.error('No tour data loaded'); + return; + } + + this.introJs.setOptions({ + steps: this.tourData.steps + }); + + this.introJs.start(); + } + + /** + * Handle tour completion + */ + onTourComplete() { + if (!this.tourSlug) return; + + // Mark the tour as completed on the server + fetch(`/tours/complete/${this.tourSlug}/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCsrfToken() + } + }).catch(error => { + console.error('Error marking tour as completed:', error); + }); + + // Show success message + alert('Congratulations! You have completed the guide.'); + } + + /** + * Handle tour exit (without completion) + */ + onTourExit() { + console.log('Tour exited'); + } + + /** + * Get CSRF token from cookies + */ + +} + +// Initialize the tour manager +window.tourManager = new TourManager(); + +// Function to start a tour from a link +function startTour(slug) { + window.tourManager.loadTour(slug); + return false; // Prevent default link action +} + +// Export for use in other modules +// export { startTour }; \ No newline at end of file diff --git a/static/js/tours/ui_element_map.json b/static/js/tours/ui_element_map.json new file mode 100644 index 00000000..bf45bb76 --- /dev/null +++ b/static/js/tours/ui_element_map.json @@ -0,0 +1,2811 @@ +{ + "pages": { + "registration_password_reset_done": { + "template": "registration/password_reset_done.html", + "elements": {} + }, + "registration_password_change_form": { + "template": "registration/password_change_form.html", + "elements": { + "logout-form": "#logout-form", + "content-main": "#content-main", + "{{ form.new_password1.id_for_label }}_helptext": "#{{ form.new_password1.id_for_label }}_helptext", + "{{ form.new_password2.id_for_label }}_helptext": "#{{ form.new_password2.id_for_label }}_helptext" + } + }, + "registration_password_reset_email": { + "template": "registration/password_reset_email.html", + "elements": {} + }, + "registration_password_reset_confirm": { + "template": "registration/password_reset_confirm.html", + "elements": {} + }, + "registration_password_reset_form": { + "template": "registration/password_reset_form.html", + "elements": {} + }, + "registration_logged_out": { + "template": "registration/logged_out.html", + "elements": {} + }, + "registration_password_reset_complete": { + "template": "registration/password_reset_complete.html", + "elements": {} + }, + "registration_password_change_done": { + "template": "registration/password_change_done.html", + "elements": { + "logout-form": "#logout-form" + } + }, + "admin_delete_selected_confirmation": { + "template": "admin/delete_selected_confirmation.html", + "elements": {} + }, + "admin_change_list_object_tools": { + "template": "admin/change_list_object_tools.html", + "elements": {} + }, + "admin_delete_confirmation": { + "template": "admin/delete_confirmation.html", + "elements": { + "deleted-objects": "#deleted-objects" + } + }, + "admin_actions": { + "template": "admin/actions.html", + "elements": {} + }, + "admin_color_theme_toggle": { + "template": "admin/color_theme_toggle.html", + "elements": {} + }, + "admin_change_list_results": { + "template": "admin/change_list_results.html", + "elements": { + "result_list": "#result_list" + } + }, + "admin_index": { + "template": "admin/index.html", + "elements": { + "content-main": "#content-main", + "content-related": "#content-related", + "recent-actions-module": "#recent-actions-module" + } + }, + "admin_pagination": { + "template": "admin/pagination.html", + "elements": {} + }, + "admin_base": { + "template": "admin/base.html", + "elements": { + "container": "#container", + "header": "#header", + "branding": "#branding", + "user-tools": "#user-tools", + "logout-form": "#logout-form", + "main": "#main", + "content-start": "#content-start", + "content": "#content", + "footer": "#footer", + "icon-auto": "#icon-auto", + "icon-moon": "#icon-moon", + "icon-sun": "#icon-sun" + } + }, + "admin_date_hierarchy": { + "template": "admin/date_hierarchy.html", + "elements": {} + }, + "admin_invalid_setup": { + "template": "admin/invalid_setup.html", + "elements": {} + }, + "admin_app_index": { + "template": "admin/app_index.html", + "elements": {} + }, + "admin_500": { + "template": "admin/500.html", + "elements": {} + }, + "admin_object_history": { + "template": "admin/object_history.html", + "elements": { + "content-main": "#content-main", + "change-history": "#change-history" + } + }, + "admin_404": { + "template": "admin/404.html", + "elements": {} + }, + "admin_login": { + "template": "admin/login.html", + "elements": { + "content-main": "#content-main", + "login-form": "#login-form" + } + }, + "admin_change_list": { + "template": "admin/change_list.html", + "elements": { + "content-main": "#content-main", + "changelist": "#changelist", + "changelist-form": "#changelist-form", + "changelist-filter": "#changelist-filter", + "changelist-filter-header": "#changelist-filter-header", + "changelist-filter-extra-actions": "#changelist-filter-extra-actions" + } + }, + "admin_popup_response": { + "template": "admin/popup_response.html", + "elements": { + "django-admin-popup-response-constants": "#django-admin-popup-response-constants" + } + }, + "admin_change_form_object_tools": { + "template": "admin/change_form_object_tools.html", + "elements": {} + }, + "admin_app_list": { + "template": "admin/app_list.html", + "elements": { + "{{ app.app_label }}-{{ model_name }}": "#{{ app.app_label }}-{{ model_name }}" + } + }, + "admin_submit_line": { + "template": "admin/submit_line.html", + "elements": {} + }, + "admin_search_form": { + "template": "admin/search_form.html", + "elements": { + "toolbar": "#toolbar", + "changelist-search": "#changelist-search", + "searchbar": "#searchbar", + "searchbar_helptext": "#searchbar_helptext" + } + }, + "admin_prepopulated_fields_js": { + "template": "admin/prepopulated_fields_js.html", + "elements": { + "django-admin-prepopulated-fields-constants": "#django-admin-prepopulated-fields-constants" + } + }, + "admin_change_form": { + "template": "admin/change_form.html", + "elements": { + "content-main": "#content-main", + "{{ opts.model_name }}_form": "#{{ opts.model_name }}_form", + "django-admin-form-add-constants": "#django-admin-form-add-constants" + } + }, + "admin_nav_sidebar": { + "template": "admin/nav_sidebar.html", + "elements": { + "toggle-nav-sidebar": "#toggle-nav-sidebar", + "nav-sidebar": "#nav-sidebar", + "nav-filter": "#nav-filter" + } + }, + "admin_base_site": { + "template": "admin/base_site.html", + "elements": { + "site-name": "#site-name" + } + }, + "admin_filter": { + "template": "admin/filter.html", + "elements": {} + }, + "admin_auth_user_change_password": { + "template": "admin/auth/user/change_password.html", + "elements": { + "content-main": "#content-main", + "{{ opts.model_name }}_form": "#{{ opts.model_name }}_form", + "{{ form.usable_password.id_for_label }}_helptext": "#{{ form.usable_password.id_for_label }}_helptext", + "{{ form.password1.id_for_label }}_helptext": "#{{ form.password1.id_for_label }}_helptext", + "{{ form.password2.id_for_label }}_helptext": "#{{ form.password2.id_for_label }}_helptext" + } + }, + "admin_auth_user_add_form": { + "template": "admin/auth/user/add_form.html", + "elements": {} + }, + "admin_includes_object_delete_summary": { + "template": "admin/includes/object_delete_summary.html", + "elements": {} + }, + "admin_includes_fieldset": { + "template": "admin/includes/fieldset.html", + "elements": { + "{{ prefix }}-{{ id_prefix}}-{{ id_suffix }}-heading": "#{{ prefix }}-{{ id_prefix}}-{{ id_suffix }}-heading", + "{{ field.field.id_for_label }}_helptext": "#{{ field.field.id_for_label }}_helptext" + } + }, + "admin_edit_inline_stacked": { + "template": "admin/edit_inline/stacked.html", + "elements": { + "{{ inline_admin_formset.formset.prefix }}-group": "#{{ inline_admin_formset.formset.prefix }}-group", + "{{ inline_admin_formset.formset.prefix }}-heading": "#{{ inline_admin_formset.formset.prefix }}-heading", + "{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}": "#{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}" + } + }, + "admin_edit_inline_tabular": { + "template": "admin/edit_inline/tabular.html", + "elements": { + "{{ inline_admin_formset.formset.prefix }}-group": "#{{ inline_admin_formset.formset.prefix }}-group", + "{{ inline_admin_formset.formset.prefix }}-heading": "#{{ inline_admin_formset.formset.prefix }}-heading", + "{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}": "#{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}" + } + }, + "admin_widgets_many_to_many_raw_id": { + "template": "admin/widgets/many_to_many_raw_id.html", + "elements": {} + }, + "admin_widgets_radio": { + "template": "admin/widgets/radio.html", + "elements": {} + }, + "admin_widgets_url": { + "template": "admin/widgets/url.html", + "elements": {} + }, + "admin_widgets_foreign_key_raw_id": { + "template": "admin/widgets/foreign_key_raw_id.html", + "elements": { + "lookup_id_{{ widget.name }}": "#lookup_id_{{ widget.name }}" + } + }, + "admin_widgets_time": { + "template": "admin/widgets/time.html", + "elements": {} + }, + "admin_widgets_clearable_file_input": { + "template": "admin/widgets/clearable_file_input.html", + "elements": { + "{{ widget.checkbox_id }}": "#{{ widget.checkbox_id }}" + } + }, + "admin_widgets_split_datetime": { + "template": "admin/widgets/split_datetime.html", + "elements": {} + }, + "admin_widgets_date": { + "template": "admin/widgets/date.html", + "elements": {} + }, + "admin_widgets_related_widget_wrapper": { + "template": "admin/widgets/related_widget_wrapper.html", + "elements": { + "change_id_{{ name }}": "#change_id_{{ name }}", + "add_id_{{ name }}": "#add_id_{{ name }}", + "delete_id_{{ name }}": "#delete_id_{{ name }}", + "view_id_{{ name }}": "#view_id_{{ name }}" + } + }, + "auth_widgets_read_only_password_hash": { + "template": "auth/widgets/read_only_password_hash.html", + "elements": {} + }, + "usersessions_usersession_list": { + "template": "usersessions/usersession_list.html", + "elements": {} + }, + "usersessions_base_manage": { + "template": "usersessions/base_manage.html", + "elements": {} + }, + "allauth_elements_td": { + "template": "allauth/elements/td.html", + "elements": {} + }, + "allauth_elements_badge": { + "template": "allauth/elements/badge.html", + "elements": {} + }, + "allauth_elements_th": { + "template": "allauth/elements/th.html", + "elements": {} + }, + "allauth_elements_form": { + "template": "allauth/elements/form.html", + "elements": {} + }, + "allauth_elements_thead": { + "template": "allauth/elements/thead.html", + "elements": {} + }, + "allauth_elements_provider": { + "template": "allauth/elements/provider.html", + "elements": {} + }, + "allauth_elements_img": { + "template": "allauth/elements/img.html", + "elements": {} + }, + "allauth_elements_h2": { + "template": "allauth/elements/h2.html", + "elements": {} + }, + "allauth_elements_table": { + "template": "allauth/elements/table.html", + "elements": {} + }, + "allauth_elements_button": { + "template": "allauth/elements/button.html", + "elements": { + "{{ attrs.id }}": "#{{ attrs.id }}" + } + }, + "allauth_elements_p": { + "template": "allauth/elements/p.html", + "elements": {} + }, + "allauth_elements_details": { + "template": "allauth/elements/details.html", + "elements": {} + }, + "allauth_elements_button_group": { + "template": "allauth/elements/button_group.html", + "elements": {} + }, + "allauth_elements_fields": { + "template": "allauth/elements/fields.html", + "elements": {} + }, + "allauth_elements_hr": { + "template": "allauth/elements/hr.html", + "elements": {} + }, + "allauth_elements_alert": { + "template": "allauth/elements/alert.html", + "elements": {} + }, + "allauth_elements_h1": { + "template": "allauth/elements/h1.html", + "elements": {} + }, + "allauth_elements_panel": { + "template": "allauth/elements/panel.html", + "elements": {} + }, + "allauth_elements_field": { + "template": "allauth/elements/field.html", + "elements": { + "{{ attrs.id }}": "#{{ attrs.id }}" + } + }, + "allauth_elements_provider_list": { + "template": "allauth/elements/provider_list.html", + "elements": {} + }, + "allauth_elements_tbody": { + "template": "allauth/elements/tbody.html", + "elements": {} + }, + "allauth_elements_tr": { + "template": "allauth/elements/tr.html", + "elements": {} + }, + "allauth_layouts_base": { + "template": "allauth/layouts/base.html", + "elements": {} + }, + "allauth_layouts_manage": { + "template": "allauth/layouts/manage.html", + "elements": {} + }, + "allauth_layouts_entrance": { + "template": "allauth/layouts/entrance.html", + "elements": {} + }, + "tests_test_403_csrf": { + "template": "tests/test_403_csrf.html", + "elements": {} + }, + "mfa_index": { + "template": "mfa/index.html", + "elements": {} + }, + "mfa_base_entrance": { + "template": "mfa/base_entrance.html", + "elements": {} + }, + "mfa_reauthenticate": { + "template": "mfa/reauthenticate.html", + "elements": {} + }, + "mfa_base_manage": { + "template": "mfa/base_manage.html", + "elements": {} + }, + "mfa_trust": { + "template": "mfa/trust.html", + "elements": { + "logout-from-stage": "#logout-from-stage" + } + }, + "mfa_authenticate": { + "template": "mfa/authenticate.html", + "elements": { + "mfa_webauthn_authenticate": "#mfa_webauthn_authenticate", + "webauthn_form": "#webauthn_form", + "logout-from-stage": "#logout-from-stage" + } + }, + "mfa_recovery_codes_index": { + "template": "mfa/recovery_codes/index.html", + "elements": { + "recovery_codes": "#recovery_codes" + } + }, + "mfa_recovery_codes_base": { + "template": "mfa/recovery_codes/base.html", + "elements": {} + }, + "mfa_recovery_codes_generate": { + "template": "mfa/recovery_codes/generate.html", + "elements": {} + }, + "mfa_webauthn_signup_form": { + "template": "mfa/webauthn/signup_form.html", + "elements": { + "mfa_webauthn_signup": "#mfa_webauthn_signup", + "logout-from-stage": "#logout-from-stage" + } + }, + "mfa_webauthn_edit_form": { + "template": "mfa/webauthn/edit_form.html", + "elements": { + "mfa_webauthn_edit": "#mfa_webauthn_edit" + } + }, + "mfa_webauthn_base": { + "template": "mfa/webauthn/base.html", + "elements": {} + }, + "mfa_webauthn_reauthenticate": { + "template": "mfa/webauthn/reauthenticate.html", + "elements": { + "mfa_webauthn_reauthenticate": "#mfa_webauthn_reauthenticate" + } + }, + "mfa_webauthn_authenticator_list": { + "template": "mfa/webauthn/authenticator_list.html", + "elements": {} + }, + "mfa_webauthn_authenticator_confirm_delete": { + "template": "mfa/webauthn/authenticator_confirm_delete.html", + "elements": {} + }, + "mfa_webauthn_add_form": { + "template": "mfa/webauthn/add_form.html", + "elements": { + "mfa_webauthn_add": "#mfa_webauthn_add" + } + }, + "mfa_webauthn_snippets_scripts": { + "template": "mfa/webauthn/snippets/scripts.html", + "elements": {} + }, + "mfa_webauthn_snippets_login_script": { + "template": "mfa/webauthn/snippets/login_script.html", + "elements": { + "mfa_login": "#mfa_login", + "mfa_credential": "#mfa_credential" + } + }, + "mfa_totp_activate_form": { + "template": "mfa/totp/activate_form.html", + "elements": { + "authenticator_secret": "#authenticator_secret" + } + }, + "mfa_totp_base": { + "template": "mfa/totp/base.html", + "elements": {} + }, + "mfa_totp_deactivate_form": { + "template": "mfa/totp/deactivate_form.html", + "elements": {} + }, + "socialaccount_base_entrance": { + "template": "socialaccount/base_entrance.html", + "elements": {} + }, + "socialaccount_login_redirect": { + "template": "socialaccount/login_redirect.html", + "elements": {} + }, + "socialaccount_login": { + "template": "socialaccount/login.html", + "elements": {} + }, + "socialaccount_base_manage": { + "template": "socialaccount/base_manage.html", + "elements": {} + }, + "socialaccount_login_cancelled": { + "template": "socialaccount/login_cancelled.html", + "elements": {} + }, + "socialaccount_connections": { + "template": "socialaccount/connections.html", + "elements": {} + }, + "socialaccount_signup": { + "template": "socialaccount/signup.html", + "elements": {} + }, + "socialaccount_authentication_error": { + "template": "socialaccount/authentication_error.html", + "elements": {} + }, + "socialaccount_snippets_login": { + "template": "socialaccount/snippets/login.html", + "elements": {} + }, + "socialaccount_snippets_login_extra": { + "template": "socialaccount/snippets/login_extra.html", + "elements": {} + }, + "socialaccount_snippets_provider_list": { + "template": "socialaccount/snippets/provider_list.html", + "elements": {} + }, + "openid_base": { + "template": "openid/base.html", + "elements": {} + }, + "openid_login": { + "template": "openid/login.html", + "elements": {} + }, + "account_confirm_password_reset_code": { + "template": "account/confirm_password_reset_code.html", + "elements": {} + }, + "account_password_reset_from_key": { + "template": "account/password_reset_from_key.html", + "elements": { + "logout-from-stage": "#logout-from-stage" + } + }, + "account_signup_closed": { + "template": "account/signup_closed.html", + "elements": {} + }, + "account_base_reauthenticate": { + "template": "account/base_reauthenticate.html", + "elements": {} + }, + "account_request_login_code": { + "template": "account/request_login_code.html", + "elements": {} + }, + "account_password_reset_done": { + "template": "account/password_reset_done.html", + "elements": {} + }, + "account_email": { + "template": "account/email.html", + "elements": {} + }, + "account_base_entrance": { + "template": "account/base_entrance.html", + "elements": {} + }, + "account_verified_email_required": { + "template": "account/verified_email_required.html", + "elements": {} + }, + "account_reauthenticate": { + "template": "account/reauthenticate.html", + "elements": {} + }, + "account_password_reset_from_key_done": { + "template": "account/password_reset_from_key_done.html", + "elements": {} + }, + "account_email_confirm": { + "template": "account/email_confirm.html", + "elements": {} + }, + "account_account_inactive": { + "template": "account/account_inactive.html", + "elements": {} + }, + "account_phone_change": { + "template": "account/phone_change.html", + "elements": { + "current_phone": "#current_phone", + "verify-phone": "#verify-phone" + } + }, + "account_password_reset": { + "template": "account/password_reset.html", + "elements": {} + }, + "account_login": { + "template": "account/login.html", + "elements": { + "passkey_login": "#passkey_login" + } + }, + "account_email_change": { + "template": "account/email_change.html", + "elements": { + "current_email": "#current_email", + "new_email": "#new_email", + "pending-email": "#pending-email" + } + }, + "account_base_manage": { + "template": "account/base_manage.html", + "elements": {} + }, + "account_base_confirm_code": { + "template": "account/base_confirm_code.html", + "elements": { + "resend": "#resend", + "logout-from-stage": "#logout-from-stage" + } + }, + "account_verification_sent": { + "template": "account/verification_sent.html", + "elements": {} + }, + "account_confirm_email_verification_code": { + "template": "account/confirm_email_verification_code.html", + "elements": {} + }, + "account_confirm_phone_verification_code": { + "template": "account/confirm_phone_verification_code.html", + "elements": {} + }, + "account_base_manage_password": { + "template": "account/base_manage_password.html", + "elements": {} + }, + "account_base_manage_phone": { + "template": "account/base_manage_phone.html", + "elements": {} + }, + "account_logout": { + "template": "account/logout.html", + "elements": {} + }, + "account_password_change": { + "template": "account/password_change.html", + "elements": {} + }, + "account_signup_by_passkey": { + "template": "account/signup_by_passkey.html", + "elements": {} + }, + "account_password_set": { + "template": "account/password_set.html", + "elements": {} + }, + "account_confirm_login_code": { + "template": "account/confirm_login_code.html", + "elements": {} + }, + "account_signup": { + "template": "account/signup.html", + "elements": {} + }, + "account_base_manage_email": { + "template": "account/base_manage_email.html", + "elements": {} + }, + "account_snippets_warn_no_email": { + "template": "account/snippets/warn_no_email.html", + "elements": {} + }, + "account_snippets_already_logged_in": { + "template": "account/snippets/already_logged_in.html", + "elements": {} + }, + "debug_toolbar_redirect": { + "template": "debug_toolbar/redirect.html", + "elements": { + "redirect_to": "#redirect_to" + } + }, + "debug_toolbar_base": { + "template": "debug_toolbar/base.html", + "elements": { + "djDebug": "#djDebug", + "{{ toolbar.store_id }}": "#{{ toolbar.store_id }}", + "djDebugToolbar": "#djDebugToolbar", + "djDebugPanelList": "#djDebugPanelList", + "djHideToolBarButton": "#djHideToolBarButton", + "djToggleThemeButton": "#djToggleThemeButton", + "djDebugToolbarHandle": "#djDebugToolbarHandle", + "djShowToolBarButton": "#djShowToolBarButton", + "djShowToolBarD": "#djShowToolBarD", + "djShowToolBarJ": "#djShowToolBarJ", + "djDebugWindow": "#djDebugWindow" + } + }, + "debug_toolbar_panels_signals": { + "template": "debug_toolbar/panels/signals.html", + "elements": {} + }, + "debug_toolbar_panels_profiling": { + "template": "debug_toolbar/panels/profiling.html", + "elements": { + "profilingMain_{{ call.id }}": "#profilingMain_{{ call.id }}", + "{{ call.id }}": "#{{ call.id }}" + } + }, + "debug_toolbar_panels_sql_explain": { + "template": "debug_toolbar/panels/sql_explain.html", + "elements": {} + }, + "debug_toolbar_panels_staticfiles": { + "template": "debug_toolbar/panels/staticfiles.html", + "elements": {} + }, + "debug_toolbar_panels_cache": { + "template": "debug_toolbar/panels/cache.html", + "elements": { + "cacheMain_{{ forloop.counter }}": "#cacheMain_{{ forloop.counter }}", + "{{ forloop.counter }}": "#{{ forloop.counter }}", + "cacheDetails_{{ forloop.counter }}": "#cacheDetails_{{ forloop.counter }}" + } + }, + "debug_toolbar_panels_template_source": { + "template": "debug_toolbar/panels/template_source.html", + "elements": {} + }, + "debug_toolbar_panels_headers": { + "template": "debug_toolbar/panels/headers.html", + "elements": {} + }, + "debug_toolbar_panels_sql": { + "template": "debug_toolbar/panels/sql.html", + "elements": { + "sqlMain_{{ forloop.counter }}": "#sqlMain_{{ forloop.counter }}", + "{{ forloop.counter }}": "#{{ forloop.counter }}", + "sqlDetails_{{ forloop.counter }}": "#sqlDetails_{{ forloop.counter }}" + } + }, + "debug_toolbar_panels_timer": { + "template": "debug_toolbar/panels/timer.html", + "elements": { + "djDebugBrowserTiming": "#djDebugBrowserTiming", + "djDebugBrowserTimingTableBody": "#djDebugBrowserTimingTableBody" + } + }, + "debug_toolbar_panels_templates": { + "template": "debug_toolbar/panels/templates.html", + "elements": {} + }, + "debug_toolbar_panels_history": { + "template": "debug_toolbar/panels/history.html", + "elements": { + "djdtHistoryRequests": "#djdtHistoryRequests" + } + }, + "debug_toolbar_panels_versions": { + "template": "debug_toolbar/panels/versions.html", + "elements": {} + }, + "debug_toolbar_panels_request_variables": { + "template": "debug_toolbar/panels/request_variables.html", + "elements": {} + }, + "debug_toolbar_panels_sql_select": { + "template": "debug_toolbar/panels/sql_select.html", + "elements": {} + }, + "debug_toolbar_panels_settings": { + "template": "debug_toolbar/panels/settings.html", + "elements": {} + }, + "debug_toolbar_panels_alerts": { + "template": "debug_toolbar/panels/alerts.html", + "elements": {} + }, + "debug_toolbar_panels_history_tr": { + "template": "debug_toolbar/panels/history_tr.html", + "elements": { + "historyMain_{{ id }}": "#historyMain_{{ id }}", + "{{ id }}": "#{{ id }}" + } + }, + "debug_toolbar_panels_request": { + "template": "debug_toolbar/panels/request.html", + "elements": {} + }, + "debug_toolbar_panels_sql_profile": { + "template": "debug_toolbar/panels/sql_profile.html", + "elements": {} + }, + "debug_toolbar_includes_theme_selector": { + "template": "debug_toolbar/includes/theme_selector.html", + "elements": {} + }, + "debug_toolbar_includes_panel_button": { + "template": "debug_toolbar/includes/panel_button.html", + "elements": { + "djdt-{{ panel.panel_id }}": "#djdt-{{ panel.panel_id }}" + } + }, + "debug_toolbar_includes_panel_content": { + "template": "debug_toolbar/includes/panel_content.html", + "elements": { + "{{ panel.panel_id }}": "#{{ panel.panel_id }}" + } + }, + "silk_sql_detail": { + "template": "silk/sql_detail.html", + "elements": { + "query-div": "#query-div", + "query": "#query", + "query-info-div": "#query-info-div", + "time-taken-div": "#time-taken-div", + "num-joins-div": "#num-joins-div", + "query-plan-div": "#query-plan-div", + "plan": "#plan", + "traceback": "#traceback" + } + }, + "silk_profiling": { + "template": "silk/profiling.html", + "elements": { + "filter-form": "#filter-form" + } + }, + "silk_clear_db": { + "template": "silk/clear_db.html", + "elements": {} + }, + "silk_profile_detail": { + "template": "silk/profile_detail.html", + "elements": { + "query-div": "#query-div", + "query-info-div": "#query-info-div", + "code": "#code", + "error-div": "#error-div", + "percent": "#percent", + "graph-div": "#graph-div", + "pyprofile-div": "#pyprofile-div" + } + }, + "silk_requests": { + "template": "silk/requests.html", + "elements": { + "filter-form": "#filter-form" + } + }, + "silk_sql": { + "template": "silk/sql.html", + "elements": { + "query-div": "#query-div", + "query-info-div": "#query-info-div", + "table-div": "#table-div", + "table-pagination": "#table-pagination" + } + }, + "silk_cprofile": { + "template": "silk/cprofile.html", + "elements": { + "query-div": "#query-div", + "pyprofile-div": "#pyprofile-div" + } + }, + "silk_raw": { + "template": "silk/raw.html", + "elements": {} + }, + "silk_summary": { + "template": "silk/summary.html", + "elements": { + "filters": "#filters", + "filter-form": "#filter-form", + "filter-table": "#filter-table", + "filter-image": "#filter-image", + "filter-cell": "#filter-cell" + } + }, + "silk_request": { + "template": "silk/request.html", + "elements": { + "request-summary": "#request-summary", + "request-info": "#request-info", + "pre-curl": "#pre-curl" + } + }, + "silk_inclusion_request_summary_row": { + "template": "silk/inclusion/request_summary_row.html", + "elements": {} + }, + "silk_inclusion_profile_summary": { + "template": "silk/inclusion/profile_summary.html", + "elements": {} + }, + "silk_inclusion_heading": { + "template": "silk/inclusion/heading.html", + "elements": {} + }, + "silk_inclusion_request_menu": { + "template": "silk/inclusion/request_menu.html", + "elements": {} + }, + "silk_inclusion_profile_menu": { + "template": "silk/inclusion/profile_menu.html", + "elements": {} + }, + "silk_inclusion_request_summary": { + "template": "silk/inclusion/request_summary.html", + "elements": {} + }, + "silk_inclusion_code": { + "template": "silk/inclusion/code.html", + "elements": {} + }, + "silk_inclusion_root_menu": { + "template": "silk/inclusion/root_menu.html", + "elements": {} + }, + "silk_base_base": { + "template": "silk/base/base.html", + "elements": { + "content": "#content", + "header": "#header", + "filter": "#filter", + "data": "#data" + } + }, + "silk_base_root_base": { + "template": "silk/base/root_base.html", + "elements": { + "filter-button": "#filter-button", + "filter-item": "#filter-item", + "num-filters": "#num-filters", + "cbp-spmenu-s2": "#cbp-spmenu-s2", + "filter-form2": "#filter-form2" + } + }, + "silk_base_detail_base": { + "template": "silk/base/detail_base.html", + "elements": {} + }, + "django_tables2_bootstrap": { + "template": "django_tables2/bootstrap.html", + "elements": {} + }, + "django_tables2_semantic": { + "template": "django_tables2/semantic.html", + "elements": {} + }, + "django_tables2_table": { + "template": "django_tables2/table.html", + "elements": {} + }, + "django_tables2_bootstrap4-responsive": { + "template": "django_tables2/bootstrap4-responsive.html", + "elements": {} + }, + "django_tables2_bootstrap-responsive": { + "template": "django_tables2/bootstrap-responsive.html", + "elements": {} + }, + "django_tables2_bootstrap5": { + "template": "django_tables2/bootstrap5.html", + "elements": {} + }, + "django_tables2_bootstrap4": { + "template": "django_tables2/bootstrap4.html", + "elements": {} + }, + "django_tables2_bootstrap5-responsive": { + "template": "django_tables2/bootstrap5-responsive.html", + "elements": {} + }, + "django_bootstrap5_pagination": { + "template": "django_bootstrap5/pagination.html", + "elements": {} + }, + "django_bootstrap5_field_errors": { + "template": "django_bootstrap5/field_errors.html", + "elements": {} + }, + "django_bootstrap5_form_errors": { + "template": "django_bootstrap5/form_errors.html", + "elements": {} + }, + "django_bootstrap5_messages": { + "template": "django_bootstrap5/messages.html", + "elements": {} + }, + "django_bootstrap5_field_help_text": { + "template": "django_bootstrap5/field_help_text.html", + "elements": { + "{{ id_help_text }}": "#{{ id_help_text }}" + } + }, + "django_bootstrap5_bootstrap5": { + "template": "django_bootstrap5/bootstrap5.html", + "elements": {} + }, + "django_bootstrap5_widgets_radio_select": { + "template": "django_bootstrap5/widgets/radio_select.html", + "elements": { + "{{ option.attrs.id }}": "#{{ option.attrs.id }}" + } + }, + "django_bootstrap5_widgets_clearable_file_input": { + "template": "django_bootstrap5/widgets/clearable_file_input.html", + "elements": { + "{{ widget.checkbox_id }}": "#{{ widget.checkbox_id }}" + } + }, + "django_bootstrap5_widgets_radio_select_button_group": { + "template": "django_bootstrap5/widgets/radio_select_button_group.html", + "elements": { + "{{ widget.attrs.id }}": "#{{ widget.attrs.id }}", + "{{ option.attrs.id }}": "#{{ option.attrs.id }}" + } + }, + "bootstrap5_whole_uni_form": { + "template": "bootstrap5/whole_uni_form.html", + "elements": {} + }, + "bootstrap5_display_form": { + "template": "bootstrap5/display_form.html", + "elements": {} + }, + "bootstrap5_uni_form": { + "template": "bootstrap5/uni_form.html", + "elements": {} + }, + "bootstrap5_uni_formset": { + "template": "bootstrap5/uni_formset.html", + "elements": {} + }, + "bootstrap5_accordion": { + "template": "bootstrap5/accordion.html", + "elements": { + "{{ accordion.css_id }}": "#{{ accordion.css_id }}" + } + }, + "bootstrap5_table_inline_formset": { + "template": "bootstrap5/table_inline_formset.html", + "elements": { + "{{ form_id }}_table": "#{{ form_id }}_table" + } + }, + "bootstrap5_accordion-group": { + "template": "bootstrap5/accordion-group.html", + "elements": { + "{{ div.css_id }}": "#{{ div.css_id }}" + } + }, + "bootstrap5_inputs": { + "template": "bootstrap5/inputs.html", + "elements": {} + }, + "bootstrap5_betterform": { + "template": "bootstrap5/betterform.html", + "elements": {} + }, + "bootstrap5_whole_uni_formset": { + "template": "bootstrap5/whole_uni_formset.html", + "elements": {} + }, + "bootstrap5_errors": { + "template": "bootstrap5/errors.html", + "elements": {} + }, + "bootstrap5_field": { + "template": "bootstrap5/field.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_errors_formset": { + "template": "bootstrap5/errors_formset.html", + "elements": {} + }, + "bootstrap5_layout_inline_field": { + "template": "bootstrap5/layout/inline_field.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_help_text_and_errors": { + "template": "bootstrap5/layout/help_text_and_errors.html", + "elements": {} + }, + "bootstrap5_layout_radioselect_inline": { + "template": "bootstrap5/layout/radioselect_inline.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_field_errors": { + "template": "bootstrap5/layout/field_errors.html", + "elements": { + "{{field.errors.field_id}}_error": "#{{field.errors.field_id}}_error", + "{{field.auto_id}}_error": "#{{field.auto_id}}_error", + "error_{{ forloop.counter }}_{{ field.auto_id }}": "#error_{{ forloop.counter }}_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_uneditable_input": { + "template": "bootstrap5/layout/uneditable_input.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_checkboxselectmultiple_inline": { + "template": "bootstrap5/layout/checkboxselectmultiple_inline.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_baseinput": { + "template": "bootstrap5/layout/baseinput.html", + "elements": { + "{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}": "#{% if input.id %}{{ input.id }}{% else %}{{ input.input_type }}-id-{{ input.name|slugify }}{% endif %}" + } + }, + "bootstrap5_layout_help_text": { + "template": "bootstrap5/layout/help_text.html", + "elements": { + "{{ field.auto_id }}_helptext": "#{{ field.auto_id }}_helptext" + } + }, + "bootstrap5_layout_row": { + "template": "bootstrap5/layout/row.html", + "elements": { + "{{ div.css_id }}": "#{{ div.css_id }}" + } + }, + "bootstrap5_layout_button": { + "template": "bootstrap5/layout/button.html", + "elements": {} + }, + "bootstrap5_layout_field_errors_block": { + "template": "bootstrap5/layout/field_errors_block.html", + "elements": { + "{{field.errors.field_id}}_error": "#{{field.errors.field_id}}_error", + "{{field.auto_id}}_error": "#{{field.auto_id}}_error", + "error_{{ forloop.counter }}_{{ field.auto_id }}": "#error_{{ forloop.counter }}_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_field_with_buttons": { + "template": "bootstrap5/layout/field_with_buttons.html", + "elements": { + "{{ div.css_id }}": "#{{ div.css_id }}", + "{{field.errors.field_id}}_error": "#{{field.errors.field_id}}_error", + "{{field.auto_id}}_error": "#{{field.auto_id}}_error", + "error_{{ forloop.counter }}_{{ field.auto_id }}": "#error_{{ forloop.counter }}_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_buttonholder": { + "template": "bootstrap5/layout/buttonholder.html", + "elements": { + "{{ buttonholder.css_id }}": "#{{ buttonholder.css_id }}" + } + }, + "bootstrap5_layout_div": { + "template": "bootstrap5/layout/div.html", + "elements": { + "{{ div.css_id }}": "#{{ div.css_id }}" + } + }, + "bootstrap5_layout_tab-link": { + "template": "bootstrap5/layout/tab-link.html", + "elements": {} + }, + "bootstrap5_layout_alert": { + "template": "bootstrap5/layout/alert.html", + "elements": { + "{{ alert.css_id }}": "#{{ alert.css_id }}" + } + }, + "bootstrap5_layout_radio_checkbox_select": { + "template": "bootstrap5/layout/radio_checkbox_select.html", + "elements": { + "{{field.errors.field_id}}_error": "#{{field.errors.field_id}}_error", + "{{field.auto_id}}_error": "#{{field.auto_id}}_error", + "error_{{ forloop.counter }}_{{ field.auto_id }}": "#error_{{ forloop.counter }}_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_column": { + "template": "bootstrap5/layout/column.html", + "elements": { + "{{ div.css_id }}": "#{{ div.css_id }}" + } + }, + "bootstrap5_layout_prepended_appended_text": { + "template": "bootstrap5/layout/prepended_appended_text.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_formactions": { + "template": "bootstrap5/layout/formactions.html", + "elements": { + "{{ formactions.id }}": "#{{ formactions.id }}" + } + }, + "bootstrap5_layout_fieldset": { + "template": "bootstrap5/layout/fieldset.html", + "elements": { + "{{ fieldset.css_id }}": "#{{ fieldset.css_id }}" + } + }, + "bootstrap5_layout_multifield": { + "template": "bootstrap5/layout/multifield.html", + "elements": {} + }, + "bootstrap5_layout_modal": { + "template": "bootstrap5/layout/modal.html", + "elements": { + "{{ modal.css_id }}": "#{{ modal.css_id }}", + "{{ modal.title_id }}-label": "#{{ modal.title_id }}-label" + } + }, + "bootstrap5_layout_field_file": { + "template": "bootstrap5/layout/field_file.html", + "elements": { + "{{ widget.data.checkbox_id }}": "#{{ widget.data.checkbox_id }}" + } + }, + "bootstrap5_layout_floating_field": { + "template": "bootstrap5/layout/floating_field.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "bootstrap5_layout_attrs": { + "template": "bootstrap5/layout/attrs.html", + "elements": {} + }, + "bootstrap5_layout_tab": { + "template": "bootstrap5/layout/tab.html", + "elements": { + "{{ tabs.css_id }}": "#{{ tabs.css_id }}" + } + }, + "bootstrap5_layout_switch": { + "template": "bootstrap5/layout/switch.html", + "elements": { + "div_{{ field.auto_id }}": "#div_{{ field.auto_id }}" + } + }, + "rest_framework_admin": { + "template": "rest_framework/admin.html", + "elements": { + "content": "#content", + "get-form": "#get-form", + "extra-actions-menu": "#extra-actions-menu", + "createModal": "#createModal", + "myModalLabel": "#myModalLabel", + "editModal": "#editModal", + "errorModal": "#errorModal", + "drf_csrf": "#drf_csrf" + } + }, + "rest_framework_base": { + "template": "rest_framework/base.html", + "elements": { + "content": "#content", + "get-form": "#get-form", + "deleteModal": "#deleteModal", + "extra-actions-menu": "#extra-actions-menu", + "post-object-form": "#post-object-form", + "post-generic-content-form": "#post-generic-content-form", + "put-object-form": "#put-object-form", + "put-generic-content-form": "#put-generic-content-form", + "drf_csrf": "#drf_csrf" + } + }, + "rest_framework_raw_data_form": { + "template": "rest_framework/raw_data_form.html", + "elements": {} + }, + "rest_framework_login": { + "template": "rest_framework/login.html", + "elements": {} + }, + "rest_framework_login_base": { + "template": "rest_framework/login_base.html", + "elements": { + "div_id_username": "#div_id_username", + "id_username": "#id_username", + "div_id_password": "#div_id_password", + "id_password": "#id_password", + "submit-id-submit": "#submit-id-submit" + } + }, + "rest_framework_api": { + "template": "rest_framework/api.html", + "elements": {} + }, + "rest_framework_filters_base": { + "template": "rest_framework/filters/base.html", + "elements": { + "filtersModal": "#filtersModal" + } + }, + "rest_framework_filters_search": { + "template": "rest_framework/filters/search.html", + "elements": {} + }, + "rest_framework_filters_ordering": { + "template": "rest_framework/filters/ordering.html", + "elements": {} + }, + "rest_framework_pagination_numbers": { + "template": "rest_framework/pagination/numbers.html", + "elements": {} + }, + "rest_framework_pagination_previous_and_next": { + "template": "rest_framework/pagination/previous_and_next.html", + "elements": {} + }, + "rest_framework_horizontal_select": { + "template": "rest_framework/horizontal/select.html", + "elements": {} + }, + "rest_framework_horizontal_dict_field": { + "template": "rest_framework/horizontal/dict_field.html", + "elements": {} + }, + "rest_framework_horizontal_form": { + "template": "rest_framework/horizontal/form.html", + "elements": {} + }, + "rest_framework_horizontal_list_fieldset": { + "template": "rest_framework/horizontal/list_fieldset.html", + "elements": {} + }, + "rest_framework_horizontal_textarea": { + "template": "rest_framework/horizontal/textarea.html", + "elements": {} + }, + "rest_framework_horizontal_radio": { + "template": "rest_framework/horizontal/radio.html", + "elements": {} + }, + "rest_framework_horizontal_checkbox_multiple": { + "template": "rest_framework/horizontal/checkbox_multiple.html", + "elements": {} + }, + "rest_framework_horizontal_checkbox": { + "template": "rest_framework/horizontal/checkbox.html", + "elements": {} + }, + "rest_framework_horizontal_fieldset": { + "template": "rest_framework/horizontal/fieldset.html", + "elements": {} + }, + "rest_framework_horizontal_input": { + "template": "rest_framework/horizontal/input.html", + "elements": {} + }, + "rest_framework_horizontal_select_multiple": { + "template": "rest_framework/horizontal/select_multiple.html", + "elements": {} + }, + "rest_framework_horizontal_list_field": { + "template": "rest_framework/horizontal/list_field.html", + "elements": {} + }, + "rest_framework_admin_dict_value": { + "template": "rest_framework/admin/dict_value.html", + "elements": {} + }, + "rest_framework_admin_list": { + "template": "rest_framework/admin/list.html", + "elements": {} + }, + "rest_framework_admin_simple_list_value": { + "template": "rest_framework/admin/simple_list_value.html", + "elements": {} + }, + "rest_framework_admin_detail": { + "template": "rest_framework/admin/detail.html", + "elements": {} + }, + "rest_framework_admin_list_value": { + "template": "rest_framework/admin/list_value.html", + "elements": {} + }, + "rest_framework_docs_link": { + "template": "rest_framework/docs/link.html", + "elements": { + "{{ section_key }}-{{ link_key|slugify }}": "#{{ section_key }}-{{ link_key|slugify }}" + } + }, + "rest_framework_docs_index": { + "template": "rest_framework/docs/index.html", + "elements": { + "main": "#main" + } + }, + "rest_framework_docs_document": { + "template": "rest_framework/docs/document.html", + "elements": { + "{{ section_key }}": "#{{ section_key }}" + } + }, + "rest_framework_docs_interact": { + "template": "rest_framework/docs/interact.html", + "elements": { + "{{ section_key }}_{{ link_key|slugify }}_modal": "#{{ section_key }}_{{ link_key|slugify }}_modal", + "response": "#response" + } + }, + "rest_framework_docs_sidebar": { + "template": "rest_framework/docs/sidebar.html", + "elements": { + "menu-content": "#menu-content", + "{{ section_key }}-dropdown": "#{{ section_key }}-dropdown", + "selected-authentication": "#selected-authentication", + "auth-control": "#auth-control", + "selected-language": "#selected-language", + "language-control": "#language-control" + } + }, + "rest_framework_docs_error": { + "template": "rest_framework/docs/error.html", + "elements": {} + }, + "rest_framework_docs_auth_basic": { + "template": "rest_framework/docs/auth/basic.html", + "elements": { + "auth_basic_modal": "#auth_basic_modal", + "username": "#username", + "password": "#password" + } + }, + "rest_framework_docs_auth_token": { + "template": "rest_framework/docs/auth/token.html", + "elements": { + "auth_token_modal": "#auth_token_modal", + "scheme": "#scheme", + "schemeHelpBlock": "#schemeHelpBlock", + "token": "#token", + "tokenHelpBlock": "#tokenHelpBlock" + } + }, + "rest_framework_docs_auth_session": { + "template": "rest_framework/docs/auth/session.html", + "elements": { + "auth_session_modal": "#auth_session_modal" + } + }, + "rest_framework_docs_langs_python": { + "template": "rest_framework/docs/langs/python.html", + "elements": {} + }, + "rest_framework_docs_langs_javascript": { + "template": "rest_framework/docs/langs/javascript.html", + "elements": {} + }, + "rest_framework_docs_langs_shell": { + "template": "rest_framework/docs/langs/shell.html", + "elements": {} + }, + "rest_framework_docs_langs_shell-intro": { + "template": "rest_framework/docs/langs/shell-intro.html", + "elements": {} + }, + "rest_framework_docs_langs_python-intro": { + "template": "rest_framework/docs/langs/python-intro.html", + "elements": {} + }, + "rest_framework_docs_langs_javascript-intro": { + "template": "rest_framework/docs/langs/javascript-intro.html", + "elements": {} + }, + "rest_framework_inline_select": { + "template": "rest_framework/inline/select.html", + "elements": {} + }, + "rest_framework_inline_dict_field": { + "template": "rest_framework/inline/dict_field.html", + "elements": {} + }, + "rest_framework_inline_form": { + "template": "rest_framework/inline/form.html", + "elements": {} + }, + "rest_framework_inline_list_fieldset": { + "template": "rest_framework/inline/list_fieldset.html", + "elements": {} + }, + "rest_framework_inline_textarea": { + "template": "rest_framework/inline/textarea.html", + "elements": {} + }, + "rest_framework_inline_radio": { + "template": "rest_framework/inline/radio.html", + "elements": {} + }, + "rest_framework_inline_checkbox_multiple": { + "template": "rest_framework/inline/checkbox_multiple.html", + "elements": {} + }, + "rest_framework_inline_checkbox": { + "template": "rest_framework/inline/checkbox.html", + "elements": {} + }, + "rest_framework_inline_fieldset": { + "template": "rest_framework/inline/fieldset.html", + "elements": {} + }, + "rest_framework_inline_input": { + "template": "rest_framework/inline/input.html", + "elements": {} + }, + "rest_framework_inline_select_multiple": { + "template": "rest_framework/inline/select_multiple.html", + "elements": {} + }, + "rest_framework_inline_list_field": { + "template": "rest_framework/inline/list_field.html", + "elements": {} + }, + "rest_framework_vertical_select": { + "template": "rest_framework/vertical/select.html", + "elements": {} + }, + "rest_framework_vertical_dict_field": { + "template": "rest_framework/vertical/dict_field.html", + "elements": {} + }, + "rest_framework_vertical_form": { + "template": "rest_framework/vertical/form.html", + "elements": {} + }, + "rest_framework_vertical_list_fieldset": { + "template": "rest_framework/vertical/list_fieldset.html", + "elements": {} + }, + "rest_framework_vertical_textarea": { + "template": "rest_framework/vertical/textarea.html", + "elements": {} + }, + "rest_framework_vertical_radio": { + "template": "rest_framework/vertical/radio.html", + "elements": {} + }, + "rest_framework_vertical_checkbox_multiple": { + "template": "rest_framework/vertical/checkbox_multiple.html", + "elements": {} + }, + "rest_framework_vertical_checkbox": { + "template": "rest_framework/vertical/checkbox.html", + "elements": {} + }, + "rest_framework_vertical_fieldset": { + "template": "rest_framework/vertical/fieldset.html", + "elements": {} + }, + "rest_framework_vertical_input": { + "template": "rest_framework/vertical/input.html", + "elements": {} + }, + "rest_framework_vertical_select_multiple": { + "template": "rest_framework/vertical/select_multiple.html", + "elements": {} + }, + "rest_framework_vertical_list_field": { + "template": "rest_framework/vertical/list_field.html", + "elements": {} + }, + "django_extensions_widgets_foreignkey_searchinput": { + "template": "django_extensions/widgets/foreignkey_searchinput.html", + "elements": { + "lookup_{{ name }}": "#lookup_{{ name }}", + "lookup_id_{{ name }}": "#lookup_id_{{ name }}" + } + }, + "django_ledger_closing_entry_closing_entry_update": { + "template": "django_ledger/closing_entry/closing_entry_update.html", + "elements": {} + }, + "django_ledger_closing_entry_closing_entry_create": { + "template": "django_ledger/closing_entry/closing_entry_create.html", + "elements": { + "djl-closing-entry-create-button": "#djl-closing-entry-create-button", + "djl-bill-create-back-button": "#djl-bill-create-back-button" + } + }, + "django_ledger_closing_entry_closing_entry_list": { + "template": "django_ledger/closing_entry/closing_entry_list.html", + "elements": {} + }, + "django_ledger_closing_entry_closing_entry_detail": { + "template": "django_ledger/closing_entry/closing_entry_detail.html", + "elements": {} + }, + "django_ledger_closing_entry_closing_entry_delete": { + "template": "django_ledger/closing_entry/closing_entry_delete.html", + "elements": {} + }, + "django_ledger_closing_entry_includes_card_closing_entry": { + "template": "django_ledger/closing_entry/includes/card_closing_entry.html", + "elements": { + "djl-bill-card-widget": "#djl-bill-card-widget", + "{{ closing_entry_model.get_mark_as_posted_html_id }}-button": "#{{ closing_entry_model.get_mark_as_posted_html_id }}-button", + "{{ closing_entry_model.get_update_transactions_html_id }}-button": "#{{ closing_entry_model.get_update_transactions_html_id }}-button", + "{{ closing_entry_model.get_mark_as_unposted_html_id }}-button": "#{{ closing_entry_model.get_mark_as_unposted_html_id }}-button", + "{{ closing_entry_model.get_delete_html_id }}-button": "#{{ closing_entry_model.get_delete_html_id }}-button" + } + }, + "django_ledger_closing_entry_tags_closing_entry_table": { + "template": "django_ledger/closing_entry/tags/closing_entry_table.html", + "elements": { + "{{ closing_entry_model.get_html_id }}": "#{{ closing_entry_model.get_html_id }}", + "closing-entry-action-{{ closing_entry_model.uuid }}": "#closing-entry-action-{{ closing_entry_model.uuid }}", + "dropdown-menu-{{ closing_entry_model.uuid }}": "#dropdown-menu-{{ closing_entry_model.uuid }}" + } + }, + "django_ledger_closing_entry_tags_closing_entry_txs_table": { + "template": "django_ledger/closing_entry/tags/closing_entry_txs_table.html", + "elements": { + "{{ ce_tx.get_html_id }}": "#{{ ce_tx.get_html_id }}" + } + }, + "django_ledger_expense_expense_list": { + "template": "django_ledger/expense/expense_list.html", + "elements": {} + }, + "django_ledger_expense_expense_create": { + "template": "django_ledger/expense/expense_create.html", + "elements": {} + }, + "django_ledger_expense_expense_update": { + "template": "django_ledger/expense/expense_update.html", + "elements": {} + }, + "django_ledger_expense_tags_expense_item_table": { + "template": "django_ledger/expense/tags/expense_item_table.html", + "elements": { + "invoice-action-{{ invoice.uuid }}": "#invoice-action-{{ invoice.uuid }}", + "dropdown-menu-{{ expense_item.uuid }}": "#dropdown-menu-{{ expense_item.uuid }}" + } + }, + "django_ledger_unit_unit_update": { + "template": "django_ledger/unit/unit_update.html", + "elements": {} + }, + "django_ledger_unit_unit_create": { + "template": "django_ledger/unit/unit_create.html", + "elements": {} + }, + "django_ledger_unit_unit_list": { + "template": "django_ledger/unit/unit_list.html", + "elements": {} + }, + "django_ledger_unit_unit_detail": { + "template": "django_ledger/unit/unit_detail.html", + "elements": {} + }, + "django_ledger_ledger_ledger_create": { + "template": "django_ledger/ledger/ledger_create.html", + "elements": {} + }, + "django_ledger_ledger_ledger_update": { + "template": "django_ledger/ledger/ledger_update.html", + "elements": {} + }, + "django_ledger_ledger_ledger_delete": { + "template": "django_ledger/ledger/ledger_delete.html", + "elements": {} + }, + "django_ledger_ledger_ledger_list": { + "template": "django_ledger/ledger/ledger_list.html", + "elements": {} + }, + "django_ledger_ledger_tags_ledgers_table": { + "template": "django_ledger/ledger/tags/ledgers_table.html", + "elements": { + "dropdown-menu5": "#dropdown-menu5", + "ledger-action-{{ ledger_model.uuid }}": "#ledger-action-{{ ledger_model.uuid }}", + "dropdown-menu-{{ ledger_model.uuid }}": "#dropdown-menu-{{ ledger_model.uuid }}" + } + }, + "django_ledger_auth_login": { + "template": "django_ledger/auth/login.html", + "elements": { + "djl-login-bg-image": "#djl-login-bg-image", + "djl-el-login-form": "#djl-el-login-form" + } + }, + "django_ledger_entity_entity_delete": { + "template": "django_ledger/entity/entity_delete.html", + "elements": {} + }, + "django_ledger_entity_home": { + "template": "django_ledger/entity/home.html", + "elements": {} + }, + "django_ledger_entity_entity_create": { + "template": "django_ledger/entity/entity_create.html", + "elements": {} + }, + "django_ledger_entity_entitiy_list": { + "template": "django_ledger/entity/entitiy_list.html", + "elements": {} + }, + "django_ledger_entity_entity_update": { + "template": "django_ledger/entity/entity_update.html", + "elements": {} + }, + "django_ledger_entity_entity_dashboard": { + "template": "django_ledger/entity/entity_dashboard.html", + "elements": {} + }, + "django_ledger_entity_includes_card_entity": { + "template": "django_ledger/entity/includes/card_entity.html", + "elements": {} + }, + "django_ledger_financial_statements_cash_flow": { + "template": "django_ledger/financial_statements/cash_flow.html", + "elements": {} + }, + "django_ledger_financial_statements_income_statement": { + "template": "django_ledger/financial_statements/income_statement.html", + "elements": {} + }, + "django_ledger_financial_statements_balance_sheet": { + "template": "django_ledger/financial_statements/balance_sheet.html", + "elements": {} + }, + "django_ledger_financial_statements_tags_balance_sheet_statement": { + "template": "django_ledger/financial_statements/tags/balance_sheet_statement.html", + "elements": { + "account-action-{{ account.uuid }}": "#account-action-{{ account.uuid }}", + "dropdown-menu-{{ acc.uuid }}": "#dropdown-menu-{{ acc.uuid }}" + } + }, + "django_ledger_financial_statements_tags_cash_flow_statement": { + "template": "django_ledger/financial_statements/tags/cash_flow_statement.html", + "elements": {} + }, + "django_ledger_financial_statements_tags_income_statement": { + "template": "django_ledger/financial_statements/tags/income_statement.html", + "elements": { + "account-action-{{ account.uuid }}": "#account-action-{{ account.uuid }}", + "dropdown-menu-{{ acc.uuid }}": "#dropdown-menu-{{ acc.uuid }}" + } + }, + "django_ledger_includes_widget_bs": { + "template": "django_ledger/includes/widget_bs.html", + "elements": {} + }, + "django_ledger_includes_widget_ic": { + "template": "django_ledger/includes/widget_ic.html", + "elements": {} + }, + "django_ledger_includes_page_header": { + "template": "django_ledger/includes/page_header.html", + "elements": {} + }, + "django_ledger_includes_widget_ratios": { + "template": "django_ledger/includes/widget_ratios.html", + "elements": {} + }, + "django_ledger_includes_breadcrumbs": { + "template": "django_ledger/includes/breadcrumbs.html", + "elements": {} + }, + "django_ledger_includes_messages": { + "template": "django_ledger/includes/messages.html", + "elements": {} + }, + "django_ledger_includes_footer": { + "template": "django_ledger/includes/footer.html", + "elements": {} + }, + "django_ledger_includes_nav": { + "template": "django_ledger/includes/nav.html", + "elements": { + "djl-navbar-menu": "#djl-navbar-menu", + "djl-el=logout-button-nav": "#djl-el=logout-button-nav" + } + }, + "django_ledger_includes_card_markdown": { + "template": "django_ledger/includes/card_markdown.html", + "elements": {} + }, + "django_ledger_chart_of_accounts_coa_list": { + "template": "django_ledger/chart_of_accounts/coa_list.html", + "elements": {} + }, + "django_ledger_chart_of_accounts_coa_update": { + "template": "django_ledger/chart_of_accounts/coa_update.html", + "elements": { + "{{ form.form_id }}": "#{{ form.form_id }}" + } + }, + "django_ledger_chart_of_accounts_coa_create": { + "template": "django_ledger/chart_of_accounts/coa_create.html", + "elements": { + "{{ form.get_form_id }}": "#{{ form.get_form_id }}" + } + }, + "django_ledger_chart_of_accounts_includes_coa_card": { + "template": "django_ledger/chart_of_accounts/includes/coa_card.html", + "elements": {} + }, + "django_ledger_product_product_delete": { + "template": "django_ledger/product/product_delete.html", + "elements": {} + }, + "django_ledger_product_product_create": { + "template": "django_ledger/product/product_create.html", + "elements": {} + }, + "django_ledger_product_product_update": { + "template": "django_ledger/product/product_update.html", + "elements": {} + }, + "django_ledger_product_product_list": { + "template": "django_ledger/product/product_list.html", + "elements": {} + }, + "django_ledger_product_tags_product_table": { + "template": "django_ledger/product/tags/product_table.html", + "elements": { + "product-action-{{ invoice.uuid }}": "#product-action-{{ invoice.uuid }}", + "dropdown-menu-{{ product.uuid }}": "#dropdown-menu-{{ product.uuid }}" + } + }, + "django_ledger_purchase_order_po_detail": { + "template": "django_ledger/purchase_order/po_detail.html", + "elements": {} + }, + "django_ledger_purchase_order_po_delete": { + "template": "django_ledger/purchase_order/po_delete.html", + "elements": {} + }, + "django_ledger_purchase_order_po_create": { + "template": "django_ledger/purchase_order/po_create.html", + "elements": {} + }, + "django_ledger_purchase_order_po_list": { + "template": "django_ledger/purchase_order/po_list.html", + "elements": {} + }, + "django_ledger_purchase_order_po_update": { + "template": "django_ledger/purchase_order/po_update.html", + "elements": {} + }, + "django_ledger_purchase_order_includes_po_item_formset": { + "template": "django_ledger/purchase_order/includes/po_item_formset.html", + "elements": { + "{{ f.instance.html_id_unit_cost }}": "#{{ f.instance.html_id_unit_cost }}", + "{{ f.instance.html_id_quantity }}": "#{{ f.instance.html_id_quantity }}", + "{{ f.instance.html_id_total_amount }}": "#{{ f.instance.html_id_total_amount }}" + } + }, + "django_ledger_purchase_order_includes_po_table": { + "template": "django_ledger/purchase_order/includes/po_table.html", + "elements": { + "bill-action-{{ po.uuid }}": "#bill-action-{{ po.uuid }}", + "dropdown-menu-{{ po.uuid }}": "#dropdown-menu-{{ po.uuid }}" + } + }, + "django_ledger_purchase_order_includes_card_po": { + "template": "django_ledger/purchase_order/includes/card_po.html", + "elements": { + "{{ po_model.get_mark_as_review_html_id }}-button": "#{{ po_model.get_mark_as_review_html_id }}-button", + "{{ po_model.get_mark_as_approved_html_id }}-button": "#{{ po_model.get_mark_as_approved_html_id }}-button", + "{{ po_model.get_mark_as_fulfilled_html_id }}-button": "#{{ po_model.get_mark_as_fulfilled_html_id }}-button", + "{{ po_model.get_mark_as_delete_html_id }}-button": "#{{ po_model.get_mark_as_delete_html_id }}-button", + "{{ po_model.get_mark_as_void_html_id }}-button": "#{{ po_model.get_mark_as_void_html_id }}-button", + "{{ po_model.get_mark_as_canceled_html_id }}-button": "#{{ po_model.get_mark_as_canceled_html_id }}-button" + } + }, + "django_ledger_purchase_order_tags_po_item_table": { + "template": "django_ledger/purchase_order/tags/po_item_table.html", + "elements": {} + }, + "django_ledger_components_activity_form": { + "template": "django_ledger/components/activity_form.html", + "elements": {} + }, + "django_ledger_components_date_picker": { + "template": "django_ledger/components/date_picker.html", + "elements": { + "{{ date_picker_id }}": "#{{ date_picker_id }}" + } + }, + "django_ledger_components_filters": { + "template": "django_ledger/components/filters.html", + "elements": {} + }, + "django_ledger_components_breadcrumbs": { + "template": "django_ledger/components/breadcrumbs.html", + "elements": {} + }, + "django_ledger_components_feedback_button": { + "template": "django_ledger/components/feedback_button.html", + "elements": { + "{{ bug_modal_html_id }}": "#{{ bug_modal_html_id }}", + "{{ feature_modal_html_id }}": "#{{ feature_modal_html_id }}" + } + }, + "django_ledger_components_menu": { + "template": "django_ledger/components/menu.html", + "elements": {} + }, + "django_ledger_components_icon": { + "template": "django_ledger/components/icon.html", + "elements": {} + }, + "django_ledger_components_period_navigator": { + "template": "django_ledger/components/period_navigator.html", + "elements": {} + }, + "django_ledger_components_chart_container": { + "template": "django_ledger/components/chart_container.html", + "elements": { + "{{ chart_id }}": "#{{ chart_id }}" + } + }, + "django_ledger_components_modals": { + "template": "django_ledger/components/modals.html", + "elements": { + "{{ object.get_html_id }}": "#{{ object.get_html_id }}" + } + }, + "django_ledger_components_default_entity": { + "template": "django_ledger/components/default_entity.html", + "elements": { + "djetler-set-entity-form-{{ form_id }}": "#djetler-set-entity-form-{{ form_id }}" + } + }, + "django_ledger_components_modals_v2": { + "template": "django_ledger/components/modals_v2.html", + "elements": { + "{{ html_id }}": "#{{ html_id }}" + } + }, + "django_ledger_transactions_tags_txs_table": { + "template": "django_ledger/transactions/tags/txs_table.html", + "elements": {} + }, + "django_ledger_bills_bill_detail": { + "template": "django_ledger/bills/bill_detail.html", + "elements": { + "djl-bill-detail-amount-paid": "#djl-bill-detail-amount-paid", + "djl-bill-detail-amount-prepaid": "#djl-bill-detail-amount-prepaid", + "djl-bill-detail-amount-unearned": "#djl-bill-detail-amount-unearned", + "djl-bill-detail-amount-owed": "#djl-bill-detail-amount-owed" + } + }, + "django_ledger_bills_bill_delete": { + "template": "django_ledger/bills/bill_delete.html", + "elements": {} + }, + "django_ledger_bills_bill_update": { + "template": "django_ledger/bills/bill_update.html", + "elements": {} + }, + "django_ledger_bills_bill_void": { + "template": "django_ledger/bills/bill_void.html", + "elements": {} + }, + "django_ledger_bills_bill_create": { + "template": "django_ledger/bills/bill_create.html", + "elements": { + "djl-bill-model-create-form-id": "#djl-bill-model-create-form-id", + "djl-bill-create-button": "#djl-bill-create-button", + "djl-bill-create-back-button": "#djl-bill-create-back-button" + } + }, + "django_ledger_bills_bill_list": { + "template": "django_ledger/bills/bill_list.html", + "elements": {} + }, + "django_ledger_bills_includes_card_bill": { + "template": "django_ledger/bills/includes/card_bill.html", + "elements": { + "djl-bill-card-widget": "#djl-bill-card-widget", + "djl-bill-detail-update-button": "#djl-bill-detail-update-button", + "{{ bill.get_mark_as_review_html_id }}-button": "#{{ bill.get_mark_as_review_html_id }}-button", + "{{ bill.get_mark_as_approved_html_id }}-button": "#{{ bill.get_mark_as_approved_html_id }}-button", + "{{ bill.get_mark_as_paid_html_id }}-button": "#{{ bill.get_mark_as_paid_html_id }}-button", + "{{ bill.get_mark_as_void_html_id }}-button": "#{{ bill.get_mark_as_void_html_id }}-button", + "{{ bill.get_mark_as_cenceled_html_id }}-button": "#{{ bill.get_mark_as_cenceled_html_id }}-button" + } + }, + "django_ledger_bills_tags_bill_item_formset": { + "template": "django_ledger/bills/tags/bill_item_formset.html", + "elements": { + "{{ f.instance.html_id_quantity }}": "#{{ f.instance.html_id_quantity }}", + "{{ f.instance.html_id_unit_cost }}": "#{{ f.instance.html_id_unit_cost }}", + "{{ f.instance.html_id_total_amount }}": "#{{ f.instance.html_id_total_amount }}" + } + }, + "django_ledger_bills_tags_bill_table": { + "template": "django_ledger/bills/tags/bill_table.html", + "elements": { + "{{ bill.get_html_id }}": "#{{ bill.get_html_id }}", + "{{ bill.get_html_amount_due_id }}": "#{{ bill.get_html_amount_due_id }}", + "{{ bill.get_html_amount_paid_id }}": "#{{ bill.get_html_amount_paid_id }}", + "bill-action-{{ bill.uuid }}": "#bill-action-{{ bill.uuid }}", + "dropdown-menu-{{ bill.uuid }}": "#dropdown-menu-{{ bill.uuid }}" + } + }, + "django_ledger_layouts_content_layout_1": { + "template": "django_ledger/layouts/content_layout_1.html", + "elements": {} + }, + "django_ledger_layouts_base": { + "template": "django_ledger/layouts/base.html", + "elements": {} + }, + "django_ledger_layouts_content_layout_2": { + "template": "django_ledger/layouts/content_layout_2.html", + "elements": {} + }, + "django_ledger_bank_account_bank_account_create": { + "template": "django_ledger/bank_account/bank_account_create.html", + "elements": {} + }, + "django_ledger_bank_account_bank_account_update": { + "template": "django_ledger/bank_account/bank_account_update.html", + "elements": {} + }, + "django_ledger_bank_account_bank_account_list": { + "template": "django_ledger/bank_account/bank_account_list.html", + "elements": {} + }, + "django_ledger_bank_account_tags_bank_accounts_table": { + "template": "django_ledger/bank_account/tags/bank_accounts_table.html", + "elements": { + "bank-action-{{ bank_acc.uuid }}": "#bank-action-{{ bank_acc.uuid }}", + "dropdown-menu-{{ bank_acc.uuid }}": "#dropdown-menu-{{ bank_acc.uuid }}" + } + }, + "django_ledger_inventory_inventory_item_create": { + "template": "django_ledger/inventory/inventory_item_create.html", + "elements": {} + }, + "django_ledger_inventory_inventory_recount": { + "template": "django_ledger/inventory/inventory_recount.html", + "elements": {} + }, + "django_ledger_inventory_inventory_item_update": { + "template": "django_ledger/inventory/inventory_item_update.html", + "elements": {} + }, + "django_ledger_inventory_inventory_list": { + "template": "django_ledger/inventory/inventory_list.html", + "elements": {} + }, + "django_ledger_inventory_inventory_item_list": { + "template": "django_ledger/inventory/inventory_item_list.html", + "elements": {} + }, + "django_ledger_inventory_tags_inventory_item_table": { + "template": "django_ledger/inventory/tags/inventory_item_table.html", + "elements": { + "inv-item-action-{{ inv_item.uuid }}": "#inv-item-action-{{ inv_item.uuid }}", + "dropdown-menu-{{ inv_item.uuid }}": "#dropdown-menu-{{ inv_item.uuid }}" + } + }, + "django_ledger_inventory_tags_inventory_table": { + "template": "django_ledger/inventory/tags/inventory_table.html", + "elements": {} + }, + "django_ledger_data_import_data_import_job_list": { + "template": "django_ledger/data_import/data_import_job_list.html", + "elements": {} + }, + "django_ledger_data_import_import_job_update": { + "template": "django_ledger/data_import/import_job_update.html", + "elements": {} + }, + "django_ledger_data_import_import_job_create": { + "template": "django_ledger/data_import/import_job_create.html", + "elements": { + "file-js-django-ledger": "#file-js-django-ledger" + } + }, + "django_ledger_data_import_data_import_job_txs": { + "template": "django_ledger/data_import/data_import_job_txs.html", + "elements": {} + }, + "django_ledger_data_import_import_job_delete": { + "template": "django_ledger/data_import/import_job_delete.html", + "elements": {} + }, + "django_ledger_data_import_tags_data_import_job_txs_imported": { + "template": "django_ledger/data_import/tags/data_import_job_txs_imported.html", + "elements": {} + }, + "django_ledger_data_import_tags_data_import_job_txs_table": { + "template": "django_ledger/data_import/tags/data_import_job_txs_table.html", + "elements": {} + }, + "django_ledger_data_import_tags_data_import_job_list_table": { + "template": "django_ledger/data_import/tags/data_import_job_list_table.html", + "elements": { + "customer-action-{{ job.uuid }}": "#customer-action-{{ job.uuid }}", + "dropdown-menu-{{ customer.uuid }}": "#dropdown-menu-{{ customer.uuid }}" + } + }, + "django_ledger_estimate_estimate_update": { + "template": "django_ledger/estimate/estimate_update.html", + "elements": {} + }, + "django_ledger_estimate_estimate_create": { + "template": "django_ledger/estimate/estimate_create.html", + "elements": {} + }, + "django_ledger_estimate_estimate_list": { + "template": "django_ledger/estimate/estimate_list.html", + "elements": {} + }, + "django_ledger_estimate_estimate_detail": { + "template": "django_ledger/estimate/estimate_detail.html", + "elements": { + "djl-cj-detail-estimated-revenue": "#djl-cj-detail-estimated-revenue", + "djl-cj-detail-estimated-cost": "#djl-cj-detail-estimated-cost" + } + }, + "django_ledger_estimate_includes_estimate_table": { + "template": "django_ledger/estimate/includes/estimate_table.html", + "elements": { + "{{ ce_model.get_html_id }}": "#{{ ce_model.get_html_id }}", + "cj-action-{{ ce_model.uuid }}": "#cj-action-{{ ce_model.uuid }}", + "dropdown-menu-{{ ce_model.uuid }}": "#dropdown-menu-{{ ce_model.uuid }}" + } + }, + "django_ledger_estimate_includes_card_estimate": { + "template": "django_ledger/estimate/includes/card_estimate.html", + "elements": { + "{{ estimate_model.get_mark_as_draft_html_id }}-button": "#{{ estimate_model.get_mark_as_draft_html_id }}-button", + "{{ estimate_model.get_mark_as_review_html_id }}-button": "#{{ estimate_model.get_mark_as_review_html_id }}-button", + "{{ estimate_model.get_mark_as_approved_html_id }}-button": "#{{ estimate_model.get_mark_as_approved_html_id }}-button" + } + }, + "django_ledger_estimate_includes_estimate_item_table": { + "template": "django_ledger/estimate/includes/estimate_item_table.html", + "elements": {} + }, + "django_ledger_estimate_tags_ce_item_formset": { + "template": "django_ledger/estimate/tags/ce_item_formset.html", + "elements": { + "{{ f.instance.html_id_quantity }}": "#{{ f.instance.html_id_quantity }}", + "{{ f.instance.html_id_unit_cost }}": "#{{ f.instance.html_id_unit_cost }}", + "{{ f.instance.html_id_total_amount }}": "#{{ f.instance.html_id_total_amount }}" + } + }, + "django_ledger_account_account_list": { + "template": "django_ledger/account/account_list.html", + "elements": {} + }, + "django_ledger_account_account_create_child": { + "template": "django_ledger/account/account_create_child.html", + "elements": {} + }, + "django_ledger_account_account_detail": { + "template": "django_ledger/account/account_detail.html", + "elements": {} + }, + "django_ledger_account_account_update": { + "template": "django_ledger/account/account_update.html", + "elements": {} + }, + "django_ledger_account_account_create": { + "template": "django_ledger/account/account_create.html", + "elements": { + "{{ form.form_id }}": "#{{ form.form_id }}" + } + }, + "django_ledger_account_tags_accounts_table": { + "template": "django_ledger/account/tags/accounts_table.html", + "elements": { + "account-action-{{ account.uuid }}": "#account-action-{{ account.uuid }}", + "dropdown-menu-{{ account.uuid }}": "#dropdown-menu-{{ account.uuid }}" + } + }, + "django_ledger_account_tags_account_txs_table": { + "template": "django_ledger/account/tags/account_txs_table.html", + "elements": { + "tx-action-{{ tx.uuid }}": "#tx-action-{{ tx.uuid }}", + "dropdown-menu-{{ tx.uuid }}": "#dropdown-menu-{{ tx.uuid }}" + } + }, + "django_ledger_service_service_update": { + "template": "django_ledger/service/service_update.html", + "elements": {} + }, + "django_ledger_service_service_create": { + "template": "django_ledger/service/service_create.html", + "elements": {} + }, + "django_ledger_service_service_delete": { + "template": "django_ledger/service/service_delete.html", + "elements": {} + }, + "django_ledger_service_service_list": { + "template": "django_ledger/service/service_list.html", + "elements": {} + }, + "django_ledger_service_tags_services_table": { + "template": "django_ledger/service/tags/services_table.html", + "elements": { + "sercice-action-{{ invoice.uuid }}": "#sercice-action-{{ invoice.uuid }}", + "dropdown-menu-{{ service.uuid }}": "#dropdown-menu-{{ service.uuid }}" + } + }, + "django_ledger_journal_entry_je_create": { + "template": "django_ledger/journal_entry/je_create.html", + "elements": {} + }, + "django_ledger_journal_entry_je_list": { + "template": "django_ledger/journal_entry/je_list.html", + "elements": {} + }, + "django_ledger_journal_entry_je_update": { + "template": "django_ledger/journal_entry/je_update.html", + "elements": {} + }, + "django_ledger_journal_entry_je_detail": { + "template": "django_ledger/journal_entry/je_detail.html", + "elements": {} + }, + "django_ledger_journal_entry_je_detail_txs": { + "template": "django_ledger/journal_entry/je_detail_txs.html", + "elements": {} + }, + "django_ledger_journal_entry_je_delete": { + "template": "django_ledger/journal_entry/je_delete.html", + "elements": {} + }, + "django_ledger_journal_entry_includes_card_journal_entry": { + "template": "django_ledger/journal_entry/includes/card_journal_entry.html", + "elements": {} + }, + "django_ledger_journal_entry_tags_je_table": { + "template": "django_ledger/journal_entry/tags/je_table.html", + "elements": { + "je-action-{{ journal_entry_model.uuid }}": "#je-action-{{ journal_entry_model.uuid }}", + "dropdown-menu-{{ journal_entry_model.uuid }}": "#dropdown-menu-{{ journal_entry_model.uuid }}" + } + }, + "django_ledger_journal_entry_tags_je_txs_table": { + "template": "django_ledger/journal_entry/tags/je_txs_table.html", + "elements": {} + }, + "django_ledger_uom_uom_list": { + "template": "django_ledger/uom/uom_list.html", + "elements": {} + }, + "django_ledger_uom_uom_delete": { + "template": "django_ledger/uom/uom_delete.html", + "elements": {} + }, + "django_ledger_uom_uom_update": { + "template": "django_ledger/uom/uom_update.html", + "elements": {} + }, + "django_ledger_uom_uom_create": { + "template": "django_ledger/uom/uom_create.html", + "elements": {} + }, + "django_ledger_uom_tags_uom_table": { + "template": "django_ledger/uom/tags/uom_table.html", + "elements": { + "uom-action-{{ uom.uuid }}": "#uom-action-{{ uom.uuid }}", + "dropdown-menu-{{ invoice.uuid }}": "#dropdown-menu-{{ invoice.uuid }}" + } + }, + "django_ledger_customer_customer_update": { + "template": "django_ledger/customer/customer_update.html", + "elements": {} + }, + "django_ledger_customer_customer_list": { + "template": "django_ledger/customer/customer_list.html", + "elements": {} + }, + "django_ledger_customer_customer_create": { + "template": "django_ledger/customer/customer_create.html", + "elements": {} + }, + "django_ledger_customer_includes_card_customer": { + "template": "django_ledger/customer/includes/card_customer.html", + "elements": {} + }, + "django_ledger_customer_tags_customer_table": { + "template": "django_ledger/customer/tags/customer_table.html", + "elements": { + "customer-action-{{ customer.uuid }}": "#customer-action-{{ customer.uuid }}", + "dropdown-menu-{{ customer.uuid }}": "#dropdown-menu-{{ customer.uuid }}" + } + }, + "django_ledger_vendor_vendor_update": { + "template": "django_ledger/vendor/vendor_update.html", + "elements": {} + }, + "django_ledger_vendor_vendor_list": { + "template": "django_ledger/vendor/vendor_list.html", + "elements": {} + }, + "django_ledger_vendor_vendor_create": { + "template": "django_ledger/vendor/vendor_create.html", + "elements": {} + }, + "django_ledger_vendor_includes_card_vendor": { + "template": "django_ledger/vendor/includes/card_vendor.html", + "elements": { + "djl-vendor-card-widget": "#djl-vendor-card-widget" + } + }, + "django_ledger_vendor_tags_vendor_table": { + "template": "django_ledger/vendor/tags/vendor_table.html", + "elements": { + "vendor-action-{{ vendor.uuid }}": "#vendor-action-{{ vendor.uuid }}", + "dropdown-menu-{{ vendor.uuid }}": "#dropdown-menu-{{ vendor.uuid }}" + } + }, + "django_ledger_invoice_invoice_update": { + "template": "django_ledger/invoice/invoice_update.html", + "elements": {} + }, + "django_ledger_invoice_invoice_create": { + "template": "django_ledger/invoice/invoice_create.html", + "elements": { + "djl-bill-create-form-id": "#djl-bill-create-form-id", + "djl-invoice-create-button": "#djl-invoice-create-button", + "djl-invoice-create-back-button": "#djl-invoice-create-back-button" + } + }, + "django_ledger_invoice_invoice_list": { + "template": "django_ledger/invoice/invoice_list.html", + "elements": {} + }, + "django_ledger_invoice_invoice_detail": { + "template": "django_ledger/invoice/invoice_detail.html", + "elements": {} + }, + "django_ledger_invoice_invoice_delete": { + "template": "django_ledger/invoice/invoice_delete.html", + "elements": {} + }, + "django_ledger_invoice_includes_card_invoice": { + "template": "django_ledger/invoice/includes/card_invoice.html", + "elements": { + "{{ invoice.get_mark_as_review_html_id }}-button": "#{{ invoice.get_mark_as_review_html_id }}-button", + "{{ invoice.get_mark_as_approved_html_id }}-button": "#{{ invoice.get_mark_as_approved_html_id }}-button", + "{{ invoice.get_mark_as_paid_html_id }}-button": "#{{ invoice.get_mark_as_paid_html_id }}-button", + "{{ invoice.get_mark_as_void_html_id }}-button": "#{{ invoice.get_mark_as_void_html_id }}-button", + "{{ invoice.get_mark_as_canceled_html_id }}-button": "#{{ invoice.get_mark_as_canceled_html_id }}-button" + } + }, + "django_ledger_invoice_tags_invoice_item_formset": { + "template": "django_ledger/invoice/tags/invoice_item_formset.html", + "elements": { + "{{ f.instance.html_id_quantity }}": "#{{ f.instance.html_id_quantity }}", + "{{ f.instance.html_id_unit_cost }}": "#{{ f.instance.html_id_unit_cost }}", + "{{ f.instance.html_id_total_amount }}": "#{{ f.instance.html_id_total_amount }}" + } + }, + "django_ledger_invoice_tags_invoice_table": { + "template": "django_ledger/invoice/tags/invoice_table.html", + "elements": { + "invoice-action-{{ invoice.uuid }}": "#invoice-action-{{ invoice.uuid }}", + "dropdown-menu-{{ invoice.uuid }}": "#dropdown-menu-{{ invoice.uuid }}" + } + }, + "appointment_default_thank_you": { + "template": "appointment/default_thank_you.html", + "elements": {} + }, + "appointment_thank_you": { + "template": "appointment/thank_you.html", + "elements": {} + }, + "appointment_appointment_client_information": { + "template": "appointment/appointment_client_information.html", + "elements": { + "user-info": "#user-info", + "service-datetime-chosen": "#service-datetime-chosen" + } + }, + "appointment_appointments": { + "template": "appointment/appointments.html", + "elements": { + "calendar": "#calendar", + "slot-list": "#slot-list", + "reason_for_rescheduling": "#reason_for_rescheduling", + "staff_id": "#staff_id", + "service-datetime-chosen": "#service-datetime-chosen" + } + }, + "appointment_enter_verification_code": { + "template": "appointment/enter_verification_code.html", + "elements": { + "verification-code": "#verification-code" + } + }, + "appointment_rescheduling_thank_you": { + "template": "appointment/rescheduling_thank_you.html", + "elements": {} + }, + "appointment_set_password": { + "template": "appointment/set_password.html", + "elements": {} + }, + "base_templates_base": { + "template": "base_templates/base.html", + "elements": {} + }, + "administration_manage_staff_personal_info": { + "template": "administration/manage_staff_personal_info.html", + "elements": { + "updatePersonalInfoForm": "#updatePersonalInfoForm" + } + }, + "administration_manage_staff_member": { + "template": "administration/manage_staff_member.html", + "elements": {} + }, + "administration_display_appointment": { + "template": "administration/display_appointment.html", + "elements": {} + }, + "administration_user_profile": { + "template": "administration/user_profile.html", + "elements": {} + }, + "administration_manage_working_hours": { + "template": "administration/manage_working_hours.html", + "elements": { + "workingHoursForm": "#workingHoursForm", + "\n {% if working_hours_instance %}{{ working_hours_instance.id }}{% else %}0{% endif %}": "#\n {% if working_hours_instance %}{{ working_hours_instance.id }}{% else %}0{% endif %}", + "{% if staff_user_id %}{{ staff_user_id }}{% else %}0{% endif %}": "#{% if staff_user_id %}{{ staff_user_id }}{% else %}0{% endif %}", + "start-timepicker": "#start-timepicker", + "{{ working_hours_form.start_time.id_for_label }}": "#{{ working_hours_form.start_time.id_for_label }}", + "end-timepicker": "#end-timepicker", + "{{ working_hours_form.end_time.id_for_label }}": "#{{ working_hours_form.end_time.id_for_label }}", + "addWorkingHoursUrl": "#addWorkingHoursUrl", + "updateWorkingHoursUrl": "#updateWorkingHoursUrl" + } + }, + "administration_staff_list": { + "template": "administration/staff_list.html", + "elements": {} + }, + "administration_manage_service": { + "template": "administration/manage_service.html", + "elements": {} + }, + "administration_staff_index": { + "template": "administration/staff_index.html", + "elements": { + "calendar": "#calendar", + "event-list-container": "#event-list-container", + "customContextMenu": "#customContextMenu", + "newAppointmentOption": "#newAppointmentOption", + "clientName": "#clientName", + "clientEmail": "#clientEmail", + "emailError": "#emailError", + "clientPhone": "#clientPhone", + "clientAddress": "#clientAddress", + "want_reminder": "#want_reminder", + "additional_info": "#additional_info" + } + }, + "administration_manage_day_off": { + "template": "administration/manage_day_off.html", + "elements": { + "{{ day_off_form.start_date.id_for_label }}_display": "#{{ day_off_form.start_date.id_for_label }}_display", + "{{ day_off_form.start_date.id_for_label }}": "#{{ day_off_form.start_date.id_for_label }}", + "{{ day_off_form.end_date.id_for_label }}_display": "#{{ day_off_form.end_date.id_for_label }}_display", + "{{ day_off_form.end_date.id_for_label }}": "#{{ day_off_form.end_date.id_for_label }}", + "{{ day_off_form.description.id_for_label }}": "#{{ day_off_form.description.id_for_label }}" + } + }, + "administration_email_change_verification_code": { + "template": "administration/email_change_verification_code.html", + "elements": {} + }, + "administration_service_list": { + "template": "administration/service_list.html", + "elements": {} + }, + "error_pages_404_not_found": { + "template": "error_pages/404_not_found.html", + "elements": { + "svg2": "#svg2", + "metadata8": "#metadata8", + "defs6": "#defs6", + "Strips2_1": "#Strips2_1", + "rect5419": "#rect5419", + "linearGradient6096": "#linearGradient6096", + "stop6094": "#stop6094", + "layer1": "#layer1", + "g6219": "#g6219", + "path6180": "#path6180", + "g6174": "#g6174", + "path4488": "#path4488", + "path4490": "#path4490", + "path4496": "#path4496", + "rect4553": "#rect4553", + "path4513": "#path4513", + "path4517": "#path4517", + "path4521": "#path4521", + "path4525": "#path4525", + "path4533": "#path4533", + "path4537": "#path4537", + "path4541": "#path4541", + "path4545": "#path4545", + "path4549": "#path4549", + "path4556": "#path4556", + "path4560": "#path4560", + "path4529": "#path4529", + "path4614": "#path4614", + "path4616": "#path4616", + "path4565": "#path4565", + "path4567": "#path4567", + "path4570": "#path4570", + "path4578": "#path4578", + "path4578-1": "#path4578-1", + "path4610": "#path4610", + "path4573": "#path4573", + "path4575": "#path4575", + "path4579": "#path4579", + "layer3": "#layer3", + "text4526": "#text4526", + "path4555": "#path4555", + "text4526-2": "#text4526-2", + "path4558": "#path4558", + "errorText": "#errorText", + "back": "#back" + } + }, + "error_pages_304_already_submitted": { + "template": "error_pages/304_already_submitted.html", + "elements": { + "Layer_1": "#Layer_1" + } + }, + "error_pages_403_forbidden_rescheduling": { + "template": "error_pages/403_forbidden_rescheduling.html", + "elements": {} + }, + "error_pages_403_forbidden": { + "template": "error_pages/403_forbidden.html", + "elements": { + "back": "#back" + } + }, + "modal_event_details_modal": { + "template": "modal/event_details_modal.html", + "elements": { + "eventDetailsModal": "#eventDetailsModal", + "eventModalLabel": "#eventModalLabel", + "eventModalBody": "#eventModalBody", + "eventGoBtn": "#eventGoBtn", + "eventCancelBtn": "#eventCancelBtn", + "eventEditBtn": "#eventEditBtn", + "eventSubmitBtn": "#eventSubmitBtn", + "eventDeleteBtn": "#eventDeleteBtn" + } + }, + "modal_error_modal": { + "template": "modal/error_modal.html", + "elements": { + "errorModal": "#errorModal", + "errorModalLabel": "#errorModalLabel", + "errorModalMessage": "#errorModalMessage" + } + }, + "modal_confirm_modal": { + "template": "modal/confirm_modal.html", + "elements": { + "confirmModal": "#confirmModal", + "modalLabel": "#modalLabel", + "modalBody": "#modalBody", + "modalActionBtn": "#modalActionBtn" + } + }, + "email_sender_reminder_email": { + "template": "email_sender/reminder_email.html", + "elements": {} + }, + "email_sender_reschedule_email": { + "template": "email_sender/reschedule_email.html", + "elements": {} + }, + "email_sender_admin_new_appointment_email": { + "template": "email_sender/admin_new_appointment_email.html", + "elements": {} + }, + "email_sender_thank_you_email": { + "template": "email_sender/thank_you_email.html", + "elements": {} + }, + "ordered_model_admin_order_controls": { + "template": "ordered_model/admin/order_controls.html", + "elements": {} + }, + "plans_fake_payments": { + "template": "plans/fake_payments.html", + "elements": {} + }, + "plans_create_order": { + "template": "plans/create_order.html", + "elements": {} + }, + "plans_billing_info_create_or_update": { + "template": "plans/billing_info_create_or_update.html", + "elements": {} + }, + "plans_pagination": { + "template": "plans/pagination.html", + "elements": {} + }, + "plans_base": { + "template": "plans/base.html", + "elements": {} + }, + "plans_expiration_messages": { + "template": "plans/expiration_messages.html", + "elements": {} + }, + "plans_pricing": { + "template": "plans/pricing.html", + "elements": {} + }, + "plans_current": { + "template": "plans/current.html", + "elements": {} + }, + "plans_order_list": { + "template": "plans/order_list.html", + "elements": {} + }, + "plans_account_activation": { + "template": "plans/account_activation.html", + "elements": {} + }, + "plans_order_detail_table": { + "template": "plans/order_detail_table.html", + "elements": {} + }, + "plans_upgrade": { + "template": "plans/upgrade.html", + "elements": {} + }, + "plans_extend": { + "template": "plans/extend.html", + "elements": { + "pricing_form": "#pricing_form" + } + }, + "plans_billing_info_delete": { + "template": "plans/billing_info_delete.html", + "elements": {} + }, + "plans_plan_table": { + "template": "plans/plan_table.html", + "elements": {} + }, + "plans_order_detail": { + "template": "plans/order_detail.html", + "elements": { + "order_printable_documents": "#order_printable_documents" + } + }, + "plans_invoices_PL_EN": { + "template": "plans/invoices/PL_EN.html", + "elements": {} + }, + "plans_invoices_PL_EN_layout": { + "template": "plans/invoices/PL_EN_layout.html", + "elements": { + "full_number": "#full_number", + "shipping": "#shipping", + "items": "#items" + } + }, + "plans_invoices_invoice_base": { + "template": "plans/invoices/invoice_base.html", + "elements": {} + }, + "admin_import_export_change_list_export": { + "template": "admin/import_export/change_list_export.html", + "elements": {} + }, + "admin_import_export_base": { + "template": "admin/import_export/base.html", + "elements": {} + }, + "admin_import_export_change_list_import": { + "template": "admin/import_export/change_list_import.html", + "elements": {} + }, + "admin_import_export_change_list": { + "template": "admin/import_export/change_list.html", + "elements": {} + }, + "admin_import_export_change_list_export_item": { + "template": "admin/import_export/change_list_export_item.html", + "elements": {} + }, + "admin_import_export_change_list_import_export": { + "template": "admin/import_export/change_list_import_export.html", + "elements": {} + }, + "admin_import_export_import": { + "template": "admin/import_export/import.html", + "elements": {} + }, + "admin_import_export_resource_fields_list": { + "template": "admin/import_export/resource_fields_list.html", + "elements": {} + }, + "admin_import_export_change_list_import_item": { + "template": "admin/import_export/change_list_import_item.html", + "elements": {} + }, + "admin_import_export_change_form": { + "template": "admin/import_export/change_form.html", + "elements": {} + }, + "admin_import_export_export": { + "template": "admin/import_export/export.html", + "elements": {} + }, + "schema_graph_schema": { + "template": "schema_graph/schema.html", + "elements": { + "schema-graph-app": "#schema-graph-app" + } + }, + "django_filters_rest_framework_form": { + "template": "django_filters/rest_framework/form.html", + "elements": {} + }, + "django_filters_rest_framework_crispy_form": { + "template": "django_filters/rest_framework/crispy_form.html", + "elements": {} + }, + "django_filters_widgets_multiwidget": { + "template": "django_filters/widgets/multiwidget.html", + "elements": {} + } + }, + "common_elements": { + "navigation": { + "inventory": "#inventory-menu, .inventory-nav, nav .inventory", + "finance": "#finance-menu, .finance-nav, nav .finance", + "customers": "#customers-menu, .customers-nav, nav .customers" + }, + "actions": { + "add": ".btn-add, .add-button, button:contains('Add')", + "edit": ".btn-edit, .edit-button, button:contains('Edit')", + "save": ".btn-save, button[type='submit'], #save-button", + "cancel": ".btn-cancel, #cancel-button, button:contains('Cancel')", + "delete": ".btn-delete, .delete-button, button:contains('Delete')" + }, + "forms": { + "search": "#search-form, .search-input, input[name='q']", + "date_range": ".date-range, input[type='date']", + "dropdown": "select, .dropdown, .select-field" + } + } +} \ No newline at end of file diff --git a/templates/administration/display_appointment.html b/templates/administration/display_appointment.html index 954be742..c936b1a0 100644 --- a/templates/administration/display_appointment.html +++ b/templates/administration/display_appointment.html @@ -81,7 +81,8 @@
- + + {% trans 'Service price' %}: {{ appointment.get_appointment_amount_to_pay_text }}
diff --git a/templates/base.html b/templates/base.html index abc030c3..053f18b6 100644 --- a/templates/base.html +++ b/templates/base.html @@ -40,6 +40,7 @@ + {% if LANGUAGE_CODE == 'ar' %} @@ -76,6 +77,7 @@ {% endblock period_navigation %} {% block content %} + {% endblock content%} {% block body %} {% endblock body%} @@ -96,6 +98,11 @@ + + + + + @@ -115,6 +122,7 @@ +{% endblock %} \ No newline at end of file diff --git a/templates/tours/tour_list.html b/templates/tours/tour_list.html new file mode 100644 index 00000000..386882bf --- /dev/null +++ b/templates/tours/tour_list.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block title %}Interactive Guides{% endblock %} + +{% block content %} +
+

Interactive Guides

+

Learn how to use the car inventory system with these interactive step-by-step guides.

+ +
+ {% for tour in tours %} +
+
+
+
{{ tour.name }}
+

{{ tour.description }}

+
+ +
+
+ {% empty %} +
+
+ No interactive guides available at this time. +
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/tours/__init__.py b/tours/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tours/admin.py b/tours/admin.py new file mode 100644 index 00000000..0bdb93a8 --- /dev/null +++ b/tours/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from . import models + +# Register your models here. +admin.site.register(models.Tour) +admin.site.register(models.TourCompletion) \ No newline at end of file diff --git a/tours/apps.py b/tours/apps.py new file mode 100644 index 00000000..57f8071a --- /dev/null +++ b/tours/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ToursConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'tours' diff --git a/tours/management/__init__.py b/tours/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tours/management/commands/__init__.py b/tours/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tours/management/commands/generate_tours.py b/tours/management/commands/generate_tours.py new file mode 100644 index 00000000..b7fa82e7 --- /dev/null +++ b/tours/management/commands/generate_tours.py @@ -0,0 +1,84 @@ +from django.core.management.base import BaseCommand +import yaml +import os +import json +from django.conf import settings + + +class Command(BaseCommand): + help = "Generate IntroJS tour definitions from workflow documentation" + + def handle(self, *args, **kwargs): + input_file = "haikal_kb.yaml" + output_dir = os.path.join(settings.BASE_DIR, 'static', 'js', 'tours') + + # Create output directory if it doesn't exist + os.makedirs(output_dir, exist_ok=True) + + try: + with open(input_file, 'r', encoding='utf-8') as f: + kb = yaml.safe_load(f) + except Exception as e: + self.stdout.write(self.style.ERROR(f"Error reading knowledge base file: {e}")) + return + + workflows = kb.get("user_workflows", {}) + + tours_created = 0 + + # Map of common UI elements to their likely selectors + element_selectors = { + "inventory": "#inventory-menu, .inventory-nav, nav .inventory", + "add car": "#add-car-button, .btn-add-car, button:contains('Add Car')", + "save": "button[type='submit'], .btn-save, #save-button", + "cancel": ".btn-cancel, #cancel-button, button:contains('Cancel')", + "vin": "#vin-input, input[name='vin'], .vin-field", + "make": "#make-select, select[name='make'], .make-field", + "model": "#model-select, select[name='model'], .model-field", + "series": "#series-select, select[name='series'], .series-field", + "trim": "#trim-select, select[name='trim'], .trim-field", + "price": "#price-input, input[name='price'], .price-field", + "color": "#color-select, select[name='color'], .color-field", + "invoice": "#invoice-section, .invoice-tab, #create-invoice", + "customer": "#customer-select, select[name='customer'], .customer-field", + "finance": "#finance-menu, .finance-nav, nav .finance", + } + + for workflow_name, workflow in workflows.items(): + steps = workflow.get("steps", []) + if not steps: + continue + + tour_steps = [] + + for i, step in enumerate(steps): + # Try to identify UI element from step description + element = None + for key, selector in element_selectors.items(): + if key.lower() in step.lower(): + element = selector + break + + tour_step = { + "title": f"Step {i + 1}", + "intro": step, + "position": "bottom" + } + + if element: + tour_step["element"] = element + + tour_steps.append(tour_step) + + # Save the tour definition as JSON + tour_filename = workflow_name.lower().replace(' ', '_') + '_tour.json' + with open(os.path.join(output_dir, tour_filename), 'w', encoding='utf-8') as f: + json.dump({ + "name": workflow_name, + "description": workflow.get("description", ""), + "steps": tour_steps + }, f, indent=2) + + tours_created += 1 + + self.stdout.write(self.style.SUCCESS(f"✅ Created {tours_created} IntroJS tour definitions in {output_dir}")) diff --git a/tours/management/commands/generate_ui_map.py b/tours/management/commands/generate_ui_map.py new file mode 100644 index 00000000..30258ec3 --- /dev/null +++ b/tours/management/commands/generate_ui_map.py @@ -0,0 +1,88 @@ +from django.core.management.base import BaseCommand +from django.urls import get_resolver +import os +import json +from django.template.loaders.app_directories import get_app_template_dirs + + +class Command(BaseCommand): + help = "Generate UI element map for IntroJS tours" + + def handle(self, *args, **kwargs): + output_file = os.path.join('static', 'js', 'tours', 'ui_element_map.json') + + ui_map = { + "pages": {}, + "common_elements": { + "navigation": { + "inventory": "#inventory-menu, .inventory-nav, nav .inventory", + "finance": "#finance-menu, .finance-nav, nav .finance", + "customers": "#customers-menu, .customers-nav, nav .customers" + }, + "actions": { + "add": ".btn-add, .add-button, button:contains('Add')", + "edit": ".btn-edit, .edit-button, button:contains('Edit')", + "save": ".btn-save, button[type='submit'], #save-button", + "cancel": ".btn-cancel, #cancel-button, button:contains('Cancel')", + "delete": ".btn-delete, .delete-button, button:contains('Delete')" + }, + "forms": { + "search": "#search-form, .search-input, input[name='q']", + "date_range": ".date-range, input[type='date']", + "dropdown": "select, .dropdown, .select-field" + } + } + } + + # Extract URL patterns to identify pages + resolver = get_resolver() + for url_pattern in resolver.url_patterns: + if hasattr(url_pattern, 'name') and url_pattern.name: + pattern_name = url_pattern.name + # Skip admin and API URLs + if pattern_name.startswith(('admin:', 'api:')): + continue + + ui_map["pages"][pattern_name] = { + "url_pattern": str(url_pattern.pattern), + "elements": {} + } + + # Scan templates for UI elements with IDs + template_dirs = get_app_template_dirs('templates') + for template_dir in template_dirs: + for root, dirs, files in os.walk(template_dir): + for file in files: + if not file.endswith(('.html', '.htm')): + continue + + try: + with open(os.path.join(root, file), 'r', encoding='utf-8') as f: + content = f.read() + + # Try to identify the page/view this template is for + template_path = os.path.relpath(os.path.join(root, file), template_dir) + page_key = template_path.replace('/', '_').replace('.html', '') + + # Create page entry if it doesn't exist + if page_key not in ui_map["pages"]: + ui_map["pages"][page_key] = { + "template": template_path, + "elements": {} + } + + # Extract elements with IDs + import re + id_matches = re.findall(r'id=["\']([^"\']+)["\']', content) + for id_match in id_matches: + ui_map["pages"][page_key]["elements"][id_match] = f"#{id_match}" + + except Exception as e: + self.stdout.write(self.style.WARNING(f"Error processing template {file}: {e}")) + + # Save UI map as JSON + os.makedirs(os.path.dirname(output_file), exist_ok=True) + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(ui_map, f, indent=2) + + self.stdout.write(self.style.SUCCESS(f"✅ UI element map saved to {output_file}")) diff --git a/tours/management/commands/import_tours.py b/tours/management/commands/import_tours.py new file mode 100644 index 00000000..16474a30 --- /dev/null +++ b/tours/management/commands/import_tours.py @@ -0,0 +1,45 @@ +from django.core.management.base import BaseCommand +import yaml +import os +from django.utils.text import slugify +from tours.models import Tour + + +class Command(BaseCommand): + help = "Import tours from knowledge base" + + def handle(self, *args, **kwargs): + input_file = "haikal_kb.yaml" + + try: + with open(input_file, 'r', encoding='utf-8') as f: + kb = yaml.safe_load(f) + except Exception as e: + self.stdout.write(self.style.ERROR(f"Error reading knowledge base file: {e}")) + return + + workflows = kb.get("user_workflows", {}) + + tours_created = 0 + + for workflow_name, workflow in workflows.items(): + slug = slugify(workflow_name) + tour_file = f"{slug}_tour.json" + + tour, created = Tour.objects.update_or_create( + slug=slug, + defaults={ + 'name': workflow_name, + 'description': workflow.get('description', ''), + 'tour_file': tour_file, + 'is_active': True + } + ) + + if created: + tours_created += 1 + self.stdout.write(self.style.SUCCESS(f"Created tour: {workflow_name}")) + else: + self.stdout.write(self.style.SUCCESS(f"Updated tour: {workflow_name}")) + + self.stdout.write(self.style.SUCCESS(f"✅ Imported {tours_created} tours from knowledge base")) diff --git a/tours/migrations/0001_initial.py b/tours/migrations/0001_initial.py new file mode 100644 index 00000000..d0939f6e --- /dev/null +++ b/tours/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# Generated by Django 5.2.1 on 2025-06-06 14:05 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Tour', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('description', models.TextField(blank=True)), + ('slug', models.SlugField(unique=True)), + ('tour_file', models.CharField(max_length=255)), + ('is_active', models.BooleanField(default=True)), + ], + ), + migrations.CreateModel( + name='TourCompletion', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('completed_on', models.DateTimeField(auto_now_add=True)), + ('tour', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tours.tour')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('tour', 'user')}, + }, + ), + ] diff --git a/tours/migrations/__init__.py b/tours/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tours/models.py b/tours/models.py new file mode 100644 index 00000000..5179072f --- /dev/null +++ b/tours/models.py @@ -0,0 +1,22 @@ +from django.db import models + + +class Tour(models.Model): + name = models.CharField(max_length=100) + description = models.TextField(blank=True) + slug = models.SlugField(unique=True) + tour_file = models.CharField(max_length=255) + is_active = models.BooleanField(default=True) + + def __str__(self): + return self.name + + +class TourCompletion(models.Model): + tour = models.ForeignKey(Tour, on_delete=models.CASCADE) + user = models.ForeignKey('auth.User', on_delete=models.CASCADE) + completed_on = models.DateTimeField(auto_now_add=True) + + class Meta: + unique_together = ('tour', 'user') + diff --git a/tours/tests.py b/tours/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/tours/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/tours/urls.py b/tours/urls.py new file mode 100644 index 00000000..ffa32531 --- /dev/null +++ b/tours/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.tour_list, name='tour_list'), + path('data//', views.get_tour_data, name='get_tour_data'), + path('complete//', views.mark_tour_completed, name='mark_tour_complete'), + path('start//', views.start_tour_view, name='start_tour'), +] diff --git a/tours/views.py b/tours/views.py new file mode 100644 index 00000000..06a6839d --- /dev/null +++ b/tours/views.py @@ -0,0 +1,55 @@ +import os +import json +from django.shortcuts import render, get_object_or_404 +from django.http import JsonResponse +from django.contrib.auth.decorators import login_required +from django.conf import settings +from .models import Tour, TourCompletion + + +@login_required +def tour_list(request): + tours = Tour.objects.filter(is_active=True) + return render(request, 'tours/tour_list.html', {'tours': tours}) + + +@login_required +def get_tour_data(request, slug): + tour = get_object_or_404(Tour, slug=slug, is_active=True) + + # Check if user has already completed this tour + completed = TourCompletion.objects.filter(tour=tour, user=request.user).exists() + + # Load the tour data from JSON file + tour_file_path = os.path.join(settings.BASE_DIR, 'static', 'js', 'tours', tour.tour_file) + + try: + with open(tour_file_path, 'r') as f: + tour_data = json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + return JsonResponse({'error': 'Tour data not found or invalid'}, status=404) + + return JsonResponse({ + 'tour': tour_data, + 'completed': completed + }) + + +@login_required +def mark_tour_completed(request, slug): + if request.method != 'POST': + return JsonResponse({'error': 'Method not allowed'}, status=405) + + tour = get_object_or_404(Tour, slug=slug, is_active=True) + + # Mark the tour as completed for this user + TourCompletion.objects.get_or_create(tour=tour, user=request.user) + + return JsonResponse({'status': 'success'}) + + +@login_required +def start_tour_view(request, slug): + tour = get_object_or_404(Tour, slug=slug, is_active=True) + # Redirect to the page where the tour should start + return render(request, 'tours/start_tour.html', {'tour': tour})