refactor articles_archive to DI controller and table-list

This commit is contained in:
2026-02-12 23:53:05 +01:00
parent 0d4e175b1a
commit 6832009020
16 changed files with 600 additions and 199 deletions

View File

@@ -92,7 +92,7 @@ Artykuły.
| id | PK | | id | PK |
| status | -1 = archiwum, 0 = nieaktywny, 1 = aktywny | | status | -1 = archiwum, 0 = nieaktywny, 1 = aktywny |
**Używane w:** `admin\controls\ArticlesArchive`, `Domain\Article\ArticleRepository::find()` **Używane w:** `admin\Controllers\ArticlesArchiveController`, `Domain\Article\ArticleRepository::find()`, `Domain\Article\ArticleRepository::listArchivedForAdmin()`
## pp_articles_pages ## pp_articles_pages
Strony artykułów. Strony artykułów.
@@ -287,3 +287,31 @@ Szablony tresci e-maili (uzytkownik + administracyjne/systemowe).
**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `admin\\Controllers\\NewsletterController`, `front\\factory\\Newsletter` **Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `admin\\Controllers\\NewsletterController`, `front\\factory\\Newsletter`
**Aktualizacja 2026-02-12 (ver. 0.257):** modul `/admin/newsletter` korzysta z `Domain\\Newsletter\\NewsletterRepository` (DI kontroler + fasada legacy). **Aktualizacja 2026-02-12 (ver. 0.257):** modul `/admin/newsletter` korzysta z `Domain\\Newsletter\\NewsletterRepository` (DI kontroler + fasada legacy).
## pp_scontainers
Kontenery statyczne (modul /admin/scontainers).
| Kolumna | Opis |
|---------|------|
| id | PK |
| status | 1 = aktywny, 0 = nieaktywny |
| show_title | 1 = pokaz tytul, 0 = ukryj tytul |
**Uzywane w:** `Domain\Scontainers\ScontainersRepository`, `admin\Controllers\ScontainersController`, `front\factory\Scontainers`
## pp_scontainers_langs
Tlumaczenia kontenerow statycznych (per jezyk).
| Kolumna | Opis |
|---------|------|
| id | PK |
| container_id | FK do pp_scontainers |
| lang_id | ID jezyka (np. pl, en) |
| title | Tytul kontenera |
| text | Tresc HTML kontenera |
**Uzywane w:** `Domain\Scontainers\ScontainersRepository`, `front\factory\Scontainers`
**Aktualizacja 2026-02-12 (ver. 0.259):** modul `/admin/scontainers` korzysta z `Domain\Scontainers\ScontainersRepository` (DI kontroler + fasada legacy).
**Aktualizacja 2026-02-12 (ver. 0.260):** modul `/admin/articles_archive` korzysta z `Domain\Article\ArticleRepository` (`listArchivedForAdmin`, `restore`, `deletePermanently`) przez `admin\Controllers\ArticlesArchiveController`.

View File

