From 18dd7829d98bc163db678dae64b30336f8b90356 Mon Sep 17 00:00:00 2001 From: ismail <=> Date: Mon, 28 Apr 2025 14:40:08 +0300 Subject: [PATCH] clean base V1-update --- .gitignore | 157 +-- Dockerfile | 28 +- api/views.py | 22 +- apply_initial_migrations.sh | 21 + car_inventory/urls.py | 18 +- generate.py | 2 +- haikalbot/migrations/0001_initial.py | 23 - haikalbot/migrations/0002_initial.py | 22 - inventory/admin.py | 16 +- inventory/apps.py | 6 +- inventory/forms.py | 146 +-- .../__pycache__/__init__.cpython-311.pyc | Bin 191 -> 0 bytes .../management/commands/__pycache__/.DS_Store | Bin 10244 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 200 -> 0 bytes .../create_fake_data.cpython-311.pyc | Bin 4809 -> 0 bytes .../__pycache__/export_models.cpython-311.pyc | Bin 1788 -> 0 bytes .../__pycache__/transfer_data.cpython-311.pyc | Bin 12050 -> 0 bytes .../__pycache__/translate.cpython-311.pyc | Bin 2931 -> 0 bytes inventory/migrations/0001_initial.py | 1008 ++++++++--------- inventory/services.py | 12 +- inventory/signals.py | 551 +-------- inventory/tasks.py | 580 ++++++++++ .../custom_filters.cpython-311.pyc | Bin 15512 -> 0 bytes inventory/views.py | 30 +- load_initial_data.sh | 25 + requirements.txt | 9 - requirements_dev.txt | 68 ++ scripts/generate.py | 2 +- scripts/run.py | 55 +- scripts/run1.py | 17 +- staticfiles/account/js/account.js | 20 + staticfiles/account/js/onload.js | 12 + staticfiles/admin/js/collapse.js | 43 + staticfiles/css/SaudiRiyalFont.ttf | Bin 0 -> 1872 bytes staticfiles/css/SaudiRiyalFont.woff | Bin 0 -> 1968 bytes staticfiles/css/SaudiRiyalFont.woff2 | Bin 0 -> 760 bytes templates/account/signup-wizard.html | 52 +- templates/base.html | 10 +- templates/welcome_base.html | 2 + 39 files changed, 1545 insertions(+), 1412 deletions(-) create mode 100755 apply_initial_migrations.sh delete mode 100644 haikalbot/migrations/0001_initial.py delete mode 100644 haikalbot/migrations/0002_initial.py delete mode 100644 inventory/management/__pycache__/__init__.cpython-311.pyc delete mode 100644 inventory/management/commands/__pycache__/.DS_Store delete mode 100644 inventory/management/commands/__pycache__/__init__.cpython-311.pyc delete mode 100644 inventory/management/commands/__pycache__/create_fake_data.cpython-311.pyc delete mode 100644 inventory/management/commands/__pycache__/export_models.cpython-311.pyc delete mode 100644 inventory/management/commands/__pycache__/transfer_data.cpython-311.pyc delete mode 100644 inventory/management/commands/__pycache__/translate.cpython-311.pyc create mode 100644 inventory/tasks.py delete mode 100644 inventory/templatetags/__pycache__/custom_filters.cpython-311.pyc create mode 100755 load_initial_data.sh create mode 100644 requirements_dev.txt create mode 100644 staticfiles/account/js/account.js create mode 100644 staticfiles/account/js/onload.js create mode 100644 staticfiles/admin/js/collapse.js create mode 100644 staticfiles/css/SaudiRiyalFont.ttf create mode 100644 staticfiles/css/SaudiRiyalFont.woff create mode 100644 staticfiles/css/SaudiRiyalFont.woff2 diff --git a/.gitignore b/.gitignore index 8ac15553..4e09b8e3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,11 +15,12 @@ car*.json car_inventory/settings.py car_inventory/__pycache__ scripts/dsrpipe.py -# Backup files # -*.bak +def_venv +# Backup files # +*.bak -# If you are using PyCharm # +# If you are using PyCharm # # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml @@ -55,95 +56,95 @@ out/ # JIRA plugin atlassian-ide-plugin.xml -# Python # -*.py[cod] -*$py.class +# Python # +*.py[cod] +*$py.class -# Distribution / packaging -.Python build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ +# Distribution / packaging +.Python build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ *.whl -*.egg-info/ -.installed.cfg -*.egg -*.manifest -*.spec +*.egg-info/ +.installed.cfg +*.egg +*.manifest +*.spec inventory/management/commands/run.py -# Installer logs -pip-log.txt -pip-delete-this-directory.txt +# Installer logs +pip-log.txt +pip-delete-this-directory.txt -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -.pytest_cache/ -nosetests.xml -coverage.xml -*.cover -.hypothesis/ +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ -# Jupyter Notebook -.ipynb_checkpoints +# Jupyter Notebook +.ipynb_checkpoints -# pyenv -.python-version +# pyenv +.python-version -# celery -celerybeat-schedule.* +# celery +celerybeat-schedule.* -# SageMath parsed files -*.sage.py +# SageMath parsed files +*.sage.py -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ -# mkdocs documentation -/site +# mkdocs documentation +/site -# mypy -.mypy_cache/ +# mypy +.mypy_cache/ -# Sublime Text # -*.tmlanguage.cache -*.tmPreferences.cache -*.stTheme.cache -*.sublime-workspace -*.sublime-project +# Sublime Text # +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project -# sftp configuration file -sftp-config.json +# sftp configuration file +sftp-config.json -# Package control specific files Package -Control.last-run -Control.ca-list -Control.ca-bundle -Control.system-ca-bundle -GitHub.sublime-settings +# Package control specific files Package +Control.last-run +Control.ca-list +Control.ca-bundle +Control.system-ca-bundle +GitHub.sublime-settings -# Visual Studio Code # -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json +# Visual Studio Code # +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json .history \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index eacc006c..8dcfb0ca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,18 +4,23 @@ FROM python:3.11.11-slim-bullseye # Set the working directory to /app WORKDIR /app +# Install the dependencies +RUN apt-get update && apt-get install -y libgl1 +RUN apt-get update && apt-get install -y libglib2.0-dev +RUN apt-get update && apt-get install -y libzbar0 +RUN apt-get update && apt-get install -y cmake build-essential xmlsec1 libxmlsec1-dev +RUN apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl + +COPY requirements_dev.txt . + +RUN pip install --upgrade pip + +RUN pip install -r requirements_dev.txt # Create a new user and group RUN groupadd -r appgroup RUN useradd -r -g appgroup -G appgroup -m -d /app -s /bin/false appuser # Copy the requirements file -COPY requirements.txt . - -# Install the dependencies -RUN pip install -r requirements.txt -RUN apt-get update && apt-get install -y libgl1 -RUN apt-get update && apt-get install -y libglib2.0-dev -RUN apt-get update && apt-get install -y libzbar0 # Copy the application code COPY . . @@ -23,17 +28,12 @@ COPY . . # Expose the port EXPOSE 8000 -# Copy the entrypoint script -COPY entrypoint.sh /app/entrypoint.sh # Make the script executable -RUN chmod +x /app/entrypoint.sh +RUN chmod +x *.sh # Change ownership of the app directory to the new user RUN chown -R appuser:appgroup /app -RUN find /app -path "*/migrations/*.py" -not -name "__init__.py" -delete -RUN find /app -path "*/migrations/*.pyc" -delete - # Set the entrypoint to execute the script as the new user -ENTRYPOINT ["sh", "-c", "python3 manage.py makemigrations && python3 manage.py migrate && python3 manage.py collectstatic --no-input && python3 manage.py runserver 0.0.0.0:8000"] \ No newline at end of file +ENTRYPOINT ["sh", "-c", "python3 manage.py runserver 0.0.0.0:8000"] \ No newline at end of file diff --git a/api/views.py b/api/views.py index 56de2c53..84153c37 100644 --- a/api/views.py +++ b/api/views.py @@ -11,7 +11,7 @@ from django.shortcuts import render from inventory.utils import get_user_type from . import models, serializers from .services import get_car_data, get_from_cardatabase -from rest_framework.authtoken.models import Token +# from rest_framework.authtoken.models import Token from django.utils.decorators import method_decorator from inventory import models as inventory_models @@ -20,20 +20,20 @@ from inventory import models as inventory_models class LoginView(APIView): permission_classes = [permissions.AllowAny,] - def post(self, request, *args, **kwargs): - username = request.data.get('username') - password = request.data.get('password') + # def post(self, request, *args, **kwargs): + # username = request.data.get('username') + # password = request.data.get('password') - if username is None or password is None: - return Response({'error': 'Please provide both username and password.'}, status=status.HTTP_400_BAD_REQUEST) + # if username is None or password is None: + # return Response({'error': 'Please provide both username and password.'}, status=status.HTTP_400_BAD_REQUEST) - user = authenticate(username=username, password=password) + # user = authenticate(username=username, password=password) - if not user: - return Response({'error': 'Invalid credentials.'}, status=status.HTTP_401_UNAUTHORIZED) + # if not user: + # return Response({'error': 'Invalid credentials.'}, status=status.HTTP_401_UNAUTHORIZED) - token, created = Token.objects.get_or_create(user=user) - return Response({'token': token.key, 'user_id': user.id, 'username': user.username}, status=status.HTTP_200_OK) + # token, created = Token.objects.get_or_create(user=user) + # return Response({'token': token.key, 'user_id': user.id, 'username': user.username}, status=status.HTTP_200_OK) class CarVINViewSet(APIView): diff --git a/apply_initial_migrations.sh b/apply_initial_migrations.sh new file mode 100755 index 00000000..386ff6af --- /dev/null +++ b/apply_initial_migrations.sh @@ -0,0 +1,21 @@ +#!/bin/sh +echo "Delete Old Migrations" +find ./inventory -type f -iname "000*.py" -delete + +echo "Delete Old Cache" +find ./car_inventory -type d -iname "__pycache__"|xargs rm -rf +find ./inventory -type d -iname "__pycache__"|xargs rm -rf + +echo "Apply Base Migrate" +python3 manage.py migrate + +echo "Apply Make Migratinos" +python3 manage.py makemigrations + +echo "Apply Final Migrate" +python3 manage.py migrate + +echo "Collect Static" +python3 manage.py collectstatic --no-input + +echo "Done" diff --git a/car_inventory/urls.py b/car_inventory/urls.py index ecb50987..d74d43e0 100644 --- a/car_inventory/urls.py +++ b/car_inventory/urls.py @@ -4,16 +4,16 @@ from django.conf.urls.static import static from django.conf import settings from django.conf.urls.i18n import i18n_patterns from inventory import views -import debug_toolbar -from schema_graph.views import Schema +# import debug_toolbar +# from schema_graph.views import Schema # from two_factor.urls import urlpatterns as tf_urls urlpatterns = [ - path('__debug__/', include(debug_toolbar.urls)), - path('silk/', include('silk.urls', namespace='silk')), + # path('__debug__/', include(debug_toolbar.urls)), + # path('silk/', include('silk.urls', namespace='silk')), path('api-auth/', include('rest_framework.urls')), - path('api/', include('api.urls')), - path('dj-rest-auth/', include('dj_rest_auth.urls')), + # path('api/', include('api.urls')), + # path('dj-rest-auth/', include('dj_rest_auth.urls')), ] @@ -21,13 +21,13 @@ urlpatterns += i18n_patterns( path('admin/', admin.site.urls), path('switch_language/', views.switch_language, name='switch_language'), path('accounts/', include('allauth.urls')), - path('prometheus/', include('django_prometheus.urls')), + # path('prometheus/', include('django_prometheus.urls')), path('', include('inventory.urls')), path('ledger/', include('django_ledger.urls', namespace='django_ledger')), - path("haikalbot/", include("haikalbot.urls")), + # path("haikalbot/", include("haikalbot.urls")), path('appointment/', include('appointment.urls')), path('plans/', include('plans.urls')), - path("schema/", Schema.as_view()), + # path("schema/", Schema.as_view()), # path('', include(tf_urls)), ) diff --git a/generate.py b/generate.py index 1fc182bc..f9cc4445 100644 --- a/generate.py +++ b/generate.py @@ -5,7 +5,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings") django.setup() from inventory.models import * -from rich import print +# from rich import print import random import datetime diff --git a/haikalbot/migrations/0001_initial.py b/haikalbot/migrations/0001_initial.py deleted file mode 100644 index 9c202e5c..00000000 --- a/haikalbot/migrations/0001_initial.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2.20 on 2025-03-20 17:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - 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)), - ], - ), - ] diff --git a/haikalbot/migrations/0002_initial.py b/haikalbot/migrations/0002_initial.py deleted file mode 100644 index 62877afe..00000000 --- a/haikalbot/migrations/0002_initial.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.20 on 2025-03-20 17:15 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('inventory', '0001_initial'), - ('haikalbot', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='chatlog', - name='dealer', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer'), - ), - ] diff --git a/inventory/admin.py b/inventory/admin.py index bd45258a..2c15bd11 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -1,9 +1,9 @@ -from appointment.models import Appointment +# from appointment.models import Appointment from django.contrib import admin from . import models from django_ledger import models as ledger_models -from django_pdf_actions.actions import export_to_pdf_landscape, export_to_pdf_portrait -from appointment import models as appointment_models +# from django_pdf_actions.actions import export_to_pdf_landscape, export_to_pdf_portrait +# from appointment import models as appointment_models from import_export.admin import ExportMixin from import_export.resources import ModelResource @@ -72,14 +72,14 @@ admin.site.register(models.UserActivityLog) @admin.register(models.Car) class CarAdmin(admin.ModelAdmin): search_fields = ('vin',) - actions = [export_to_pdf_landscape, export_to_pdf_portrait] + # actions = [export_to_pdf_landscape, export_to_pdf_portrait] @admin.register(models.CarMake) class CarMakeAdmin(admin.ModelAdmin): list_display = ('name', 'arabic_name', 'is_sa_import') search_fields = ('name', 'arabic_name') list_filter = ('is_sa_import', 'name',) - actions = [export_to_pdf_landscape, export_to_pdf_portrait] + # actions = [export_to_pdf_landscape, export_to_pdf_portrait] class Meta: verbose_name = "Car Make" @@ -152,9 +152,9 @@ class CarOptionAdmin(admin.ModelAdmin): # search_fields = ('user__username', 'action') # list_filter = ('timestamp',) -@admin.register(ledger_models.ItemTransactionModel) -class ItemTransactionModelAdmin(admin.ModelAdmin): +# @admin.register(ledger_models.ItemTransactionModel) +# class ItemTransactionModelAdmin(admin.ModelAdmin): - actions = [export_to_pdf_landscape, export_to_pdf_portrait] +# actions = [export_to_pdf_landscape, export_to_pdf_portrait] diff --git a/inventory/apps.py b/inventory/apps.py index f316aa12..7a84f50f 100644 --- a/inventory/apps.py +++ b/inventory/apps.py @@ -6,7 +6,7 @@ class InventoryConfig(AppConfig): def ready(self): import inventory.signals - # from decimal import Decimal - # from inventory.models import VatRate - # VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True) + #from decimal import Decimal + #from inventory.models import VatRate + #VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True) diff --git a/inventory/forms.py b/inventory/forms.py index 571d76aa..1cc9586e 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -1,19 +1,12 @@ from django.core.cache import cache from django.contrib.auth.models import Permission -from django.contrib.auth.models import Group -from appointment.models import Appointment, Service, StaffMember -from django.urls import reverse -from django_countries.widgets import CountrySelectWidget -from django_ledger.models import CustomerModel +from appointment.models import Service from phonenumber_field.formfields import PhoneNumberField from django.core.validators import MinLengthValidator -from django.core.validators import RegexValidator from django import forms from django.contrib.auth import get_user_model -from phonenumber_field.phonenumber import PhoneNumber from .models import CustomGroup, Status, Stage from .mixins import AddClassMixin -from django.forms.models import inlineformset_factory from django_ledger.forms.invoice import ( InvoiceModelCreateForm as InvoiceModelCreateFormBase, ) @@ -21,17 +14,14 @@ from django_ledger.forms.estimate import ( EstimateModelCreateForm as EstimateModelCreateFormBase, ) -# from django_ledger.forms.ledger import LedgerModelCreateForm as LedgerModelCreateFormBase from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase from django_ledger.forms.journal_entry import JournalEntryModelCreateForm as JournalEntryModelCreateFormBase from .models import ( Dealer, DealersMake, - # Branch, Vendor, Schedule, - Customer, Car, CarTransfer, CarFinance, @@ -40,16 +30,11 @@ from .models import ( CarColors, ExteriorColors, InteriorColors, - # SaleQuotation, CarLocation, - Representative, - - # SaleQuotationCar, AdditionalServices, Staff, Opportunity, - Lead, Activity, Notes, @@ -65,7 +50,6 @@ from django.forms import ( ) from django.utils.translation import gettext_lazy as _ import django_tables2 as tables -from django.forms import formset_factory User = get_user_model() @@ -90,14 +74,6 @@ class AdditionalServiceForm(forms.ModelForm): model = AdditionalServices fields = ["name", "price", "description", "taxable", "uom"] - -# class PaymentForm(forms.ModelForm): -# invoice = forms.ModelChoiceField(queryset=InvoiceModel.objects.all(),label="Invoice", required=True) -# class Meta: -# model = Payment -# fields = ['amount','payment_method', 'reference_number'] - - class StaffForm(forms.ModelForm): """ Represents a form for managing Staff entities, including associated user email updates @@ -128,22 +104,6 @@ class StaffForm(forms.ModelForm): model = Staff fields = ["name", "arabic_name", "phone_number", "staff_type"] - # def __init__(self, *args, **kwargs): - # user_instance = kwargs.get("instance") - # if user_instance and user_instance.user: - # initial = kwargs.setdefault("initial", {}) - # initial["email"] = user_instance.user.email - # super().__init__(*args, **kwargs) - # - # def save(self, commit=True): - # user_instance = super().save(commit=False) - # user = user_instance.user - # user.email = self.cleaned_data["email"] - # if commit: - # user.save() - # user_instance.save() - # return user_instance - # Dealer Form class DealerForm(forms.ModelForm): @@ -258,28 +218,6 @@ class OrganizationForm(CustomerForm): logo = forms.ImageField(required=False) -# class CustomerForm(forms.ModelForm, AddClassMixin): -# class Meta: -# model = Customer -# fields = [ -# "title", -# "first_name", -# "middle_name", -# "last_name", -# "gender", -# "dob", -# "email", -# "national_id", - -# "phone_number", -# "address", -# ] -# widgets = { -# "phone_number": forms.TextInput(attrs={"class": "phone"}), -# "dob": forms.DateInput(attrs={"type": "date"}), -# } - - class CarForm( forms.ModelForm, AddClassMixin, @@ -338,10 +276,6 @@ class CarForm( self.fields["vendor"].queryset = ledger_models.VendorModel.objects.filter( active=True ) - # queryset = self.fields["vendor"].queryset - # self.fields["vendor"].choices = [ - # (obj.pk, obj.get_local_name()) for obj in queryset - # ] class CarUpdateForm(forms.ModelForm, AddClassMixin): @@ -382,19 +316,6 @@ class CarUpdateForm(forms.ModelForm, AddClassMixin): dealer = kwargs.pop("dealer", None) super().__init__(*args, **kwargs) - # if dealer and 'branch' in self.fields: - # self.fields['branch'].queryset = Branch.objects.filter(dealer=dealer) - # self.fields['branch'].choices = [ - # (branch.id, branch.get_local_name()) for branch in self.fields['branch'].queryset - # ] - - # if "vendor" in self.fields: - # queryset = self.fields["vendor"].queryset - # if queryset: - # self.fields["vendor"].choices = [ - # (vendor.id, vendor.get_local_name()) for vendor in queryset - # ] - class CarFinanceForm(forms.ModelForm): """ @@ -424,13 +345,6 @@ class CarFinanceForm(forms.ModelForm): "additional_services", ] - # def __init__(self, *args, **kwargs): - # super().__init__(*args, **kwargs) - # if self.instance.pk: - # self.fields[ - # "additional_finances" - # ].initial = self.instance.additional_services.all() - def save(self, commit=True): instance = super().save() instance.additional_services.set(self.cleaned_data["additional_finances"]) @@ -617,43 +531,6 @@ class CarColorsForm(forms.ModelForm): return cleaned_data -# class QuotationForm(forms.ModelForm): -# cars = ModelMultipleChoiceField( -# queryset=Car.objects.none(), # Default empty queryset -# widget=forms.CheckboxSelectMultiple, -# label="Select Cars", -# ) -# -# class Meta: -# model = SaleQuotation -# fields = ["customer", "cars", "remarks"] -# -# def __init__(self, *args, **kwargs): -# super().__init__(*args, **kwargs) -# -# self.fields["cars"].queryset = Car.objects.filter( -# finances__isnull=False -# ).distinct() - - -# class OrganizationForm(forms.ModelForm): -# class Meta: -# model = Organization -# fields = [ -# "name", -# "arabic_name", -# "crn", -# "vrn", -# "phone_number", -# "address", -# "logo", -# ] - -# def __init__(self, *args, **kwargs): -# dealer = kwargs.pop("dealer", None) -# super().__init__(*args, **kwargs) - - class RepresentativeForm(forms.ModelForm): """ A form for creating or updating instances of the Representative model. @@ -958,17 +835,6 @@ class WizardForm3(forms.Form): }, ) - # def clean(self): - # cleaned_data = super().clean() - # password = cleaned_data.get("password") - # confirm_password = cleaned_data.get("confirm_password") - - # if password != confirm_password: - # raise forms.ValidationError("Passwords do not match.") - # else: - # return cleaned_data - - class ItemForm(forms.Form): """ A form for handling item-related inputs in the application. @@ -991,9 +857,6 @@ class ItemForm(forms.Form): validators=[MinLengthValidator(5)], ) quantity = forms.DecimalField(label="Quantity", required=True) - # unit = forms.DecimalField(label="Unit", required=True) - # unit_cost = forms.DecimalField(label="Unit Cost", required=True) - # unit_sales_price = forms.DecimalField(label="Unit Sales Price", required=True) class PaymentForm(forms.Form): @@ -1278,10 +1141,6 @@ class BillModelCreateForm(BillModelCreateFormBase): self.fields["cash_account"].widget = forms.HiddenInput() self.fields["prepaid_account"].widget = forms.HiddenInput() self.fields["unearned_account"].widget = forms.HiddenInput() - # self.fields["date_draft"] = forms.DateField( - # widget=DateInput(attrs={"type": "date"}) - # ) - class SaleOrderForm(forms.ModelForm): """ @@ -1568,6 +1427,3 @@ class JournalEntryModelCreateForm(JournalEntryModelCreateFormBase): :type bar: int """ pass - -# class LedgerModelCreateForm(LedgerModelCreateFormBase): -# pass \ No newline at end of file diff --git a/inventory/management/__pycache__/__init__.cpython-311.pyc b/inventory/management/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 98179969c42524f34b586086c9ef1dd43e2aa573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191 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 diff --git a/inventory/management/commands/__pycache__/transfer_data.cpython-311.pyc b/inventory/management/commands/__pycache__/transfer_data.cpython-311.pyc deleted file mode 100644 index 3e51c4b1a4c4eb175b25319c0dfe04e7515102e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12050 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 allowed_users: # raise ValidationError(_("You have reached the maximum number of staff users allowed for your plan.")) - - @receiver(post_save, sender=models.Dealer) def create_vat(sender, instance, created, **kwargs): """ @@ -1176,21 +665,21 @@ def create_make_ledger_accounts(sender, instance, created, **kwargs): entity = instance.entity coa = entity.get_default_coa() - last_account = entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).order_by('-created').first() - if len(last_account.code) == 4: - code = f"{int(last_account.code)}{1:03d}" - elif len(last_account.code) > 4: - code = f"{int(last_account.code)+1}" + # for make in models.CarMake.objects.all(): + # last_account = entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).order_by('-created').first() + # if len(last_account.code) == 4: + # code = f"{int(last_account.code)}{1:03d}" + # elif len(last_account.code) > 4: + # code = f"{int(last_account.code)+1}" + # entity.create_account( + # name=make.name, + # code=code, + # role=roles.ASSET_CA_RECEIVABLES, + # coa_model=coa, + # balance_type="credit", + # active=True + # ) - for make in models.CarMake.objects.all(): - entity.create_account( - name=make.name, - code=code, - role=roles.ASSET_CA_RECEIVABLES, - coa_model=coa, - balance_type="credit", - active=True - ) # @receiver(post_save, sender=VendorModel) @@ -1333,4 +822,4 @@ def update_finance_cost(sender, instance, created, **kwargs): # else: # save_journal(instance,ledger,vendor) # else: - # save_journal(instance,ledger,vendor) \ No newline at end of file + # save_journal(instance,ledger,vendor) diff --git a/inventory/tasks.py b/inventory/tasks.py new file mode 100644 index 00000000..adb82e9b --- /dev/null +++ b/inventory/tasks.py @@ -0,0 +1,580 @@ +from django_ledger.io import roles +from django.core.mail import send_mail +from background_task import background +from django.utils.translation import gettext_lazy as _ +from inventory.models import DealerSettings,CarMake,Dealer + +@background +def create_coa_accounts(pk): + instance = Dealer.objects.get(pk=pk) + entity = instance.entity + coa = entity.get_default_coa() + + # Cash Account + asset_ca_cash = entity.create_account( + coa_model=coa, + code="1101", + role=roles.ASSET_CA_CASH, + name=_("Cash"), + balance_type="debit", + active=True, + ) + asset_ca_cash.role_default = True + asset_ca_cash.save() + + # Accounts Receivable Account + asset_ca_receivables = entity.create_account( + coa_model=coa, + code="1102", + role=roles.ASSET_CA_RECEIVABLES, + name=_("Accounts Receivable"), + balance_type="debit", + active=True, + ) + asset_ca_receivables.role_default = True + asset_ca_receivables.save() + + # Inventory Account + asset_ca_inventory = entity.create_account( + coa_model=coa, + code="1103", + role=roles.ASSET_CA_INVENTORY, + name=_("Inventory"), + balance_type="debit", + active=True, + ) + asset_ca_inventory.role_default = True + asset_ca_inventory.save() + + + # Prepaid Expenses Account + asset_ca_prepaid = entity.create_account( + coa_model=coa, + code="1104", + role=roles.ASSET_CA_PREPAID, + name=_("Prepaid Expenses"), + balance_type="debit", + active=True, + ) + asset_ca_prepaid.role_default = True + asset_ca_prepaid.save() + + # Employee Expenses Account + asset_ca_prepaid_employee = entity.create_account( + coa_model=coa, + code="1105", + role=roles.ASSET_CA_PREPAID, + name=_("Employee Advance"), + balance_type="debit", + active=True, + ) + + + # VAT Payable Account + liability_ltl_vat_receivable = entity.create_account( + coa_model=coa, + code="1106", + role=roles.ASSET_CA_RECEIVABLES, + name=_("VAT Receivable"), + balance_type="debit", + active=True, + ) + + # Buildings Accumulated Depreciation Account + asset_ppe_buildings_accum_depreciation = entity.create_account( + coa_model=coa, + code="1201", + role=roles.ASSET_PPE_BUILDINGS_ACCUM_DEPRECIATION, + name=_("Buildings - Accum. Depreciation"), + balance_type="credit", + active=True, + ) + asset_ppe_buildings_accum_depreciation.role_default = True + asset_ppe_buildings_accum_depreciation.save() + + # intangible Account + asset_lti_land_intangable = entity.create_account( + coa_model=coa, + code="1202", + role=roles.ASSET_INTANGIBLE_ASSETS, + name=_("Intangible Assets"), + balance_type="debit", + active=True, + ) + asset_lti_land_intangable.role_default = True + asset_lti_land_intangable.save() + + # investment property Account + asset_lti_land_investment = entity.create_account( + coa_model=coa, + code="1204", + role=roles.ASSET_LTI_SECURITIES, + name=_("Investments"), + balance_type="debit", + active=True, + ) + asset_lti_land_investment.role_default = True + asset_lti_land_investment.save() + + # # Notes Receivable Account + # asset_lti_notes_receivable = entity.create_account( + # coa_model=coa, + # code="1201", + # role=roles.ASSET_LTI_NOTES_RECEIVABLE, + # name=_("Notes Receivable"), + # balance_type="debit", + # active=True, + # ) + # asset_lti_notes_receivable.role_default = True + # asset_lti_notes_receivable.save() + + # # Land Account + # asset_lti_land = entity.create_account( + # coa_model=coa, + # code="1202", + # role=roles.ASSET_LTI_LAND, + # name=_("Land"), + # balance_type="debit", + # active=True, + # ) + # asset_lti_land.role_default = True + # asset_lti_land.save() + + + # Buildings Account + asset_ppe_buildings = entity.create_account( + coa_model=coa, + code="1301", + role=roles.ASSET_PPE_BUILDINGS, + name=_("Buildings"), + balance_type="debit", + active=True, + ) + asset_ppe_buildings.role_default = True + asset_ppe_buildings.save() + + + + # Accounts Payable Account + liability_cl_acc_payable = entity.create_account( + coa_model=coa, + code="2101", + role=roles.LIABILITY_CL_ACC_PAYABLE, + name=_("Accounts Payable"), + balance_type="credit", + active=True, + ) + liability_cl_acc_payable.role_default = True + liability_cl_acc_payable.save() + + # Deferred Revenue Account + liability_cl_def_rev = entity.create_account( + coa_model=coa, + code="2103", + role=roles.LIABILITY_CL_DEFERRED_REVENUE, + name=_("Deferred Revenue"), + balance_type="credit", + active=True, + ) + liability_cl_def_rev.role_default = True + liability_cl_def_rev.save() + + # Wages Payable Account + liability_cl_wages_payable = entity.create_account( + coa_model=coa, + code="2102", + role=roles.LIABILITY_CL_WAGES_PAYABLE, + name=_("Wages Payable"), + balance_type="credit", + active=True, + ) + liability_cl_wages_payable.role_default = True + liability_cl_wages_payable.save() + + # Long-Term Notes Payable Account + liability_ltl_notes_payable = entity.create_account( + coa_model=coa, + code="2201", + role=roles.LIABILITY_LTL_NOTES_PAYABLE, + name=_("Long-Term Notes Payable"), + balance_type="credit", + active=True, + ) + liability_ltl_notes_payable.role_default = True + liability_ltl_notes_payable.save() + + # VAT Payable Account + liability_ltl_vat_payable = entity.create_account( + coa_model=coa, + code="2106", + role=roles.LIABILITY_CL_OTHER, + name=_("VAT Payable"), + balance_type="credit", + active=True, + ) + + # taxes Payable Account + liability_ltl_taxes_payable = entity.create_account( + coa_model=coa, + code="2107", + role=roles.LIABILITY_CL_OTHER, + name=_("Taxes Payable"), + balance_type="credit", + active=True, + ) + + # social insurance Payable Account + liability_ltl_social_insurance_payable = entity.create_account( + coa_model=coa, + code="2108", + role=roles.LIABILITY_LTL_NOTES_PAYABLE, + name=_("Social Insurance Payable"), + balance_type="credit", + active=True, + ) + + # End of Service Benefits + entity.create_account(coa_model=coa, code="2202", role=roles.LIABILITY_LTL_NOTES_PAYABLE, name=_("End of Service Benefits"), balance_type="credit", active=True) + + # Mortgage Payable Account + liability_ltl_mortgage_payable = entity.create_account( + coa_model=coa, + code="2203", + role=roles.LIABILITY_LTL_MORTGAGE_PAYABLE, + name=_("Mortgage Payable"), + balance_type="credit", + active=True, + ) + liability_ltl_mortgage_payable.role_default = True + liability_ltl_mortgage_payable.save() + + # Capital + equity_capital = entity.create_account(coa_model=coa, code="3101", role=roles.EQUITY_CAPITAL, name=_("Registered Capital"), balance_type="credit", active=True) + equity_capital.role_default = True + equity_capital.save() + entity.create_account(coa_model=coa, code="3102", role=roles.EQUITY_CAPITAL, name=_("Additional Paid-In Capital"), balance_type="credit", active=True) + + # Other Equity + other_equity = entity.create_account(coa_model=coa, code="3201", role=roles.EQUITY_COMMON_STOCK, name=_("Opening Balances"), balance_type="credit", active=True) + other_equity.role_default = True + other_equity.save() + + # Reserves + reserve = entity.create_account(coa_model=coa, code="3301", role=roles.EQUITY_ADJUSTMENT, name=_("Statutory Reserve"), balance_type="credit", active=True) + reserve.role_default = True + reserve.save() + entity.create_account(coa_model=coa, code="3302", role=roles.EQUITY_ADJUSTMENT, name=_("Foreign Currency Translation Reserve"), balance_type="credit", active=True) + + # Retained Earnings Account + equity_retained_earnings = entity.create_account( + coa_model=coa, + code="3401", + role=roles.EQUITY_PREFERRED_STOCK, + name=_("Operating Profits and Losses"), + balance_type="credit", + active=True, + ) + equity_retained_earnings.role_default = True + equity_retained_earnings.save() + + equity_retained_earnings_losses = entity.create_account( + coa_model=coa, + code="3402", + role=roles.EQUITY_PREFERRED_STOCK, + name=_("Retained Earnings (or Losses)"), + balance_type="credit", + active=True, + ) + + # Sales Revenue Account + income_operational = entity.create_account( + coa_model=coa, + code="4101", + role=roles.INCOME_OPERATIONAL, + name=_("Sales Revenue"), + balance_type="credit", + active=True, + ) + income_operational.role_default = True + income_operational.save() + + # Interest Income Account + income_interest = entity.create_account( + coa_model=coa, + code="4102", + role=roles.INCOME_INTEREST, + name=_("Interest Income"), + balance_type="credit", + active=True, + ) + income_interest.role_default = True + income_interest.save() + + # Uneared Income Account + income_unearned = entity.create_account( + coa_model=coa, + code="4103", + role=roles.INCOME_OTHER, + name=_("Unearned Income"), + balance_type="credit", + active=True, + ) + + # Operating Revenues + entity.create_account(coa_model=coa, code="4104", role=roles.INCOME_OPERATIONAL, name=_("Sales/Service Revenue"), balance_type="credit", active=True) + + #Non-Operating Revenues + entity.create_account(coa_model=coa, code="4201", role=roles.INCOME_OTHER, name=_("Non-Operating Revenues"), balance_type="credit", active=True) + + + # Cost of Goods Sold (COGS) Account + expense_cogs = entity.create_account( + coa_model=coa, + code="5101", + role=roles.COGS, + name=_("Cost of Goods Sold"), + balance_type="debit", + active=True, + ) + expense_cogs.role_default = True + expense_cogs.save() + + + # accrued Expenses Account + expense_cogs = entity.create_account( + coa_model=coa, + code="6117", + role=roles.EXPENSE_OPERATIONAL, + name=_("Accrued Expenses"), + balance_type="debit", + active=True, + ) + + # accrued salaries Account + expense_cogs = entity.create_account( + coa_model=coa, + code="6118", + role=roles.EXPENSE_OPERATIONAL, + name=_("Accrued Salaries"), + balance_type="debit", + active=True, + ) + + # Rent Expense Account + expense_rent = entity.create_account( + coa_model=coa, + code="6102", + role=roles.EXPENSE_OPERATIONAL, + name=_("Rent Expense"), + balance_type="debit", + active=True, + ) + # expense_rent.role_default = True + # expense_rent.save() + + # Salaries and Administrative Fees + expense_salaries = entity.create_account( + coa_model=coa, + code="6103", + role=roles.EXPENSE_OPERATIONAL, + name=_("Salaries and Administrative Fees"), + balance_type="debit", + active=True, + ) + + # Medical Insurance + expense_medical_insurance = entity.create_account( + coa_model=coa, + code="6104", + role=roles.EXPENSE_OPERATIONAL, + name=_("Medical Insurance"), + balance_type="debit", + active=True, + ) + + # Marketing and Advertising Expenses + expense_marketing = entity.create_account( + coa_model=coa, + code="6105", + role=roles.EXPENSE_OPERATIONAL, + name=_("Marketing and Advertising Expenses"), + balance_type="debit", + active=True, + ) + + # Commissions and Incentives + expense_commissions = entity.create_account( + coa_model=coa, + code="6106", + role=roles.EXPENSE_OPERATIONAL, + name=_("Commissions and Incentives"), + balance_type="debit", + active=True, + ) + + # Travel Tickets + expense_travel = entity.create_account( + coa_model=coa, + code="6107", + role=roles.EXPENSE_OPERATIONAL, + name=_("Travel Tickets"), + balance_type="debit", + active=True, + ) + + # Social Insurance + expense_other = entity.create_account( + coa_model=coa, + code="6108", + role=roles.EXPENSE_OPERATIONAL, + name=_("Social Insurance"), + balance_type="debit", + active=True, + ) + + # Government Fees + expense_other = entity.create_account( + coa_model=coa, + code="6109", + role=roles.EXPENSE_OPERATIONAL, + name=_("Government Fees"), + balance_type="debit", + active=True, + ) + + # Fees and Subscriptions + expense_other = entity.create_account( + coa_model=coa, + code="6110", + role=roles.EXPENSE_OPERATIONAL, + name=_("Fees and Subscriptions"), + balance_type="debit", + active=True, + ) + + # Office Services Expenses + expense_other = entity.create_account( + coa_model=coa, + code="6111", + role=roles.EXPENSE_OPERATIONAL, + name=_("Office Services Expenses"), + balance_type="debit", + active=True, + ) + + # Office Supplies and Printing + expense_other = entity.create_account( + coa_model=coa, + code="6112", + role=roles.EXPENSE_OPERATIONAL, + name=_("Office Supplies and Printing"), + balance_type="debit", + active=True, + ) + + # Hospitality Expenses + expense_other = entity.create_account( + coa_model=coa, + code="6113", + role=roles.EXPENSE_OPERATIONAL, + name=_("Hospitality Expenses"), + balance_type="debit", + active=True, + ) + + # Bank Commissions + expense_other = entity.create_account( + coa_model=coa, + code="6114", + role=roles.EXPENSE_OPERATIONAL, + name=_("Bank Commissions"), + balance_type="debit", + active=True, + ) + + # Other Expenses + expense_other = entity.create_account( + coa_model=coa, + code="6115", + role=roles.EXPENSE_OPERATIONAL, + name=_("Other Expenses"), + balance_type="debit", + active=True, + ) + + # Transportation Expenses + expense_other = entity.create_account( + coa_model=coa, + code="6116", + role=roles.EXPENSE_OPERATIONAL, + name=_("Transportation Expenses"), + balance_type="debit", + active=True, + ) + + # 5.1 Direct Costs + entity.create_account(coa_model=coa, code="6201", role=roles.EXPENSE_OPERATIONAL, name=_("Cost of Goods Sold"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6202", role=roles.EXPENSE_OPERATIONAL, name=_("Salaries and Wages"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6203", role=roles.EXPENSE_OPERATIONAL, name=_("Sales Commissions"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6204", role=roles.EXPENSE_OPERATIONAL, name=_("Shipping and Customs Clearance"), balance_type="debit", active=True) + + # 5.3 Non-Operating Expenses + entity.create_account(coa_model=coa, code="6301", role=roles.EXPENSE_OTHER, name=_("Zakat"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6302", role=roles.EXPENSE_OTHER, name=_("Taxes"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6303", role=roles.EXPENSE_OTHER, name=_("Foreign Currency Translation"), balance_type="debit", active=True) + entity.create_account(coa_model=coa, code="6304", role=roles.EXPENSE_OTHER, name=_("Interest Expenses"), balance_type="debit", active=True) + + +# @background +# def create_groups(instance): +# group_names = ["Inventory", "Accountant", "Sales"] +# for group_name in group_names: +# group, _ = Group.objects.get_or_create(name=f"{instance.pk}_{group_name}") +# group_manager,_ = CustomGroup.objects.get_or_create(name=group_name, dealer=instance, group=group) +# group_manager.set_default_permissions() +# instance.user.groups.add(group) + +@background +def create_settings(pk): + instance = Dealer.objects.get(pk=pk) + + DealerSettings.objects.create( + dealer=instance, + invoice_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(), + invoice_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).first(), + invoice_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE).first(), + bill_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(), + bill_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID).first(), + bill_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).first() + ) + +@background +def create_accounts_for_make(pk): + instance = Dealer.objects.get(pk=pk) + entity = instance.entity + coa = entity.get_default_coa() + + for make in CarMake.objects.all(): + last_account = entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).order_by('-created').first() + if len(last_account.code) == 4: + code = f"{int(last_account.code)}{1:03d}" + elif len(last_account.code) > 4: + code = f"{int(last_account.code)+1}" + entity.create_account( + name=make.name, + code=code, + role=roles.ASSET_CA_RECEIVABLES, + coa_model=coa, + balance_type="credit", + active=True + ) + + + +@background +def send_email(from_, to_, subject, message): + subject = subject + message = message + from_email = from_ + recipient_list = [to_] + send_mail(subject, message, from_email, recipient_list) \ No newline at end of file diff --git a/inventory/templatetags/__pycache__/custom_filters.cpython-311.pyc b/inventory/templatetags/__pycache__/custom_filters.cpython-311.pyc deleted file mode 100644 index 5eefe0ce6a0f0aa931bd3105708a76709e1c705c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15512 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 4: code = f"{int(last_account.code) + 1}" + code = f"{int(last_account.code) + 1}" # account = entity.create_account( # name=car_makes[make].name, @@ -240,12 +256,24 @@ def run(): .order_by("-created") .first() ) + path = "" + depth=3, + ) + # 00060004001S + last_account = ( + entity.get_all_accounts() + .filter(role=roles.COGS) + .order_by("-created") + .first() + ) path = "" if len(last_account.code) == 12: path = f"{int(last_account.path)}{1:03d}" elif len(last_account.code) > 12: path = f"{int(last_account.path) + 1}" + path = f"{int(last_account.path) + 1}" # account.path = path + try: try: account = cogs.add_child(instance=account) account.move(cogs, pos="sorted-sibling") @@ -254,6 +282,7 @@ def run(): except Exception as e: print(e) + # form_data = { # 'name': car_makes[make].name, # 'code': code, @@ -263,6 +292,7 @@ def run(): # 'coa_model': coa # Ensure the COA model is included # } + # Create the form instance with the data # create_form = AccountModelCreateForm(data=form_data, coa_model=coa) # # Validate and save the form @@ -286,3 +316,26 @@ def run(): # print(f"Account {account.name} created successfully.") # else: # print(f"Failed to create account {account.name}. Errors: {form.errors}") + + # create_form = AccountModelCreateForm(data=form_data, coa_model=coa) + # # Validate and save the form + # if create_form.is_valid(): + # account = create_form.save(commit=False) + # account.coa_model = coa # Set the entity for the account + + # Add the account as a child of the COGS account + # cogs.add_child(instance=account) + + # print(f"Account '{account.name}' created successfully.") + # else: + # print(f"Failed to create account. Errors: {create_form.errors}") + # form = AccountModelUpdateForm(instance=account) + + # if form.is_valid(): + # instance = form.save(commit=False) + # instance._position = "sorted-sibling" + # instance._ref_node_id = cogs.pk + # instance.save() + # print(f"Account {account.name} created successfully.") + # else: + # print(f"Failed to create account {account.name}. Errors: {form.errors}") diff --git a/scripts/run1.py b/scripts/run1.py index ee02fa03..ed0be9b3 100644 --- a/scripts/run1.py +++ b/scripts/run1.py @@ -8,7 +8,7 @@ from django_ledger.models.invoice import InvoiceModel from django_ledger.utils import accruable_net_summary from decimal import Decimal from django_ledger.models import EstimateModel,EntityModel,ItemModel,ItemTransactionModel,AccountModel,CustomerModel,EntityManagementModel -from rich import print +# from rich import print from datetime import date from inventory.models import Car, Dealer, VatRate,Lead,CarMake,CarModel,Schedule,CustomGroup from inventory.utils import CarFinanceCalculator @@ -30,19 +30,19 @@ def run(): entity = EntityModel.objects.get(admin__email="ismail.mosa.ibrahim@gmail.com") coa = entity.get_default_coa() cogs = entity.get_default_coa_accounts().filter(role=roles.COGS).first() - + last_account = entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).order_by('-created').first() if len(last_account.code) == 4: code = f"{int(last_account.code)}{1:03d}" elif len(last_account.code) > 4: code = f"{int(last_account.code)+1}" - + print(code) - + # # Loop through car makes and create accounts # for make in range(len(car_makes)): # Start from 0 to include all items # # Generate a unique code - # code = f"{cogs.code}{make + 1:03d}" # Example: "COGS-001", "COGS-002", etc. + # code = f"{cogs.code}{make + 1:03d}" # Example: "COGS-001", "COGS-002", etc. # account = entity.create_account( # name=car_makes[make].name, # code=code, @@ -50,11 +50,11 @@ def run(): # coa_model=coa, # balance_type="debit", # active=True - # ) + # ) # try: # account = cogs.add_child(instance=account) # account.move(cogs, pos="sorted-sibling") - + # account.refresh_from_db() # account.save() # except Exception as e: @@ -67,5 +67,4 @@ def run(): # 'active': True, # 'coa_model': coa # Ensure the COA model is included # } - - \ No newline at end of file + diff --git a/staticfiles/account/js/account.js b/staticfiles/account/js/account.js new file mode 100644 index 00000000..fbc5135c --- /dev/null +++ b/staticfiles/account/js/account.js @@ -0,0 +1,20 @@ +(function () { + const allauth = window.allauth = window.allauth || {} + + function manageEmailForm (o) { + const actions = document.getElementsByName('action_remove') + if (actions.length) { + actions[0].addEventListener('click', function (e) { + if (!window.confirm(o.i18n.confirmDelete)) { + e.preventDefault() + } + }) + } + } + + allauth.account = { + forms: { + manageEmailForm + } + } +})() diff --git a/staticfiles/account/js/onload.js b/staticfiles/account/js/onload.js new file mode 100644 index 00000000..1a224c9c --- /dev/null +++ b/staticfiles/account/js/onload.js @@ -0,0 +1,12 @@ +(function () { + document.addEventListener('DOMContentLoaded', function () { + Array.from(document.querySelectorAll('script[data-allauth-onload]')).forEach(scriptElt => { + const funcRef = scriptElt.dataset.allauthOnload + if (typeof funcRef === 'string' && funcRef.startsWith('allauth.')) { + const funcArg = JSON.parse(scriptElt.textContent) + const func = funcRef.split('.').reduce((acc, part) => acc && acc[part], window) + func(funcArg) + } + }) + }) +})() diff --git a/staticfiles/admin/js/collapse.js b/staticfiles/admin/js/collapse.js new file mode 100644 index 00000000..c6c7b0f6 --- /dev/null +++ b/staticfiles/admin/js/collapse.js @@ -0,0 +1,43 @@ +/*global gettext*/ +'use strict'; +{ + window.addEventListener('load', function() { + // Add anchor tag for Show/Hide link + const fieldsets = document.querySelectorAll('fieldset.collapse'); + for (const [i, elem] of fieldsets.entries()) { + // Don't hide if fields in this fieldset have errors + if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) { + elem.classList.add('collapsed'); + const h2 = elem.querySelector('h2'); + const link = document.createElement('a'); + link.id = 'fieldsetcollapser' + i; + link.className = 'collapse-toggle'; + link.href = '#'; + link.textContent = gettext('Show'); + h2.appendChild(document.createTextNode(' (')); + h2.appendChild(link); + h2.appendChild(document.createTextNode(')')); + } + } + // Add toggle to hide/show anchor tag + const toggleFunc = function(ev) { + if (ev.target.matches('.collapse-toggle')) { + ev.preventDefault(); + ev.stopPropagation(); + const fieldset = ev.target.closest('fieldset'); + if (fieldset.classList.contains('collapsed')) { + // Show + ev.target.textContent = gettext('Hide'); + fieldset.classList.remove('collapsed'); + } else { + // Hide + ev.target.textContent = gettext('Show'); + fieldset.classList.add('collapsed'); + } + } + }; + document.querySelectorAll('fieldset.module').forEach(function(el) { + el.addEventListener('click', toggleFunc); + }); + }); +} diff --git a/staticfiles/css/SaudiRiyalFont.ttf b/staticfiles/css/SaudiRiyalFont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d6b5ebce8feefe0709feb6865cbf910907c24add GIT binary patch literal 1872 zcmeHIT}TvB7(I7pcV&S9f*RP$7xhf_@bL2vKBk*L7iaWmidwpod-x zq$mi4=pl$6dZ;MqMMA2Ff+D1PiHJagw4z>mh`{aK-C5bnAbO1M@ZEdP_c!0YGxH4u zfOR+l6&=A~_o2&G?nyvzq_%wDp1nb|&t7dPe?` z(iyRmhH*VkhIv$=8osQ{y-QlXmK0j9H`M524rB0Vk=rH6Bk+%xs8qN7`*F zx*_*QIoHyDf3T?a3-TRQ0Ew6$-t6cY-Wx(2j3ub^sd@CP zr&7zb$-Qu7c0k%AbCAzqE`6~~QYq!O??EydRnDM#uCCP`GB=--95zZVZgOPrAk{)! zy&;6Wjg;IWPbioF>-aD(VwtCqeOq++fJ#mGR0f*N?G)W?lCxXWx4AhN3AavblSj^# zfn6eC`phPea@C`W9UiUBqrH1V2~>#z%F`0(@;6%atsCoI1IN6k(&jZqAH_FVP399l zTk2Nc7K>|}>%_{L8fiFc)|q0bUberWFj{<9KB51${mr=n1-M|p`vUnWwXp&njW$+M zh0`{6(C3kjox~q)tRY{x9b5}c>WV?ffH3`GYM(P@jM6JbQ?6{9Ud8jeiHEP^277{f$*P0%9@gMG@&9$=uE zvUcu_&4*evQ2g}v%T61Nk4*&QiAdP+d+Uv6Bc}o~Uu{FJzur&3wUho>a4$AHn{{b(%WKF%+AQ{ z#3U3ST6`!-(Y6o$0n$PXt@NRNDDpc1_{E@f1sXJ&v$IbPmTjekIfQ^5wJeXE$_~`!$)^l!MzWAo~6*2 zi56Pc8E|)DpJ&-2ZhY@rZEy;&+a{&g^;g~o7bEsZmRn2eTGO#?B5fQoudz)0bm845 zNO1G8Ut!Td)=oBC@iI8hKgE*!00o5$9QQNq7g>~9@t|cbV_)qKY$KH-y%AU~2iybf z{UJ-w&9C!k!ZzyAFFlS^f%sl>$hC`vZ^Z#B*TC>#kMKR$N>7to@Ud55MQ2v1kH%pu zl%?&^8t!)+eqE$fH)Rl~NmhYhRS$?uU`hE*`4t&1cC@%plOhXy^ANq8EymMC_k_Bd ztkSd!0mC(I3?l`6B9;;OI$BMmMo>o+e2IF&cY!mgLJoO&<%r^YB6*l3X@(B(N}f_) zBx}iyH6{7l{H2nX<;Y7)*dL3uW(G1aO zB`@@W(bq-2HpY`)tEZ|6`sJbyRS-p;W9kE`;?N3WYExp5sMQBXm2Yx+RZL(ShTOf% z)3Eu1IK|U7SbzPCN$AC)Y+2JziHUbg)nR2ClQ_XsWo~C_a!9F&W4&X8>wor(?+Rms zV*TQ-)VWkEO%97GwQu{InY`}x|1yoYdd6EY|Ly(Xm*)!m{-N$pE3B=3^&Y=&N6V9Q zkK-QFfi>xONg6s7`1*goj{HVbv43M3<7bUdCh5&lKRR@rsC;m8(I1cN*-4?q0{ywsK?>>Ooa9yN7JDVufIpHr13V;g7w}1mv)KJ_iE}hW zFL7^Z+|9@7bBP7|u3KV-^5VS2DwRY-Vh#AR#2MgGiMxPZiL>bIb%}HID(!7si?%lx zc`KGrZL(+)7vs?!TH2!(*nT4nV#9R;C$eJ4Hcqb?2N%LaVHlXW$PkwplR+;22m(li z6*068?ljgLbdVMhbqK<-<`tt_uGWnGt;hj&0Hv zEU!`-QUlsgtu%cAJcIw1CbqKi literal 0 HcmV?d00001 diff --git a/staticfiles/css/SaudiRiyalFont.woff2 b/staticfiles/css/SaudiRiyalFont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f80724774e4284b186080cd9b1497e7d51975212 GIT binary patch literal 760 zcmV4EC)p!V+IiwoZrZP9>&gy zDS0+N1fwV4#g(a!)_w$EcF%vGnZ5e}MgS2CUtr~8B*#J_{`*g-K8xsqWG(ERU_WDC z?lL>PCKaneb44Y7;+p!24OES9@6yuXd=OfQH_5 zdOlcM{lFtl;KeuG5GPMY#C)p(;Qm9dz27Ny9B$Ild|~wuJ(j=KwGTQbW6azqK4}*% zmNaj_H+hh0)-|(hN+q59y*5 z9{S2}S~WchHsb{)2_>47t8f6PaBse;jcLAn|W0i6ljqqbS$&cUzdsUQrr`kyTcqVE_PLrcRIm literal 0 HcmV?d00001 diff --git a/templates/account/signup-wizard.html b/templates/account/signup-wizard.html index eaf5b7c9..db411d17 100644 --- a/templates/account/signup-wizard.html +++ b/templates/account/signup-wizard.html @@ -39,7 +39,7 @@
    -
    + {{form1|crispy}}
    @@ -47,12 +47,12 @@
    {{form2|crispy}}
    -
    +
    -
    + {{form3|crispy}}
    -
    +
    @@ -96,7 +96,7 @@ const validator1 = new JustValidate('#wizardValidationForm2', { validateBeforeSubmitting: true, }); - + validator1.addField('#wizardValidationForm2 [name="phone_number"]', [ { rule: 'required', @@ -131,7 +131,7 @@ rule: 'minLength', value: 6, }, - + ]); validator.addField('#wizardValidationForm1 [name="confirm_password"]', [ { @@ -154,13 +154,13 @@ validator.addField('#wizardValidationForm1 [name="terms"]', [ { rule: 'required', - }, + }, ]) - + /* validator = new JustValidate('#wizardValidationForm1', { - rules: { + rules: { email: { required: true, email: true, @@ -198,10 +198,10 @@ const url = "{% url 'account_signup' %}"; let submit_btn = document.getElementById('submit_btn'); const csrftoken = getCookie('csrftoken'); - + submit_btn.addEventListener('click', async () => { - const allFormData = getAllFormData(); - + const allFormData = getAllFormData(); + try { showLoading(); const response = await fetch(url, { @@ -225,17 +225,17 @@ } catch (error) { notify("error",error); } - + }); function getAllFormData() { const forms = document.querySelectorAll('form'); const formData = {}; - + forms.forEach((form, index) => { const formId = form.id || `form${index + 1}`; formData[formId] = {}; - + const formElements = form.elements; for (let element of formElements) { if (element.name) { @@ -245,7 +245,7 @@ }); return formData; } - + function showLoading() { Swal.fire({ title: "{% trans 'Please Wait' %}", @@ -256,17 +256,31 @@ } }); } - + function hideLoading() { Swal.close(); } - + function notify(tag,msg){ Swal.fire({ icon: tag, titleText: msg }); - } + } + function getCookie(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; + } {% endblock customJS %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 08c34baf..9fb869bf 100644 --- a/templates/base.html +++ b/templates/base.html @@ -82,14 +82,10 @@
    {% include 'footer.html' %}
    - - {% block customJS %} - - - - {% endblock %} + + @@ -133,5 +129,7 @@ datePickers.forEach(dp => djLedger.getCalendar(dp.attributes.id.value, dateNavigationUrl)) {% endif %} + {% block customJS %} + {% endblock %} \ No newline at end of file diff --git a/templates/welcome_base.html b/templates/welcome_base.html index 703e213d..bacdf61c 100644 --- a/templates/welcome_base.html +++ b/templates/welcome_base.html @@ -70,6 +70,8 @@ + {% block customJS %} + {% endblock customJS %} \ No newline at end of file