direct-content-only switch makes more sense than leaf_only

This commit is contained in:
Micha 2026-02-05 00:01:23 +01:00
parent d5878dbb47
commit 62448ba63d
4 changed files with 42 additions and 53 deletions

View File

@ -95,7 +95,7 @@ class StockController extends BaseController
'locations' => $this->getDatabase()->locations_hierarchy()->orderBy('location_path', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations_hierarchy()->orderBy('location_path', 'COLLATE NOCASE'),
'locationsResolved' => $this->getDatabase()->locations_resolved(), 'locationsResolved' => $this->getDatabase()->locations_resolved(),
'currentStockLocationContent' => $this->getStockService()->GetCurrentStockLocationContent(isset($request->getQueryParams()['include_out_of_stock'])), 'currentStockLocationContent' => $this->getStockService()->GetCurrentStockLocationContent(isset($request->getQueryParams()['include_out_of_stock'])),
'showLeafLocationsOnly' => isset($request->getQueryParams()['leaf_locations_only']) 'showDirectContentOnly' => isset($request->getQueryParams()['direct_content_only'])
]); ]);
} }

View File

@ -2477,8 +2477,8 @@ msgstr ""
msgid "List actions" msgid "List actions"
msgstr "" msgstr ""
msgid "Show only leaf locations" msgid "Show direct content only"
msgstr "" msgstr ""
msgid "When enabled, only locations without sub-locations are shown. When disabled, parent locations show aggregated content from all sub-locations." msgid "When enabled, each location shows only products stored directly there. When disabled, locations include products from all sub-locations."
msgstr "" msgstr ""

View File

@ -32,15 +32,15 @@ if (GetUriParam("include_out_of_stock"))
$("#include-out-of-stock").prop("checked", false); $("#include-out-of-stock").prop("checked", false);
} }
$(document).on("change", "#leaf-locations-only", function() $(document).on("change", "#direct-content-only", function()
{ {
if (this.checked) if (this.checked)
{ {
UpdateUriParam("leaf_locations_only", true); UpdateUriParam("direct_content_only", true);
} }
else else
{ {
RemoveUriParam("leaf_locations_only"); RemoveUriParam("direct_content_only");
} }
window.location.reload(); window.location.reload();

View File

@ -53,15 +53,15 @@
<div class="form-check custom-control custom-checkbox"> <div class="form-check custom-control custom-checkbox">
<input class="form-check-input custom-control-input" <input class="form-check-input custom-control-input"
type="checkbox" type="checkbox"
id="leaf-locations-only" id="direct-content-only"
@if($showLeafLocationsOnly) checked @endif> @if($showDirectContentOnly) checked @endif>
<label class="form-check-label custom-control-label" <label class="form-check-label custom-control-label"
for="leaf-locations-only"> for="direct-content-only">
{{ $__t('Show only leaf locations') }} {{ $__t('Show direct content only') }}
<i class="fa-solid fa-question-circle text-muted" <i class="fa-solid fa-question-circle text-muted"
data-toggle="tooltip" data-toggle="tooltip"
data-trigger="hover click" data-trigger="hover click"
title="{{ $__t('When enabled, only locations without sub-locations are shown. When disabled, parent locations show aggregated content from all sub-locations.') }}"></i> title="{{ $__t('When enabled, each location shows only products stored directly there. When disabled, locations include products from all sub-locations.') }}"></i>
</label> </label>
</div> </div>
<div class="float-right"> <div class="float-right">
@ -88,59 +88,48 @@
$locationsArray = iterator_to_array($locations); $locationsArray = iterator_to_array($locations);
$locationsResolvedArray = iterator_to_array($locationsResolved); $locationsResolvedArray = iterator_to_array($locationsResolved);
$stockContentArray = iterator_to_array($currentStockLocationContent); $stockContentArray = iterator_to_array($currentStockLocationContent);
@endphp @endphp
@foreach($locationsArray as $location) @foreach($locationsArray as $location)
@php @php
// Determine if this location has children
$hasChildren = count(array_filter($locationsArray, function($loc) use ($location) {
return $loc->parent_location_id == $location->id;
})) > 0;
// Flag to skip this location
$skipLocation = $showLeafLocationsOnly && $hasChildren;
$currentStockEntriesForLocation = []; $currentStockEntriesForLocation = [];
if (!$skipLocation) { if ($showDirectContentOnly) {
// Get stock entries for this location // Only show products directly at this location
if ($showLeafLocationsOnly) { $currentStockEntriesForLocation = array_filter($stockContentArray, function($entry) use ($location) {
// Only show products directly at this location return $entry->location_id == $location->id;
$currentStockEntriesForLocation = array_filter($stockContentArray, function($entry) use ($location) { });
return $entry->location_id == $location->id; } else {
}); // Aggregate products from this location and all descendant locations
} else { $descendantLocationIds = array_map(function($r) {
// Aggregate products from this location and all descendant locations return $r->location_id;
$descendantLocationIds = array_map(function($r) { }, array_filter($locationsResolvedArray, function($r) use ($location) {
return $r->location_id; return $r->ancestor_location_id == $location->id;
}, array_filter($locationsResolvedArray, function($r) use ($location) { }));
return $r->ancestor_location_id == $location->id;
}));
$currentStockEntriesForLocation = array_filter($stockContentArray, function($entry) use ($descendantLocationIds) { $currentStockEntriesForLocation = array_filter($stockContentArray, function($entry) use ($descendantLocationIds) {
return in_array($entry->location_id, $descendantLocationIds); return in_array($entry->location_id, $descendantLocationIds);
}); });
// Aggregate amounts by product_id // Aggregate amounts by product_id
$aggregatedEntries = []; $aggregatedEntries = [];
foreach ($currentStockEntriesForLocation as $entry) { foreach ($currentStockEntriesForLocation as $entry) {
$productId = $entry->product_id; $productId = $entry->product_id;
if (!isset($aggregatedEntries[$productId])) { if (!isset($aggregatedEntries[$productId])) {
$aggregatedEntries[$productId] = (object)[ $aggregatedEntries[$productId] = (object)[
'product_id' => $productId, 'product_id' => $productId,
'location_id' => $location->id, 'location_id' => $location->id,
'amount' => 0, 'amount' => 0,
'amount_opened' => 0 'amount_opened' => 0
]; ];
}
$aggregatedEntries[$productId]->amount += $entry->amount;
$aggregatedEntries[$productId]->amount_opened += $entry->amount_opened;
} }
$currentStockEntriesForLocation = array_values($aggregatedEntries); $aggregatedEntries[$productId]->amount += $entry->amount;
$aggregatedEntries[$productId]->amount_opened += $entry->amount_opened;
} }
$currentStockEntriesForLocation = array_values($aggregatedEntries);
} }
@endphp @endphp
@if($skipLocation || count($currentStockEntriesForLocation) == 0) @if(count($currentStockEntriesForLocation) == 0)
@continue @continue
@endif @endif
<div class="page"> <div class="page">