@@ -437,3 +437,21 @@ Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users`
- UPDATE: modul `/admin/newsletter/` - tymczasowo wylaczono liste `email_templates_user` (Szablony uzytkownika). - UPDATE: modul `/admin/newsletter/` - tymczasowo wylaczono liste `email_templates_user` (Szablony uzytkownika).
- UPDATE: lista i edycja szablonow newslettera w panelu ograniczona do szablonow administracyjnych (`is_admin = 1`). - UPDATE: lista i edycja szablonow newslettera w panelu ograniczona do szablonow administracyjnych (`is_admin = 1`).
- CLEANUP: usuniete nieuzywane widoki: `admin/templates/newsletter/prepare.php`, `admin/templates/newsletter/preview.php`, `admin/templates/newsletter/email-templates-user.php`. - CLEANUP: usuniete nieuzywane widoki: `admin/templates/newsletter/prepare.php`, `admin/templates/newsletter/preview.php`, `admin/templates/newsletter/email-templates-user.php`.
## Aktualizacja 2026-02-12 (ver. 0.259)
- NOWE: `Domain\Scontainers\ScontainersRepository` (listForAdmin/find/save/delete/detailsForLanguage + czyszczenie cache frontu).
- NOWE: `admin\Controllers\ScontainersController` (DI) dla akcji `list/view_list`, `container_edit`, `container_save`, `container_delete`.
- UPDATE: `/admin/scontainers/*` przepiete z legacy `grid/gridEdit` na `components/table-list` i `components/form-edit`.
- UPDATE: `admin\Site` ma fabryke DI dla modulu `Scontainers` oraz mapowanie akcji `container_*` -> `edit/save/delete`.
- UPDATE: `admin\factory\Scontainers` dziala jako fasada do `Domain\Scontainers\ScontainersRepository`.
- UPDATE: `front\factory\Scontainers` korzysta z `Domain\Scontainers\ScontainersRepository`.
- CLEANUP: usuniete legacy klasy `autoload/admin/controls/class.Scontainers.php`, `autoload/admin/view/class.Scontainers.php`.
- Testy: 158 tests, 397 assertions.
## Aktualizacja 2026-02-12 (ver. 0.260)
- NOWE: `Domain\Article\ArticleRepository` rozszerzone o `listArchivedForAdmin()`, `restore()`, `deletePermanently()`.
- NOWE: `admin\Controllers\ArticlesArchiveController` (DI) dla akcji `list/view_list`, `article_restore`, `article_delete`.
- UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ArticlesArchive` oraz mapowanie akcji `article_restore -> restore`.
- UPDATE: `/admin/articles_archive/view_list/` przepiete z legacy `grid` na `components/table-list`.
- CLEANUP: usuniete legacy klasy `autoload/admin/controls/class.ArticlesArchive.php`, `autoload/admin/factory/class.ArticlesArchive.php`, `autoload/admin/view/class.ArticlesArchive.php`.
- Testy: 165 tests, 424 assertions.

View File

@@ -634,3 +634,23 @@ Gdy `persist = true`:
- UPDATE: tymczasowo wylaczono modul `Szablony uzytkownika`. - UPDATE: tymczasowo wylaczono modul `Szablony uzytkownika`.
- UPDATE: aktywna obsluga tylko szablonow administracyjnych (`is_admin = 1`). - UPDATE: aktywna obsluga tylko szablonow administracyjnych (`is_admin = 1`).
- CLEANUP: usuniete nieuzywane widoki `prepare.php`, `preview.php`, `email-templates-user.php`. - CLEANUP: usuniete nieuzywane widoki `prepare.php`, `preview.php`, `email-templates-user.php`.
## Aktualizacja 2026-02-12 (ver. 0.259)
- **Scontainers** - **ZMIGROWANE** (2026-02-12)
- NOWE: `Domain\Scontainers\ScontainersRepository` (listForAdmin, find, save, delete, detailsForLanguage)
- NOWE: `admin\Controllers\ScontainersController` (DI)
- UPDATE: `/admin/scontainers/view_list/` migrowane na `components/table-list`
- UPDATE: `/admin/scontainers/container_edit/` migrowane na `components/form-edit`
- UPDATE: `admin\factory\Scontainers` jako fasada do repozytorium
- UPDATE: `front\factory\Scontainers` korzysta z repozytorium domenowego
- CLEANUP: usuniete `autoload/admin/controls/class.Scontainers.php` i `autoload/admin/view/class.Scontainers.php`
- Testy po zmianie: **158 tests, 397 assertions**
## Aktualizacja 2026-02-12 (ver. 0.260)
- **ArticlesArchive** - **ZMIGROWANE** (2026-02-12)
- NOWE: `admin\Controllers\ArticlesArchiveController` (DI)
- UPDATE: `Domain\Article\ArticleRepository` rozszerzone o `listArchivedForAdmin()`, `restore()`, `deletePermanently()`
- UPDATE: `/admin/articles_archive/view_list/` migrowane na `components/table-list`
- UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ArticlesArchive` + mapowanie `article_restore -> restore`
- CLEANUP: usuniete `autoload/admin/controls/class.ArticlesArchive.php`, `autoload/admin/factory/class.ArticlesArchive.php`, `autoload/admin/view/class.ArticlesArchive.php`
- Testy po zmianie: **165 tests, 424 assertions**

View File

@@ -224,3 +224,25 @@ Ostatnio zweryfikowano: 2026-02-12
```text ```text
OK (150 tests, 372 assertions) OK (150 tests, 372 assertions)
``` ```
## Aktualizacja suite (release 0.259)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (158 tests, 397 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Scontainers/ScontainersRepositoryTest.php`
- `tests/Unit/admin/Controllers/ScontainersControllerTest.php`
## Aktualizacja suite (release 0.260)
Ostatnio zweryfikowano: 2026-02-12
```text
OK (165 tests, 424 assertions)
```
Nowe testy dodane 2026-02-12:
- `tests/Unit/Domain/Article/ArticleRepositoryTest.php` (rozszerzenie o testy `restore`, `deletePermanently`, `listArchivedForAdmin`)
- `tests/Unit/admin/Controllers/ArticlesArchiveControllerTest.php`

View File

@@ -1,67 +1,5 @@
<?php <?= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>
global $gdb;
$grid = new \grid( 'pp_articles' ); <?php if (!empty($this->viewModel->customScriptView)): ?>
$grid -> gdb_opt = $gdb; <?= \Tpl::view($this->viewModel->customScriptView, ['list' => $this->viewModel]); ?>
$grid -> sql = 'SELECT *' <?php endif; ?>
. 'FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title '
. 'FROM '
. 'pp_articles AS pa WHERE status = -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] '
. 'ORDER BY '
. '[order_p1] [order_p2]';
$grid -> sql_count = 'SELECT '
. 'COUNT(0) FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title '
. 'FROM '
. 'pp_articles AS pa WHERE status = -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] ';
$grid -> debug = true;
$grid -> order = [ 'column' => 'date_add', 'type' => 'DESC' ];
$grid -> columns_view = [
[
'name' => 'Lp.',
'th' => [ 'class' => 'g-lp' ],
'td' => [ 'class' => 'g-center' ],
'autoincrement' => true
],
[
'name' => 'Tytuł',
'db' => 'id',
'replace' => [ 'sql' => "SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = [id] AND title != '' ORDER BY o ASC LIMIT 1" ]
],
[
'name' => 'Data dodania',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 140px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_add]" ) );'
],
[
'name' => 'Data modyfikacji',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 140px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_modify]" ) );'
],
[
'name' => 'Akcja',
'th' => [ 'class' => 'g-center' ],
'td' => [ 'class' => 'g-center', 'style' => 'width: 50px;' ],
'content' => '<a href="/admin/articles_archive/article_restore/id=[id]">przywróć</a>'
],
[
'name' => 'Akcja',
'action' => [ 'type' => 'delete', 'url' => '/admin/articles_archive/article_delete/id=[id]' ],
'th' => [ 'class' => 'g-center' ],
'td' => [ 'class' => 'g-center', 'style' => 'width: 50px;' ]
]
];
echo $grid -> draw();

View File

@@ -331,6 +331,32 @@ class ArticleRepository
return (bool)$result; return (bool)$result;
} }
/**
* Przywraca artykul z archiwum (status = 0).
*/
public function restore(int $articleId): bool
{
$result = $this->db->update('pp_articles', ['status' => 0], ['id' => $articleId]);
return (bool)$result;
}
/**
* Trwale usuwa artykul wraz z relacjami i plikami z dysku.
*/
public function deletePermanently(int $articleId): bool
{
$this->db->delete('pp_articles_pages', ['article_id' => $articleId]);
$this->db->delete('pp_articles_langs', ['article_id' => $articleId]);
$this->db->delete('pp_articles_images', ['article_id' => $articleId]);
$this->db->delete('pp_articles_files', ['article_id' => $articleId]);
$this->db->delete('pp_articles', ['id' => $articleId]);
\S::delete_dir('../upload/article_images/article_' . $articleId . '/');
\S::delete_dir('../upload/article_files/article_' . $articleId . '/');
return true;
}
/** /**
* Zwraca liste artykulow do panelu admin z filtrowaniem, sortowaniem i paginacja. * Zwraca liste artykulow do panelu admin z filtrowaniem, sortowaniem i paginacja.
* *
@@ -431,6 +457,93 @@ class ArticleRepository
]; ];
} }
/**
* Zwraca liste artykulow z archiwum do panelu admin z filtrowaniem, sortowaniem i paginacja.
*
* @return array{items: array<int, array<string, mixed>>, total: int}
*/
public function listArchivedForAdmin(
array $filters,
string $sortColumn = 'date_add',
string $sortDir = 'DESC',
int $page = 1,
int $perPage = 15
): array {
$sortColumn = trim($sortColumn);
$sortDir = strtoupper(trim($sortDir));
$allowedSortColumns = [
'title' => 'title',
'date_add' => 'pa.date_add',
'date_modify' => 'pa.date_modify',
];
$sortSql = $allowedSortColumns[$sortColumn] ?? 'pa.date_add';
$sortDir = $sortDir === 'ASC' ? 'ASC' : 'DESC';
$page = max(1, $page);
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
$offset = ($page - 1) * $perPage;
$where = ['pa.status = -1'];
$params = [];
$title = trim((string)($filters['title'] ?? ''));
if (strlen($title) > 255) {
$title = substr($title, 0, 255);
}
if ($title !== '') {
$where[] = "(
SELECT title
FROM pp_articles_langs AS pal, pp_langs AS pl
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
ORDER BY o ASC
LIMIT 1
) LIKE :title";
$params[':title'] = '%' . $title . '%';
}
$this->appendDateRangeFilter($where, $params, 'pa.date_add', 'date_add_from', 'date_add_to', $filters);
$this->appendDateRangeFilter($where, $params, 'pa.date_modify', 'date_modify_from', 'date_modify_to', $filters);
$whereSql = implode(' AND ', $where);
$sqlCount = "
SELECT COUNT(0)
FROM pp_articles AS pa
WHERE {$whereSql}
";
$stmtCount = $this->db->query($sqlCount, $params);
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
$sql = "
SELECT
pa.id,
pa.date_add,
pa.date_modify,
(
SELECT title
FROM pp_articles_langs AS pal, pp_langs AS pl
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
ORDER BY o ASC
LIMIT 1
) AS title
FROM pp_articles AS pa
WHERE {$whereSql}
ORDER BY {$sortSql} {$sortDir}, pa.id {$sortDir}
LIMIT {$perPage} OFFSET {$offset}
";
$stmt = $this->db->query($sql, $params);
$items = $stmt ? $stmt->fetchAll() : [];
return [
'items' => is_array($items) ? $items : [],
'total' => $total,
];
}
/** /**
* Zapisuje kolejnosc zdjec galerii artykulu. * Zapisuje kolejnosc zdjec galerii artykulu.
*/ */

