diff --git a/modules/EcommerceFinance/Repositories/ThirdPartyWarehouseStorageMirrorRepository.php b/modules/EcommerceFinance/Repositories/ThirdPartyWarehouseStorageMirrorRepository.php index 54f7bebf..48ff2aa6 100644 --- a/modules/EcommerceFinance/Repositories/ThirdPartyWarehouseStorageMirrorRepository.php +++ b/modules/EcommerceFinance/Repositories/ThirdPartyWarehouseStorageMirrorRepository.php @@ -260,28 +260,88 @@ class ThirdPartyWarehouseStorageMirrorRepository $anchorAt = $this->stateAnchor($state); $rangeStart = min($period['start'], $anchorAt); $rangeEnd = max($period['end'], $anchorAt); - $movementPairs = $this->confirmedMovements($headerGeneration, $itemGeneration, null) - ->where('h.occurred_at', '>=', $rangeStart) - ->where('h.occurred_at', '<', $rangeEnd) - ->select(['h.wms_co_id', 'i.sku_code']); + $latestProducts = $this->connection->table(self::PRODUCT_TABLE) + ->where('sku_type', 'normal')->whereNotNull('sku_id')->where('sku_id', '!=', '') + ->groupBy('sku_id')->select('sku_id')->selectRaw('MAX(autoid) AS autoid'); + $latestWarehouses = $this->connection->table(self::WAREHOUSE_TABLE) + ->whereNotNull('wms_co_id')->groupBy('wms_co_id') + ->select('wms_co_id')->selectRaw('MAX(Id) AS Id'); $inventoryPairs = $this->connection->table(self::INVENTORY_TABLE) ->where('generation', $inventoryGeneration) ->whereNotNull('sku_code')->where('sku_code', '!=', '') - ->select(['wms_co_id', 'sku_code']) - ->union($movementPairs); - $anchors = $this->connection->query()->fromSub($inventoryPairs, 'pairs') + ->select(['wms_co_id', 'sku_code']); + $candidates = $this->connection->query()->fromSub($inventoryPairs, 'pairs') + ->select(['pairs.wms_co_id', 'pairs.sku_code']); + $this->containsFilter($candidates, 'pairs.sku_code', $filters['product_code'] ?? ''); + $warehouseFilter = trim((string) ($filters['warehouse_provider'] ?? '')); + if ($warehouseFilter !== '') { + $warehouseIds = $this->connection->query()->fromSub( + clone $latestWarehouses, + 'filter_latest_warehouse', + )->join(self::WAREHOUSE_TABLE . ' as filter_warehouse', function ($join): void { + $join->on('filter_warehouse.wms_co_id', '=', 'filter_latest_warehouse.wms_co_id') + ->on('filter_warehouse.Id', '=', 'filter_latest_warehouse.Id'); + }); + $this->containsFilter($warehouseIds, 'filter_warehouse.name', $warehouseFilter); + $candidates->whereIn('pairs.wms_co_id', $warehouseIds->select('filter_warehouse.wms_co_id')); + } + $categoryFilter = trim((string) ($filters['category'] ?? '')); + if ($categoryFilter !== '') { + $categorySkus = $this->connection->table(self::PRODUCT_TABLE) + ->where('sku_type', 'normal') + ->whereNotNull('sku_id')->where('sku_id', '!=', '') + ->select('sku_id')->distinct(); + $this->containsFilter($categorySkus, 'category', $categoryFilter); + $candidates->whereIn('pairs.sku_code', $categorySkus); + } + + $total = (clone $candidates)->count(); + $pagePairs = (clone $candidates) + ->orderBy('pairs.wms_co_id')->orderBy('pairs.sku_code') + ->forPage($page, $perPage); + $pairRows = (clone $pagePairs)->get(); + if ($pairRows->isEmpty()) { + return [ + 'data' => [], + 'total' => $total, + 'state' => $state, + 'sync' => $this->syncStatus($state), + ]; + } + + $dimensionedPagePairs = $this->connection->query()->fromSub($pagePairs, 'pairs') + ->leftJoinSub($latestProducts, 'latest_product', 'latest_product.sku_id', '=', 'pairs.sku_code') + ->leftJoin(self::PRODUCT_TABLE . ' as s', function ($join): void { + $join->on('s.sku_id', '=', 'latest_product.sku_id') + ->on('s.autoid', '=', 'latest_product.autoid'); + }) + ->leftJoinSub($latestWarehouses, 'latest_warehouse', 'latest_warehouse.wms_co_id', '=', 'pairs.wms_co_id') + ->leftJoin(self::WAREHOUSE_TABLE . ' as w', function ($join): void { + $join->on('w.wms_co_id', '=', 'latest_warehouse.wms_co_id') + ->on('w.Id', '=', 'latest_warehouse.Id'); + }) + ->select(['pairs.wms_co_id', 'pairs.sku_code', 's.category', 'w.name as warehouse_name']); + $anchors = $this->connection->query()->fromSub($dimensionedPagePairs, 'pairs') ->leftJoin(self::INVENTORY_TABLE . ' as inventory', function ($join) use ($inventoryGeneration): void { $join->on('inventory.wms_co_id', '=', 'pairs.wms_co_id') ->on('inventory.sku_code', '=', 'pairs.sku_code') ->where('inventory.generation', '=', $inventoryGeneration); }) - ->select(['pairs.wms_co_id', 'pairs.sku_code']) + ->select(['pairs.wms_co_id', 'pairs.sku_code', 'pairs.category', 'pairs.warehouse_name']) ->selectRaw('COALESCE(inventory.qty, 0) AS snapshot_qty') ->selectRaw('COALESCE(inventory.captured_at, ?) AS snapshot_at', [$anchorAt]); $movements = $this->confirmedMovements($headerGeneration, $itemGeneration, null) ->where('h.occurred_at', '>=', $rangeStart) ->where('h.occurred_at', '<', $rangeEnd) + ->where(function (Builder $pairs) use ($pairRows): void { + foreach ($pairRows as $pair) { + $pairs->orWhere(function (Builder $candidate) use ($pair): void { + $candidate->where('h.wms_co_id', (int) $pair->wms_co_id) + ->where('i.sku_code', (string) $pair->sku_code); + }); + } + }) ->select([ 'h.wms_co_id', 'h.io_type', 'h.occurred_at', 'i.sku_code', 'i.qty as movement_qty', 'i.qty_type as movement_qty_type', @@ -301,8 +361,11 @@ class ThirdPartyWarehouseStorageMirrorRepository $join->on('mv.wms_co_id', '=', 'a.wms_co_id') ->on('mv.sku_code', '=', 'a.sku_code'); }) - ->groupBy(['a.wms_co_id', 'a.sku_code', 'a.snapshot_qty', 'a.snapshot_at']) - ->select(['a.wms_co_id', 'a.sku_code']) + ->groupBy([ + 'a.wms_co_id', 'a.sku_code', 'a.category', 'a.warehouse_name', + 'a.snapshot_qty', 'a.snapshot_at', + ]) + ->select(['a.wms_co_id', 'a.sku_code', 'a.category', 'a.warehouse_name']) ->selectRaw($openingSql . ' AS opening_qty', $openingBindings) ->selectRaw($closingSql . ' AS closing_qty', $closingBindings); foreach (self::MOVEMENT_COLUMNS as $column => $type) { @@ -314,37 +377,8 @@ class ThirdPartyWarehouseStorageMirrorRepository } $monthly->selectRaw('0 AS opening_aux'); - $latestProducts = $this->connection->table(self::PRODUCT_TABLE) - ->where('sku_type', 'normal')->whereNotNull('sku_id')->where('sku_id', '!=', '') - ->groupBy('sku_id')->select('sku_id')->selectRaw('MAX(autoid) AS autoid'); - $latestWarehouses = $this->connection->table(self::WAREHOUSE_TABLE) - ->whereNotNull('wms_co_id')->groupBy('wms_co_id') - ->select('wms_co_id')->selectRaw('MAX(Id) AS Id'); - $query = $this->connection->query()->fromSub($monthly, 'm') - ->leftJoinSub($latestProducts, 'latest_product', 'latest_product.sku_id', '=', 'm.sku_code') - ->leftJoin(self::PRODUCT_TABLE . ' as s', function ($join): void { - $join->on('s.sku_id', '=', 'latest_product.sku_id') - ->on('s.autoid', '=', 'latest_product.autoid'); - }) - ->leftJoinSub($latestWarehouses, 'latest_warehouse', 'latest_warehouse.wms_co_id', '=', 'm.wms_co_id') - ->leftJoin(self::WAREHOUSE_TABLE . ' as w', function ($join): void { - $join->on('w.wms_co_id', '=', 'latest_warehouse.wms_co_id') - ->on('w.Id', '=', 'latest_warehouse.Id'); - }) - ->select(['m.*', 's.category', 'w.name as warehouse_name']); - $this->containsFilter($query, 'm.sku_code', $filters['product_code'] ?? ''); - $this->containsFilter($query, 's.category', $filters['category'] ?? ''); - $this->containsFilter($query, 'w.name', $filters['warehouse_provider'] ?? ''); - $nonZero = ['opening_qty', 'closing_qty', ...array_keys(self::MOVEMENT_COLUMNS)]; - $query->where(function (Builder $values) use ($nonZero): void { - foreach ($nonZero as $index => $column) { - $method = $index === 0 ? 'where' : 'orWhere'; - $values->{$method}('m.' . $column, '<>', 0); - } - }); - - $total = (clone $query)->count(); - $rows = $query->orderBy('w.name')->orderBy('m.sku_code')->forPage($page, $perPage)->get() + $rows = $this->connection->query()->fromSub($monthly, 'm') + ->select('m.*')->orderBy('m.warehouse_name')->orderBy('m.sku_code')->get() ->map(static function (object $row) use ($period): object { $warehouse = trim((string) ($row->warehouse_name ?? ''));