diff --git a/admin/templates/banners/banners-list-custom-script.php b/admin/templates/banners/banners-list-custom-script.php new file mode 100644 index 0000000..56ab843 --- /dev/null +++ b/admin/templates/banners/banners-list-custom-script.php @@ -0,0 +1,100 @@ + + + diff --git a/admin/templates/banners/banners-list.php b/admin/templates/banners/banners-list.php index 45cd47a..3e70c9a 100644 --- a/admin/templates/banners/banners-list.php +++ b/admin/templates/banners/banners-list.php @@ -1,105 +1,5 @@ $this->viewModel]); ?> - - - - viewModel->customScriptView)): ?> viewModel->customScriptView, ['list' => $this->viewModel]); ?> diff --git a/admin/templates/filemanager/filemanager.php b/admin/templates/filemanager/filemanager.php index 114d499..dc2d008 100644 --- a/admin/templates/filemanager/filemanager.php +++ b/admin/templates/filemanager/filemanager.php @@ -1 +1,4 @@ - +filemanager_url ?? '/libraries/filemanager-9.14.2/dialog.php')); +?> + diff --git a/admin/templates/product-archive/products-list-custom-script.php b/admin/templates/product-archive/products-list-custom-script.php new file mode 100644 index 0000000..aacad98 --- /dev/null +++ b/admin/templates/product-archive/products-list-custom-script.php @@ -0,0 +1,100 @@ + + + diff --git a/admin/templates/product-archive/products-list.php b/admin/templates/product-archive/products-list.php new file mode 100644 index 0000000..3e70c9a --- /dev/null +++ b/admin/templates/product-archive/products-list.php @@ -0,0 +1,5 @@ + $this->viewModel]); ?> + +viewModel->customScriptView)): ?> + viewModel->customScriptView, ['list' => $this->viewModel]); ?> + diff --git a/admin/templates/product_archive/products-list-table.php b/admin/templates/product_archive/products-list-table.php deleted file mode 100644 index f2ac941..0000000 --- a/admin/templates/product_archive/products-list-table.php +++ /dev/null @@ -1,41 +0,0 @@ - current_page - 1 ) * 10 + 1;?> - products as $product ):?> - - - - - -
- - <?= $product['images'][0]['alt'];?> - - Brak zdjęcia - -
-
- - - -
- - - - - - - - - - - - - '>kombinacje () - - - '>edytuj - - - ' class="product-unarchive">przywróć - - - diff --git a/admin/templates/product_archive/products-list.php b/admin/templates/product_archive/products-list.php deleted file mode 100644 index b86d2ac..0000000 --- a/admin/templates/product_archive/products-list.php +++ /dev/null @@ -1,152 +0,0 @@ -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
#NazwaCenaCena promocyjnaStan MGKombinacjeEdytujPrzywróć
- -
- -
-
-
-
- diff --git a/autoload/Domain/Product/ProductRepository.php b/autoload/Domain/Product/ProductRepository.php index 4d5dd67..e397697 100644 --- a/autoload/Domain/Product/ProductRepository.php +++ b/autoload/Domain/Product/ProductRepository.php @@ -9,6 +9,8 @@ namespace Domain\Product; */ class ProductRepository { + private const MAX_PER_PAGE = 100; + /** * @var \medoo Instancja Medoo ORM */ @@ -50,6 +52,118 @@ class ProductRepository return $product ?: null; } + /** + * Zwraca liste produktow z archiwum do panelu admin. + * + * @return array{items: array>, total: int} + */ + public function listArchivedForAdmin( + array $filters, + string $sortColumn = 'id', + string $sortDir = 'DESC', + int $page = 1, + int $perPage = 10 + ): array { + $allowedSortColumns = [ + 'id' => 'psp.id', + 'name' => 'name', + 'price_brutto' => 'psp.price_brutto', + 'price_brutto_promo' => 'psp.price_brutto_promo', + 'quantity' => 'psp.quantity', + 'combinations' => 'combinations', + ]; + + $sortSql = $allowedSortColumns[$sortColumn] ?? 'psp.id'; + $sortDir = strtoupper(trim($sortDir)) === 'ASC' ? 'ASC' : 'DESC'; + $page = max(1, $page); + $perPage = min(self::MAX_PER_PAGE, max(1, $perPage)); + $offset = ($page - 1) * $perPage; + + $where = ['psp.archive = 1', 'psp.parent_id IS NULL']; + $params = []; + + $phrase = trim((string)($filters['phrase'] ?? '')); + if (strlen($phrase) > 255) { + $phrase = substr($phrase, 0, 255); + } + + if ($phrase !== '') { + $where[] = '( + psp.ean LIKE :phrase + OR psp.sku LIKE :phrase + OR EXISTS ( + SELECT 1 + FROM pp_shop_products_langs AS pspl2 + WHERE pspl2.product_id = psp.id + AND pspl2.name LIKE :phrase + ) + )'; + $params[':phrase'] = '%' . $phrase . '%'; + } + + $whereSql = implode(' AND ', $where); + + $sqlCount = " + SELECT COUNT(0) + FROM pp_shop_products AS psp + WHERE {$whereSql} + "; + + $stmtCount = $this->db->query($sqlCount, $params); + $countRows = $stmtCount ? $stmtCount->fetchAll() : []; + $total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0; + + $sql = " + SELECT + psp.id, + psp.price_brutto, + psp.price_brutto_promo, + psp.quantity, + psp.sku, + psp.ean, + ( + SELECT pspl.name + FROM pp_shop_products_langs AS pspl + INNER JOIN pp_langs AS pl ON pl.id = pspl.lang_id + WHERE pspl.product_id = psp.id + AND pspl.name <> '' + ORDER BY pl.o ASC + LIMIT 1 + ) AS name, + ( + SELECT pspi.src + FROM pp_shop_products_images AS pspi + WHERE pspi.product_id = psp.id + ORDER BY pspi.o ASC, pspi.id ASC + LIMIT 1 + ) AS image_src, + ( + SELECT pspi.alt + FROM pp_shop_products_images AS pspi + WHERE pspi.product_id = psp.id + ORDER BY pspi.o ASC, pspi.id ASC + LIMIT 1 + ) AS image_alt, + ( + SELECT COUNT(0) + FROM pp_shop_products AS pspc + WHERE pspc.parent_id = psp.id + ) AS combinations + FROM pp_shop_products AS psp + WHERE {$whereSql} + ORDER BY {$sortSql} {$sortDir}, psp.id {$sortDir} + LIMIT {$perPage} OFFSET {$offset} + "; + + $stmt = $this->db->query($sql, $params); + $items = $stmt ? $stmt->fetchAll() : []; + + return [ + 'items' => is_array($items) ? $items : [], + 'total' => $total, + ]; + } + /** * Pobiera cenę produktu (promocyjną jeśli jest niższa, w przeciwnym razie regularną) * diff --git a/autoload/admin/Controllers/BannerController.php b/autoload/admin/Controllers/BannerController.php index d2c8a74..666a64c 100644 --- a/autoload/admin/Controllers/BannerController.php +++ b/autoload/admin/Controllers/BannerController.php @@ -147,7 +147,8 @@ class BannerController '/admin/banners/view_list/', 'Brak danych w tabeli.', '/admin/banners/banner_edit/', - 'Dodaj baner' + 'Dodaj baner', + 'banners/banners-list-custom-script' ); return \Tpl::view('banners/banners-list', [ diff --git a/autoload/admin/Controllers/FilemanagerController.php b/autoload/admin/Controllers/FilemanagerController.php new file mode 100644 index 0000000..ba2535e --- /dev/null +++ b/autoload/admin/Controllers/FilemanagerController.php @@ -0,0 +1,46 @@ +ensureFilemanagerAccessKey(); + $filemanagerUrl = $this->buildFilemanagerUrl($akey); + + return \Tpl::view('filemanager/filemanager', [ + 'filemanager_url' => $filemanagerUrl, + ]); + } + + private function ensureFilemanagerAccessKey(): string + { + $expiresAt = (int)($_SESSION['rfm_akey_expires'] ?? 0); + $existingKey = trim((string)($_SESSION['rfm_akey'] ?? '')); + + if ($existingKey !== '' && $expiresAt >= time()) { + $_SESSION['rfm_akey_expires'] = time() + self::RFM_KEY_TTL; + return $existingKey; + } + + try { + $newKey = bin2hex(random_bytes(16)); + } catch (\Throwable $e) { + $newKey = sha1(uniqid('rfm', true)); + } + + $_SESSION['rfm_akey'] = $newKey; + $_SESSION['rfm_akey_expires'] = time() + self::RFM_KEY_TTL; + + return $newKey; + } + + private function buildFilemanagerUrl(string $akey): string + { + return self::FILEMANAGER_DIALOG_PATH . '?akey=' . rawurlencode($akey); + } +} + diff --git a/autoload/admin/Controllers/ProductArchiveController.php b/autoload/admin/Controllers/ProductArchiveController.php index b364335..5883b59 100644 --- a/autoload/admin/Controllers/ProductArchiveController.php +++ b/autoload/admin/Controllers/ProductArchiveController.php @@ -14,24 +14,142 @@ class ProductArchiveController public function list(): string { - $current_page = \S::get_session( 'archive_products_list_current_page' ); + $sortableColumns = ['id', 'name', 'price_brutto', 'price_brutto_promo', 'quantity']; - if ( !$current_page ) { - $current_page = 1; - \S::set_session( 'archive_products_list_current_page', $current_page ); + $filterDefinitions = [ + [ + 'key' => 'phrase', + 'label' => 'Nazwa / EAN / SKU', + 'type' => 'text', + ], + ]; + + $listRequest = \admin\Support\TableListRequestFactory::fromRequest( + $filterDefinitions, + $sortableColumns, + 'id', + [10, 15, 25, 50, 100], + 10 + ); + + $result = $this->productRepository->listArchivedForAdmin( + $listRequest['filters'], + $listRequest['sortColumn'], + $listRequest['sortDir'], + $listRequest['page'], + $listRequest['perPage'] + ); + + $rows = []; + $lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1; + foreach ($result['items'] as $item) { + $id = (int)($item['id'] ?? 0); + $name = trim((string)($item['name'] ?? '')); + $sku = trim((string)($item['sku'] ?? '')); + $ean = trim((string)($item['ean'] ?? '')); + $imageSrc = trim((string)($item['image_src'] ?? '')); + $imageAlt = trim((string)($item['image_alt'] ?? '')); + $priceBrutto = (string)($item['price_brutto'] ?? ''); + $priceBruttoPromo = (string)($item['price_brutto_promo'] ?? ''); + $quantity = (int)($item['quantity'] ?? 0); + $combinations = (int)($item['combinations'] ?? 0); + + if ($imageSrc === '') { + $imageSrc = '/admin/layout/images/no-image.png'; + } elseif (!preg_match('#^(https?:)?//#i', $imageSrc) && strpos($imageSrc, '/') !== 0) { + $imageSrc = '/' . ltrim($imageSrc, '/'); + } + + $categories = trim((string)\admin\factory\ShopProduct::product_categories($id)); + $categoriesHtml = ''; + if ($categories !== '') { + $categoriesHtml = '' + . htmlspecialchars($categories, ENT_QUOTES, 'UTF-8') + . ''; + } + + $skuEanParts = []; + if ($sku !== '') { + $skuEanParts[] = 'SKU: ' . htmlspecialchars($sku, ENT_QUOTES, 'UTF-8'); + } + if ($ean !== '') { + $skuEanParts[] = 'EAN: ' . htmlspecialchars($ean, ENT_QUOTES, 'UTF-8'); + } + $skuEanHtml = ''; + if (!empty($skuEanParts)) { + $skuEanHtml = '' . implode(', ', $skuEanParts) . ''; + } + + $productCell = '
' + . '' . htmlspecialchars($imageAlt, ENT_QUOTES, 'UTF-8') . '' + . '
' + . '
' + . '' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '' + . '
' + . $categoriesHtml + . $skuEanHtml; + + $rows[] = [ + 'lp' => $lp++ . '.', + 'product' => $productCell, + 'price_brutto' => $priceBrutto !== '' ? $priceBrutto : '-', + 'price_brutto_promo' => $priceBruttoPromo !== '' ? $priceBruttoPromo : '-', + 'quantity' => (string)$quantity, + '_actions' => [ + [ + 'label' => 'Przywroc', + 'url' => '/admin/product_archive/unarchive/product_id=' . $id, + 'class' => 'btn btn-xs btn-success', + 'confirm' => 'Na pewno chcesz przywrocic wybrany produkt z archiwum?', + 'confirm_ok' => 'Przywroc', + 'confirm_cancel' => 'Anuluj', + ], + ], + ]; } - $query = \S::get_session( 'archive_products_list_query' ); - $query_array = []; - if ( $query ) { - parse_str( $query, $query_array ); - } + $total = (int)$result['total']; + $totalPages = max(1, (int)ceil($total / $listRequest['perPage'])); - return \Tpl::view( 'product_archive/products-list', [ - 'current_page' => $current_page, - 'query_array' => $query_array, - 'pagination_max' => ceil( \admin\factory\ShopProduct::count_product( [ 'archive' => 1 ] ) / 10 ) - ] ); + $viewModel = new \admin\ViewModels\Common\PaginatedTableViewModel( + [ + ['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false], + ['key' => 'product', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true], + ['key' => 'price_brutto', 'sort_key' => 'price_brutto', 'label' => 'Cena', 'class' => 'text-center', 'sortable' => true], + ['key' => 'price_brutto_promo', 'sort_key' => 'price_brutto_promo', 'label' => 'Cena promocyjna', 'class' => 'text-center', 'sortable' => true], + ['key' => 'quantity', 'sort_key' => 'quantity', 'label' => 'Stan MG', 'class' => 'text-center', 'sortable' => true] + ], + $rows, + $listRequest['viewFilters'], + [ + 'column' => $listRequest['sortColumn'], + 'dir' => $listRequest['sortDir'], + ], + [ + 'page' => $listRequest['page'], + 'per_page' => $listRequest['perPage'], + 'total' => $total, + 'total_pages' => $totalPages, + ], + array_merge($listRequest['queryFilters'], [ + 'sort' => $listRequest['sortColumn'], + 'dir' => $listRequest['sortDir'], + 'per_page' => $listRequest['perPage'], + ]), + $listRequest['perPageOptions'], + $sortableColumns, + '/admin/product_archive/products_list/', + 'Brak danych w tabeli.', + null, + null, + 'product-archive/products-list-custom-script' + ); + + return \Tpl::view('product-archive/products-list', [ + 'viewModel' => $viewModel, + ]); } public function unarchive(): void diff --git a/autoload/admin/class.Site.php b/autoload/admin/class.Site.php index 4172a23..7d196bd 100644 --- a/autoload/admin/class.Site.php +++ b/autoload/admin/class.Site.php @@ -227,6 +227,14 @@ class Site new \Domain\Product\ProductRepository( $mdb ) ); }, + // Alias dla starego modułu /admin/archive/products_list/ + 'Archive' => function() { + global $mdb; + + return new \admin\Controllers\ProductArchiveController( + new \Domain\Product\ProductRepository( $mdb ) + ); + }, 'Dictionaries' => function() { global $mdb; @@ -234,6 +242,9 @@ class Site new \Domain\Dictionaries\DictionariesRepository( $mdb ) ); }, + 'Filemanager' => function() { + return new \admin\Controllers\FilemanagerController(); + }, ]; return self::$newControllers; diff --git a/autoload/admin/controls/class.Archive.php b/autoload/admin/controls/class.Archive.php deleted file mode 100644 index 1db4624..0000000 --- a/autoload/admin/controls/class.Archive.php +++ /dev/null @@ -1,30 +0,0 @@ - $current_page, - 'query_array' => $query_array, - 'pagination_max' => ceil( \admin\factory\ShopProduct::count_product() / 10 ) - ] ); - } -} \ No newline at end of file diff --git a/autoload/admin/controls/class.Filemanager.php b/autoload/admin/controls/class.Filemanager.php deleted file mode 100644 index cfa6e21..0000000 --- a/autoload/admin/controls/class.Filemanager.php +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/autoload/admin/controls/class.ShopProduct.php b/autoload/admin/controls/class.ShopProduct.php index 62541b6..e076736 100644 --- a/autoload/admin/controls/class.ShopProduct.php +++ b/autoload/admin/controls/class.ShopProduct.php @@ -257,23 +257,11 @@ class ShopProduct // ajax_load_products ARCHIVE static public function ajax_load_products_archive() { - $response = [ 'status' => 'error', 'msg' => 'Podczas ładowania produktów wystąpił błąd. Proszę spróbować ponownie.' ]; - - \S::set_session( 'products_list_current_page', \S::get( 'current_page' ) ); - \S::set_session( 'products_list_query', \S::get( 'query' ) ); - - if ( $products = \admin\factory\ShopProduct::ajax_products_list_archive( \S::get_session( 'products_list_current_page' ), \S::get_session( 'products_list_query' ) ) ) { - $response = [ - 'status' => 'ok', - 'pagination_max' => ceil( $products['products_count'] / 10 ), - 'html' => \Tpl::view( 'product_archive/products-list-table', [ - 'products' => $products['products'], - 'current_page' => \S::get( 'current_page' ), - ] ) - ]; - } - - echo json_encode( $response ); + echo json_encode( [ + 'status' => 'deprecated', + 'msg' => 'Endpoint nie jest juz wspierany. Uzyj /admin/product_archive/products_list/.', + 'redirect_url' => '/admin/product_archive/products_list/' + ] ); exit; } diff --git a/autoload/admin/view/class.FileManager.php b/autoload/admin/view/class.FileManager.php deleted file mode 100644 index f6c4b1e..0000000 --- a/autoload/admin/view/class.FileManager.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/updates/0.10/ver_0.200.zip b/updates/0.10/ver_0.200.zip new file mode 100644 index 0000000..1058d88 Binary files /dev/null and b/updates/0.10/ver_0.200.zip differ diff --git a/updates/0.10/ver_0.200_deleted_files.txt b/updates/0.10/ver_0.200_deleted_files.txt new file mode 100644 index 0000000..31bca08 --- /dev/null +++ b/updates/0.10/ver_0.200_deleted_files.txt @@ -0,0 +1,8 @@ +# Deleted files for update ver_0.200 +# Generated: 2026-02-11 00:02:27 + +admin/templates/product_archive/products-list-table.php +admin/templates/product_archive/products-list.php +autoload/admin/controls/class.Archive.php +autoload/admin/controls/class.Filemanager.php +autoload/admin/view/class.FileManager.php