View File

@@ -0,0 +1,147 @@
<?php
namespace admin\Controllers;
use Domain\Article\ArticleRepository;
use admin\ViewModels\Common\PaginatedTableViewModel;
class ArticlesArchiveController
{
private ArticleRepository $repository;
public function __construct(ArticleRepository $repository)
{
$this->repository = $repository;
}
public function list(): string
{
$sortableColumns = ['title', 'date_add', 'date_modify'];
$filterDefinitions = [
[
'key' => 'title',
'label' => 'Tytul',
'type' => 'text',
],
];
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
$filterDefinitions,
$sortableColumns,
'date_add'
);
$result = $this->repository->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);
$title = trim((string)($item['title'] ?? ''));
$rows[] = [
'lp' => $lp++ . '.',
'title' => '<a href="/admin/articles/article_edit/id=' . $id . '">' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</a>',
'date_add' => !empty($item['date_add']) ? date('Y-m-d H:i', strtotime((string)$item['date_add'])) : '-',
'date_modify' => !empty($item['date_modify']) ? date('Y-m-d H:i', strtotime((string)$item['date_modify'])) : '-',
'_actions' => [
[
'label' => 'Przywroc',
'url' => '/admin/articles_archive/article_restore/id=' . $id,
'class' => 'btn btn-xs btn-success',
'confirm' => 'Na pewno chcesz przywrocic wybrany artykul?',
'confirm_ok' => 'Przywroc',
'confirm_cancel' => 'Anuluj',
],
[
'label' => 'Usun',
'url' => '/admin/articles_archive/article_delete/id=' . $id,
'class' => 'btn btn-xs btn-danger',
'confirm' => 'Na pewno chcesz trwale usunac wybrany artykul?',
'confirm_ok' => 'Usun',
'confirm_cancel' => 'Anuluj',
],
],
];
}
$total = (int)$result['total'];
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
$viewModel = new PaginatedTableViewModel(
[
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
['key' => 'title', 'sort_key' => 'title', 'label' => 'Tytul', 'sortable' => true, 'raw' => true],
['key' => 'date_add', 'sort_key' => 'date_add', 'label' => 'Data dodania', 'class' => 'text-center', 'sortable' => true],
['key' => 'date_modify', 'sort_key' => 'date_modify', 'label' => 'Data modyfikacji', '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/articles_archive/view_list/',
'Brak danych w tabeli.'
);
return \Tpl::view('articles/articles-archive-list', [
'viewModel' => $viewModel,
]);
}
public function view_list(): string
{
return $this->list();
}
public function restore(): void
{
if ($this->repository->restore((int)\S::get('id'))) {
\S::alert('Artykul zostal przywrocony.');
}
header('Location: /admin/articles_archive/view_list/');
exit;
}
public function article_restore(): void
{
$this->restore();
}
public function delete(): void
{
if ($this->repository->deletePermanently((int)\S::get('id'))) {
\S::alert('Artykul zostal trwale usuniety.');
}
header('Location: /admin/articles_archive/view_list/');
exit;
}
public function article_delete(): void
{
$this->delete();
}
}

View File

@@ -211,6 +211,13 @@ class Site
new \Domain\Layouts\LayoutsRepository( $mdb ) new \Domain\Layouts\LayoutsRepository( $mdb )
); );
}, },
'ArticlesArchive' => function() {
global $mdb;
return new \admin\Controllers\ArticlesArchiveController(
new \Domain\Article\ArticleRepository( $mdb )
);
},
'Banners' => function() { 'Banners' => function() {
global $mdb; global $mdb;
@@ -286,6 +293,14 @@ class Site
new \Domain\Newsletter\NewsletterPreviewRenderer() new \Domain\Newsletter\NewsletterPreviewRenderer()
); );
}, },
'Scontainers' => function() {
global $mdb;
return new \admin\Controllers\ScontainersController(
new \Domain\Scontainers\ScontainersRepository( $mdb ),
new \Domain\Languages\LanguagesRepository( $mdb )
);
},
]; ];
return self::$newControllers; return self::$newControllers;
@@ -319,6 +334,7 @@ class Site
'article_edit' => 'edit', 'article_edit' => 'edit',
'article_save' => 'save', 'article_save' => 'save',
'article_delete' => 'delete', 'article_delete' => 'delete',
'article_restore' => 'restore',
'banner_edit' => 'edit', 'banner_edit' => 'edit',
'banner_save' => 'save', 'banner_save' => 'save',
'banner_delete' => 'delete', 'banner_delete' => 'delete',
@@ -332,6 +348,9 @@ class Site
'layout_edit' => 'edit', 'layout_edit' => 'edit',
'layout_save' => 'save', 'layout_save' => 'save',
'layout_delete' => 'delete', 'layout_delete' => 'delete',
'container_edit' => 'edit',
'container_save' => 'save',
'container_delete' => 'delete',
]; ];
public static function route() public static function route()

View File

