Compare commits
No commits in common. "ee8d8cf2878e85b27251d7c3b011da480aede93e" and "86792930f0447a253e9f4693f4805c567cb50998" have entirely different histories.
ee8d8cf287
...
86792930f0
@ -6,64 +6,17 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def check_create_coa_accounts(task):
|
def check_create_coa_accounts(task):
|
||||||
"""
|
logger.info("Checking if all accounts are created")
|
||||||
Hook to verify account creation and handle failures
|
instance = task.kwargs["dealer"]
|
||||||
"""
|
entity = instance.entity
|
||||||
if task.success:
|
coa = entity.get_default_coa()
|
||||||
logger.info("Account creation task completed successfully")
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.warning("Account creation task failed, checking status...")
|
for account_data in get_accounts_data():
|
||||||
|
if entity.get_all_accounts().filter(code=account_data["code"]).exists():
|
||||||
try:
|
logger.info(f"Default account already exists: {account_data['code']}")
|
||||||
dealer_id = task.kwargs.get('dealer_id')
|
continue
|
||||||
if not dealer_id:
|
logger.info(f"Default account does not exist: {account_data['code']}")
|
||||||
logger.error("No dealer_id in task kwargs")
|
create_account(entity, coa, account_data)
|
||||||
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):
|
def print_results(task):
|
||||||
|
|||||||
@ -685,7 +685,7 @@ class Car(Base):
|
|||||||
)
|
)
|
||||||
#
|
#
|
||||||
additional_services = models.ManyToManyField(
|
additional_services = models.ManyToManyField(
|
||||||
AdditionalServices, related_name="additionals"
|
AdditionalServices, related_name="additionals", blank=True, null=True
|
||||||
)
|
)
|
||||||
cost_price = models.DecimalField(
|
cost_price = models.DecimalField(
|
||||||
max_digits=14,
|
max_digits=14,
|
||||||
@ -3307,7 +3307,6 @@ class CustomGroup(models.Model):
|
|||||||
"payment",
|
"payment",
|
||||||
"vendor",
|
"vendor",
|
||||||
"additionalservices",
|
"additionalservices",
|
||||||
'customer'
|
|
||||||
],
|
],
|
||||||
other_perms=[
|
other_perms=[
|
||||||
"view_car",
|
"view_car",
|
||||||
|
|||||||
@ -135,101 +135,55 @@ def create_car_location(sender, instance, created, **kwargs):
|
|||||||
print(f"Failed to create CarLocation for car {instance.vin}: {e}")
|
print(f"Failed to create CarLocation for car {instance.vin}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# Create Entity
|
||||||
@receiver(post_save, sender=models.Dealer)
|
@receiver(post_save, sender=models.Dealer)
|
||||||
def create_ledger_entity(sender, instance, created, **kwargs):
|
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:
|
if created:
|
||||||
try:
|
entity_name = instance.user.dealer.name
|
||||||
# Use transaction to ensure atomicity
|
entity = EntityModel.create_entity(
|
||||||
with transaction.atomic():
|
name=entity_name,
|
||||||
entity_name = instance.user.dealer.name
|
admin=instance.user,
|
||||||
entity = EntityModel.create_entity(
|
use_accrual_method=True,
|
||||||
name=entity_name,
|
fy_start_month=1,
|
||||||
admin=instance.user,
|
)
|
||||||
use_accrual_method=True,
|
|
||||||
fy_start_month=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
if entity:
|
if entity:
|
||||||
instance.entity = entity
|
instance.entity = entity
|
||||||
instance.save(update_fields=['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 synchronously first
|
# Create COA accounts, background task
|
||||||
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(
|
async_task(
|
||||||
func="inventory.tasks.create_coa_accounts",
|
func="inventory.tasks.create_coa_accounts",
|
||||||
dealer_id=instance.id, # Pass ID instead of object
|
dealer=instance,
|
||||||
hook="inventory.hooks.check_create_coa_accounts",
|
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))
|
# async_task('inventory.tasks.check_create_coa_accounts', instance, schedule_type='O', schedule_time=timedelta(seconds=20))
|
||||||
|
|
||||||
# create_settings(instance.pk)
|
# create_settings(instance.pk)
|
||||||
|
|||||||
@ -62,117 +62,14 @@ def create_settings(pk):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_coa_accounts(dealer_id, **kwargs):
|
def create_coa_accounts(**kwargs):
|
||||||
"""
|
logger.info("creating all accounts are created")
|
||||||
Create COA accounts with retry logic and proper error handling
|
instance = kwargs.get("dealer")
|
||||||
"""
|
entity = instance.entity
|
||||||
from .models import Dealer
|
coa = entity.get_default_coa()
|
||||||
from .utils import create_account, get_accounts_data
|
|
||||||
|
|
||||||
max_retries = 3
|
for account_data in get_accounts_data():
|
||||||
retry_delay = 2 # seconds
|
create_account(entity, coa, account_data)
|
||||||
|
|
||||||
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):
|
# def create_coa_accounts1(pk):
|
||||||
|
|||||||
@ -494,13 +494,8 @@ def po_item_formset_table(context, po_model, itemtxs_formset, user):
|
|||||||
@register.inclusion_tag("bill/tags/bill_item_formset.html", takes_context=True)
|
@register.inclusion_tag("bill/tags/bill_item_formset.html", takes_context=True)
|
||||||
def bill_item_formset_table(context, item_formset):
|
def bill_item_formset_table(context, item_formset):
|
||||||
bill = BillModel.objects.get(uuid=context["view"].kwargs["bill_pk"])
|
bill = BillModel.objects.get(uuid=context["view"].kwargs["bill_pk"])
|
||||||
for form in item_formset.forms:
|
|
||||||
form.fields["item_model"].queryset = form.fields["item_model"].queryset.exclude(
|
|
||||||
item_role="product"
|
|
||||||
)
|
|
||||||
for item in item_formset:
|
for item in item_formset:
|
||||||
if item:
|
if item:
|
||||||
print(item.fields["item_model"])
|
|
||||||
item.initial["quantity"] = item.instance.po_quantity
|
item.initial["quantity"] = item.instance.po_quantity
|
||||||
item.initial["unit_cost"] = item.instance.po_unit_cost
|
item.initial["unit_cost"] = item.instance.po_unit_cost
|
||||||
# print(item.instance.po_quantity)
|
# print(item.instance.po_quantity)
|
||||||
|
|||||||
@ -15,7 +15,6 @@ from django.utils import timezone
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django_ledger.io import roles
|
from django_ledger.io import roles
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import IntegrityError
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django_q.tasks import async_task
|
from django_q.tasks import async_task
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
@ -2387,19 +2386,7 @@ def get_accounts_data():
|
|||||||
|
|
||||||
|
|
||||||
def create_account(entity, coa, account_data):
|
def create_account(entity, coa, account_data):
|
||||||
"""
|
|
||||||
Create account with proper validation and error handling
|
|
||||||
"""
|
|
||||||
try:
|
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(
|
account = entity.create_account(
|
||||||
coa_model=coa,
|
coa_model=coa,
|
||||||
code=account_data["code"],
|
code=account_data["code"],
|
||||||
@ -2408,37 +2395,11 @@ def create_account(entity, coa, account_data):
|
|||||||
balance_type=_(account_data["balance_type"]),
|
balance_type=_(account_data["balance_type"]),
|
||||||
active=True,
|
active=True,
|
||||||
)
|
)
|
||||||
|
account.role_default = account_data["default"]
|
||||||
if account:
|
account.save()
|
||||||
account.role_default = account_data["default"]
|
logger.info(f"Created default account: {account}")
|
||||||
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:
|
except Exception as e:
|
||||||
logger.error(f"Error creating account {account_data['code']}: {e}")
|
logger.error(f"Error creating default 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):
|
def get_or_generate_car_image(car):
|
||||||
@ -2503,9 +2464,9 @@ def force_regenerate_car_image(car):
|
|||||||
class CarImageAPIClient:
|
class CarImageAPIClient:
|
||||||
"""Simple client to handle authenticated requests to the car image API"""
|
"""Simple client to handle authenticated requests to the car image API"""
|
||||||
|
|
||||||
BASE_URL = settings.TENHAL_IMAGE_GENERATOR_URL
|
BASE_URL = "http://10.10.1.111:8888"
|
||||||
USERNAME = settings.TENHAL_IMAGE_GENERATOR_USERNAME
|
USERNAME = "faheed"
|
||||||
PASSWORD = settings.TENHAL_IMAGE_GENERATOR_PASSWORD
|
PASSWORD = "Tenhal@123"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.session = None
|
self.session = None
|
||||||
@ -2568,7 +2529,7 @@ class CarImageAPIClient:
|
|||||||
"make": payload["make"],
|
"make": payload["make"],
|
||||||
"model": payload["model"],
|
"model": payload["model"],
|
||||||
"exterior_color": payload["color"],
|
"exterior_color": payload["color"],
|
||||||
"angle": "front three-quarter",
|
"angle": "3/4 rear",
|
||||||
"reference_image": "",
|
"reference_image": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,156 +1,132 @@
|
|||||||
annotated-types==0.7.0
|
annotated-types
|
||||||
anyio==4.9.0
|
anyio
|
||||||
arrow==1.3.0
|
arrow
|
||||||
asgiref==3.9.1
|
asgiref
|
||||||
attrs==25.3.0
|
attrs
|
||||||
autobahn==24.4.2
|
Babel
|
||||||
Automat==25.4.16
|
beautifulsoup4
|
||||||
Babel==2.15.0
|
blessed
|
||||||
beautifulsoup4==4.13.4
|
cattrs
|
||||||
blessed==1.21.0
|
certifi
|
||||||
cattrs==25.1.1
|
cffi
|
||||||
certifi==2025.7.9
|
charset-normalizer
|
||||||
cffi==1.17.1
|
click
|
||||||
channels==4.2.2
|
colorama
|
||||||
charset-normalizer==3.4.2
|
crispy-bootstrap5
|
||||||
click==8.2.1
|
cryptography
|
||||||
colorama==0.4.6
|
cssbeautifier
|
||||||
constantly==23.10.4
|
defusedxml
|
||||||
crispy-bootstrap5==2025.6
|
diff-match-patch
|
||||||
cryptography==45.0.5
|
distro
|
||||||
cssbeautifier==1.15.4
|
Django
|
||||||
daphne==4.2.1
|
django-allauth
|
||||||
defusedxml==0.7.1
|
django-appconf
|
||||||
diff-match-patch==20241021
|
django-appointment
|
||||||
distro==1.9.0
|
django-background-tasks
|
||||||
Django==5.2.4
|
django-bootstrap5
|
||||||
django-allauth==65.10.0
|
django-ckeditor
|
||||||
django-appconf==1.1.0
|
django-cors-headers
|
||||||
django-appointment==3.8.0
|
django-countries
|
||||||
django-background-tasks==1.2.8
|
django-crispy-forms
|
||||||
django-bootstrap5==25.1
|
django-debug-toolbar
|
||||||
django-ckeditor==6.7.3
|
django-easy-audit
|
||||||
django-cors-headers==4.7.0
|
django-extensions
|
||||||
django-countries==7.6.1
|
django-filter
|
||||||
django-crispy-forms==2.4
|
django-imagekit
|
||||||
django-debug-toolbar==5.2.0
|
django-import-export
|
||||||
django-easy-audit==1.3.7
|
django-js-asset
|
||||||
django-extensions==4.1
|
django-ledger
|
||||||
django-filter==25.1
|
django-manager-utils
|
||||||
django-imagekit==5.0.0
|
django-next-url-mixin
|
||||||
django-import-export==4.3.8
|
django-ordered-model
|
||||||
django-js-asset==3.1.2
|
django-phonenumber-field
|
||||||
django-ledger==0.7.6.1
|
django-picklefield
|
||||||
django-manager-utils==3.1.5
|
django-plans
|
||||||
django-next-url-mixin==0.4.0
|
django-q2
|
||||||
django-ordered-model==3.7.4
|
django-query-builder
|
||||||
django-phonenumber-field==8.0.0
|
django-schema-graph
|
||||||
django-picklefield==3.3
|
django-sequences
|
||||||
django-plans==2.0.0
|
django-tables2
|
||||||
django-prometheus==2.4.1
|
django-treebeard
|
||||||
django-q2==1.8.0
|
django-widget-tweaks
|
||||||
django-query-builder==3.2.0
|
djangorestframework
|
||||||
django-schema-graph==3.1.0
|
djhtml
|
||||||
django-sequences==3.0
|
djlint
|
||||||
django-tables2==2.7.5
|
docopt
|
||||||
django-treebeard==4.7.1
|
EditorConfig
|
||||||
django-widget-tweaks==1.5.0
|
Faker
|
||||||
djangorestframework==3.16.0
|
fleming
|
||||||
djhtml==3.0.8
|
fonttools
|
||||||
djlint==1.36.4
|
fpdf
|
||||||
docopt==0.6.2
|
fpdf2
|
||||||
EditorConfig==0.17.1
|
greenlet
|
||||||
Faker==37.4.0
|
h11
|
||||||
fleming==0.7.0
|
httpcore
|
||||||
fonttools==4.58.5
|
httpx
|
||||||
# fpdf==1.7.2
|
icalendar
|
||||||
fpdf2==2.8.3
|
idna
|
||||||
greenlet==3.2.3
|
jiter
|
||||||
gunicorn==23.0.0
|
jsbeautifier
|
||||||
h11==0.16.0
|
json5
|
||||||
h2==4.2.0
|
jsonpatch
|
||||||
hpack==4.1.0
|
jsonpointer
|
||||||
httpcore==1.0.9
|
jwt
|
||||||
httpx==0.28.1
|
langchain
|
||||||
hyperframe==6.1.0
|
langchain-core
|
||||||
hyperlink==21.0.0
|
langchain-ollama
|
||||||
icalendar==6.3.1
|
langchain-text-splitters
|
||||||
idna==3.10
|
langsmith
|
||||||
incremental==24.7.2
|
luhnchecker
|
||||||
jiter==0.10.0
|
Markdown
|
||||||
jsbeautifier==1.15.4
|
markdown-it-py
|
||||||
json5==0.12.0
|
mdurl
|
||||||
jsonpatch==1.33
|
num2words
|
||||||
jsonpointer==3.0.0
|
numpy
|
||||||
jwt==1.4.0
|
ofxtools
|
||||||
langchain==0.3.26
|
ollama
|
||||||
langchain-core==0.3.68
|
openai
|
||||||
langchain-ollama==0.3.4
|
opencv-python
|
||||||
langchain-text-splitters==0.3.8
|
orjson
|
||||||
langsmith==0.4.4
|
packaging
|
||||||
luhnchecker==0.0.12
|
pandas
|
||||||
Markdown==3.8.2
|
pathspec
|
||||||
markdown-it-py==3.0.0
|
phonenumbers
|
||||||
mdurl==0.1.2
|
pilkit
|
||||||
num2words==0.5.14
|
pillow
|
||||||
numpy==2.3.1
|
psycopg2-binary
|
||||||
ofxtools==0.9.5
|
pycparser
|
||||||
ollama==0.5.1
|
pydantic
|
||||||
openai==1.93.3
|
pydantic_core
|
||||||
opencv-python==4.11.0.86
|
Pygments
|
||||||
orjson==3.10.18
|
python-dateutil
|
||||||
packaging==24.2
|
python-slugify
|
||||||
pandas==2.3.1
|
python-stdnum
|
||||||
pathspec==0.12.1
|
pytz
|
||||||
phonenumbers==8.13.42
|
pyvin
|
||||||
pilkit==3.0
|
PyYAML
|
||||||
pillow==10.4.0
|
pyzbar
|
||||||
priority==1.3.0
|
redis
|
||||||
prometheus_client==0.22.1
|
regex
|
||||||
psycopg2-binary==2.9.10
|
requests
|
||||||
pyasn1==0.6.1
|
requests-toolbelt
|
||||||
pyasn1_modules==0.4.2
|
rich
|
||||||
pycparser==2.22
|
ruff
|
||||||
pydantic==2.11.7
|
setuptools
|
||||||
pydantic_core==2.33.2
|
six
|
||||||
Pygments==2.19.2
|
sniffio
|
||||||
pyOpenSSL==25.1.0
|
soupsieve
|
||||||
python-dateutil==2.9.0.post0
|
SQLAlchemy
|
||||||
python-dotenv==1.1.1
|
sqlparse
|
||||||
python-slugify==8.0.4
|
suds
|
||||||
python-stdnum==2.1
|
swapper
|
||||||
pytz==2025.2
|
tablib
|
||||||
pyvin==0.0.2
|
tenacity
|
||||||
PyYAML==6.0.2
|
text-unidecode
|
||||||
pyzbar==0.1.9
|
tqdm
|
||||||
redis==6.2.0
|
types-python-dateutil
|
||||||
regex==2024.11.6
|
typing-inspection
|
||||||
requests==2.32.4
|
typing_extensions
|
||||||
requests-toolbelt==1.0.0
|
tzdata
|
||||||
rich==14.0.0
|
urllib3
|
||||||
ruff==0.12.2
|
wcwidth
|
||||||
service-identity==24.2.0
|
zstandard
|
||||||
setuptools==80.9.0
|
|
||||||
six==1.17.0
|
|
||||||
sniffio==1.3.1
|
|
||||||
soupsieve==2.7
|
|
||||||
SQLAlchemy==2.0.41
|
|
||||||
sqlparse==0.5.3
|
|
||||||
suds==1.2.0
|
|
||||||
swapper==1.3.0
|
|
||||||
tablib==3.8.0
|
|
||||||
tenacity==9.1.2
|
|
||||||
text-unidecode==1.3
|
|
||||||
tqdm==4.67.1
|
|
||||||
Twisted==25.5.0
|
|
||||||
txaio==25.6.1
|
|
||||||
types-python-dateutil==2.9.0.20250708
|
|
||||||
typing-inspection==0.4.1
|
|
||||||
typing_extensions==4.14.1
|
|
||||||
tzdata==2025.2
|
|
||||||
urllib3==2.5.0
|
|
||||||
uvicorn==0.35.0
|
|
||||||
uvicorn-worker==0.3.0
|
|
||||||
wcwidth==0.2.13
|
|
||||||
zope.interface==7.2
|
|
||||||
zstandard==0.23.0
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 493 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 470 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 418 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 450 KiB |
@ -2,9 +2,19 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load django_ledger %}
|
{% load django_ledger %}
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
{% if bill.get_itemtxs_data.1.total_amount__sum > 0 %}
|
||||||
<form id="bill-update-form"
|
<form id="bill-update-form"
|
||||||
action="{% url 'bill-update-items' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill_pk %}"
|
action="{% url 'bill-update-items' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill_pk %}"
|
||||||
method="post">
|
method="post">
|
||||||
|
{% else %}
|
||||||
|
<form id="bill-update-form"
|
||||||
|
hx-trigger="load delay:300ms"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#bill-update-form"
|
||||||
|
hx-select="#bill-update-form"
|
||||||
|
hx-post="{% url 'bill-update-items' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill_pk %}"
|
||||||
|
method="post">
|
||||||
|
{% endif %}
|
||||||
<div class="container-fluid py-4">
|
<div class="container-fluid py-4">
|
||||||
<!-- Page Header -->
|
<!-- Page Header -->
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
@ -115,13 +125,13 @@
|
|||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="d-flex justify-content-start gap-2">
|
<div class="d-flex justify-content-start gap-2">
|
||||||
{% comment %} {% if not item_formset.has_po %}
|
{% if not item_formset.has_po %}
|
||||||
<a href="{% url 'django_ledger:product-create' entity_slug=entity_slug %}"
|
<a href="{% url 'django_ledger:product-create' entity_slug=entity_slug %}"
|
||||||
class="btn btn-phoenix-primary">
|
class="btn btn-phoenix-primary">
|
||||||
<i class="fas fa-plus me-1"></i>
|
<i class="fas fa-plus me-1"></i>
|
||||||
{% trans 'New Item' %}
|
{% trans 'New Item' %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %} {% endcomment %}
|
{% endif %}
|
||||||
<button type="submit" class="btn btn-phoenix-primary">
|
<button type="submit" class="btn btn-phoenix-primary">
|
||||||
<i class="fas fa-save me-1"></i>
|
<i class="fas fa-save me-1"></i>
|
||||||
{% trans 'Save Changes' %}
|
{% trans 'Save Changes' %}
|
||||||
|
|||||||
@ -50,15 +50,15 @@
|
|||||||
{% trans 'Filters' %} <i class="fas fa-sliders-h ms-2"></i>
|
{% trans 'Filters' %} <i class="fas fa-sliders-h ms-2"></i>
|
||||||
</h2>
|
</h2>
|
||||||
<form method="GET" class="row g-3 align-items-end">
|
<form method="GET" class="row g-3 align-items-end">
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="start_date" class="form-label">{% trans 'Start Date' %}</label>
|
<label for="start_date" class="form-label">{% trans 'Start Date' %}</label>
|
||||||
<input type="date" class="form-control" id="start_date" name="start_date" value="{{ start_date|default_if_none:'' }}">
|
<input type="date" class="form-control" id="start_date" name="start_date" value="{{ start_date|default_if_none:'' }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="end_date" class="form-label">{% trans 'End Date' %}</label>
|
<label for="end_date" class="form-label">{% trans 'End Date' %}</label>
|
||||||
<input type="date" class="form-control" id="end_date" name="end_date" value="{{ end_date|default_if_none:'' }}">
|
<input type="date" class="form-control" id="end_date" name="end_date" value="{{ end_date|default_if_none:'' }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-2">
|
||||||
<button type="submit" class="btn btn-primary w-100">
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
<i class="fas fa-filter me-2"></i>{% trans 'Filter' %}
|
<i class="fas fa-filter me-2"></i>{% trans 'Filter' %}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user