[FIX] ASSET: Combined filter and view fix for asset and category

This commit is contained in:
Horilla
2024-10-03 16:25:31 +05:30
parent afdcec65d0
commit 9df5e1554f
9 changed files with 72 additions and 273 deletions

View File

@@ -91,6 +91,9 @@ class AssetFilter(CustomFilterSet):
Custom filter set for Asset instances.
"""
search = django_filters.CharFilter(method="search_method")
category = django_filters.CharFilter(field_name="asset_category_id")
class Meta:
"""
A nested class that specifies the configuration for the filter.
@@ -107,6 +110,15 @@ class AssetFilter(CustomFilterSet):
for visible in self.form.visible_fields():
visible.field.widget.attrs["id"] = str(uuid.uuid4())
def search_method(self, queryset, _, value):
"""
Search method
"""
return (
queryset.filter(asset_name__icontains=value)
| queryset.filter(asset_category_id__asset_category_name__icontains=value)
).distinct()
class CustomAssetFilter(CustomFilterSet):
"""
@@ -227,6 +239,8 @@ class AssetCategoryFilter(CustomFilterSet):
Custom filter set for AssetCategory instances.
"""
search = django_filters.CharFilter(method="serach_method")
class Meta:
"""
Specifies the model and fields to be used for filtering AssetCategory instances.
@@ -245,6 +259,23 @@ class AssetCategoryFilter(CustomFilterSet):
for visible in self.form.visible_fields():
visible.field.widget.attrs["id"] = str(uuid.uuid4())
def serach_method(self, queryset, _, value):
"""
Search method
"""
return (
queryset.filter(asset_category_name__icontains=value)
| queryset.filter(asset__asset_name__icontains=value)
).distinct()
def filter_queryset(self, queryset):
# Get the base filtered queryset
queryset = super().filter_queryset(queryset)
assets = AssetFilter(data=self.data).qs
return (
queryset.filter(asset__pk__in=assets.values_list("pk", flat=True))
).distinct()
class AssetRequestReGroup:
"""

View File