@@ -1,26 +0,0 @@
<?php
namespace admin\controls;
class ArticlesArchive
{
public static function article_restore()
{
if ( \admin\factory\ArticlesArchive::article_restore( \S::get( 'id' ) ) )
\S::alert( 'Artykuł został przywrócony.' );
header( 'Location: /admin/articles_archive/view_list/' );
exit;
}
public static function article_delete()
{
if ( \admin\factory\ArticlesArchive::article_delete( \S::get( 'id' ) ) )
\S::alert( 'Artykuł został usunięty.' );
header( 'Location: /admin/articles_archive/view_list/' );
exit;
}
public static function view_list()
{
return \admin\view\ArticlesArchive::articles_list();
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace admin\factory;
class ArticlesArchive
{
public static function article_restore( $article_id )
{
global $mdb;
return $mdb -> update( 'pp_articles', [ 'status' => 0 ], [ 'id' => (int)$article_id ] );
}
public static function article_delete( $article_id )
{
global $mdb;
$mdb -> delete( 'pp_articles_pages', [ 'article_id' => (int)$article_id ] );
$mdb -> delete( 'pp_articles_langs', [ 'article_id' => (int)$article_id ] );
$mdb -> delete( 'pp_articles_images', [ 'article_id' => (int)$article_id ] );
$mdb -> delete( 'pp_articles_files', [ 'article_id' => (int)$article_id ] );
$mdb -> delete( 'pp_articles', [ 'id' => (int)$article_id ] );
\S::delete_dir( '../upload/article_images/article_' . (int)$article_id . '/' );
\S::delete_dir( '../upload/article_files/article_' . (int)$article_id . '/' );
return true;
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace admin\view;
class ArticlesArchive
{
public static function articles_list()
{
$tpl = new \Tpl;
return $tpl -> render( 'articles/articles-archive-list' );
}
}

View File

@@ -443,6 +443,95 @@ class ArticleRepositoryTest extends TestCase
$this->assertFalse($result); $this->assertFalse($result);
} }
public function testRestoreSetsStatusToZero(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('update')
->with('pp_articles', ['status' => 0], ['id' => 25])
->willReturn(true);
$repository = new ArticleRepository($mockDb);
$result = $repository->restore(25);
$this->assertTrue($result);
}
public function testDeletePermanentlyRemovesArticleAndRelations(): void
{
$mockDb = $this->createMock(\medoo::class);
$deleteCalls = [];
$mockDb->expects($this->exactly(5))
->method('delete')
->willReturnCallback(function ($table, $where) use (&$deleteCalls) {
$deleteCalls[] = ['table' => $table, 'where' => $where];
return true;
});
$repository = new ArticleRepository($mockDb);
$result = $repository->deletePermanently(77);
$this->assertTrue($result);
$this->assertCount(5, $deleteCalls);
$this->assertSame('pp_articles_pages', $deleteCalls[0]['table']);
$this->assertSame('pp_articles_langs', $deleteCalls[1]['table']);
$this->assertSame('pp_articles_images', $deleteCalls[2]['table']);
$this->assertSame('pp_articles_files', $deleteCalls[3]['table']);
$this->assertSame('pp_articles', $deleteCalls[4]['table']);
}
public function testListArchivedForAdminWhitelistsSortAndDirection(): void
{
$mockDb = $this->createMock(\medoo::class);
$queries = [];
$mockDb->method('query')
->willReturnCallback(function ($sql, $params = []) use (&$queries) {
$queries[] = ['sql' => $sql, 'params' => $params];
if (strpos($sql, 'COUNT(0)') !== false) {
return new class {
public function fetchAll()
{
return [[1]];
}
};
}
return new class {
public function fetchAll()
{
return [[
'id' => 1,
'date_add' => '2020-01-01 00:00:00',
'date_modify' => '2020-01-01 00:00:00',
'title' => 'A',
]];
}
};
});
$repository = new ArticleRepository($mockDb);
$repository->listArchivedForAdmin(
[],
'date_add DESC; DROP TABLE pp_articles; --',
'DESC; DELETE FROM pp_users; --',
1,
100000
);
$this->assertCount(2, $queries);
$dataSql = $queries[1]['sql'];
$this->assertMatchesRegularExpression('/ORDER BY\s+pa\.date_add\s+DESC,\s+pa\.id\s+DESC/i', $dataSql);
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
$this->assertStringNotContainsString('DELETE FROM pp_users', $dataSql);
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
$this->assertStringContainsString('pa.status = -1', $dataSql);
}
public function testListForAdminWhitelistsSortAndDirection(): void public function testListForAdminWhitelistsSortAndDirection(): void
{ {
$mockDb = $this->createMock(\medoo::class); $mockDb = $this->createMock(\medoo::class);

View File

@@ -0,0 +1,52 @@
<?php
namespace Tests\Unit\admin\Controllers;
use PHPUnit\Framework\TestCase;
use admin\Controllers\ArticlesArchiveController;
use Domain\Article\ArticleRepository;
class ArticlesArchiveControllerTest extends TestCase
{
private $repository;
private $controller;
protected function setUp(): void
{
$this->repository = $this->createMock(ArticleRepository::class);
$this->controller = new ArticlesArchiveController($this->repository);
}
public function testConstructorAcceptsRepository(): void
{
$controller = new ArticlesArchiveController($this->repository);
$this->assertInstanceOf(ArticlesArchiveController::class, $controller);
}
public function testHasMainActionMethods(): void
{
$this->assertTrue(method_exists($this->controller, 'list'));
$this->assertTrue(method_exists($this->controller, 'view_list'));
$this->assertTrue(method_exists($this->controller, 'restore'));
$this->assertTrue(method_exists($this->controller, 'delete'));
}
public function testActionMethodReturnTypes(): void
{
$reflection = new \ReflectionClass($this->controller);
$this->assertEquals('string', (string)$reflection->getMethod('list')->getReturnType());
$this->assertEquals('string', (string)$reflection->getMethod('view_list')->getReturnType());
$this->assertEquals('void', (string)$reflection->getMethod('restore')->getReturnType());
$this->assertEquals('void', (string)$reflection->getMethod('delete')->getReturnType());
}
public function testConstructorRequiresArticleRepository(): void
{
$reflection = new \ReflectionClass(ArticlesArchiveController::class);
$constructor = $reflection->getConstructor();
$params = $constructor->getParameters();
$this->assertCount(1, $params);
$this->assertEquals('Domain\Article\ArticleRepository', $params[0]->getType()->getName());
}
}

BIN
updates/0.20/ver_0.260.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,3 @@
F: ../autoload/admin/controls/class.ArticlesArchive.php
F: ../autoload/admin/factory/class.ArticlesArchive.php
F: ../autoload/admin/view/class.ArticlesArchive.php

View File

@@ -1,4 +1,19 @@
<b>ver. 0.258 - 12.02.2026</b><br /> <b>ver. 0.260 - 12.02.2026</b><br />
- NEW - migracja modulu `ArticlesArchive` do architektury Domain + DI (`admin\\Controllers\\ArticlesArchiveController`)
- UPDATE - `Domain\\Article\\ArticleRepository` rozszerzone o metody `listArchivedForAdmin`, `restore`, `deletePermanently`
- UPDATE - widok `/admin/articles_archive/view_list/` przepiety z legacy `grid` na `components/table-list`
- UPDATE - routing DI (`admin\\Site`) rozszerzony o modul `ArticlesArchive` + mapowanie akcji `article_restore -> restore`
- CLEANUP - usuniete legacy klasy `autoload/admin/controls/class.ArticlesArchive.php`, `autoload/admin/factory/class.ArticlesArchive.php`, `autoload/admin/view/class.ArticlesArchive.php`
- UPDATE - plik do usuniecia dodany w `updates/0.20/ver_0.260_files.txt`
<hr><b>ver. 0.259 - 12.02.2026</b><br />
- NEW - migracja modulu `Scontainers` do architektury Domain + DI (`Domain\\Scontainers\\ScontainersRepository`, `admin\\Controllers\\ScontainersController`)
- UPDATE - widoki `/admin/scontainers/*` przepiete z legacy `grid/gridEdit` na `components/table-list` i `components/form-edit`
- UPDATE - routing DI (`admin\\Site`) rozszerzony o modul `Scontainers` + mapowanie akcji `container_edit/container_save/container_delete`
- UPDATE - `admin\\factory\\Scontainers` dziala jako fasada do repozytorium (backward compatibility)
- UPDATE - `front\\factory\\Scontainers` korzysta z `Domain\\Scontainers\\ScontainersRepository`
- CLEANUP - usuniete legacy klasy `autoload/admin/controls/class.Scontainers.php`, `autoload/admin/view/class.Scontainers.php`
- UPDATE - plik do usuniecia dodany w `updates/0.20/ver_0.259_files.txt`
<hr><b>ver. 0.258 - 12.02.2026</b><br />
- UPDATE - modul `Newsletter`: funkcjonalnosc `Wysylka - przygotowanie` zostala tymczasowo wylaczona (menu + akcje `prepare/send/preview`) - UPDATE - modul `Newsletter`: funkcjonalnosc `Wysylka - przygotowanie` zostala tymczasowo wylaczona (menu + akcje `prepare/send/preview`)
- UPDATE - modul `Newsletter`: lista `Szablony uzytkownika` zostala tymczasowo wylaczona (menu + akcja `email_templates_user`) - UPDATE - modul `Newsletter`: lista `Szablony uzytkownika` zostala tymczasowo wylaczona (menu + akcja `email_templates_user`)
- UPDATE - `NewsletterController`: lista szablonow ograniczona do szablonow administracyjnych (`is_admin = 1`) - UPDATE - `NewsletterController`: lista szablonow ograniczona do szablonow administracyjnych (`is_admin = 1`)
@@ -8,7 +23,7 @@
<hr><b>ver. 0.257 - 12.02.2026</b><br /> <hr><b>ver. 0.257 - 12.02.2026</b><br />
- NEW - migracja modulu `Newsletter` do architektury Domain + DI (`Domain\\Newsletter\\NewsletterRepository`, `Domain\\Newsletter\\NewsletterPreviewRenderer`, `admin\\Controllers\\NewsletterController`) - NEW - migracja modulu `Newsletter` do architektury Domain + DI (`Domain\\Newsletter\\NewsletterRepository`, `Domain\\Newsletter\\NewsletterPreviewRenderer`, `admin\\Controllers\\NewsletterController`)
- UPDATE - widoki `/admin/newsletter/*` przepiete z legacy `grid/gridEdit` na nowe komponenty (`components/table-list`, `components/form-edit`) + nowy endpoint `/admin/newsletter/preview/` - UPDATE - widoki `/admin/newsletter/*` przepiete z legacy `grid/gridEdit` na nowe komponenty (`components/table-list`, `components/form-edit`) + nowy endpoint `/admin/newsletter/preview/`
- UPDATE - routing DI (`admin\\Site`) rozszerzony o moduł `Newsletter` - UPDATE - routing DI (`admin\\Site`) rozszerzony o moduĹ‚ `Newsletter`
- UPDATE - `admin\\factory\\Newsletter` dziala jako fasada do nowego repozytorium (backward compatibility) - UPDATE - `admin\\factory\\Newsletter` dziala jako fasada do nowego repozytorium (backward compatibility)
- UPDATE - `front\\factory\\Newsletter` nie korzysta juz z `admin\\view\\Newsletter` - UPDATE - `front\\factory\\Newsletter` nie korzysta juz z `admin\\view\\Newsletter`
- CLEANUP - usuniete legacy klasy `autoload/admin/controls/class.Newsletter.php`, `autoload/admin/view/class.Newsletter.php` - CLEANUP - usuniete legacy klasy `autoload/admin/controls/class.Newsletter.php`, `autoload/admin/view/class.Newsletter.php`
@@ -29,7 +44,7 @@
- UPDATE - migracja widokow languages (`languages-list`, `language-edit`, `translations-list`, `translation-edit`) na `components/table-list` i `components/form-edit` - UPDATE - migracja widokow languages (`languages-list`, `language-edit`, `translations-list`, `translation-edit`) na `components/table-list` i `components/form-edit`
- UPDATE - routing DI dla `Languages` w `admin\\Site` oraz kompatybilna fasada `admin\\factory\\Languages` delegujaca do repozytorium - UPDATE - routing DI dla `Languages` w `admin\\Site` oraz kompatybilna fasada `admin\\factory\\Languages` delegujaca do repozytorium
- UPDATE - naprawiono zapis edycji jezyka (ID jezyka pobierane z URL przy edycji) - UPDATE - naprawiono zapis edycji jezyka (ID jezyka pobierane z URL przy edycji)
- UPDATE - globalne poprawki UX filtrów w `components/table-list` (kompaktowe kolumny `Aktywny`/`Domyslny`, spacing i pelna szerokosc selecta) - UPDATE - globalne poprawki UX filtrĂłw w `components/table-list` (kompaktowe kolumny `Aktywny`/`Domyslny`, spacing i pelna szerokosc selecta)
- CLEANUP - usuniete legacy klasy: `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php` - CLEANUP - usuniete legacy klasy: `autoload/admin/controls/class.Languages.php`, `autoload/admin/view/class.Languages.php`
<hr> <hr>
<b>ver. 0.253 - 12.02.2026</b><br /> <b>ver. 0.253 - 12.02.2026</b><br />
@@ -92,74 +107,74 @@
- UPDATE - refaktoryzacja: article_save przeniesiony do Domain\Article\ArticleRepository::save() z prywatnymi helperami - UPDATE - refaktoryzacja: article_save przeniesiony do Domain\Article\ArticleRepository::save() z prywatnymi helperami
- UPDATE - refaktoryzacja: article_delete przeniesiony do Domain\Article\ArticleRepository::archive() - UPDATE - refaktoryzacja: article_delete przeniesiony do Domain\Article\ArticleRepository::archive()
- UPDATE - ArticlesController: nowe akcje save() i delete() z DI - UPDATE - ArticlesController: nowe akcje save() i delete() z DI
- UPDATE - admin\factory\Articles::article_save() i articles_set_archive() delegują do repozytorium (kompatybilność) - UPDATE - admin\factory\Articles::article_save() i articles_set_archive() delegujÄ… do repozytorium (kompatybilność)
<hr><b>ver. 0.243</b><br /> <hr><b>ver. 0.243</b><br />
- UPDATE - refaktoryzacja: cleanup nieprzypisanych plików/zdjęć artykułów przeniesiony do Domain\Article\ArticleRepository - UPDATE - refaktoryzacja: cleanup nieprzypisanych plikĂłw/zdjęć artykułów przeniesiony do Domain\Article\ArticleRepository
- UPDATE - ArticlesController::edit() używa repozytorium do cleanupu, a admin\factory\Articles zachowuje delegowanie (kompatybilność) - UPDATE - ArticlesController::edit() uĹĽywa repozytorium do cleanupu, a admin\factory\Articles zachowuje delegowanie (kompatybilność)
<hr><b>ver. 0.242</b><br /> <hr><b>ver. 0.242</b><br />
- NEW - refaktoryzacja: Domain\Article\ArticleRepository + migracja article_edit do admin\Controllers\ArticlesController (DI) - NEW - refaktoryzacja: Domain\Article\ArticleRepository + migracja article_edit do admin\Controllers\ArticlesController (DI)
- UPDATE - admin\factory\Articles::article_details() deleguje do nowego repozytorium (kompatybilność zachowana) - UPDATE - admin\factory\Articles::article_details() deleguje do nowego repozytorium (kompatybilność zachowana)
- UPDATE - metody przejęte przez nowe kontrolery oznaczone jako @deprecated w legacy kontrolerach admin\controls - UPDATE - metody przejÄ™te przez nowe kontrolery oznaczone jako @deprecated w legacy kontrolerach admin\controls
<hr><b>ver. 0.241</b><br /> <hr><b>ver. 0.241</b><br />
- NEW - refaktoryzacja: admin\Controllers\ProductArchiveController - archiwum produktów z DI - NEW - refaktoryzacja: admin\Controllers\ProductArchiveController - archiwum produktĂłw z DI
- NEW - ProductRepository::archive(), unarchive() - operacje archiwizacji w repozytorium - NEW - ProductRepository::archive(), unarchive() - operacje archiwizacji w repozytorium
- FIX - naprawiono SQL w liście archiwum (puste wyszukiwanie filtrowało wszystkie wyniki) - FIX - naprawiono SQL w liĹ›cie archiwum (puste wyszukiwanie filtrowaĹ‚o wszystkie wyniki)
- FIX - naprawiono brakujący filtr archive = 1 w zapytaniu bez wyszukiwania - FIX - naprawiono brakujÄ…cy filtr archive = 1 w zapytaniu bez wyszukiwania
- UPDATE - wyczyszczono szablony archiwum (usunięto zbędne funkcje: apilo, baselinker, duplikowanie) - UPDATE - wyczyszczono szablony archiwum (usuniÄ™to zbÄ™dne funkcje: apilo, baselinker, duplikowanie)
<hr> <hr>
<b>ver. 0.240</b><br /> <b>ver. 0.240</b><br />
- NEW - refaktoryzacja: Domain\Settings\SettingsRepository + admin\Controllers\SettingsController (architektura Domain-Driven) - NEW - refaktoryzacja: Domain\Settings\SettingsRepository + admin\Controllers\SettingsController (architektura Domain-Driven)
- NEW - refaktoryzacja: Domain\Cache\CacheRepository - czyszczenie cache z obsługą Redis - NEW - refaktoryzacja: Domain\Cache\CacheRepository - czyszczenie cache z obsĹugÄ… Redis
- FIX - komunikat potwierdzenia zapisu ustawień w panelu administratora - FIX - komunikat potwierdzenia zapisu ustawieĹ„ w panelu administratora
- FIX - naprawiono element #content w layoucie admina (powiadomienia grid.js) - FIX - naprawiono element #content w layoucie admina (powiadomienia grid.js)
<hr><b>ver. 0.239</b><br /> <hr><b>ver. 0.239</b><br />
- NEW - refaktoryzacja: Domain\Banner\BannerRepository + admin\Controllers\BannerController (pełna migracja kontrolera) - NEW - refaktoryzacja: Domain\Banner\BannerRepository + admin\Controllers\BannerController (peĹ‚na migracja kontrolera)
- NEW - refaktoryzacja: Domain\Product\ProductRepository::getPrice(), getName() - migracja kolejnych metod - NEW - refaktoryzacja: Domain\Product\ProductRepository::getPrice(), getName() - migracja kolejnych metod
- NEW - router admin z obsługą nowych kontrolerów (fallback na stare) - NEW - router admin z obsĹugÄ… nowych kontrolerĂłw (fallback na stare)
- UPDATE - shop\Product::get_product_price(), get_product_name() używają nowego repozytorium (kompatybilność zachowana) - UPDATE - shop\Product::get_product_price(), get_product_name() uĹĽywajÄ… nowego repozytorium (kompatybilność zachowana)
<hr> <hr>
<b>ver. 0.238</b><br /> <b>ver. 0.238</b><br />
- NEW - refaktoryzacja: Domain\Product\ProductRepository - pierwsza klasa w nowej architekturze Domain-Driven - NEW - refaktoryzacja: Domain\Product\ProductRepository - pierwsza klasa w nowej architekturze Domain-Driven
- NEW - Dependency Injection zamiast global variables - NEW - Dependency Injection zamiast global variables
- UPDATE - shop\Product::get_product_quantity() używa teraz nowego repozytorium (kompatybilność zachowana) - UPDATE - shop\Product::get_product_quantity() uĹĽywa teraz nowego repozytorium (kompatybilność zachowana)
<hr> <hr>
<b>ver. 0.237</b><br /> <b>ver. 0.237</b><br />
- NEW - automatyczne czyszczenie cache produktu po aktualizacji przez CRON (Sellasist, Apilo, Baselinker) - NEW - automatyczne czyszczenie cache produktu po aktualizacji przez CRON (Sellasist, Apilo, Baselinker)
- UPDATE - przycisk "Wyczyść cache" w panelu administratora z obsługą AJAX i komunikatami o postępie - UPDATE - przycisk "Wyczyść cache" w panelu administratora z obsĹugÄ… AJAX i komunikatami o postÄ™pie
<hr> <hr>
<b>ver. 0.236</b><br /> <b>ver. 0.236</b><br />
- FIX - zabezpieczenie przed duplikatami zamówień w Apilo - automatyczne pobieranie ID zamówienia przy błędzie "idExternal już wykorzystywany" - FIX - zabezpieczenie przed duplikatami zamĂłwieĹ„ w Apilo - automatyczne pobieranie ID zamĂłwienia przy błędzie "idExternal juĹĽ wykorzystywany"
<hr> <hr>
<b>ver. 0.235</b><br /> <b>ver. 0.235</b><br />
- FIX - poprawka funkcji aktualizacji - FIX - poprawka funkcji aktualizacji
<hr> <hr>
<b>ver. 0.234</b><br /> <b>ver. 0.234</b><br />
- NEW - przycisk zaznaczania zamówienia jako wysłane do trustmate.io - NEW - przycisk zaznaczania zamĂłwienia jako wysĹ‚ane do trustmate.io
<hr> <hr>
<b>ver. 0.232</b><br /> <b>ver. 0.232</b><br />
- NEW - opcje GPSR - NEW - opcje GPSR
<hr> <hr>
<b>ver. 0.231</b><br /> <b>ver. 0.231</b><br />
- FIX - poprawki bezpieczeństwa + dwuetapowa weryfikacja logowania - FIX - poprawki bezpieczeĹ„stwa + dwuetapowa weryfikacja logowania
<hr> <hr>
<b>ver. 0.230</b><br /> <b>ver. 0.230</b><br />
- FIX - poprawki bezpieczeństwa - FIX - poprawki bezpieczeĹ„stwa
<hr> <hr>
<b>ver. 0.229</b><br /> <b>ver. 0.229</b><br />
- NEW - pola dodatkowe z opcją wymagane/niewymagane - NEW - pola dodatkowe z opcjÄ… wymagane/niewymagane
<hr> <hr>
<b>ver. 0.228</b><br /> <b>ver. 0.228</b><br />
- NEW - cron do wysyłania zamówień do trustmate.io - NEW - cron do wysyĹ‚ania zamĂłwieĹ„ do trustmate.io
<hr> <hr>
<b>ver. 0.227</b><br /> <b>ver. 0.227</b><br />
- NEW - historia kodów rabatowych - NEW - historia kodĂłw rabatowych
<hr> <hr>
<b>ver. 0.226</b><br /> <b>ver. 0.226</b><br />
- NEW - dodanie opcji faktury do zamówienia - NEW - dodanie opcji faktury do zamĂłwienia
<hr> <hr>
<b>ver. 0.225</b><br /> <b>ver. 0.225</b><br />
- NEW - przycisk czyszczenia cache<br> - NEW - przycisk czyszczenia cache<br>
- NEW - ponowne wysyłanie zamówienia do apilo - NEW - ponowne wysyĹ‚anie zamĂłwienia do apilo
<hr> <hr>
<b>ver. 0.224</b><br /> <b>ver. 0.224</b><br />
- NEW - sortowanie form dostawy - NEW - sortowanie form dostawy
@@ -171,20 +186,20 @@
- NEW - integracja z Orlen Paczka - NEW - integracja z Orlen Paczka
<hr> <hr>
<b>ver. 0.221</b><br /> <b>ver. 0.221</b><br />
- NEW - Automatyczne przekierowania adresów URL produktów, zmiany w pliku htaccess - NEW - Automatyczne przekierowania adresĂłw URL produktĂłw, zmiany w pliku htaccess
<hr> <hr>
<b>ver. 0.220</b><br /> <b>ver. 0.220</b><br />
- NEW - Dodanie możliwości wyświetlenia na strone ostatnio dodane produkty [PRODUKTY_NEW] lub [PRODUKTY_NEW:10].<br> - NEW - Dodanie moĹĽliwoĹ›ci wyĹ›wietlenia na strone ostatnio dodane produkty [PRODUKTY_NEW] lub [PRODUKTY_NEW:10].<br>
- NEW - Dodanie możliwości wyświetlenia na strone popularnych produktów [PRODUKTY_TOP] lub [PRODUKTY_TOP:10]. - NEW - Dodanie moĹĽliwoĹ›ci wyĹ›wietlenia na strone popularnych produktĂłw [PRODUKTY_TOP] lub [PRODUKTY_TOP:10].
<hr> <hr>
<b>ver. 0.219</b><br /> <b>ver. 0.219</b><br />
- NEW - Dodanie możliwości zmiany daty w artykułach - NEW - Dodanie moĹĽliwoĹ›ci zmiany daty w artykuĹ‚ach
<hr> <hr>
<b>ver. 0.218</b><br /> <b>ver. 0.218</b><br />
- NEW - indywidualny kod GTM - NEW - indywidualny kod GTM
<hr> <hr>
<b>ver. 0.217</b><br /> <b>ver. 0.217</b><br />
- NEW - zwiększenie obsługi REDIS - NEW - zwiÄ™kszenie obsĹ‚ugi REDIS
<hr> <hr>
<b>ver. 0.216</b><br /> <b>ver. 0.216</b><br />
- NEW - aktualizacja api i cron (apilo) - NEW - aktualizacja api i cron (apilo)
@@ -199,43 +214,43 @@
- FIX - wyliczenie darmowej dostawy - FIX - wyliczenie darmowej dostawy
<hr> <hr>
<b>ver. 0.212</b><br /> <b>ver. 0.212</b><br />
- NEW - zmiany w zapisywaniu zamówienia do apilo - NEW - zmiany w zapisywaniu zamĂłwienia do apilo
<hr> <hr>
<b>ver. 0.211</b><br /> <b>ver. 0.211</b><br />
- NEW - Debugowanie apilo + wyświetlanie podkategorii - NEW - Debugowanie apilo + wyĹ›wietlanie podkategorii
<hr> <hr>
<b>ver. 0.210</b><br /> <b>ver. 0.210</b><br />
- NEW - dodatkowe pola w widoku produktów - NEW - dodatkowe pola w widoku produktĂłw
<hr> <hr>
<b>ver. 0.209</b><br /> <b>ver. 0.209</b><br />
- NEW - zmiany w widoku produktów (panel administratora) - NEW - zmiany w widoku produktĂłw (panel administratora)
<hr> <hr>
<b>ver. 0.208</b><br /> <b>ver. 0.208</b><br />
- NEW - zmiany w wyszukiwarce produktów - NEW - zmiany w wyszukiwarce produktĂłw
<hr> <hr>
<b>ver. 0.204-0.207</b><br /> <b>ver. 0.204-0.207</b><br />
- NEW - htaccess update - NEW - htaccess update
<hr> <hr>
<b>ver. 0.204-0.206</b><br /> <b>ver. 0.204-0.206</b><br />
- NEW - wysyłanie produktów do apilo - NEW - wysyĹ‚anie produktĂłw do apilo
<hr> <hr>
<b>ver. 0.203</b><br /> <b>ver. 0.203</b><br />
- NEW - zmiana sposobu wyliczania cen produkty z dodatkami - NEW - zmiana sposobu wyliczania cen produkty z dodatkami
<hr> <hr>
<b>ver. 0.202</b><br /> <b>ver. 0.202</b><br />
- NEW - dodano "ówne zdjęcie" w edycji artykułu - NEW - dodano "główne zdjÄ™cie" w edycji artykuĹ‚u
<hr> <hr>
<b>ver. 0.201</b><br /> <b>ver. 0.201</b><br />
- FIX - aktualizacja statusów na podstawie baselinkera - FIX - aktualizacja statusĂłw na podstawie baselinkera
<hr> <hr>
<b>ver. 0.200</b><br /> <b>ver. 0.200</b><br />
- NEW - wysyłanie produktów do baselinker - NEW - wysyĹ‚anie produktĂłw do baselinker
<hr> <hr>
<b>ver. 0.199</b><br /> <b>ver. 0.199</b><br />
- NEW - usprawnienie edycji danych do XML - NEW - usprawnienie edycji danych do XML
<hr> <hr>
<b>ver. 0.198</b><br /> <b>ver. 0.198</b><br />
- NEW - automatyczne generowanie kodów SKU - NEW - automatyczne generowanie kodĂłw SKU
<hr> <hr>
<b>ver. 0.197</b><br /> <b>ver. 0.197</b><br />
- FIX - poprawki w Dashboard - FIX - poprawki w Dashboard
@@ -244,7 +259,7 @@
- FIX - integracja z apilo.com - FIX - integracja z apilo.com
<hr> <hr>
<b>ver. 0.195</b><br /> <b>ver. 0.195</b><br />
- FIX - aktualizacja statusów - FIX - aktualizacja statusĂłw
<hr> <hr>
<b>ver. 0.194</b><br /> <b>ver. 0.194</b><br />
- UPDATE - integracja apilo - UPDATE - integracja apilo
@@ -253,46 +268,46 @@
- UPDATE - aktualizacja synchronizacji z baselinker - UPDATE - aktualizacja synchronizacji z baselinker
<hr> <hr>
<b>ver. 0.192</b><br /> <b>ver. 0.192</b><br />
- NEW - pobieranie statusów z sellasist - NEW - pobieranie statusĂłw z sellasist
<hr> <hr>
<b>ver. 0.191</b><br /> <b>ver. 0.191</b><br />
- NEW - integracja z selasist - NEW - integracja z selasist
<hr> <hr>
<b>ver. 0.190</b><br /> <b>ver. 0.190</b><br />
- FIX - produkty powiązane - FIX - produkty powiÄ…zane
<hr> <hr>
<b>ver. 0.189</b><br /> <b>ver. 0.189</b><br />
- FIX - ceny promocyjne produktów z dodatkiem - FIX - ceny promocyjne produktĂłw z dodatkiem
<hr> <hr>
<b>ver. 0.188</b><br /> <b>ver. 0.188</b><br />
- NEW - widok listy produktów - NEW - widok listy produktĂłw
<hr> <hr>
<b>ver. 0.187</b><br /> <b>ver. 0.187</b><br />
- FIX - pobieranie cen z APILO - FIX - pobieranie cen z APILO
<hr> <hr>
<b>ver. 0.186</b><br /> <b>ver. 0.186</b><br />
- FIX - dodawanie do koszyka tych samych produktów ale z różną personalizacją - FIX - dodawanie do koszyka tych samych produktĂłw ale z różnÄ… personalizacjÄ…
<hr> <hr>
<b>ver. 0.185</b><br /> <b>ver. 0.185</b><br />
- FIX - masowa edycja produktów - FIX - masowa edycja produktĂłw
<hr> <hr>
<b>ver. 0.184</b><br /> <b>ver. 0.184</b><br />
- NEW - druga część integracji z apilo, masowa edycja produktów - NEW - druga część integracji z apilo, masowa edycja produktĂłw
<hr> <hr>
<b>ver. 0.183</b><br /> <b>ver. 0.183</b><br />
- NEW - pierwsza część integracji z apilo - NEW - pierwsza część integracji z apilo
<hr> <hr>
<b>ver. 0.182</b><br /> <b>ver. 0.182</b><br />
- FIX - layout - FIX - layout
<hr> <hr>
<b>ver. 0.181</b><br /> <b>ver. 0.181</b><br />
- NEW - infinitescroll - opcja włączy/wyłącz - NEW - infinitescroll - opcja włączy/wyłącz
<hr> <hr>
<b>ver. 0.180</b><br /> <b>ver. 0.180</b><br />
- NEW - aktualizacja dashboard - NEW - aktualizacja dashboard
<hr> <hr>
<b>ver. 0.179</b><br /> <b>ver. 0.179</b><br />
- NEW - obsługa EAN - NEW - obsĹ‚uga EAN
<hr> <hr>
<b>ver. 0.177, 0.178</b><br /> <b>ver. 0.177, 0.178</b><br />
- FIX - custom_label - FIX - custom_label
@@ -308,7 +323,7 @@
<hr> <hr>
<b>ver. 0.173</b><br /> <b>ver. 0.173</b><br />
- NEW - duplikowanie produktu wraz z kombinacjami - NEW - duplikowanie produktu wraz z kombinacjami
- NEW - dodanie przechodzenia pomiędzy zamówienia (poprzednie/następne zamówienie) - NEW - dodanie przechodzenia pomiÄ™dzy zamĂłwienia (poprzednie/nastÄ™pne zamĂłwienie)
<hr> <hr>
<b>ver. 0.172</b><br /> <b>ver. 0.172</b><br />
- FIX - poprawki w Cache - FIX - poprawki w Cache
@@ -320,22 +335,22 @@
- NEW - usuwanie cache produktu przy zapisie - NEW - usuwanie cache produktu przy zapisie
<hr> <hr>
<b>ver. 0.169</b><br /> <b>ver. 0.169</b><br />
- FIX - poprawki w liście produktów - FIX - poprawki w liĹ›cie produktĂłw
<hr> <hr>
<b>ver. 0.168</b><br /> <b>ver. 0.168</b><br />
- NEW - archiwum produktów - NEW - archiwum produktĂłw
<hr> <hr>
<b>ver. 0.167</b><br /> <b>ver. 0.167</b><br />
- NEW - dodanie obsługi cen i stanów magazynowych kombinacji produktów - NEW - dodanie obsĹ‚ugi cen i stanĂłw magazynowych kombinacji produktĂłw
<hr> <hr>
<b>ver. 0.166</b><br /> <b>ver. 0.166</b><br />
- NEW - współpraca z GTM - NEW - współpraca z GTM
<hr> <hr>
<b>ver. 0.164/5</b><br /> <b>ver. 0.164/5</b><br />
- FIX - ukrywanie produktów nieaktywnych - FIX - ukrywanie produktĂłw nieaktywnych
<hr> <hr>
<b>ver. 0.163</b><br /> <b>ver. 0.163</b><br />
- NEW - automatyczne podpowiadanie produktów do zestawu na podstawie wcześniejszych zakupów klientów - NEW - automatyczne podpowiadanie produktĂłw do zestawu na podstawie wczeĹ›niejszych zakupĂłw klientĂłw
<hr> <hr>
<b>ver. 0.162</b><br /> <b>ver. 0.162</b><br />
- NEW - GA4 - NEW - GA4
@@ -351,7 +366,7 @@
- FIX - cron Baselinker - FIX - cron Baselinker
<hr> <hr>
<b>ver. 0.158</b><br /> <b>ver. 0.158</b><br />
- UPDATE - poprawa kolorystyki przycisków - UPDATE - poprawa kolorystyki przyciskĂłw
<hr> <hr>
<b>ver. 0.157</b><br /> <b>ver. 0.157</b><br />
- NEW - szybka zmiana statusu produktu - NEW - szybka zmiana statusu produktu
@@ -363,10 +378,10 @@
- NEW - infinite scroll w widoku kategorii - NEW - infinite scroll w widoku kategorii
<hr> <hr>
<b>ver. 0.154</b><br /> <b>ver. 0.154</b><br />
- FIX - atrybuty produktów - FIX - atrybuty produktĂłw
<hr> <hr>
<b>ver. 0.153</b><br /> <b>ver. 0.153</b><br />
- FIX - atrybuty produktów - FIX - atrybuty produktĂłw
<hr> <hr>
<b>ver. 0.152</b><br /> <b>ver. 0.152</b><br />
- FIX - tematy maili - FIX - tematy maili
@@ -375,7 +390,7 @@
- FIX - tematy maili - FIX - tematy maili
<hr> <hr>
<b>ver. 0.150</b><br /> <b>ver. 0.150</b><br />
- NEW - domyślna forma transportu - NEW - domyĹ›lna forma transportu
<hr> <hr>
<b>ver. 0.149</b><br /> <b>ver. 0.149</b><br />
- NEW - tematy maili - NEW - tematy maili
@@ -393,13 +408,14 @@
- NEW - omnibus ready - NEW - omnibus ready
<hr> <hr>
<b>ver. 0.144</b><br /> <b>ver. 0.144</b><br />
- FIX - usunięcie adresu marianek.pl z kodu - FIX - usuniÄ™cie adresu marianek.pl z kodu
<hr> <hr>
<b>ver. 0.143</b><br /> <b>ver. 0.143</b><br />
- FIX - poprawa generowania plików WEBP - FIX - poprawa generowania plikĂłw WEBP
<hr> <hr>
<b>ver. 0.142</b><br /> <b>ver. 0.142</b><br />
- FIX - poprawa adresu strony ównej - FIX - poprawa adresu strony głównej