[FIX] ASSET: Combined filter and view fix for asset and category
This commit is contained in:
@@ -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:
|
||||
"""
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user