update
This commit is contained in:
parent
05b18e9da3
commit
a079ceec6d
@ -6,17 +6,64 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_create_coa_accounts(task):
|
||||
logger.info("Checking if all accounts are created")
|
||||
instance = task.kwargs["dealer"]
|
||||
entity = instance.entity
|
||||
coa = entity.get_default_coa()
|
||||
"""
|
||||
Hook to verify account creation and handle failures
|
||||
"""
|
||||
if task.success:
|
||||
logger.info("Account creation task completed successfully")
|
||||
return
|
||||
|
||||
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)
|
||||
logger.warning("Account creation task failed, checking status...")
|
||||
|
||||
try:
|
||||
dealer_id = task.kwargs.get('dealer_id')
|
||||
if not dealer_id:
|
||||
logger.error("No dealer_id in task kwargs")
|
||||
return
|
||||
|
||||
from .models import Dealer
|
||||
instance = Dealer.objects.select_related('entity').get(id=dealer_id)
|
||||
entity = instance.entity
|
||||
|
||||
if not entity:
|
||||
logger.error(f"No entity for dealer {dealer_id}")
|
||||
return
|
||||
|
||||
coa = entity.get_default_coa()
|
||||
if not coa:
|
||||
logger.error(f"No COA for entity {entity.id}")
|
||||
return
|
||||
|
||||
# Check which accounts are missing and create them
|
||||
from .utils import get_accounts_data, create_account
|
||||
|
||||
missing_accounts = []
|
||||
for account_data in get_accounts_data():
|
||||
if not entity.get_all_accounts().filter(code=account_data["code"]).exists():
|
||||
missing_accounts.append(account_data)
|
||||
logger.info(f"Missing account: {account_data['code']}")
|
||||
|
||||
if missing_accounts:
|
||||
logger.info(f"Creating {len(missing_accounts)} missing accounts")
|
||||
for account_data in missing_accounts:
|
||||
create_account(entity, coa, account_data)
|
||||
else:
|
||||
logger.info("All accounts are already created")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in check_create_coa_accounts hook: {e}")
|
||||
# def check_create_coa_accounts(task):
|
||||
# logger.info("Checking if all accounts are created")
|
||||
# instance = task.kwargs["dealer"]
|
||||
# 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):
|
||||
|
||||
@ -685,7 +685,7 @@ class Car(Base):
|
||||
)
|
||||
#
|
||||
additional_services = models.ManyToManyField(
|
||||
AdditionalServices, related_name="additionals", blank=True, null=True
|
||||
AdditionalServices, related_name="additionals"
|
||||
)
|
||||
cost_price = models.DecimalField(
|
||||
max_digits=14,
|
||||
|
||||
@ -135,55 +135,101 @@ def create_car_location(sender, instance, created, **kwargs):
|
||||
print(f"Failed to create CarLocation for car {instance.vin}: {e}")
|
||||
|
||||
|
||||
# Create Entity
|
||||
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal handler for creating ledger entities and initializing accounts for a new Dealer instance upon creation.
|
||||
|
||||
This signal is triggered when a new Dealer instance is saved to the database. It performs the following actions:
|
||||
1. Creates a ledger entity for the Dealer with necessary configurations.
|
||||
2. Generates a chart of accounts (COA) for the entity and assigns it as the default.
|
||||
3. Creates predefined unit of measures (UOMs) related to the entity.
|
||||
4. Initializes and assigns default accounts under various roles (e.g., assets, liabilities) for the entity with their
|
||||
respective configurations (e.g., account code, balance type).
|
||||
|
||||
This function ensures all necessary financial records and accounts are set up when a new Dealer is added, preparing the
|
||||
system for future financial transactions and accounting operations.
|
||||
|
||||
:param sender: The model class that sent the signal (in this case, Dealer).
|
||||
:param instance: The instance of the model being saved.
|
||||
:param created: A boolean indicating whether a new record was created.
|
||||
:param kwargs: Additional keyword arguments passed by the signal.
|
||||
:return: None
|
||||
"""
|
||||
if created:
|
||||
entity_name = instance.user.dealer.name
|
||||
entity = EntityModel.create_entity(
|
||||
name=entity_name,
|
||||
admin=instance.user,
|
||||
use_accrual_method=True,
|
||||
fy_start_month=1,
|
||||
)
|
||||
try:
|
||||
# Use transaction to ensure atomicity
|
||||
with transaction.atomic():
|
||||
entity_name = instance.user.dealer.name
|
||||
entity = EntityModel.create_entity(
|
||||
name=entity_name,
|
||||
admin=instance.user,
|
||||
use_accrual_method=True,
|
||||
fy_start_month=1,
|
||||
)
|
||||
|
||||
if entity:
|
||||
instance.entity = entity
|
||||
instance.save()
|
||||
coa = entity.create_chart_of_accounts(
|
||||
assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
|
||||
)
|
||||
if coa:
|
||||
# Create unit of measures
|
||||
entity.create_uom(name="Unit", unit_abbr="unit")
|
||||
for u in models.UnitOfMeasure.choices:
|
||||
entity.create_uom(name=u[1], unit_abbr=u[0])
|
||||
if entity:
|
||||
instance.entity = entity
|
||||
instance.save(update_fields=['entity'])
|
||||
|
||||
# Create COA accounts, background task
|
||||
# Create COA synchronously first
|
||||
coa = entity.create_chart_of_accounts(
|
||||
assign_as_default=True, commit=True,
|
||||
coa_name=_(f"{entity_name}-COA")
|
||||
)
|
||||
|
||||
if coa:
|
||||
# Create essential UOMs synchronously
|
||||
entity.create_uom(name="Unit", unit_abbr="unit")
|
||||
|
||||
# Schedule async task after successful synchronous operations
|
||||
async_task(
|
||||
func="inventory.tasks.create_coa_accounts",
|
||||
dealer=instance,
|
||||
dealer_id=instance.id, # Pass ID instead of object
|
||||
hook="inventory.hooks.check_create_coa_accounts",
|
||||
ack_failure=True, # Ensure task failures are acknowledged
|
||||
sync=False # Explicitly set to async
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create ledger entity for dealer {instance.id}: {e}")
|
||||
# Schedule retry task
|
||||
async_task(
|
||||
func="inventory.tasks.retry_entity_creation",
|
||||
dealer_id=instance.id,
|
||||
retry_count=0
|
||||
)
|
||||
# Create Entity
|
||||
# @receiver(post_save, sender=models.Dealer)
|
||||
# def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
# """
|
||||
# Signal handler for creating ledger entities and initializing accounts for a new Dealer instance upon creation.
|
||||
|
||||
# This signal is triggered when a new Dealer instance is saved to the database. It performs the following actions:
|
||||
# 1. Creates a ledger entity for the Dealer with necessary configurations.
|
||||
# 2. Generates a chart of accounts (COA) for the entity and assigns it as the default.
|
||||
# 3. Creates predefined unit of measures (UOMs) related to the entity.
|
||||
# 4. Initializes and assigns default accounts under various roles (e.g., assets, liabilities) for the entity with their
|
||||
# respective configurations (e.g., account code, balance type).
|
||||
|
||||
# This function ensures all necessary financial records and accounts are set up when a new Dealer is added, preparing the
|
||||
# system for future financial transactions and accounting operations.
|
||||
|
||||
# :param sender: The model class that sent the signal (in this case, Dealer).
|
||||
# :param instance: The instance of the model being saved.
|
||||
# :param created: A boolean indicating whether a new record was created.
|
||||
# :param kwargs: Additional keyword arguments passed by the signal.
|
||||
# :return: None
|
||||
# """
|
||||
# if created:
|
||||
# entity_name = instance.user.dealer.name
|
||||
# entity = EntityModel.create_entity(
|
||||
# name=entity_name,
|
||||
# admin=instance.user,
|
||||
# use_accrual_method=True,
|
||||
# fy_start_month=1,
|
||||
# )
|
||||
|
||||
# if entity:
|
||||
# instance.entity = entity
|
||||
# instance.save()
|
||||
# coa = entity.create_chart_of_accounts(
|
||||
# assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
|
||||
# )
|
||||
# if coa:
|
||||
# # Create unit of measures
|
||||
# entity.create_uom(name="Unit", unit_abbr="unit")
|
||||
# for u in models.UnitOfMeasure.choices:
|
||||
# entity.create_uom(name=u[1], unit_abbr=u[0])
|
||||
|
||||
# # Create COA accounts, background task
|
||||
# async_task(
|
||||
# func="inventory.tasks.create_coa_accounts",
|
||||
# dealer=instance,
|
||||
# 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)
|
||||
|
||||
@ -62,14 +62,117 @@ def create_settings(pk):
|
||||
)
|
||||
|
||||
|
||||
def create_coa_accounts(**kwargs):
|
||||
logger.info("creating all accounts are created")
|
||||
instance = kwargs.get("dealer")
|
||||
entity = instance.entity
|
||||
coa = entity.get_default_coa()
|
||||
def create_coa_accounts(dealer_id, **kwargs):
|
||||
"""
|
||||
Create COA accounts with retry logic and proper error handling
|
||||
"""
|
||||
from .models import Dealer
|
||||
from .utils import create_account, get_accounts_data
|
||||
|
||||
for account_data in get_accounts_data():
|
||||
create_account(entity, coa, account_data)
|
||||
max_retries = 3
|
||||
retry_delay = 2 # seconds
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
logger.info(f"Attempt {attempt + 1} to create accounts for dealer {dealer_id}")
|
||||
|
||||
# Get fresh instance from database
|
||||
instance = Dealer.objects.select_related('entity').get(id=dealer_id)
|
||||
entity = instance.entity
|
||||
|
||||
if not entity:
|
||||
logger.error(f"No entity found for dealer {dealer_id}")
|
||||
return False
|
||||
|
||||
coa = entity.get_default_coa()
|
||||
|
||||
if not coa:
|
||||
logger.error(f"No COA found for entity {entity.id}")
|
||||
return False
|
||||
|
||||
logger.info("Creating default accounts")
|
||||
accounts_created = 0
|
||||
|
||||
with transaction.atomic():
|
||||
for account_data in get_accounts_data():
|
||||
logger.info(f"Creating account: {account_data['code']}")
|
||||
if create_account(entity, coa, account_data):
|
||||
accounts_created += 1
|
||||
|
||||
logger.info(f"Successfully created {accounts_created} accounts")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Attempt {attempt + 1} failed: {e}")
|
||||
|
||||
if attempt < max_retries - 1:
|
||||
logger.info(f"Retrying in {retry_delay} seconds...")
|
||||
time.sleep(retry_delay * (attempt + 1)) # Exponential backoff
|
||||
else:
|
||||
logger.error(f"All {max_retries} attempts failed for dealer {dealer_id}")
|
||||
# Schedule a cleanup or notification task
|
||||
async_task(
|
||||
"inventory.tasks.handle_account_creation_failure",
|
||||
dealer_id=dealer_id,
|
||||
error=str(e)
|
||||
)
|
||||
return False
|
||||
|
||||
def retry_entity_creation(dealer_id, retry_count=0):
|
||||
"""
|
||||
Retry entity creation if initial attempt failed
|
||||
"""
|
||||
from .models import Dealer
|
||||
from yourapp.models import EntityModel
|
||||
|
||||
max_retries = 3
|
||||
|
||||
if retry_count >= max_retries:
|
||||
logger.error(f"Max retries reached for dealer {dealer_id}")
|
||||
return
|
||||
|
||||
try:
|
||||
instance = Dealer.objects.get(id=dealer_id)
|
||||
if not instance.entity:
|
||||
# Retry entity creation
|
||||
entity_name = instance.user.dealer.name
|
||||
entity = EntityModel.create_entity(
|
||||
name=entity_name,
|
||||
admin=instance.user,
|
||||
use_accrual_method=True,
|
||||
fy_start_month=1,
|
||||
)
|
||||
|
||||
if entity:
|
||||
instance.entity = entity
|
||||
instance.save()
|
||||
logger.info(f"Successfully created entity on retry {retry_count + 1}")
|
||||
|
||||
# Now trigger account creation
|
||||
async_task(
|
||||
"inventory.tasks.create_coa_accounts",
|
||||
dealer_id=dealer_id
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Retry {retry_count + 1} failed: {e}")
|
||||
# Schedule another retry
|
||||
async_task(
|
||||
"inventory.tasks.retry_entity_creation",
|
||||
dealer_id=dealer_id,
|
||||
retry_count=retry_count + 1
|
||||
)
|
||||
# def create_coa_accounts(**kwargs):
|
||||
# logger.info("creating all accounts are created")
|
||||
# instance = kwargs.get("dealer")
|
||||
# logger.info(f"Dealer Instance : {instance}")
|
||||
# entity = instance.entity
|
||||
# coa = entity.get_default_coa()
|
||||
|
||||
# logger.info("Creating default accounts")
|
||||
# for account_data in get_accounts_data():
|
||||
# logger.info(f"Creating account: {account_data['code']}")
|
||||
# create_account(entity, coa, account_data)
|
||||
|
||||
|
||||
# def create_coa_accounts1(pk):
|
||||
|
||||
@ -15,6 +15,7 @@ from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from django_ledger.io import roles
|
||||
from django.contrib import messages
|
||||
from django.db import IntegrityError
|
||||
from django.shortcuts import redirect
|
||||
from django_q.tasks import async_task
|
||||
from django.core.mail import send_mail
|
||||
@ -2386,7 +2387,19 @@ def get_accounts_data():
|
||||
|
||||
|
||||
def create_account(entity, coa, account_data):
|
||||
"""
|
||||
Create account with proper validation and error handling
|
||||
"""
|
||||
try:
|
||||
# Check if account already exists
|
||||
existing_account = entity.get_all_accounts().filter(
|
||||
code=account_data["code"]
|
||||
).first()
|
||||
|
||||
if existing_account:
|
||||
logger.info(f"Account already exists: {account_data['code']}")
|
||||
return True
|
||||
|
||||
account = entity.create_account(
|
||||
coa_model=coa,
|
||||
code=account_data["code"],
|
||||
@ -2395,11 +2408,37 @@ def create_account(entity, coa, account_data):
|
||||
balance_type=_(account_data["balance_type"]),
|
||||
active=True,
|
||||
)
|
||||
account.role_default = account_data["default"]
|
||||
account.save()
|
||||
logger.info(f"Created default account: {account}")
|
||||
|
||||
if account:
|
||||
account.role_default = account_data["default"]
|
||||
account.save()
|
||||
logger.info(f"Successfully created account: {account_data['code']}")
|
||||
return True
|
||||
|
||||
except IntegrityError:
|
||||
logger.warning(f"Account {account_data['code']} already exists (IntegrityError)")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating default account: {account_data['code']}, {e}")
|
||||
logger.error(f"Error creating account {account_data['code']}: {e}")
|
||||
return False
|
||||
|
||||
return False
|
||||
# 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,
|
||||
# )
|
||||
# logger.info(f"Created account: {account}")
|
||||
# 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 get_or_generate_car_image(car):
|
||||
|
||||
@ -63,7 +63,7 @@ EditorConfig==0.17.1
|
||||
Faker==37.4.0
|
||||
fleming==0.7.0
|
||||
fonttools==4.58.5
|
||||
fpdf==1.7.2
|
||||
# fpdf==1.7.2
|
||||
fpdf2==2.8.3
|
||||
greenlet==3.2.3
|
||||
gunicorn==23.0.0
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 493 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 470 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 450 KiB |
Loading…
x
Reference in New Issue
Block a user