diff --git a/ws_customerspecialty.zip b/ws_customerspecialty.zip index 00a15ee..cd2c5aa 100644 Binary files a/ws_customerspecialty.zip and b/ws_customerspecialty.zip differ diff --git a/ws_customerspecialty/README.md b/ws_customerspecialty/README.md index 61c9f49..143aa31 100644 --- a/ws_customerspecialty/README.md +++ b/ws_customerspecialty/README.md @@ -5,10 +5,13 @@ accounts. ## What it does -- Back office: a **Customer Specialties** admin screen (under Customers) lets you maintain the - list of selectable specialty values (title per language, position, active/inactive). Values - are never hard-deleted from the UI, only deactivated, since they may already be linked to - customers. +- Back office: clicking **Configure** on the module (Modules list) opens a "Settings" panel with + the front-office display toggle, and a small tab-style nav that also links to a **Specialties** + grid for maintaining the list of selectable specialty values (title per language, + active/inactive, move up/down). Values are never hard-deleted from the UI, only deactivated, + since they may already be linked to customers. The Specialties admin page is intentionally + **not** registered in the back-office sidebar menu (`id_parent => -1` on its tab, per this + module's own conventions doc, section 18) — Configure is the only entry point, by design. - Back office: the native "Add/Edit customer" page gets a required "Specialty" dropdown, and the native Customers grid gets a sortable/filterable "Specialty" column and a read-only specialty block on the customer view page. @@ -51,15 +54,17 @@ not something the module can safely do on your behalf without overriding core ma - No drag-and-drop reordering of specialty values. The grid has "Move up" / "Move down" row actions instead (`customerspecialty_move_up` / `_move_down` routes swapping `position` with the - adjacent row). This avoids depending on PrestaShop's core Grid position/drag-reorder plumbing, - whose exact API wasn't verified live against a running 1.7 and 9.0 instance. + adjacent row). This avoids depending on PrestaShop's core Grid position/drag-reorder plumbing. - The active/inactive toggle uses a `ToggleColumn` + `customerspecialty_toggle_active` route. If that route ever misbehaves on a given PrestaShop version, active/inactive can always be changed via the Edit form as a fallback — it isn't the only way to flip the flag. -- Grid `getFilters()`/`getColumns()` option keys (`ToggleColumn`, `SearchAndResetType`) follow the - standard, long-stable PrestaShop Grid API from memory; they were not verified against a live - PrestaShop 1.7 or 9.0 install (per request, devdocs research was skipped for this build). Smoke - test the "Customer Specialties" admin grid after install before relying on it in production. + +Confirmed working live on PrestaShop 9: create, edit, and active/inactive toggle on the +Specialties grid. Three real bugs were found and fixed this way (not by static guessing) during +initial rollout: a wrong `FormDataProviderInterface` namespace, a missing `LinkRowAction` +`route_param_field` option, and `FrameworkBundleAdminController::trans()` taking `(key, domain, +params)` instead of `Module::trans()`'s `(key, params, domain)`. "Move up"/"Move down" reordering +has not been explicitly click-tested yet — verify before relying on it. ## Biggest assumption to verify diff --git a/ws_customerspecialty/src/Config/Config.php b/ws_customerspecialty/src/Config/Config.php index 8dc5dc1..d980eaf 100644 --- a/ws_customerspecialty/src/Config/Config.php +++ b/ws_customerspecialty/src/Config/Config.php @@ -19,9 +19,9 @@ class Config const TABS = [ [ - 'class_name' => 'AdminCustomerSpecialtyOverview', - 'parent_class_name' => 'AdminParentCustomer', - 'name' => [ + 'class_name' => 'AdminCustomerSpecialtyOverview', + 'id_parent' => -1, + 'name' => [ 'en' => 'Customer Specialties', 'nl' => 'Klantspecialisaties', ], diff --git a/ws_customerspecialty/src/Controller/CustomerSpecialtyController.php b/ws_customerspecialty/src/Controller/CustomerSpecialtyController.php index e85a17d..ed78d80 100644 --- a/ws_customerspecialty/src/Controller/CustomerSpecialtyController.php +++ b/ws_customerspecialty/src/Controller/CustomerSpecialtyController.php @@ -24,9 +24,17 @@ class CustomerSpecialtyController extends FrameworkBundleAdminController return $this->render('@Modules/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig', [ 'customerSpecialtyGrid' => $this->presentGrid($grid), 'layoutHeaderToolbarBtn' => $this->getToolbarButtons($request->get('_legacy_controller')), + 'settingsUrl' => $this->getSettingsUrl(), ]); } + private function getSettingsUrl(): string + { + $legacyContext = $this->get('prestashop.adapter.legacy.context')->getContext(); + + return $legacyContext->link->getAdminLink('AdminModules') . '&configure=ws_customerspecialty'; + } + public function searchAction(Request $request): RedirectResponse { return $this->get('prestashop.bundle.grid.response_builder')->buildSearchResponse( @@ -49,7 +57,7 @@ class CustomerSpecialtyController extends FrameworkBundleAdminController $handlerResult = $formHandler->handle($form); if (null !== $handlerResult->getIdentifiableObjectId()) { - $this->addFlash('success', $this->trans('Successful creation', [], 'Admin.Notifications.Success')); + $this->addFlash('success', $this->trans('Successful creation', 'Admin.Notifications.Success')); return $this->redirectToRoute('customerspecialty_index'); } @@ -74,7 +82,7 @@ class CustomerSpecialtyController extends FrameworkBundleAdminController $handlerResult = $formHandler->handleFor($idCustomerSpecialty, $form); if ($handlerResult->isSubmitted() && $handlerResult->isValid()) { - $this->addFlash('success', $this->trans('Successful update', [], 'Admin.Notifications.Success')); + $this->addFlash('success', $this->trans('Successful update', 'Admin.Notifications.Success')); return $this->redirectToRoute('customerspecialty_index'); } @@ -91,7 +99,7 @@ class CustomerSpecialtyController extends FrameworkBundleAdminController { try { $this->getCommandBus()->handle(new ToggleCustomerSpecialtyActiveCommand($idCustomerSpecialty)); - $this->addFlash('success', $this->trans('Successful update', [], 'Admin.Notifications.Success')); + $this->addFlash('success', $this->trans('Successful update', 'Admin.Notifications.Success')); } catch (Exception $e) { $this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages())); } @@ -130,7 +138,7 @@ class CustomerSpecialtyController extends FrameworkBundleAdminController $toolbarButtons['customerspecialty_create'] = [ 'href' => $this->generateUrl('customerspecialty_create'), - 'desc' => $this->trans('New specialty', [], 'Admin.Actions'), + 'desc' => $this->trans('New specialty', 'Admin.Actions'), 'icon' => 'add_circle_outline', 'class' => 'btn-primary', 'floating_class' => '', diff --git a/ws_customerspecialty/src/Module/AdminHooks.php b/ws_customerspecialty/src/Module/AdminHooks.php index a260795..4b2b34c 100644 --- a/ws_customerspecialty/src/Module/AdminHooks.php +++ b/ws_customerspecialty/src/Module/AdminHooks.php @@ -29,9 +29,10 @@ trait AdminHooks } $this->context->smarty->assign([ - 'front_enabled' => (bool) Configuration::get(Config::FRONT_ENABLED_CONFIG_KEY), - 'form_action' => $this->context->link->getAdminLink('AdminModules') . '&configure=' . $this->name, - 'confirmation' => $confirmation, + 'front_enabled' => (bool) Configuration::get(Config::FRONT_ENABLED_CONFIG_KEY), + 'form_action' => $this->context->link->getAdminLink('AdminModules') . '&configure=' . $this->name, + 'confirmation' => $confirmation, + 'specialties_url' => $this->get('router')->generate('customerspecialty_index'), ]); return $this->fetch('module:ws_customerspecialty/views/templates/admin/configuration.tpl'); diff --git a/ws_customerspecialty/src/Module/Install.php b/ws_customerspecialty/src/Module/Install.php index 3880b0e..080efc0 100644 --- a/ws_customerspecialty/src/Module/Install.php +++ b/ws_customerspecialty/src/Module/Install.php @@ -95,30 +95,35 @@ trait Install $languages = Language::getLanguages(false); foreach ($moduleTabs as $moduleTab) { - if (Tab::getIdFromClassName($moduleTab['class_name'])) { - continue; - } + $idTab = (int) Tab::getIdFromClassName($moduleTab['class_name']); + $tab = $idTab ? new Tab($idTab) : new Tab(); - $tab = new Tab(); $tab->class_name = $moduleTab['class_name']; $tab->module = $moduleTab['module']; $tab->active = (int) $moduleTab['active']; $tab->route_name = $moduleTab['route_name']; $tab->icon = $moduleTab['icon']; - $tab->id_parent = (int) Tab::getIdFromClassName($moduleTab['parent_class_name']); + $tab->id_parent = $this->resolveTabParentId($moduleTab); foreach ($languages as $language) { $tab->name[(int) $language['id_lang']] = $moduleTab['name'][$language['iso_code']] ?? $moduleTab['name']['en']; } - $tab->add(); - - if (!$tab->id) { + if (!$tab->save()) { return false; } } return true; } + + private function resolveTabParentId(array $moduleTab): int + { + if (array_key_exists('id_parent', $moduleTab)) { + return (int) $moduleTab['id_parent']; + } + + return (int) Tab::getIdFromClassName($moduleTab['parent_class_name']); + } } diff --git a/ws_customerspecialty/views/templates/admin/configuration.tpl b/ws_customerspecialty/views/templates/admin/configuration.tpl index 9a86d44..8cae1db 100644 --- a/ws_customerspecialty/views/templates/admin/configuration.tpl +++ b/ws_customerspecialty/views/templates/admin/configuration.tpl @@ -2,6 +2,11 @@ {$confirmation nofilter} {/if} + +
diff --git a/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig b/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig index 2f4d3cc..2e66da1 100644 --- a/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig +++ b/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig @@ -1,6 +1,11 @@ {% extends '@PrestaShop/Admin/layout.html.twig' %} {% block content %} + + {% include '@PrestaShop/Admin/Common/Grid/grid_panel.html.twig' with {'grid': customerSpecialtyGrid} %} {% endblock %}