From 6e344926b916c65418fc932b19323c3750c1d23c Mon Sep 17 00:00:00 2001 From: ismail Date: Sun, 24 Aug 2025 11:53:34 +0300 Subject: [PATCH] add models phone number validator --- inventory/forms.py | 1 + inventory/hooks.py | 22 ++ inventory/management/commands/run1.py | 9 + inventory/models.py | 13 +- inventory/signals.py | 6 +- inventory/tasks.py | 433 +------------------------- inventory/utils.py | 413 ++++++++++++++++++++++++ 7 files changed, 463 insertions(+), 434 deletions(-) create mode 100644 inventory/hooks.py create mode 100644 inventory/management/commands/run1.py diff --git a/inventory/forms.py b/inventory/forms.py index 4af30c0b..89dfe772 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -146,6 +146,7 @@ class StaffForm(forms.ModelForm): ) class Meta: + model = Staff fields = ["first_name","last_name", "arabic_name", "phone_number", "address", "logo", "group"] diff --git a/inventory/hooks.py b/inventory/hooks.py new file mode 100644 index 00000000..d210796c --- /dev/null +++ b/inventory/hooks.py @@ -0,0 +1,22 @@ +import logging +from inventory.models import Dealer +from .utils import get_accounts_data,create_account + +logger = logging.getLogger(__name__) + +def check_create_coa_accounts(task): + logger.info("Checking if all accounts are created") + instance_id = task.args[0] + instance = Dealer.objects.get(pk=instance_id) + entity = instance.entity + coa = entity.get_default_coa() + + for account_data in get_accounts_data(): + if entity.get_all_accounts().filter(code=account_data["code"]).exists(): + logger.info(f"Default account already exists: {account_data['code']}") + continue + logger.info(f"Default account does not exist: {account_data['code']}") + create_account(entity, coa, account_data) + +def print_results(task): + print(task.kwargs.get("dealer")) \ No newline at end of file diff --git a/inventory/management/commands/run1.py b/inventory/management/commands/run1.py new file mode 100644 index 00000000..da71f31c --- /dev/null +++ b/inventory/management/commands/run1.py @@ -0,0 +1,9 @@ +from django.core.management.base import BaseCommand +from django_q.tasks import async_task, result + + +class Command(BaseCommand): + def handle(self, *args, **kwargs): + from inventory.models import Dealer + instance = Dealer.objects.first() + async_task(name="test_task_test",func="inventory.tasks.test_task",dealer=instance,hook="inventory.hooks.print_results") \ No newline at end of file diff --git a/inventory/models.py b/inventory/models.py index ee42f924..da8cfaa6 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -2,6 +2,7 @@ import uuid from datetime import datetime from django.conf import settings from django.contrib.auth.models import Permission +from inventory.validators import SaudiPhoneNumberValidator from decimal import Decimal from django.urls import reverse from django.utils.text import slugify @@ -1305,7 +1306,7 @@ class Dealer(models.Model, LocalizedNameMixin): ) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) name = models.CharField(max_length=255, verbose_name=_("English Name")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) address = models.CharField( max_length=200, blank=True, null=True, verbose_name=_("Address") ) @@ -1431,7 +1432,7 @@ class Staff(models.Model): last_name = models.CharField(max_length=255, verbose_name=_("Last Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) staff_type = models.CharField( choices=StaffTypes.choices, max_length=255, verbose_name=_("Staff Type") ) @@ -1825,7 +1826,7 @@ class Organization(models.Model, LocalizedNameMixin): ) vrn = models.CharField(max_length=15, verbose_name=_("VAT Registration Number")) email = models.EmailField(verbose_name=_("Email")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) address = models.CharField( max_length=200, blank=True, null=True, verbose_name=_("Address") ) @@ -1959,7 +1960,7 @@ class Representative(models.Model, LocalizedNameMixin): id_number = models.CharField( max_length=10, unique=True, verbose_name=_("ID Number") ) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) email = models.EmailField(max_length=255, verbose_name=_("Email Address")) address = models.CharField( max_length=200, blank=True, null=True, verbose_name=_("Address") @@ -1979,7 +1980,7 @@ class Lead(models.Model): first_name = models.CharField(max_length=50, verbose_name=_("First Name")) last_name = models.CharField(max_length=50, verbose_name=_("Last Name")) email = models.EmailField(verbose_name=_("Email")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) address = models.CharField( max_length=200, blank=True, null=True, verbose_name=_("Address") ) @@ -2667,7 +2668,7 @@ class Vendor(models.Model, LocalizedNameMixin): arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) name = models.CharField(max_length=255, verbose_name=_("English Name")) contact_person = models.CharField(max_length=100, verbose_name=_("Contact Person")) - phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) + phone_number = models.CharField(max_length=255, verbose_name=_("Phone Number"),validators=[SaudiPhoneNumberValidator]) email = models.EmailField(max_length=255, verbose_name=_("Email Address")) address = models.CharField(max_length=200, verbose_name=_("Address")) logo = models.ImageField( diff --git a/inventory/signals.py b/inventory/signals.py index 773f8e4c..12582a3d 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -1,7 +1,7 @@ from datetime import datetime, timedelta from decimal import Decimal from django.urls import reverse -from inventory.tasks import create_coa_accounts,check_create_coa_accounts, create_make_accounts +from inventory.tasks import create_coa_accounts, create_make_accounts from django.contrib.auth.models import Group from django.db.models.signals import post_save, post_delete from django.dispatch import receiver @@ -178,8 +178,8 @@ def create_ledger_entity(sender, instance, created, **kwargs): entity.create_uom(name=u[1], unit_abbr=u[0]) # Create COA accounts, background task - async_task(create_coa_accounts, instance) - async_task('inventory.tasks.check_create_coa_accounts', instance, schedule_type='O', schedule_time=timedelta(seconds=20)) + async_task(name="create_coa_accounts",func=create_coa_accounts,dealer_pk=instance.pk,hook="inventory.hooks.check_create_coa_accounts") + # async_task('inventory.tasks.check_create_coa_accounts', instance, schedule_type='O', schedule_time=timedelta(seconds=20)) # create_settings(instance.pk) # create_accounts_for_make(instance.pk) diff --git a/inventory/tasks.py b/inventory/tasks.py index 9ad55056..fb9a2661 100644 --- a/inventory/tasks.py +++ b/inventory/tasks.py @@ -14,11 +14,11 @@ from django.core.files.base import ContentFile from django.contrib.auth import get_user_model from allauth.account.models import EmailAddress from django.core.mail import EmailMultiAlternatives +from .utils import get_accounts_data,create_account from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import User, Group, Permission from inventory.models import DealerSettings, Dealer,Schedule,Notification,CarReservation,CarStatusChoices - logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) @@ -47,435 +47,15 @@ def create_settings(pk): .filter(role=roles.LIABILITY_CL_ACC_PAYABLE) .first(), ) -def get_accounts_data(): - return [ - # Current Assets (must start with 1) - { - "code": "1010", - "name": "Cash on Hand", - "role": roles.ASSET_CA_CASH, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_CA_CASH - }, - { - "code": "1020", - "name": "Bank", - "role": roles.ASSET_CA_CASH, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1030", - "name": "Accounts Receivable", - "role": roles.ASSET_CA_RECEIVABLES, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_CA_RECEIVABLES - }, - { - "code": "1040", - "name": "Inventory (Cars)", - "role": roles.ASSET_CA_INVENTORY, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_CA_INVENTORY - }, - { - "code": "1045", - "name": "Spare Parts Inventory", - "role": roles.ASSET_CA_INVENTORY, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1050", - "name": "Employee Advances", - "role": roles.ASSET_CA_RECEIVABLES, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1060", - "name": "Prepaid Expenses", - "role": roles.ASSET_CA_PREPAID, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_CA_PREPAID - }, - { - "code": "1070", - "name": "Notes Receivable", - "role": roles.ASSET_LTI_NOTES_RECEIVABLE, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_LTI_NOTES_RECEIVABLE - }, - # Fixed Assets (must also start with 1) - { - "code": "1110", - "name": "Lands", - "role": roles.ASSET_LTI_LAND, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_LTI_LAND - }, - { - "code": "1111", - "name": "Buildings", - "role": roles.ASSET_PPE_BUILDINGS, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_PPE_BUILDINGS - }, - { - "code": "1112", - "name": "Company Vehicles", - "role": roles.ASSET_PPE_EQUIPMENT, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_PPE_EQUIPMENT - }, - { - "code": "1113", - "name": "Equipment & Tools", - "role": roles.ASSET_PPE_EQUIPMENT, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1114", - "name": "Furniture & Fixtures", - "role": roles.ASSET_PPE_EQUIPMENT, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1115", - "name": "Other Fixed Assets", - "role": roles.ASSET_PPE_EQUIPMENT, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "1120", - "name": "Long-term Investments", - "role": roles.ASSET_LTI_SECURITIES, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_LTI_SECURITIES - }, - { - "code": "1130", - "name": "Intangible Assets", - "role": roles.ASSET_INTANGIBLE_ASSETS, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for ASSET_INTANGIBLE_ASSETS - }, - # Current Liabilities (must start with 2) - { - "code": "2010", - "name": "Accounts Payable", - "role": roles.LIABILITY_CL_ACC_PAYABLE, - "balance_type": roles.CREDIT, - "locked": True, - "default": True, # Default for LIABILITY_CL_ACC_PAYABLE - }, - { - "code": "2020", - "name": "Notes Payable", - "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for LIABILITY_CL_ST_NOTES_PAYABLE - }, - { - "code": "2030", - "name": "Short-term Loans", - "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - { - "code": "2040", - "name": "Employee Payables", - "role": roles.LIABILITY_CL_WAGES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for LIABILITY_CL_WAGES_PAYABLE - }, - { - "code": "2050", - "name": "Accrued Expenses", - "role": roles.LIABILITY_CL_OTHER, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for LIABILITY_CL_OTHER - }, - { - "code": "2060", - "name": "Accrued Taxes", - "role": roles.LIABILITY_CL_TAXES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, # Default for LIABILITY_CL_TAXES_PAYABLE - }, - { - "code": "2070", - "name": "Provisions", - "role": roles.LIABILITY_CL_OTHER, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - # Long-term Liabilities (must also start with 2) - { - "code": "2103", - "name": "Deferred Revenue", - "role": roles.LIABILITY_CL_DEFERRED_REVENUE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for LIABILITY_CL_DEFERRED_REVENUE - }, - { - "code": "2200", - "name": "Tax Payable", - "role": roles.LIABILITY_CL_TAXES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, - }, - { - "code": "2210", - "name": "Long-term Bank Loans", - "role": roles.LIABILITY_LTL_NOTES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for LIABILITY_LTL_NOTES_PAYABLE - }, - { - "code": "2220", - "name": "Lease Liabilities", - "role": roles.LIABILITY_LTL_NOTES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - { - "code": "2230", - "name": "Other Long-term Liabilities", - "role": roles.LIABILITY_LTL_NOTES_PAYABLE, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - # Equity (must start with 3) - { - "code": "3010", - "name": "Capital", - "role": roles.EQUITY_CAPITAL, - "balance_type": roles.CREDIT, - "locked": True, - "default": True, # Default for EQUITY_CAPITAL - }, - { - "code": "3020", - "name": "Statutory Reserve", - "role": roles.EQUITY_ADJUSTMENT, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for EQUITY_ADJUSTMENT - }, - { - "code": "3030", - "name": "Retained Earnings", - "role": roles.EQUITY_ADJUSTMENT, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - { - "code": "3040", - "name": "Profit & Loss for the Period", - "role": roles.EQUITY_ADJUSTMENT, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - # Revenue (must start with 4) - { - "code": "4010", - "name": "Car Sales", - "role": roles.INCOME_OPERATIONAL, - "balance_type": roles.CREDIT, - "locked": True, - "default": True, # Default for INCOME_OPERATIONAL - }, - { - "code": "4020", - "name": "After-Sales Services", - "role": roles.INCOME_OPERATIONAL, - "balance_type": roles.CREDIT, - "locked": False, - "default": False, - }, - { - "code": "4030", - "name": "Car Rental Income", - "role": roles.INCOME_PASSIVE, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for INCOME_PASSIVE - }, - { - "code": "4040", - "name": "Other Income", - "role": roles.INCOME_OTHER, - "balance_type": roles.CREDIT, - "locked": False, - "default": True, # Default for INCOME_OTHER - }, - # Expenses (must start with 5 for COGS, 6 for others) - { - "code": "5010", - "name": "Cost of Goods Sold", - "role": roles.COGS, - "balance_type": roles.DEBIT, - "locked": True, - "default": True, # Default for COGS - }, - { - "code": "5015", - "name": "Spare Parts Cost Consumed", - "role": roles.COGS, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6010", - "name": "Salaries & Wages", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for EXPENSE_OPERATIONAL - }, - { - "code": "6020", - "name": "Rent", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6030", - "name": "Utilities", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6040", - "name": "Advertising & Marketing", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6050", - "name": "Maintenance", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6060", - "name": "Operating Expenses", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6070", - "name": "Depreciation", - "role": roles.EXPENSE_DEPRECIATION, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for EXPENSE_DEPRECIATION - }, - { - "code": "6080", - "name": "Fees & Taxes", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6090", - "name": "Bank Charges", - "role": roles.EXPENSE_OPERATIONAL, - "balance_type": roles.DEBIT, - "locked": False, - "default": False, - }, - { - "code": "6100", - "name": "Other Expenses", - "role": roles.EXPENSE_OTHER, - "balance_type": roles.DEBIT, - "locked": False, - "default": True, # Default for EXPENSE_OTHER - }, - ] -def create_account(entity, coa, account_data): - try: - account = entity.create_account( - coa_model=coa, - code=account_data["code"], - name=account_data["name"], - role=account_data["role"], - balance_type=_(account_data["balance_type"]), - active=True, - ) - account.role_default = account_data["default"] - account.save() - logger.info(f"Created default account: {account}") - except Exception as e: - logger.error(f"Error creating default account: {account_data['code']}, {e}") -def create_coa_accounts(instance): +def create_coa_accounts(**kwargs): + logger.info("creating all accounts are created") + instance = Dealer.objects.get(pk=kwargs['dealer_pk']) entity = instance.entity coa = entity.get_default_coa() for account_data in get_accounts_data(): create_account(entity, coa, account_data) - # Check if all accounts are created - # check_create_coa_accounts(instance) -def check_create_coa_accounts(instance): - logger.info("Checking if all accounts are created") - entity = instance.entity - coa = entity.get_default_coa() - - for account_data in get_accounts_data(): - if entity.get_all_accounts().filter(code=account_data["code"]).exists(): - logger.info(f"Default account already exists: {account_data['code']}") - continue - logger.info(f"Default account does not exist: {account_data['code']}") - create_account(entity, coa, account_data) @@ -1345,4 +925,7 @@ def remove_reservation_by_id(reservation_id): reservation.car.save() reservation.delete() except Exception as e: - logger.error(f"Error removing reservation with ID {reservation_id}: {e}") \ No newline at end of file + logger.error(f"Error removing reservation with ID {reservation_id}: {e}") + +def test_task(instance): + print(instance.pk) \ No newline at end of file diff --git a/inventory/utils.py b/inventory/utils.py index a0868a04..dc87e04c 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -1922,3 +1922,416 @@ def handle_payment(request, order): # def get_user_quota(user): # return user.dealer.quota + + + +def get_accounts_data(): + return [ + # Current Assets (must start with 1) + { + "code": "1010", + "name": "Cash on Hand", + "role": roles.ASSET_CA_CASH, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_CA_CASH + }, + { + "code": "1020", + "name": "Bank", + "role": roles.ASSET_CA_CASH, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1030", + "name": "Accounts Receivable", + "role": roles.ASSET_CA_RECEIVABLES, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_CA_RECEIVABLES + }, + { + "code": "1040", + "name": "Inventory (Cars)", + "role": roles.ASSET_CA_INVENTORY, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_CA_INVENTORY + }, + { + "code": "1045", + "name": "Spare Parts Inventory", + "role": roles.ASSET_CA_INVENTORY, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1050", + "name": "Employee Advances", + "role": roles.ASSET_CA_RECEIVABLES, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1060", + "name": "Prepaid Expenses", + "role": roles.ASSET_CA_PREPAID, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_CA_PREPAID + }, + { + "code": "1070", + "name": "Notes Receivable", + "role": roles.ASSET_LTI_NOTES_RECEIVABLE, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_LTI_NOTES_RECEIVABLE + }, + # Fixed Assets (must also start with 1) + { + "code": "1110", + "name": "Lands", + "role": roles.ASSET_LTI_LAND, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_LTI_LAND + }, + { + "code": "1111", + "name": "Buildings", + "role": roles.ASSET_PPE_BUILDINGS, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_PPE_BUILDINGS + }, + { + "code": "1112", + "name": "Company Vehicles", + "role": roles.ASSET_PPE_EQUIPMENT, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_PPE_EQUIPMENT + }, + { + "code": "1113", + "name": "Equipment & Tools", + "role": roles.ASSET_PPE_EQUIPMENT, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1114", + "name": "Furniture & Fixtures", + "role": roles.ASSET_PPE_EQUIPMENT, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1115", + "name": "Other Fixed Assets", + "role": roles.ASSET_PPE_EQUIPMENT, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "1120", + "name": "Long-term Investments", + "role": roles.ASSET_LTI_SECURITIES, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_LTI_SECURITIES + }, + { + "code": "1130", + "name": "Intangible Assets", + "role": roles.ASSET_INTANGIBLE_ASSETS, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for ASSET_INTANGIBLE_ASSETS + }, + # Current Liabilities (must start with 2) + { + "code": "2010", + "name": "Accounts Payable", + "role": roles.LIABILITY_CL_ACC_PAYABLE, + "balance_type": roles.CREDIT, + "locked": True, + "default": True, # Default for LIABILITY_CL_ACC_PAYABLE + }, + { + "code": "2020", + "name": "Notes Payable", + "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for LIABILITY_CL_ST_NOTES_PAYABLE + }, + { + "code": "2030", + "name": "Short-term Loans", + "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + { + "code": "2040", + "name": "Employee Payables", + "role": roles.LIABILITY_CL_WAGES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for LIABILITY_CL_WAGES_PAYABLE + }, + { + "code": "2050", + "name": "Accrued Expenses", + "role": roles.LIABILITY_CL_OTHER, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for LIABILITY_CL_OTHER + }, + { + "code": "2060", + "name": "Accrued Taxes", + "role": roles.LIABILITY_CL_TAXES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, # Default for LIABILITY_CL_TAXES_PAYABLE + }, + { + "code": "2070", + "name": "Provisions", + "role": roles.LIABILITY_CL_OTHER, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + # Long-term Liabilities (must also start with 2) + { + "code": "2103", + "name": "Deferred Revenue", + "role": roles.LIABILITY_CL_DEFERRED_REVENUE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for LIABILITY_CL_DEFERRED_REVENUE + }, + { + "code": "2200", + "name": "Tax Payable", + "role": roles.LIABILITY_CL_TAXES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, + }, + { + "code": "2210", + "name": "Long-term Bank Loans", + "role": roles.LIABILITY_LTL_NOTES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for LIABILITY_LTL_NOTES_PAYABLE + }, + { + "code": "2220", + "name": "Lease Liabilities", + "role": roles.LIABILITY_LTL_NOTES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + { + "code": "2230", + "name": "Other Long-term Liabilities", + "role": roles.LIABILITY_LTL_NOTES_PAYABLE, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + # Equity (must start with 3) + { + "code": "3010", + "name": "Capital", + "role": roles.EQUITY_CAPITAL, + "balance_type": roles.CREDIT, + "locked": True, + "default": True, # Default for EQUITY_CAPITAL + }, + { + "code": "3020", + "name": "Statutory Reserve", + "role": roles.EQUITY_ADJUSTMENT, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for EQUITY_ADJUSTMENT + }, + { + "code": "3030", + "name": "Retained Earnings", + "role": roles.EQUITY_ADJUSTMENT, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + { + "code": "3040", + "name": "Profit & Loss for the Period", + "role": roles.EQUITY_ADJUSTMENT, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + # Revenue (must start with 4) + { + "code": "4010", + "name": "Car Sales", + "role": roles.INCOME_OPERATIONAL, + "balance_type": roles.CREDIT, + "locked": True, + "default": True, # Default for INCOME_OPERATIONAL + }, + { + "code": "4020", + "name": "After-Sales Services", + "role": roles.INCOME_OPERATIONAL, + "balance_type": roles.CREDIT, + "locked": False, + "default": False, + }, + { + "code": "4030", + "name": "Car Rental Income", + "role": roles.INCOME_PASSIVE, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for INCOME_PASSIVE + }, + { + "code": "4040", + "name": "Other Income", + "role": roles.INCOME_OTHER, + "balance_type": roles.CREDIT, + "locked": False, + "default": True, # Default for INCOME_OTHER + }, + # Expenses (must start with 5 for COGS, 6 for others) + { + "code": "5010", + "name": "Cost of Goods Sold", + "role": roles.COGS, + "balance_type": roles.DEBIT, + "locked": True, + "default": True, # Default for COGS + }, + { + "code": "5015", + "name": "Spare Parts Cost Consumed", + "role": roles.COGS, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6010", + "name": "Salaries & Wages", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for EXPENSE_OPERATIONAL + }, + { + "code": "6020", + "name": "Rent", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6030", + "name": "Utilities", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6040", + "name": "Advertising & Marketing", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6050", + "name": "Maintenance", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6060", + "name": "Operating Expenses", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6070", + "name": "Depreciation", + "role": roles.EXPENSE_DEPRECIATION, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for EXPENSE_DEPRECIATION + }, + { + "code": "6080", + "name": "Fees & Taxes", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6090", + "name": "Bank Charges", + "role": roles.EXPENSE_OPERATIONAL, + "balance_type": roles.DEBIT, + "locked": False, + "default": False, + }, + { + "code": "6100", + "name": "Other Expenses", + "role": roles.EXPENSE_OTHER, + "balance_type": roles.DEBIT, + "locked": False, + "default": True, # Default for EXPENSE_OTHER + }, + ] + +def create_account(entity, coa, account_data): + try: + account = entity.create_account( + coa_model=coa, + code=account_data["code"], + name=account_data["name"], + role=account_data["role"], + balance_type=_(account_data["balance_type"]), + active=True, + ) + account.role_default = account_data["default"] + account.save() + logger.info(f"Created default account: {account}") + except Exception as e: + logger.error(f"Error creating default account: {account_data['code']}, {e}") \ No newline at end of file