some fixes and improvements
This commit is contained in:
parent
19b2913a4e
commit
db751f7837
BIN
dbtest.sqlite3
Normal file
BIN
dbtest.sqlite3
Normal file
Binary file not shown.
@ -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 {}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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()
|
||||
@ -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.
|
||||
"""
|
||||
)
|
||||
1137
inventory/tasks.py
1137
inventory/tasks.py
File diff suppressed because it is too large
Load Diff
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
2
t1.py
2
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"])
|
||||
@ -9,7 +9,6 @@
|
||||
<div class="container py-4">
|
||||
<div class="row g-2">
|
||||
|
||||
|
||||
<!-- Bill Form -->
|
||||
<div class="col-12">
|
||||
|
||||
|
||||
@ -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 %}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -14,12 +14,11 @@
|
||||
<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>
|
||||
<td class="text-end pe-3">{{ i.total_quantity | floatformat:3 }}</td>
|
||||
<td class="text-end pe-3 fw-bold text-primary">
|
||||
<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>
|
||||
<td class="text-end pe-3">{{ i.total_quantity | floatformat:3 }}</td>
|
||||
<td class="text-end pe-3 fw-bold text-primary">
|
||||
<span class="currency">{{CURRENCY}}</span>{{ i.total_value | currency_format }}
|
||||
</td>
|
||||
</tr>
|
||||
@ -30,7 +29,7 @@
|
||||
<td colspan="2"></td>
|
||||
<td class="text-end pe-3 fw-bold">{% trans "Total Value" %}</td>
|
||||
<td class="text-end pe-3 fw-bold text-success">
|
||||
<span class="currency">{{CURRENCY}}</span>{{ inventory_total_value | currency_format }}
|
||||
<span class="currency">{{CURRENCY}}</span>{{ inventory_total_value | currency_format }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user