some fixes and improvements

This commit is contained in:
ismail 2025-07-10 19:20:46 +03:00
parent 19b2913a4e
commit db751f7837
15 changed files with 657 additions and 892 deletions

BIN
dbtest.sqlite3 Normal file

Binary file not shown.

View File

@ -40,3 +40,46 @@ def breadcrumbs(request):
url = "/" + "/".join(path[: i + 1]) + "/"
breadcrumbs.append({"name": path[i].capitalize(), "url": url})
return {"breadcrumbs": breadcrumbs}
def user_types(request):
"""
Sets various flags indicating the user's role types.
The flags are:
- request.is_dealer
- request.is_staff
- request.is_manager
- request.is_accountant
- request.is_sales
- request.is_inventory
:param request: The request object to set the flags upon.
:type request: HttpRequest
"""
request.is_dealer = False
request.is_staff = False
request.is_manager = False
request.is_accountant = False
request.is_sales = False
request.is_inventory = False
if hasattr(request.user, "dealer"):
request.is_dealer = True
elif hasattr(request.user, "staffmember"):
request.is_staff = True
staff = getattr(request.user.staffmember, "staff")
if "Accountant" in staff.groups.values_list("name", flat=True):
request.is_accountant = True
return {"is_accountant": True}
elif "Manager" in staff.groups.values_list("name", flat=True):
request.is_manager = True
return {"is_manager": True}
elif "Sales" in staff.groups.values_list("name", flat=True):
request.is_sales = True
return {"is_sales": True}
elif "Inventory" in staff.groups.values_list("name", flat=True):
request.is_inventory = True
return {"is_inventory": True}
return {}

View File

@ -107,11 +107,11 @@ class InjectDealerMiddleware:
staff = getattr(request.user.staffmember, "staff")
if "Accountant" in staff.groups.values_list("name", flat=True):
request.is_accountant = True
if "Manager" in staff.groups.values_list("name", flat=True):
elif "Manager" in staff.groups.values_list("name", flat=True):
request.is_manager = True
if "Sales" in staff.groups.values_list("name", flat=True):
elif "Sales" in staff.groups.values_list("name", flat=True):
request.is_sales = True
if "Inventory" in staff.groups.values_list("name", flat=True):
elif "Inventory" in staff.groups.values_list("name", flat=True):
request.is_inventory = True
except Exception:
pass

View File

@ -19,7 +19,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('appointment', '0001_initial'),
('appointment', '__first__'),
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'),
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),

View File

