diff --git a/dbtest.sqlite3 b/dbtest.sqlite3 new file mode 100644 index 00000000..87519031 Binary files /dev/null and b/dbtest.sqlite3 differ diff --git a/inventory/context_processors.py b/inventory/context_processors.py index 398ec101..779b6e14 100644 --- a/inventory/context_processors.py +++ b/inventory/context_processors.py @@ -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 {} diff --git a/inventory/middleware.py b/inventory/middleware.py index 73ed6a87..241312b4 100644 --- a/inventory/middleware.py +++ b/inventory/middleware.py @@ -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 diff --git a/inventory/migrations/0001_initial.py b/inventory/migrations/0001_initial.py index cf9ffd02..b53295ed 100644 --- a/inventory/migrations/0001_initial.py +++ b/inventory/migrations/0001_initial.py @@ -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'), diff --git a/inventory/models.py b/inventory/models.py index 0bf0e7d4..b09b282c 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -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", diff --git a/inventory/override.py b/inventory/override.py index ccf3ffbe..4e87d83c 100644 --- a/inventory/override.py +++ b/inventory/override.py @@ -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() \ No newline at end of file diff --git a/inventory/signals.py b/inventory/signals.py index 3670ba22..ba90031c 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -1092,6 +1092,6 @@ def bill_model_after_approve_notification(sender, instance, created, **kwargs): message=f""" Bill {instance.bill_number} has been approved. View. - please comlete the bill payment. + please complete the bill payment. """ ) \ No newline at end of file diff --git a/inventory/tasks.py b/inventory/tasks.py index 4ae0db3b..0f2b5642 100644 --- a/inventory/tasks.py +++ b/inventory/tasks.py @@ -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,740 +38,411 @@ def create_settings(pk): def create_coa_accounts(instance): - with transaction.atomic(): - entity = instance.entity - coa = entity.get_default_coa() + 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 - # }, + accounts_data = [ + # 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": True, # 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": "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 + }, + ] - # # 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 - # }, + for account_data in accounts_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}") - # # 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) - { - "code": "1010", - "name": "Cash on Hand", - "role": roles.ASSET_CA_CASH, - "balance_type": roles.DEBIT, - "locked": True, - "default": True, # Default for ASSET_CA_CASH - }, - { - "code": "1020", - "name": "Bank", - "role": roles.ASSET_CA_CASH, - "balance_type": roles.DEBIT, - "locked": True, - "default": False, - }, - { - "code": "1030", - "name": "Accounts Receivable", - "role": roles.ASSET_CA_RECEIVABLES, - "balance_type": roles.DEBIT, - "locked": True, - "default": True, # Default for ASSET_CA_RECEIVABLES - }, - { - "code": "1040", - "name": "Inventory (Cars)", - "role": roles.ASSET_CA_INVENTORY, - "balance_type": roles.DEBIT, - "locked": True, - "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": True, # 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": "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 - }, - ] - - for account_data in accounts_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() - except Exception as e: - print(e) def create_coa_accounts1(pk): with transaction.atomic(): diff --git a/inventory/views.py b/inventory/views.py index a20fd1a4..66db30dd 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -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() diff --git a/requirements_dev.txt b/requirements_dev.txt index fb84285f..459bd6fd 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -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 diff --git a/t1.py b/t1.py index dcfda023..bb0b34fd 100644 --- a/t1.py +++ b/t1.py @@ -19,4 +19,4 @@ def get_models_for_make(): models = get_models_for_make() for model in models: - print(model["Model_Name"]) + print(model["Model_Name"]) \ No newline at end of file diff --git a/templates/bill/bill_update.html b/templates/bill/bill_update.html index d3e87c4a..513cca1c 100644 --- a/templates/bill/bill_update.html +++ b/templates/bill/bill_update.html @@ -9,7 +9,6 @@
-
diff --git a/templates/bill/tags/bill_item_formset.html b/templates/bill/tags/bill_item_formset.html index cc344a21..1d62d4ea 100644 --- a/templates/bill/tags/bill_item_formset.html +++ b/templates/bill/tags/bill_item_formset.html @@ -46,7 +46,7 @@ -
+
{% for hidden_field in f.hidden_fields %} {{ hidden_field }} {% endfor %} diff --git a/templates/header.html b/templates/header.html index 6b6b6acb..ca7aeb27 100644 --- a/templates/header.html +++ b/templates/header.html @@ -64,6 +64,13 @@
+ {% endif %} diff --git a/templates/inventory/tags/inventory_table.html b/templates/inventory/tags/inventory_table.html index e61a29d9..ebdfdca1 100644 --- a/templates/inventory/tags/inventory_table.html +++ b/templates/inventory/tags/inventory_table.html @@ -14,12 +14,11 @@ {% for i in inventory_list %} - - - {{ i.item_model__name }} - {{ i.item_model__uom__name }} - {{ i.total_quantity | floatformat:3 }} - + + {{ i.item_model__name }} + {{ i.item_model__uom__name }} + {{ i.total_quantity | floatformat:3 }} + {{CURRENCY}}{{ i.total_value | currency_format }} @@ -30,7 +29,7 @@ {% trans "Total Value" %} - {{CURRENCY}}{{ inventory_total_value | currency_format }} + {{CURRENCY}}{{ inventory_total_value | currency_format }}