diff --git a/src/grid/ModelGridView.php b/src/grid/ModelGridView.php index fdae542..efb5da4 100644 --- a/src/grid/ModelGridView.php +++ b/src/grid/ModelGridView.php @@ -16,8 +16,8 @@ use hipanel\grid\RefColumn; use hipanel\modules\stock\helpers\StockLocationsProvider; use hipanel\modules\stock\models\Model; -use hipanel\modules\stock\models\VO\LocationItem; use Yii; +use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\web\User; @@ -115,15 +115,9 @@ public function columns() private function generateStockColumns(): array { $result = []; - $locations = $this->locationsProvider->getAllLocations(); - $locationIds = array_column($locations, 'id'); + $locations = ArrayHelper::index($this->locationsProvider->getAllLocations(), 'id'); foreach ($this->locationsProvider->getLocations() as $key) { - $locationId = array_search($key, $locationIds, true); - if ($locationId === false) { - continue; - } - /** @var LocationItem $location */ - $location = $locations[$locationId]; + $location = $locations[$key]; $icon = Html::tag('span', null, [ 'class' => "fa fa-fw " . $location->icon, ] diff --git a/src/models/Model.php b/src/models/Model.php index e8ee44c..2dd1b16 100644 --- a/src/models/Model.php +++ b/src/models/Model.php @@ -117,7 +117,7 @@ function ($attribute) { ); } }, - 'on' => 'create' + 'on' => 'create', ], // Update @@ -181,8 +181,10 @@ public function renderReserves(string $dc): string $legendItems = (new ModelGridLegend($this))->items(); foreach ($legendItems as $state => $item) { if (!empty($this->counters[$dc][$state])) { - $count = Html::tag('b', - Html::encode($this->counters[$dc][$state]), [ + $count = Html::tag( + 'b', + Html::encode($this->counters[$dc][$state]), + [ 'style' => "color: {$item['color']}", 'title' => $item['label'], ] @@ -191,14 +193,13 @@ public function renderReserves(string $dc): string $perPage = $this->counters[$dc][$state] > 500 ? 500 : ceil($this->counters[$dc][$state] / 50) * 50; - - $link = Html::a($count, - Url::toSearch('part', [ - 'model_id' => $this->id, - 'stock_location_in' => $dc, - 'stock_location_state' => $state, - ], 'index', ['per_page' => $perPage]), - ); + $link = Html::a($count, Url::to([ + '@part/index', + 'PartSearch[model_id]' => $this->id, + 'PartSearch[stock_location_in]' => $dc, + 'PartSearch[stock_location_state]' => $state, + 'per_page' => $perPage, + ])); $out .= $item['prefix'] . $link; } } diff --git a/src/models/VO/LocationItem.php b/src/models/VO/LocationItem.php index c7a2d5e..6810f6b 100644 --- a/src/models/VO/LocationItem.php +++ b/src/models/VO/LocationItem.php @@ -5,6 +5,7 @@ use hipanel\helpers\StringHelper; use hipanel\modules\stock\enums\StockLocationCategory; use hipanel\modules\stock\enums\StockLocationType; +use yii\helpers\Json; final readonly class LocationItem { @@ -28,19 +29,21 @@ public function __construct( public static function fromArray(array $data): self { + $objects = Json::decode($data['objects'] ?? '[]'); + return new self( id: (string)$data['id'], category: StockLocationCategory::from($data['category']), type: StockLocationType::from($data['location_type']), name: (string)$data['location_name'], customers: (string)($data['customers'] ?? ''), - objects: (array)($data['objects'] ?? []), + objects: $objects, ); } private function getLabel(): string { - if ($this->id === 'chwbox' || $this->id === 'stock:ANY') { + if ($this->id === 'chwbox' || $this->id === 'stock:ANY' || str_starts_with($this->id, 'alias_group')) { return $this->name; } diff --git a/src/repositories/StockLocationsRepository.php b/src/repositories/StockLocationsRepository.php index 4044c49..b530ead 100644 --- a/src/repositories/StockLocationsRepository.php +++ b/src/repositories/StockLocationsRepository.php @@ -30,10 +30,6 @@ public function getLocations(): array self::CACHE_DURATION ); - // todo: remove filter when API will return correct type and category without nulls - return array_map( - static fn(array $item) => LocationItem::fromArray($item), - array_filter($data, static fn(array $datum) => !in_array(null, $datum, true)) - ); + return array_map(fn(array $item) => LocationItem::fromArray($item), $data); } } diff --git a/src/widgets/StockLocationsListTreeSelect.php b/src/widgets/StockLocationsListTreeSelect.php index 8349709..f21fb3b 100644 --- a/src/widgets/StockLocationsListTreeSelect.php +++ b/src/widgets/StockLocationsListTreeSelect.php @@ -10,6 +10,7 @@ use hipanel\widgets\VueTreeSelectInput; use Yii; use yii\base\InvalidConfigException; +use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\helpers\Json; use yii\helpers\Url; @@ -42,7 +43,7 @@ public function init(): void { $this->useStorage = !$this->hasModel(); $this->value = $this->hasModel() - ? StringHelper::explode($this->model->{$this->attribute} ?? '') + ? (empty($this->model->{$this->attribute}) ? [] : StringHelper::explode($this->model->{$this->attribute})) : $this->provider->getLocations(); parent::init(); @@ -217,34 +218,74 @@ private function buildOptions(): array { $stockLocationsList = $this->provider->getAllLocations(); - $dcTree = $this->buildDataCentersTree($stockLocationsList); + $aliasGroupTree = $this->buildAliasGroupTree($stockLocationsList); +// $anyStockTree = $this->buildDataCentersTree($stockLocationsList); // todo: legacy tree, may not be useful in the future $chwTree = $this->buildCHWTree($stockLocationsList); $rackTree = $this->buildRacksTree($stockLocationsList); return array_merge( - $dcTree, + $aliasGroupTree, $chwTree, $rackTree, ); } + private function buildAliasGroupTree(array $stockLocationsList): array + { + $result = []; + $locations = array_filter($stockLocationsList, static fn(LocationItem $l) => $l->category->value === 'alias_group_by_stock_state'); + $stocks = ArrayHelper::index(array_filter( + $stockLocationsList, + static fn(LocationItem $l) => $l->category->value === 'stock' && $l->id !== 'stock:ANY' + ), 'id'); + + foreach ($locations as $l) { + if (str_ends_with($l->id, ':ANY')) { + $result[$l->type->value]['id'] = $l->id; + $result[$l->type->value]['label'] = $l->label; + } else { + $item = ['id' => $l->id, 'label' => $l->label]; + foreach ($l->objects as $objName) { + $item['children'][$objName] = ['id' => $objName, 'label' => $objName]; + if (isset($stocks[$objName])) { + $item['children'][$objName]['label'] = $stocks[$objName]->label; + } + } + $result[$l->type->value]['children'][$l->id] = $item; + } + } + $sortedResult = array_merge(array_flip([ + 'alias_group_stock', + 'alias_group_used', + 'alias_group_rma', + 'alias_group_for-test', + ]), $result); + + return [ + [ + 'id' => 'alias_group', + 'label' => Yii::t('hipanel:stock', 'Alias groups'), + 'children' => $this->removeKeysRecursively(array_values($sortedResult)), + ], + ]; + } + /** * @param $stockLocationsList LocationItem[] */ private function buildRacksTree(array $stockLocationsList): array { - $filterByLocationType = function (array $list, string $type) { - return array_filter($list, function (LocationItem $item) use ($type) { - return str_starts_with($item->category->value, 'location') && $item->type->value === $type; - }); - }; + $filterByLocationType = fn(array $list, string $type) => array_filter( + $list, + fn(LocationItem $item) => str_starts_with($item->category->value, 'location') && $item->type->value === $type + ); $dcs = $filterByLocationType($stockLocationsList, 'dc'); $buildings = $filterByLocationType($stockLocationsList, 'building'); $cages = $filterByLocationType($stockLocationsList, 'cage'); $racks = $filterByLocationType($stockLocationsList, 'rack'); - $result = $this->nestRackTreeChildren([$dcs, $buildings, $cages, $racks]); + $result = $this->nestTreeChildren([$dcs, $buildings, $cages, $racks]); return [ [ @@ -255,7 +296,7 @@ private function buildRacksTree(array $stockLocationsList): array ]; } - private function nestRackTreeChildren($dataOrders, string $parent_location = null): array|null + private function nestTreeChildren($dataOrders, string $parent_location = null): array|null { $children = []; if ($dataOrders === []) { @@ -270,7 +311,7 @@ private function nestRackTreeChildren($dataOrders, string $parent_location = nul 'label' => $item->label, ]; - $nested = $this->nestRackTreeChildren($dataOrders, $item->name); + $nested = $this->nestTreeChildren($dataOrders, $item->name); if ($nested !== null) { $children[$item->name]['children'] = $nested; }