@ -1199,17 +1199,20 @@ class Staff(models.Model, LocalizedNameMixin):
self.clear_groups()
try:
self.user.groups.add(group)
if "accountant" in group.name.lower() or "manager" in group.name.lower():
if "accountant" in group.name.lower():
self.add_superuser_permission()
except Exception as e:
print(e)
def add_superuser_permission(self):
pass
# self.dealer.entity.managers.add(self.user)
entity = self.dealer.entity
if entity.managers.count() == 0:
entity.managers.add(self.user)
def remove_superuser_permission(self):
pass
# self.dealer.entity.managers.remove(self.user)
entity = self.dealer.entity
if self.user in entity.managers.all():
entity.managers.remove(self.user)
class Meta:
verbose_name = _("Staff")
@ -2708,7 +2711,8 @@ class CustomGroup(models.Model):
"tasks",
"activity",
"payment",
'vendor'],
"vendor",
],
other_perms=[
"view_car",
"view_carlocation",

View File

@ -1,4 +1,5 @@
import logging
from .models import Dealer
from django.core.exceptions import ImproperlyConfigured,ValidationError
from django.contrib.auth.mixins import LoginRequiredMixin,PermissionRequiredMixin
from django_ledger.forms.bill import (
@ -30,7 +31,8 @@ from django_ledger.models import PurchaseOrderModel,EstimateModel,BillModel
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import UpdateView
from django.views.generic.base import RedirectView
from .models import Dealer
from django.views.generic.list import ListView
from django.utils.translation import gettext_lazy as _
logger = logging.getLogger(__name__)
@ -319,7 +321,12 @@ class BasePurchaseOrderActionActionView(LoginRequiredMixin,
f"while performing action '{self.action_name}' on Purchase Order ID: {po_model.pk}. "
f"Error: {e}"
)
print(e)
except AttributeError as e:
logger.warning(
f"User {user_username} encountered an AttributeError "
f"while performing action '{self.action_name}' on Purchase Order ID: {po_model.pk}. "
f"Error: {e}"
)
return response
class BillModelDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
@ -642,3 +649,41 @@ class BaseBillActionView(LoginRequiredMixin,PermissionRequiredMixin, RedirectVie
level=messages.ERROR,
extra_tags='is-danger')
return response
class InventoryListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
template_name = 'django_ledger/inventory/inventory_list.html'
context_object_name = 'inventory_list'
http_method_names = ['get']
def get_context_data(self, *, object_list=None, **kwargs):
context = super(InventoryListView, self).get_context_data(**kwargs)
qs = self.get_queryset()
# evaluates the queryset...
context['qs_count'] = qs.count()
# ordered inventory...
ordered_qs = qs.is_ordered()
context['inventory_ordered'] = ordered_qs
# in transit inventory...
in_transit_qs = qs.in_transit()
context['inventory_in_transit'] = in_transit_qs
# on hand inventory...
received_qs = qs.is_received()
context['inventory_received'] = received_qs
context['page_title'] = _('Inventory')
context['header_title'] = _('Inventory Status')
context['header_subtitle'] = _('Ordered/In Transit/On Hand')
context['header_subtitle_icon'] = 'ic:round-inventory'
return context
def get_queryset(self):
if self.queryset is None:
self.queryset = ItemTransactionModel.objects.inventory_pipeline_aggregate(
entity_slug=self.kwargs['entity_slug'],
)
return super().get_queryset()

View File

@ -1092,6 +1092,6 @@ def bill_model_after_approve_notification(sender, instance, created, **kwargs):
message=f"""
Bill {instance.bill_number} has been approved.
<a href="{reverse('bill-detail', kwargs={'dealer_slug': dealer.slug, 'entity_slug':dealer.entity.slug, 'bill_pk': instance.pk})}" target="_blank">View</a>.
please comlete the bill payment.
please complete the bill payment.
"""
)

View File

@ -1,3 +1,4 @@
import logging
from django.db import transaction
from django_ledger.io import roles
from django_q.tasks import async_task
@ -7,6 +8,9 @@ from django.contrib.auth.models import User,Group, Permission
from inventory.models import DealerSettings, Dealer
from django.utils.translation import gettext_lazy as _
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def create_settings(pk):
instance = Dealer.objects.get(pk=pk)
@ -34,348 +38,9 @@ def create_settings(pk):
def create_coa_accounts(instance):
with transaction.atomic():
entity = instance.entity
coa = entity.get_default_coa()
# accounts_data = [
# # Current Assets (must start with 1)
# {
# 'code': '1010',
# 'name': 'Cash on Hand',
# 'role': roles.ASSET_CA_CASH,
# 'balance_type': roles.DEBIT,
# 'locked': True,
# },
# {
# 'code': '1020',
# 'name': 'Bank',
# 'role': roles.ASSET_CA_CASH,
# 'balance_type': roles.DEBIT,
# 'locked': True,
# },
# {
# 'code': '1030',
# 'name': 'Accounts Receivable',
# 'role': roles.ASSET_CA_RECEIVABLES,
# 'balance_type': roles.DEBIT,
# 'locked': True
# },
# {
# 'code': '1040',
# 'name': 'Inventory (Cars)',
# 'role': roles.ASSET_CA_INVENTORY,
# 'balance_type': roles.DEBIT,
# 'locked': True
# },
# {
# 'code': '1045',
# 'name': 'Spare Parts Inventory',
# 'role': roles.ASSET_CA_INVENTORY,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1050',
# 'name': 'Employee Advances',
# 'role': roles.ASSET_CA_RECEIVABLES,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1060',
# 'name': 'Prepaid Expenses',
# 'role': roles.ASSET_CA_PREPAID,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1070',
# 'name': 'Notes Receivable',
# 'role': roles.ASSET_LTI_NOTES_RECEIVABLE,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# # Fixed Assets (must also start with 1)
# {
# 'code': '1110',
# 'name': 'Lands',
# 'role': roles.ASSET_LTI_LAND,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1111',
# 'name': 'Buildings',
# 'role': roles.ASSET_PPE_BUILDINGS,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1112',
# 'name': 'Company Vehicles',
# 'role': roles.ASSET_PPE_EQUIPMENT,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1113',
# 'name': 'Equipment & Tools',
# 'role': roles.ASSET_PPE_EQUIPMENT,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1114',
# 'name': 'Furniture & Fixtures',
# 'role': roles.ASSET_PPE_EQUIPMENT,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1115',
# 'name': 'Other Fixed Assets',
# 'role': roles.ASSET_PPE_EQUIPMENT,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1120',
# 'name': 'Long-term Investments',
# 'role': roles.ASSET_LTI_SECURITIES,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '1130',
# 'name': 'Intangible Assets',
# 'role': roles.ASSET_INTANGIBLE_ASSETS,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# # Current Liabilities (must start with 2)
# {
# 'code': '2010',
# 'name': 'Accounts Payable',
# 'role': roles.LIABILITY_CL_ACC_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': True
# },
# {
# 'code': '2020',
# 'name': 'Notes Payable',
# 'role': roles.LIABILITY_CL_ST_NOTES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2030',
# 'name': 'Short-term Loans',
# 'role': roles.LIABILITY_CL_ST_NOTES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2040',
# 'name': 'Employee Payables',
# 'role': roles.LIABILITY_CL_WAGES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2050',
# 'name': 'Accrued Expenses',
# 'role': roles.LIABILITY_CL_OTHER,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2060',
# 'name': 'Accrued Taxes',
# 'role': roles.LIABILITY_CL_TAXES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2070',
# 'name': 'Provisions',
# 'role': roles.LIABILITY_CL_OTHER,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# # Long-term Liabilities (must also start with 2)
# {
# 'code': '2210',
# 'name': 'Long-term Bank Loans',
# 'role': roles.LIABILITY_LTL_NOTES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2220',
# 'name': 'Lease Liabilities',
# 'role': roles.LIABILITY_LTL_NOTES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '2230',
# 'name': 'Other Long-term Liabilities',
# 'role': roles.LIABILITY_LTL_NOTES_PAYABLE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# # Equity (must start with 3)
# {
# 'code': '3010',
# 'name': 'Capital',
# 'role': roles.EQUITY_CAPITAL,
# 'balance_type': roles.CREDIT,
# 'locked': True
# },
# {
# 'code': '3020',
# 'name': 'Statutory Reserve',
# 'role': roles.EQUITY_ADJUSTMENT,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '3030',
# 'name': 'Retained Earnings',
# 'role': roles.EQUITY_ADJUSTMENT,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '3040',
# 'name': 'Profit & Loss for the Period',
# 'role': roles.EQUITY_ADJUSTMENT,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# # Revenue (must start with 4)
# {
# 'code': '4010',
# 'name': 'Car Sales',
# 'role': roles.INCOME_OPERATIONAL,
# 'balance_type': roles.CREDIT,
# 'locked': True
# },
# {
# 'code': '4020',
# 'name': 'After-Sales Services',
# 'role': roles.INCOME_OPERATIONAL,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '4030',
# 'name': 'Car Rental Income',
# 'role': roles.INCOME_PASSIVE,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# {
# 'code': '4040',
# 'name': 'Other Income',
# 'role': roles.INCOME_OTHER,
# 'balance_type': roles.CREDIT,
# 'locked': False
# },
# # 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
# },
# {
# 'code': '5015',
# 'name': 'Spare Parts Cost Consumed',
# 'role': roles.COGS,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6010',
# 'name': 'Salaries & Wages',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6020',
# 'name': 'Rent',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6030',
# 'name': 'Utilities',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6040',
# 'name': 'Advertising & Marketing',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6050',
# 'name': 'Maintenance',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6060',
# 'name': 'Operating Expenses',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6070',
# 'name': 'Depreciation',
# 'role': roles.EXPENSE_DEPRECIATION,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6080',
# 'name': 'Fees & Taxes',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6090',
# 'name': 'Bank Charges',
# 'role': roles.EXPENSE_OPERATIONAL,
# 'balance_type': roles.DEBIT,
# 'locked': False
# },
# {
# 'code': '6100',
# 'name': 'Other Expenses',
# 'role': roles.EXPENSE_OTHER,
# 'balance_type': roles.DEBIT,
# 'locked': False
# }
# ]
accounts_data = [
# Current Assets (must start with 1)
{
@ -383,7 +48,7 @@ def create_coa_accounts(instance):
"name": "Cash on Hand",
"role": roles.ASSET_CA_CASH,
"balance_type": roles.DEBIT,
"locked": True,
"locked": False,
"default": True, # Default for ASSET_CA_CASH
},
{
@ -391,7 +56,7 @@ def create_coa_accounts(instance):
"name": "Bank",
"role": roles.ASSET_CA_CASH,
"balance_type": roles.DEBIT,
"locked": True,
"locked": False,
"default": False,
},
{
@ -399,7 +64,7 @@ def create_coa_accounts(instance):
"name": "Accounts Receivable",
"role": roles.ASSET_CA_RECEIVABLES,
"balance_type": roles.DEBIT,
"locked": True,
"locked": False,
"default": True, # Default for ASSET_CA_RECEIVABLES
},
{
@ -407,7 +72,7 @@ def create_coa_accounts(instance):
"name": "Inventory (Cars)",
"role": roles.ASSET_CA_INVENTORY,
"balance_type": roles.DEBIT,
"locked": True,
"locked": False,
"default": True, # Default for ASSET_CA_INVENTORY
},
{
@ -565,6 +230,14 @@ def create_coa_accounts(instance):
"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": "2210",
"name": "Long-term Bank Loans",
@ -766,8 +439,10 @@ def create_coa_accounts(instance):
)
account.role_default = account_data["default"]
account.save()
logger.info(f"Created default account: {account}")
except Exception as e:
print(e)
logger.error(f"Error creating default account: {account_data['code']}, {e}")
def create_coa_accounts1(pk):
with transaction.atomic():

View File

@ -88,7 +88,6 @@ from django_ledger.views import (
LedgerModelCreateView as LedgerModelCreateViewBase,
)
from django_ledger.forms.account import AccountModelCreateForm, AccountModelUpdateForm
from django_ledger.views.inventory import InventoryListView as InventoryListViewBase
from django_ledger.views.entity import (
EntityModelDetailBaseView,
EntityModelDetailHandlerView,
@ -143,6 +142,7 @@ from .override import (
BillModelDetailView as BillModelDetailViewBase,
BillModelUpdateView as BillModelUpdateViewBase,
BaseBillActionView as BaseBillActionViewBase,
InventoryListView as InventoryListViewBase,
)
from django_ledger.models import (
@ -10253,9 +10253,11 @@ def upload_cars(request, dealer_slug, pk=None):
car_make = get_make(manufacturer_name)
car_model = get_model(model_name, car_make)
if (
not all([car_make, car_model])
not all([car_make])
or (make.pk != car_make.pk)
or (model.pk != car_model.pk)
# not all([car_make, car_model])
# or (make.pk != car_make.pk)
# or (model.pk != car_model.pk)
):
logger.warning(
f"User {user_username} uploaded CSV with VIN '{row['vin']}' "
@ -10368,12 +10370,3 @@ def bulk_update_car_price(request):
class InventoryListView(InventoryListViewBase):
template_name = "inventory/list.html"
permission_required = ["django_ledger.view_purchaseordermodel"]
def get_queryset(self):
dealer = get_user_type(self.request)
if self.queryset is None:
self.queryset = ItemTransactionModel.objects.inventory_pipeline_aggregate(
entity_slug=dealer.entity.slug,
)
return super().get_queryset()

View File

@ -1,126 +1,126 @@
annotated-types==0.7.0
anyio==4.9.0
arrow==1.3.0
asgiref==3.8.1
attrs==25.3.0
Babel==2.15.0
beautifulsoup4==4.13.4
blessed==1.21.0
cattrs==24.1.3
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
click==8.2.1
colorama==0.4.6
crispy-bootstrap5==2024.10
cryptography==44.0.2
cssbeautifier==1.15.4
defusedxml==0.7.1
diff-match-patch==20241021
distro==1.9.0
Django==5.2.3
django-allauth==65.6.0
django-appointment==3.8.0
django-background-tasks==1.2.8
django-bootstrap5==25.1
django-ckeditor==6.7.2
django-cors-headers==4.7.0
django-countries==7.6.1
django-crispy-forms==2.3
django-easy-audit==1.3.7
django-extensions==3.2.3
django-filter==25.1
django-import-export==4.3.7
django-js-asset==3.1.2
django-ledger==0.7.7
django-manager-utils==3.1.5
django-next-url-mixin==0.4.0
django-ordered-model==3.7.4
django-phonenumber-field==8.0.0
django-picklefield==3.3
django-plans==2.0.0
django-q2==1.8.0
django-query-builder==3.2.0
django-schema-graph==3.1.0
django-sequences==3.0
django-tables2==2.7.5
django-treebeard==4.7.1
django-widget-tweaks==1.5.0
djangorestframework==3.15.2
djhtml==3.0.7
djlint==1.36.4
docopt==0.6.2
EditorConfig==0.17.0
Faker==37.3.0
fleming==0.7.0
fonttools==4.57.0
fpdf==1.7.2
fpdf2==2.8.3
greenlet==3.2.2
h11==0.14.0
httpcore==1.0.7
httpx==0.28.1
icalendar==6.1.2
idna==3.10
jiter==0.9.0
jsbeautifier==1.15.4
json5==0.12.0
jsonpatch==1.33
jsonpointer==3.0.0
jwt==1.3.1
langchain==0.3.25
langchain-core==0.3.61
langchain-ollama==0.3.3
langchain-text-splitters==0.3.8
langsmith==0.3.42
luhnchecker==0.0.12
Markdown==3.8
markdown-it-py==3.0.0
mdurl==0.1.2
num2words==0.5.14
numpy==2.2.4
ofxtools==0.9.5
ollama==0.4.8
openai==1.68.2
opencv-python==4.11.0.86
orjson==3.10.18
packaging==24.2
pandas==2.2.3
pathspec==0.12.1
phonenumbers==8.13.42
pillow==11.2.1
pycparser==2.22
pydantic==2.10.6
pydantic_core==2.27.2
Pygments==2.19.1
python-dateutil==2.9.0.post0
python-slugify==8.0.4
python-stdnum==1.20
pytz==2025.2
pyvin==0.0.2
PyYAML==6.0.2
pyzbar==0.1.9
redis==3.5.3
regex==2024.11.6
requests==2.32.3
requests-toolbelt==1.0.0
rich==14.0.0
ruff==0.11.10
setuptools==80.3.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
types-python-dateutil==2.9.0.20250516
typing_extensions==4.13.0
tzdata==2025.2
urllib3==2.3.0
wcwidth==0.2.13
zstandard==0.23.0
annotated-types
anyio
arrow
asgiref
attrs
Babel
beautifulsoup4
blessed
cattrs
certifi
cffi
charset-normalizer
click
colorama
crispy-bootstrap5
cryptography
cssbeautifier
defusedxml
diff-match-patch
distro
Django
django-allauth
django-appointment
django-background-tasks
django-bootstrap5
django-ckeditor
django-cors-headers
django-countries
django-crispy-forms
django-easy-audit
django-extensions
django-filter
django-import-export
django-js-asset
django-ledger
django-manager-utils
django-next-url-mixin
django-ordered-model
django-phonenumber-field
django-picklefield
django-plans
django-q2
django-query-builder
django-schema-graph
django-sequences
django-tables2
django-treebeard
django-widget-tweaks
djangorestframework
djhtml
djlint
docopt
EditorConfig
Faker
fleming
fonttools
fpdf
fpdf2
greenlet
h11
httpcore
httpx
icalendar
idna
jiter
jsbeautifier
json5
jsonpatch
jsonpointer
jwt
langchain
langchain-core
langchain-ollama
langchain-text-splitters
langsmith
luhnchecker
Markdown
markdown-it-py
mdurl
num2words
numpy
ofxtools
ollama
openai
opencv-python
orjson
packaging
pandas
pathspec
phonenumbers
pillow
pycparser
pydantic
pydantic_core
Pygments
python-dateutil
python-slugify
python-stdnum
pytz
pyvin
PyYAML
pyzbar
redis
regex
requests
requests-toolbelt
rich
ruff
setuptools
six
sniffio
soupsieve
SQLAlchemy
sqlparse
suds
swapper
tablib
tenacity
text-unidecode
tqdm
types-python-dateutil
typing_extensions
tzdata
urllib3
wcwidth
zstandard

View File

@ -9,7 +9,6 @@
<div class="container py-4">
<div class="row g-2">
<!-- Bill Form -->
<div class="col-12">

View File

@ -46,7 +46,7 @@
<tr class="align-middle">
<!-- Item Column -->
<td>
<div class="d-flex flex-column">
<div class="d-flex flex-column ms-2">
{% for hidden_field in f.hidden_fields %}
{{ hidden_field }}
{% endfor %}

View File

@ -64,6 +64,13 @@
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'inventort_list' request.dealer.slug request.dealer.entity.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-boxes"></span></span><span class="nav-link-text">{% trans "Inventory List"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
</ul>

View File

@ -14,7 +14,6 @@
<tbody>
{% for i in inventory_list %}
<tr class="hover-actions-trigger">
<td class="ps-2 fw-medium">{{ i.item_model__name }}</td>
<td class="text-center">{{ i.item_model__uom__name }}</td>