@@ -19,6 +19,11 @@ SUBMENUS = [
"redirect": reverse("asset-category-view"),
"accessibility": "asset.sidebar.dashboard_accessibility",
},
{
"menu": trans("Asset Batches"),
"redirect": reverse("asset-batch-view"),
"accessibility": "asset.sidebar.lot_accessibility",
},
{
"menu": trans("Request and Allocation"),
"redirect": reverse("asset-request-allocation-view"),
@@ -45,3 +50,10 @@ def history_accessibility(request, submenu, user_perms, *args, **kwargs):
dashboard and asset category view.
"""
return request.user.has_perm("asset.view_assetassignment")
def lot_accessibility(request, subment, user_perms, *args, **kwargs):
"""
Asset batch sidebar accessibility method
"""
return request.user.has_perm("asset.view_assetlot")

View File

@@ -26,7 +26,7 @@
class="oh-modal__close"
data-dismiss="oh-modal"
aria-label="Close"
hx-get="{%url 'asset-list' cat_id=asset_creation_form.asset_category_id.initial %}?{{pg}}"
hx-get="{%url 'asset-list' cat_id=asset_creation_form.asset_category_id.initial %}?{{request.GET.urlencode}}&category={{asset_creation_form.asset_category_id.initial}}"
hx-target="#assetCategory{{asset_creation_form.asset_category_id.initial}}"
>
<ion-icon name="close-outline"></ion-icon>

View File

@@ -1,5 +1,8 @@
{% load i18n %} {% load static %}
<script>
$("#asset-count{{asset_category_id}}").html("{{assets.paginator.count}}");
$("#asset-count{{asset_category_id}}").attr("title","{{assets.paginator.count}} {% trans 'Assets' %}");
</script>
<!-- start of messages -->
{% if messages %}
<div class="oh-wrapper">

View File

@@ -16,7 +16,8 @@
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th">{% trans "Batch Number" %}</div>
<div class="oh-sticky-table__th">{% trans " Description" %}</div>
<div class="oh-sticky-table__th">{% trans "Description" %}</div>
<div class="oh-sticky-table__th">{% trans "Assets" %}</div>
{% if perms.asset.change_assetlot or perms.asset.delete_assetlot %}
<div class="oh-sticky-table__th">{% trans "Actions" %}</div>
{% endif %}
@@ -24,11 +25,17 @@
</div>
<div class="oh-sticky-table__tbody">
{% for batch_number in batch_numbers %}
<div class="oh-sticky-table__tr" draggable="true">
<div class="oh-sticky-table__tr" style="cursor: text;" draggable="true">
<div class="oh-sticky-table__td">{{batch_number.lot_number}}</div>
<div class="oh-sticky-table__td">
{{batch_number.lot_description}}
</div>
<div class="oh-sticky-table__td">
<a href="{% url "asset-category-view" %}?asset_lot_number_id={{batch_number.id}}" style="cursor: pointer;" class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round mr-1">
{{batch_number.asset_set.count}}
{% trans "Assets" %}
</a>
</div>
{% if perms.asset.change_assetlot or perms.asset.delete_assetlot %}
<div class="oh-sticky-table__td">
<div class="oh-btn-group">

View File

@@ -29,7 +29,8 @@
<div
class="oh-accordion-meta__header oh-accordion-meta__header--custom"
data-target="#assetCategory{{asset_category.id}}"
hx-get="{%url 'asset-list' cat_id=asset_category.id %}"
hx-get="{%url 'asset-list' cat_id=asset_category.id %}?category={{asset_category.pk}}&{{request.GET.urlencode}}"
hx-trigger="load"
hx-target="#assetCategory{{asset_category.id}}">
<div class="d-flex">
<span

View File

@@ -70,11 +70,6 @@
<!-- end of search -->
</div>
<div class="oh-main__titlebar-button-container">
{% if perms.asset.view_assetlot %}
<a href="{% url 'asset-batch-view'%}" style="text-decoration:none;">
<button class="oh-btn ml-2"> <ion-icon name="list-outline" class="me-1"></ion-icon>{% trans "Batch No" %}</button>
</a>
{% endif %}
<!-- import asset start -->
<!-- import asset end -->
@@ -94,7 +89,7 @@
<div class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4" x-show="open"
@click.outside="open = false" style="display: none;">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion">
{% comment %} <div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Asset Category" %}</div>
<div class="oh-accordion-body">
<form hx-get="{%url 'asset-category-view-search-filter' %}" hx-target="#assetCategoryList" hx-swap="innerHTML" id="filterForm">
@@ -117,11 +112,11 @@
</div>
</form>
</div>
</div>
</div> {% endcomment %}
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Asset" %}</div>
<div class="oh-accordion-body">
<form hx-get="{%url 'asset-list' cat_id=0 %}?asset_list='asset'" name="asset_list" hx-target="#assetCategoryList" hx-swap="innerHTML" id="filterForm2">
<form hx-get="{%url 'asset-category-view-search-filter' %}" name="asset_list" hx-target="#assetCategoryList" hx-swap="innerHTML" id="filterForm2">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
@@ -163,12 +158,12 @@
</div>
</div>
</div>
<div class="oh-dropdown__filter-footer">
<button class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton">{% trans "Filter" %}</button>
</div>
</form>
</div>
</div>
<div class="oh-dropdown__filter-footer">
<button class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton">{% trans "Filter" %}</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -1,224 +0,0 @@
{% comment %} {% extends 'index.html' %}
{% load static i18n %}
{% block content %}
<!-- start of messages -->
{% if messages %}
<div class="oh-wrapper">
{% for message in messages %}
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated {{message.tags}}">
{{ message }}
</div>
</div>
{% endfor %}
</div>
{% endif %}
<!-- end of messages -->
<main :class="sidebarOpen ? 'oh-main__sidebar-visible' : ''">
<section class="oh-wrapper oh-main__topbar" x-data="{searchShow: false}">
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Assets" %}</h1>
<a class="oh-main__titlebar-search-toggle" role="button" aria-label="Toggle Search"
@click="searchShow = !searchShow">
<ion-icon name="search-outline" class="oh-main__titlebar-serach-icon"></ion-icon>
</a>
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
<div class="oh-input-group oh-input__search-group"
:class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input name="search" hx-get=""
hx-target="#assetCategoryList" hx-trigger='keyup delay:500ms' type="text"
class="oh-input oh-input__icon" aria-label="Search Input" placeholder="Search" />
</div>
<div class="oh-main__titlebar-button-container">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}
</button>
<div class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4" x-show="open"
@click.outside="open = false" style="display: none;">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Asset" %} </div>
<div class="oh-accordion-body">
<form hx-get="{%url 'asset-list' cat_id=0 %}?asset_list='asset'" name="asset_list" hx-target="#assetCategoryList" hx-swap="innerHTML">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Asset Name" %}</label>
{{asset_filter_form.asset_name}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Tracking Id" %}</label>
{{asset_filter_form.asset_tracking_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Purchase Date" %}</label>
{{asset_filter_form.asset_purchase_date}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Purchase Cost" %}</label>
{{asset_filter_form.asset_purchase_cost}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Asset Lot Number" %}</label>
{{asset_filter_form.asset_lot_number_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Category" %}</label>
{{asset_filter_form.asset_category_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-12">
<div class="oh-input-group">
<label class="oh-label">{% trans "Status" %}</label>
{{asset_filter_form.asset_status}}
</div>
</div>
</div>
<div class="oh-dropdown__filter-footer">
<button class="oh-btn oh-btn--secondary oh-btn--small ">{% trans "Filter" %}</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="oh-btn-group ml-2">
<div>
<a href="#" class="oh-btn oh-btn--secondary oh-btn--shadow" data-toggle="oh-modal-toggle"
data-target="#AssetCategoryModal" hx-get=""
hx-target="#AssetModal"> <ion-icon class="me-2" name="add-outline"></ion-icon>{% trans "Create" %} </a>
</div>
</div>
</div>
</div>
</section>
<div class="oh-wrapper">
<div id="assetCategoryList">
<!-- list -->
<div class="oh-sticky-table__table" data-count="{{total_count}}">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th">{% trans "Asset" %}</div>
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Tracking Id" %}</div>
<div class="oh-sticky-table__th">{% trans "Batch No" %}</div>
<div class="oh-sticky-table__th"></div>
</div>
</div>
<div class="oh-sticky-table__tbody" id="assetPaginatorTarget">
{% for asset in assets %}
<div class="oh-sticky-table__tr oh-multiple-table-sort__movable" id="assetDelete{{asset.id}}">
<div class="oh-sticky-table__sd" data-toggle="oh-modal-toggle" data-target="#assetInfoModal"
hx-get="{%url 'asset-information' asset_id=asset.id %}" hx-target="#assetInfomation">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="https://ui-avatars.com/api/?name={{asset.asset_name}}&background=random" class="oh-profile__image"
alt="Mary Magdalene" />
</div>
<span class="oh-profile__name oh-text--dark">{{asset.asset_name}}</span>
</div>
</div>
<div class="oh-sticky-table__td">{{asset.asset_status}}</div>
<div class="oh-sticky-table__td">{{asset.asset_tracking_id}}</div>
<div class="oh-sticky-table__td">{{asset.asset_lot_number_id}}</div>
<div class="oh-sticky-table__td">
<div class="oh-btn-group">
<a class="oh-btn oh-btn--light-bkg w-100 " data-toggle="oh-modal-toggle" data-target="#AssetCategoryModal"
hx-get="{% url 'asset-update' asset_id=asset.id %}" title="{% trans 'Update' %}" hx-target="#AssetModal" id="oh-btn-asset-update-modal"> <ion-icon
name="create-outline" role="img" class="md hydrated" aria-label="create outline"></ion-icon></a>
<a hx-post="{%url 'asset-delete' asset_id=asset.id %}" hx-target="#assetList{{asset.asset_category_id.id}}"
hx-confirm="Do you want to delete this asset?"
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100 asset-delete" title="{% trans 'Remove' %}" data-category-id="{{asset.asset_category_id.id}}"> <ion-icon name="trash-outline"
role="img" class="md hydrated" aria-label="trash outline"></ion-icon></a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- pagination start -->
<div class="oh-pagination">
<span class="oh-pagination__page" data-toggle="modal" data-target="#addEmployeeModal"></span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1">{% trans "Page" %}</span>
<input type="number" name="page" class="oh-pagination__input" value="{{assets.number }}" min="1"
hx-get="" hx-target="">
<span class="oh-pagination__label">{% trans "of" %} {{ assets.paginator.num_pages }}</span>
</div>
<ul class="oh-pagination__items">
{% if assets.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-get="" class='oh-pagination__link'
hx-target="">{% trans "First" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-get=""
class='oh-pagination__link' hx-target="">{% trans "Previous" %}</a>
</li>
{%endif %}
{% if assets.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-get=""
class='btn btn-outline-secondary' hx-target="">{% trans "Next" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-get=""
hx-target="" class="oh-pagination__link">{% trans "Last" %}</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
</main>
{% endblock %} {% endcomment %}

View File

@@ -344,27 +344,7 @@ def asset_list(request, cat_id):
"""
context = {}
asset_under = ""
assets_in_category = Asset.objects.none()
asset_info = request.GET.get("asset_info")
asset_list_filter = request.GET.get("asset_list")
if asset_list_filter:
# if the data is present means that it is for asset filtered list
query = request.GET.get("query")
asset_under = "asset_filter"
if query:
assets_in_category = Asset.objects.filter(asset_name__icontains=query)
else:
assets_in_category = Asset.objects.all()
elif asset_info:
pass
else:
# if the data is not present means that it is for asset category list
asset_under = "asset_category"
asset_category = AssetCategory.objects.get(id=cat_id)
assets_in_category = Asset.objects.filter(asset_category_id=asset_category)
previous_data = request.GET.urlencode()
asset_filtered = AssetFilter(request.GET, queryset=assets_in_category)
asset_filtered = AssetFilter(request.GET)
asset_list = asset_filtered.qs
paginator = Paginator(asset_list, get_pagination())
@@ -372,6 +352,7 @@ def asset_list(request, cat_id):
page_obj = paginator.get_page(page_number)
requests_ids = json.dumps([instance.id for instance in page_obj.object_list])
previous_data = request.GET.urlencode()
data_dict = parse_qs(previous_data)
get_key_instances(Asset, data_dict)
context = {
@@ -379,7 +360,7 @@ def asset_list(request, cat_id):
"pg": previous_data,
"asset_category_id": cat_id,
"asset_under": asset_under,
"asset_count": len(assets_in_category) or None,
"asset_count": len(asset_list) or None,
"filter_dict": data_dict,
"requests_ids": requests_ids,
}
@@ -465,12 +446,11 @@ def filter_pagination_asset_category(request):
search = ""
previous_data = request.GET.urlencode()
asset_category_queryset = AssetCategory.objects.all().filter(
asset_category_name__icontains=search
)
asset_category_filtered = AssetCategoryFilter(
request.GET, queryset=asset_category_queryset
request.GET,
)
asset_category_queryset = asset_category_filtered.qs
asset_category_paginator = Paginator(asset_category_filtered.qs, get_pagination())
page_number = request.GET.get("page")
asset_categories = asset_category_paginator.get_page(page_number)
@@ -528,12 +508,6 @@ def asset_category_view_search_filter(request):
Raises:
None
"""
search_type = request.GET.get("type")
query = request.GET.get("search")
if search_type == "asset":
# searching asset will redirect to asset list and pass the query
return redirect(f"/asset/asset-list/0?asset_list=asset&query={query}")
context = filter_pagination_asset_category(request)
return render(request, "category/asset_category.html", context)