feat(main): New module init
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
vendor/
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# ws_customerspecialty
|
||||||
|
|
||||||
|
PrestaShop module (1.7 - 9.0 compatible) that adds a manageable "Specialty" field to customer
|
||||||
|
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: 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.
|
||||||
|
- Front office: the registration / "my account" form gets a required "Specialty" dropdown, gated
|
||||||
|
by a **Configure** toggle (`WS_CUSTOMERSPECIALTY_FRONT_ENABLED`) so it can be hidden from the
|
||||||
|
storefront without affecting back-office management.
|
||||||
|
- The customer's specialty title is exposed as a `{specialization}` order confirmation mail
|
||||||
|
variable (see below).
|
||||||
|
|
||||||
|
## Data model
|
||||||
|
|
||||||
|
The customer's specialty is stored in the module's own tables — `ws_customerspecialty`,
|
||||||
|
`ws_customerspecialty_lang`, and the pivot table `ws_customerspecialty_customer` — rather than by
|
||||||
|
altering `ps_customer` or overriding core classes. This keeps the module safe to run unchanged
|
||||||
|
across PrestaShop 1.7 through 9.0, since it never depends on core method internals that vary
|
||||||
|
between major versions.
|
||||||
|
|
||||||
|
## Order confirmation email integration
|
||||||
|
|
||||||
|
The module does **not** ship its own copy of the order confirmation mail template. Instead it
|
||||||
|
exposes the customer's specialty as `{specialization}` via the `actionGetExtraMailTemplateVars`
|
||||||
|
hook (the same pattern used in `ws_giftdropdown`). To show it in an order confirmation email, add
|
||||||
|
the placeholder to the shop's own `order_conf.html` / `order_conf.txt` mail templates, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
Specialty: {specialization}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the placeholder isn't present in the active theme's mail template, the variable is computed
|
||||||
|
but simply has nothing to render into — this is a one-time manual integration step per shop/theme,
|
||||||
|
not something the module can safely do on your behalf without overriding core mail templates.
|
||||||
|
|
||||||
|
## Compatibility notes
|
||||||
|
|
||||||
|
- Command handlers are tagged for both `tactician.handler` (PS 1.7/8) and `messenger.message_handler`
|
||||||
|
(PS 9), with matching `__invoke()`/`handle()` methods on each handler.
|
||||||
|
- No PrestaShop core class overrides, no `ALTER TABLE` on core tables.
|
||||||
|
|
||||||
|
## Deliberate differences from the legacy `pchcustomerfield` module
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
## Biggest assumption to verify
|
||||||
|
|
||||||
|
The storefront "Specialty" field on registration/account-edit relies on `additionalCustomerFormFields`
|
||||||
|
already being called by core's own front-office `CustomerFormatter` (passing `fields` by reference).
|
||||||
|
The legacy module achieved this only by overriding `CustomerFormatter` to add that hook call itself —
|
||||||
|
an override intentionally not reproduced here (see the architecture note above). If the installed
|
||||||
|
PrestaShop version's `CustomerFormatter` does not already call this hook natively, the storefront
|
||||||
|
field will not appear (back office, grid, and mail-variable behavior are unaffected either way,
|
||||||
|
since none of those depend on this hook). Verify on a real 1.7 and 9.0 install; if the hook isn't
|
||||||
|
native, the fallback is to make the field mandatory server-side via a small first-party
|
||||||
|
`CustomerFormatter` override scoped to only adding that one `Hook::exec()` call — much smaller and
|
||||||
|
safer than the legacy module's full-method copy.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "websmid/customerspecialty",
|
||||||
|
"description": "Adds a manageable specialty/profession field to customer accounts",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Isabelle Oving-Anno - De Websmid BV",
|
||||||
|
"email": "isabelle@dewebsmid.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Websmid\\CustomerSpecialty\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": ["ws_customerspecialty.php"],
|
||||||
|
"exclude-from-classmap": []
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"prepend-autoloader": false
|
||||||
|
},
|
||||||
|
"type": "prestashop-module",
|
||||||
|
"author": "Isabelle Oving-Anno - De Websmid BV",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
Generated
+18
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "523e34cf5681a91b03bd57967a2d35e0",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {},
|
||||||
|
"platform-dev": {},
|
||||||
|
"plugin-api-version": "2.6.0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
services:
|
||||||
|
websmid.customerspecialty.command_handler.save_customer_specialty_handler:
|
||||||
|
class: 'Websmid\CustomerSpecialty\Command\CommandHandler\SaveCustomerSpecialtyCommandHandler'
|
||||||
|
tags:
|
||||||
|
- { name: 'tactician.handler', command: 'Websmid\CustomerSpecialty\Command\SaveCustomerSpecialtyCommand' }
|
||||||
|
- { name: 'messenger.message_handler' }
|
||||||
|
|
||||||
|
websmid.customerspecialty.command_handler.move_customer_specialty_handler:
|
||||||
|
class: 'Websmid\CustomerSpecialty\Command\CommandHandler\MoveCustomerSpecialtyCommandHandler'
|
||||||
|
tags:
|
||||||
|
- { name: 'tactician.handler', command: 'Websmid\CustomerSpecialty\Command\MoveCustomerSpecialtyCommand' }
|
||||||
|
- { name: 'messenger.message_handler' }
|
||||||
|
|
||||||
|
websmid.customerspecialty.command_handler.toggle_customer_specialty_active_handler:
|
||||||
|
class: 'Websmid\CustomerSpecialty\Command\CommandHandler\ToggleCustomerSpecialtyActiveCommandHandler'
|
||||||
|
tags:
|
||||||
|
- { name: 'tactician.handler', command: 'Websmid\CustomerSpecialty\Command\ToggleCustomerSpecialtyActiveCommand' }
|
||||||
|
- { name: 'messenger.message_handler' }
|
||||||
|
|
||||||
|
websmid.customerspecialty.command_handler.link_customer_specialty_handler:
|
||||||
|
class: 'Websmid\CustomerSpecialty\Command\CommandHandler\LinkCustomerSpecialtyCommandHandler'
|
||||||
|
tags:
|
||||||
|
- { name: 'tactician.handler', command: 'Websmid\CustomerSpecialty\Command\LinkCustomerSpecialtyCommand' }
|
||||||
|
- { name: 'messenger.message_handler' }
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
services:
|
||||||
|
websmid.customerspecialty.form.type.customerspecialty:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Form\Type\CustomerSpecialtyType'
|
||||||
|
parent: 'form.type.translatable.aware'
|
||||||
|
tags:
|
||||||
|
- { name: form.type }
|
||||||
|
|
||||||
|
websmid.customerspecialty.form.customerspecialty_data_provider:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Form\DataProvider\CustomerSpecialtyDataProvider'
|
||||||
|
|
||||||
|
websmid.customerspecialty.form.customerspecialty_data_form_builder:
|
||||||
|
public: true
|
||||||
|
class: 'PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Builder\FormBuilder'
|
||||||
|
factory:
|
||||||
|
- '@prestashop.core.form.builder.form_builder_factory'
|
||||||
|
- 'create'
|
||||||
|
arguments:
|
||||||
|
- 'Websmid\CustomerSpecialty\Form\Type\CustomerSpecialtyType'
|
||||||
|
- '@websmid.customerspecialty.form.customerspecialty_data_provider'
|
||||||
|
|
||||||
|
websmid.customerspecialty.form.customerspecialty_data_handler:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Form\DataHandler\CustomerSpecialtyDataHandler'
|
||||||
|
arguments:
|
||||||
|
- '@prestashop.core.command_bus'
|
||||||
|
|
||||||
|
websmid.customerspecialty.form.customerspecialty_form_handler:
|
||||||
|
public: true
|
||||||
|
class: 'PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Handler\FormHandler'
|
||||||
|
factory:
|
||||||
|
- '@prestashop.core.form.identifiable_object.handler.form_handler_factory'
|
||||||
|
- 'create'
|
||||||
|
arguments:
|
||||||
|
- '@websmid.customerspecialty.form.customerspecialty_data_handler'
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
services:
|
||||||
|
websmid.customerspecialty.grid.definition.factory.customerspecialty_definition_factory:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Grid\Definition\Factory\CustomerSpecialtyGridDefinitionFactory'
|
||||||
|
parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
|
||||||
|
arguments:
|
||||||
|
- '@prestashop.adapter.legacy.configuration'
|
||||||
|
|
||||||
|
websmid.customerspecialty.grid.query.customerspecialty_query_builder:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Grid\Query\CustomerSpecialtyQueryBuilder'
|
||||||
|
parent: 'prestashop.core.grid.abstract_query_builder'
|
||||||
|
arguments:
|
||||||
|
- '@prestashop.core.query.doctrine_search_criteria_applicator'
|
||||||
|
- "@=service('prestashop.adapter.legacy.context').getContext().language.id"
|
||||||
|
- '@prestashop.core.grid.query.filter.doctrine_filter_applicator'
|
||||||
|
|
||||||
|
websmid.customerspecialty.grid.data.factory.customerspecialty_data_factory:
|
||||||
|
public: true
|
||||||
|
class: '%prestashop.core.grid.data.factory.doctrine_grid_data_factory%'
|
||||||
|
arguments:
|
||||||
|
- '@websmid.customerspecialty.grid.query.customerspecialty_query_builder'
|
||||||
|
- '@prestashop.core.hook.dispatcher'
|
||||||
|
- '@prestashop.core.grid.query.doctrine_query_parser'
|
||||||
|
- 'CustomerSpecialty'
|
||||||
|
|
||||||
|
websmid.customerspecialty.grid.customerspecialty_grid_factory:
|
||||||
|
public: true
|
||||||
|
class: 'PrestaShop\PrestaShop\Core\Grid\GridFactory'
|
||||||
|
arguments:
|
||||||
|
- '@websmid.customerspecialty.grid.definition.factory.customerspecialty_definition_factory'
|
||||||
|
- '@websmid.customerspecialty.grid.data.factory.customerspecialty_data_factory'
|
||||||
|
- '@prestashop.core.grid.filter.form_factory'
|
||||||
|
- '@prestashop.core.hook.dispatcher'
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
services:
|
||||||
|
websmid.customerspecialty.form.choice_provider.customer_specialty_choice_provider:
|
||||||
|
public: true
|
||||||
|
class: 'Websmid\CustomerSpecialty\Form\ChoiceProvider\CustomerSpecialtyChoiceProvider'
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
customerspecialty_index:
|
||||||
|
path: customerspecialty
|
||||||
|
methods: [GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::indexAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
_legacy_link: AdminCustomerSpecialtyOverview:index
|
||||||
|
|
||||||
|
customerspecialty_search:
|
||||||
|
path: customerspecialty
|
||||||
|
methods: [POST]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::searchAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
|
||||||
|
customerspecialty_create:
|
||||||
|
path: customerspecialty/create
|
||||||
|
methods: [POST, GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::createAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
|
||||||
|
customerspecialty_edit:
|
||||||
|
path: customerspecialty/edit/{idCustomerSpecialty}
|
||||||
|
methods: [POST, GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::editAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
|
||||||
|
customerspecialty_toggle_active:
|
||||||
|
path: customerspecialty/toggle-active/{idCustomerSpecialty}
|
||||||
|
methods: [GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::toggleActiveAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
|
||||||
|
customerspecialty_move_up:
|
||||||
|
path: customerspecialty/move-up/{idCustomerSpecialty}
|
||||||
|
methods: [GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::moveUpAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
|
|
||||||
|
customerspecialty_move_down:
|
||||||
|
path: customerspecialty/move-down/{idCustomerSpecialty}
|
||||||
|
methods: [GET]
|
||||||
|
defaults:
|
||||||
|
_controller: 'Websmid\CustomerSpecialty\Controller\CustomerSpecialtyController::moveDownAction'
|
||||||
|
_legacy_controller: AdminCustomerSpecialtyOverview
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: form.yml }
|
||||||
|
- { resource: grid.yml }
|
||||||
|
- { resource: command.yml }
|
||||||
|
- { resource: provider.yml }
|
||||||
|
|
||||||
|
services:
|
||||||
|
websmid.customerspecialty.entity.table_prefix_subscriber:
|
||||||
|
class: 'Websmid\CustomerSpecialty\Entity\TablePrefixSubscriber'
|
||||||
|
arguments:
|
||||||
|
- '%database_prefix%'
|
||||||
|
tags:
|
||||||
|
- { name: doctrine.event_subscriber }
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||||
|
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||||
|
header('Pragma: no-cache');
|
||||||
|
|
||||||
|
header('Location: ../');
|
||||||
|
exit;
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command\CommandHandler;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Command\LinkCustomerSpecialtyCommand;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialtyCustomer;
|
||||||
|
use DateTime;
|
||||||
|
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
|
||||||
|
|
||||||
|
final class LinkCustomerSpecialtyCommandHandler
|
||||||
|
{
|
||||||
|
private $entityManager;
|
||||||
|
|
||||||
|
public function __invoke(LinkCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
return $this->handle($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(LinkCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
$this->entityManager = SymfonyContainer::getInstance()->get('doctrine.orm.entity_manager');
|
||||||
|
$repository = $this->entityManager->getRepository(CustomerSpecialtyCustomer::class);
|
||||||
|
|
||||||
|
$link = $repository->findOneBy(['idCustomer' => $command->getIdCustomer()]);
|
||||||
|
|
||||||
|
if (!$link) {
|
||||||
|
$link = new CustomerSpecialtyCustomer();
|
||||||
|
$link->setIdCustomer($command->getIdCustomer());
|
||||||
|
$link->setDateAdd(new DateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
$link->setIdCustomerSpecialty($command->getIdCustomerSpecialty());
|
||||||
|
$link->setDateUpd(new DateTime());
|
||||||
|
|
||||||
|
$this->entityManager->persist($link);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command\CommandHandler;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Command\MoveCustomerSpecialtyCommand;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialty;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
|
||||||
|
use PrestaShopException;
|
||||||
|
|
||||||
|
final class MoveCustomerSpecialtyCommandHandler
|
||||||
|
{
|
||||||
|
private $entityManager;
|
||||||
|
|
||||||
|
public function __invoke(MoveCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
return $this->handle($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(MoveCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
$this->entityManager = SymfonyContainer::getInstance()->get('doctrine.orm.entity_manager');
|
||||||
|
$repository = $this->entityManager->getRepository(CustomerSpecialty::class);
|
||||||
|
|
||||||
|
$customerSpecialty = $repository->find($command->getIdCustomerSpecialty());
|
||||||
|
|
||||||
|
if (!$customerSpecialty) {
|
||||||
|
throw new PrestaShopException('Customer specialty not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$neighbor = $this->findNeighbor($repository, $customerSpecialty, $command->getDirection());
|
||||||
|
|
||||||
|
if (!$neighbor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentPosition = $customerSpecialty->getPosition();
|
||||||
|
$customerSpecialty->setPosition($neighbor->getPosition());
|
||||||
|
$neighbor->setPosition($currentPosition);
|
||||||
|
|
||||||
|
$this->entityManager->persist($customerSpecialty);
|
||||||
|
$this->entityManager->persist($neighbor);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findNeighbor(EntityRepository $repository, CustomerSpecialty $customerSpecialty, string $direction): ?CustomerSpecialty
|
||||||
|
{
|
||||||
|
$queryBuilder = $repository->createQueryBuilder('cs');
|
||||||
|
|
||||||
|
if (MoveCustomerSpecialtyCommand::DIRECTION_UP === $direction) {
|
||||||
|
$queryBuilder
|
||||||
|
->where('cs.position < :position')
|
||||||
|
->orderBy('cs.position', 'DESC');
|
||||||
|
} else {
|
||||||
|
$queryBuilder
|
||||||
|
->where('cs.position > :position')
|
||||||
|
->orderBy('cs.position', 'ASC');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $queryBuilder
|
||||||
|
->setParameter('position', $customerSpecialty->getPosition())
|
||||||
|
->setMaxResults(1)
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command\CommandHandler;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Command\SaveCustomerSpecialtyCommand;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialty;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialtyLang;
|
||||||
|
use DateTime;
|
||||||
|
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
|
||||||
|
use PrestaShopException;
|
||||||
|
|
||||||
|
final class SaveCustomerSpecialtyCommandHandler
|
||||||
|
{
|
||||||
|
private $entityManager;
|
||||||
|
|
||||||
|
public function __invoke(SaveCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
return $this->handle($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(SaveCustomerSpecialtyCommand $command)
|
||||||
|
{
|
||||||
|
if (empty(array_filter($command->getTitles()))) {
|
||||||
|
throw new PrestaShopException('At least one title is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager = SymfonyContainer::getInstance()->get('doctrine.orm.entity_manager');
|
||||||
|
|
||||||
|
$customerSpecialty = $this->findOrCreateCustomerSpecialty($command->getIdCustomerSpecialty());
|
||||||
|
$customerSpecialty->setActive($command->isActive());
|
||||||
|
$this->stampDates($customerSpecialty);
|
||||||
|
|
||||||
|
$this->entityManager->persist($customerSpecialty);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->saveTitles($customerSpecialty->getId(), $command->getTitles());
|
||||||
|
|
||||||
|
return $customerSpecialty->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findOrCreateCustomerSpecialty(int $idCustomerSpecialty): CustomerSpecialty
|
||||||
|
{
|
||||||
|
if ($idCustomerSpecialty > 0) {
|
||||||
|
$customerSpecialty = $this->entityManager->getRepository(CustomerSpecialty::class)->find($idCustomerSpecialty);
|
||||||
|
|
||||||
|
if ($customerSpecialty) {
|
||||||
|
return $customerSpecialty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$customerSpecialty = new CustomerSpecialty();
|
||||||
|
$customerSpecialty->setPosition($this->getNextPosition());
|
||||||
|
|
||||||
|
return $customerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getNextPosition(): int
|
||||||
|
{
|
||||||
|
$result = $this->entityManager->getRepository(CustomerSpecialty::class)
|
||||||
|
->createQueryBuilder('cs')
|
||||||
|
->select('MAX(cs.position) as maxPosition')
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult();
|
||||||
|
|
||||||
|
return null === $result ? 0 : ((int) $result + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stampDates(CustomerSpecialty $customerSpecialty): void
|
||||||
|
{
|
||||||
|
$now = new DateTime();
|
||||||
|
|
||||||
|
if (null === $customerSpecialty->getId()) {
|
||||||
|
$customerSpecialty->setDateAdd($now);
|
||||||
|
}
|
||||||
|
|
||||||
|
$customerSpecialty->setDateUpd($now);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveTitles(int $idCustomerSpecialty, array $titles): void
|
||||||
|
{
|
||||||
|
$repository = $this->entityManager->getRepository(CustomerSpecialtyLang::class);
|
||||||
|
|
||||||
|
foreach ($repository->findBy(['idCustomerSpecialty' => $idCustomerSpecialty]) as $existingLang) {
|
||||||
|
$this->entityManager->remove($existingLang);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
foreach ($titles as $idLang => $title) {
|
||||||
|
if ('' === trim((string) $title)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lang = new CustomerSpecialtyLang();
|
||||||
|
$lang->setIdCustomerSpecialty($idCustomerSpecialty);
|
||||||
|
$lang->setIdLang((int) $idLang);
|
||||||
|
$lang->setTitle($title);
|
||||||
|
|
||||||
|
$this->entityManager->persist($lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command\CommandHandler;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Command\ToggleCustomerSpecialtyActiveCommand;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialty;
|
||||||
|
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
|
||||||
|
use PrestaShopException;
|
||||||
|
|
||||||
|
final class ToggleCustomerSpecialtyActiveCommandHandler
|
||||||
|
{
|
||||||
|
public function __invoke(ToggleCustomerSpecialtyActiveCommand $command)
|
||||||
|
{
|
||||||
|
return $this->handle($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(ToggleCustomerSpecialtyActiveCommand $command)
|
||||||
|
{
|
||||||
|
$entityManager = SymfonyContainer::getInstance()->get('doctrine.orm.entity_manager');
|
||||||
|
$repository = $entityManager->getRepository(CustomerSpecialty::class);
|
||||||
|
|
||||||
|
$customerSpecialty = $repository->find($command->getIdCustomerSpecialty());
|
||||||
|
|
||||||
|
if (!$customerSpecialty) {
|
||||||
|
throw new PrestaShopException('Customer specialty not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$customerSpecialty->setActive(!$customerSpecialty->isActive());
|
||||||
|
|
||||||
|
$entityManager->persist($customerSpecialty);
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command;
|
||||||
|
|
||||||
|
class LinkCustomerSpecialtyCommand
|
||||||
|
{
|
||||||
|
private $idCustomer;
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
|
||||||
|
public function __construct(int $idCustomer, int $idCustomerSpecialty)
|
||||||
|
{
|
||||||
|
$this->idCustomer = $idCustomer;
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomer(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command;
|
||||||
|
|
||||||
|
class MoveCustomerSpecialtyCommand
|
||||||
|
{
|
||||||
|
const DIRECTION_UP = 'up';
|
||||||
|
const DIRECTION_DOWN = 'down';
|
||||||
|
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
private $direction;
|
||||||
|
|
||||||
|
public function __construct(int $idCustomerSpecialty, string $direction)
|
||||||
|
{
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
$this->direction = $direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDirection(): string
|
||||||
|
{
|
||||||
|
return $this->direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command;
|
||||||
|
|
||||||
|
class SaveCustomerSpecialtyCommand
|
||||||
|
{
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
private $active;
|
||||||
|
private $titles;
|
||||||
|
|
||||||
|
public function __construct(int $idCustomerSpecialty, bool $active, array $titles)
|
||||||
|
{
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
$this->active = $active;
|
||||||
|
$this->titles = $titles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActive(): bool
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitles(): array
|
||||||
|
{
|
||||||
|
return $this->titles;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Command;
|
||||||
|
|
||||||
|
class ToggleCustomerSpecialtyActiveCommand
|
||||||
|
{
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
|
||||||
|
public function __construct(int $idCustomerSpecialty)
|
||||||
|
{
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Config;
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
const HOOKS = [
|
||||||
|
'additionalCustomerFormFields',
|
||||||
|
'actionCustomerFormBuilderModifier',
|
||||||
|
'actionAfterCreateCustomerFormHandler',
|
||||||
|
'actionAfterUpdateCustomerFormHandler',
|
||||||
|
'actionObjectCustomerAddAfter',
|
||||||
|
'actionObjectCustomerUpdateAfter',
|
||||||
|
'actionCustomerGridDefinitionModifier',
|
||||||
|
'actionCustomerGridQueryBuilderModifier',
|
||||||
|
'displayAdminCustomers',
|
||||||
|
'actionGetExtraMailTemplateVars',
|
||||||
|
];
|
||||||
|
|
||||||
|
const TABS = [
|
||||||
|
[
|
||||||
|
'class_name' => 'AdminCustomerSpecialtyOverview',
|
||||||
|
'parent_class_name' => 'AdminParentCustomer',
|
||||||
|
'name' => [
|
||||||
|
'en' => 'Customer Specialties',
|
||||||
|
'nl' => 'Klantspecialisaties',
|
||||||
|
],
|
||||||
|
'module' => 'ws_customerspecialty',
|
||||||
|
'icon' => 'work',
|
||||||
|
'route_name' => 'customerspecialty_index',
|
||||||
|
'active' => 1,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const FRONT_ENABLED_CONFIG_KEY = 'WS_CUSTOMERSPECIALTY_FRONT_ENABLED';
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Controller;
|
||||||
|
|
||||||
|
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
|
||||||
|
use PrestaShopBundle\Security\Voter\PageVoter;
|
||||||
|
use Websmid\CustomerSpecialty\Grid\Definition\Factory\CustomerSpecialtyGridDefinitionFactory;
|
||||||
|
use Websmid\CustomerSpecialty\Grid\Filters\CustomerSpecialtyFilters;
|
||||||
|
use Websmid\CustomerSpecialty\Command\MoveCustomerSpecialtyCommand;
|
||||||
|
use Websmid\CustomerSpecialty\Command\ToggleCustomerSpecialtyActiveCommand;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use PrestaShopException;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class CustomerSpecialtyController extends FrameworkBundleAdminController
|
||||||
|
{
|
||||||
|
public function indexAction(Request $request, CustomerSpecialtyFilters $filters): Response
|
||||||
|
{
|
||||||
|
$gridFactory = $this->get('websmid.customerspecialty.grid.customerspecialty_grid_factory');
|
||||||
|
$grid = $gridFactory->getGrid($filters);
|
||||||
|
|
||||||
|
return $this->render('@Modules/ws_customerspecialty/views/templates/admin/grid/customerspecialty.html.twig', [
|
||||||
|
'customerSpecialtyGrid' => $this->presentGrid($grid),
|
||||||
|
'layoutHeaderToolbarBtn' => $this->getToolbarButtons($request->get('_legacy_controller')),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchAction(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
return $this->get('prestashop.bundle.grid.response_builder')->buildSearchResponse(
|
||||||
|
$this->get('websmid.customerspecialty.grid.definition.factory.customerspecialty_definition_factory'),
|
||||||
|
$request,
|
||||||
|
CustomerSpecialtyGridDefinitionFactory::GRID_ID,
|
||||||
|
'customerspecialty_index'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction(Request $request): Response
|
||||||
|
{
|
||||||
|
$formBuilder = $this->get('websmid.customerspecialty.form.customerspecialty_data_form_builder');
|
||||||
|
$formHandler = $this->get('websmid.customerspecialty.form.customerspecialty_form_handler');
|
||||||
|
|
||||||
|
$form = $formBuilder->getForm();
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$handlerResult = $formHandler->handle($form);
|
||||||
|
|
||||||
|
if (null !== $handlerResult->getIdentifiableObjectId()) {
|
||||||
|
$this->addFlash('success', $this->trans('Successful creation', [], 'Admin.Notifications.Success'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('customerspecialty_index');
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@Modules/ws_customerspecialty/views/templates/admin/form/customerspecialty.html.twig', [
|
||||||
|
'customerSpecialtyForm' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function editAction(Request $request, int $idCustomerSpecialty): Response
|
||||||
|
{
|
||||||
|
$formBuilder = $this->get('websmid.customerspecialty.form.customerspecialty_data_form_builder');
|
||||||
|
$formHandler = $this->get('websmid.customerspecialty.form.customerspecialty_form_handler');
|
||||||
|
|
||||||
|
$form = $formBuilder->getFormFor($idCustomerSpecialty);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
$handlerResult = $formHandler->handleFor($idCustomerSpecialty, $form);
|
||||||
|
|
||||||
|
if ($handlerResult->isSubmitted() && $handlerResult->isValid()) {
|
||||||
|
$this->addFlash('success', $this->trans('Successful update', [], 'Admin.Notifications.Success'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('customerspecialty_index');
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@Modules/ws_customerspecialty/views/templates/admin/form/customerspecialty.html.twig', [
|
||||||
|
'customerSpecialtyForm' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleActiveAction(int $idCustomerSpecialty): RedirectResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->getCommandBus()->handle(new ToggleCustomerSpecialtyActiveCommand($idCustomerSpecialty));
|
||||||
|
$this->addFlash('success', $this->trans('Successful update', [], 'Admin.Notifications.Success'));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute('customerspecialty_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moveUpAction(int $idCustomerSpecialty): RedirectResponse
|
||||||
|
{
|
||||||
|
return $this->move($idCustomerSpecialty, MoveCustomerSpecialtyCommand::DIRECTION_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moveDownAction(int $idCustomerSpecialty): RedirectResponse
|
||||||
|
{
|
||||||
|
return $this->move($idCustomerSpecialty, MoveCustomerSpecialtyCommand::DIRECTION_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function move(int $idCustomerSpecialty, string $direction): RedirectResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->getCommandBus()->handle(new MoveCustomerSpecialtyCommand($idCustomerSpecialty, $direction));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->addFlash('error', $this->getErrorMessageForException($e, $this->getErrorMessages()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute('customerspecialty_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getToolbarButtons(string $securitySubject): array
|
||||||
|
{
|
||||||
|
$toolbarButtons = [];
|
||||||
|
|
||||||
|
if (!$this->isGranted(PageVoter::CREATE, $securitySubject)) {
|
||||||
|
return $toolbarButtons;
|
||||||
|
}
|
||||||
|
|
||||||
|
$toolbarButtons['customerspecialty_create'] = [
|
||||||
|
'href' => $this->generateUrl('customerspecialty_create'),
|
||||||
|
'desc' => $this->trans('New specialty', [], 'Admin.Actions'),
|
||||||
|
'icon' => 'add_circle_outline',
|
||||||
|
'class' => 'btn-primary',
|
||||||
|
'floating_class' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $toolbarButtons;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getErrorMessages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
PrestaShopException::class => [
|
||||||
|
'key' => 'An error occurred while saving the customer specialty.',
|
||||||
|
'domain' => 'Modules.Wscustomerspecialty.Admin',
|
||||||
|
'parameters' => [],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCommandBus()
|
||||||
|
{
|
||||||
|
return $this->get('prestashop.core.command_bus');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Entity;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Table(name="ws_customerspecialty")
|
||||||
|
* @ORM\Entity()
|
||||||
|
*/
|
||||||
|
class CustomerSpecialty
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id_ws_customerspecialty", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="position", type="integer")
|
||||||
|
*/
|
||||||
|
private $position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="active", type="boolean")
|
||||||
|
*/
|
||||||
|
private $active;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="date_add", type="datetime")
|
||||||
|
*/
|
||||||
|
private $dateAdd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="date_upd", type="datetime")
|
||||||
|
*/
|
||||||
|
private $dateUpd;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPosition(): int
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPosition(int $position): self
|
||||||
|
{
|
||||||
|
$this->position = $position;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActive(): bool
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setActive(bool $active): self
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateAdd(): ?DateTime
|
||||||
|
{
|
||||||
|
return $this->dateAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateAdd(DateTime $dateAdd): self
|
||||||
|
{
|
||||||
|
$this->dateAdd = $dateAdd;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateUpd(): ?DateTime
|
||||||
|
{
|
||||||
|
return $this->dateUpd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateUpd(DateTime $dateUpd): self
|
||||||
|
{
|
||||||
|
$this->dateUpd = $dateUpd;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id_ws_customerspecialty' => $this->id,
|
||||||
|
'position' => $this->position,
|
||||||
|
'active' => $this->active,
|
||||||
|
'date_add' => $this->dateAdd ? $this->dateAdd->format('Y-m-d H:i:s') : null,
|
||||||
|
'date_upd' => $this->dateUpd ? $this->dateUpd->format('Y-m-d H:i:s') : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Entity;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Table(name="ws_customerspecialty_customer")
|
||||||
|
* @ORM\Entity()
|
||||||
|
*/
|
||||||
|
class CustomerSpecialtyCustomer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id_ws_customerspecialty_customer", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="id_customer", type="integer", unique=true)
|
||||||
|
*/
|
||||||
|
private $idCustomer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="id_ws_customerspecialty", type="integer")
|
||||||
|
*/
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="date_add", type="datetime")
|
||||||
|
*/
|
||||||
|
private $dateAdd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="date_upd", type="datetime")
|
||||||
|
*/
|
||||||
|
private $dateUpd;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomer(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIdCustomer(int $idCustomer): self
|
||||||
|
{
|
||||||
|
$this->idCustomer = $idCustomer;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIdCustomerSpecialty(int $idCustomerSpecialty): self
|
||||||
|
{
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateAdd(): ?DateTime
|
||||||
|
{
|
||||||
|
return $this->dateAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateAdd(DateTime $dateAdd): self
|
||||||
|
{
|
||||||
|
$this->dateAdd = $dateAdd;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateUpd(): ?DateTime
|
||||||
|
{
|
||||||
|
return $this->dateUpd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateUpd(DateTime $dateUpd): self
|
||||||
|
{
|
||||||
|
$this->dateUpd = $dateUpd;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id_ws_customerspecialty_customer' => $this->id,
|
||||||
|
'id_customer' => $this->idCustomer,
|
||||||
|
'id_ws_customerspecialty' => $this->idCustomerSpecialty,
|
||||||
|
'date_add' => $this->dateAdd ? $this->dateAdd->format('Y-m-d H:i:s') : null,
|
||||||
|
'date_upd' => $this->dateUpd ? $this->dateUpd->format('Y-m-d H:i:s') : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Table(name="ws_customerspecialty_lang")
|
||||||
|
* @ORM\Entity()
|
||||||
|
*/
|
||||||
|
class CustomerSpecialtyLang
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id_ws_customerspecialty_lang", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="id_ws_customerspecialty", type="integer")
|
||||||
|
*/
|
||||||
|
private $idCustomerSpecialty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="id_lang", type="integer")
|
||||||
|
*/
|
||||||
|
private $idLang;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="title", type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdCustomerSpecialty(): int
|
||||||
|
{
|
||||||
|
return $this->idCustomerSpecialty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIdCustomerSpecialty(int $idCustomerSpecialty): self
|
||||||
|
{
|
||||||
|
$this->idCustomerSpecialty = $idCustomerSpecialty;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdLang(): int
|
||||||
|
{
|
||||||
|
return $this->idLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIdLang(int $idLang): self
|
||||||
|
{
|
||||||
|
$this->idLang = $idLang;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle(string $title): self
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id_ws_customerspecialty_lang' => $this->id,
|
||||||
|
'id_ws_customerspecialty' => $this->idCustomerSpecialty,
|
||||||
|
'id_lang' => $this->idLang,
|
||||||
|
'title' => $this->title,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Entity;
|
||||||
|
|
||||||
|
use Doctrine\Common\EventSubscriber;
|
||||||
|
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||||
|
use Doctrine\ORM\Events;
|
||||||
|
|
||||||
|
class TablePrefixSubscriber implements EventSubscriber
|
||||||
|
{
|
||||||
|
private $prefix;
|
||||||
|
|
||||||
|
public function __construct(string $prefix)
|
||||||
|
{
|
||||||
|
$this->prefix = $prefix ?: 'ps_';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubscribedEvents(): array
|
||||||
|
{
|
||||||
|
return [Events::loadClassMetadata];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadClassMetadata(LoadClassMetadataEventArgs $args): void
|
||||||
|
{
|
||||||
|
$classMetadata = $args->getClassMetadata();
|
||||||
|
|
||||||
|
if (strpos($classMetadata->getName(), 'Websmid\\CustomerSpecialty\\') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tableName = $classMetadata->getTableName();
|
||||||
|
|
||||||
|
if (strpos($tableName, $this->prefix) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classMetadata->setPrimaryTable(['name' => $this->prefix . $tableName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Form\ChoiceProvider;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\ConfigurableFormChoiceProviderInterface;
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\FormChoiceAttributeProviderInterface;
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\FormChoiceProviderInterface;
|
||||||
|
use Context;
|
||||||
|
use Db;
|
||||||
|
|
||||||
|
final class CustomerSpecialtyChoiceProvider implements
|
||||||
|
FormChoiceProviderInterface,
|
||||||
|
FormChoiceAttributeProviderInterface,
|
||||||
|
ConfigurableFormChoiceProviderInterface
|
||||||
|
{
|
||||||
|
public function getChoices(array $options = []): array
|
||||||
|
{
|
||||||
|
$includeInactive = $options['include_inactive'] ?? false;
|
||||||
|
$idLang = (int) Context::getContext()->language->id;
|
||||||
|
|
||||||
|
$sql = '
|
||||||
|
SELECT cs.`id_ws_customerspecialty`, csl.`title`
|
||||||
|
FROM `' . _DB_PREFIX_ . 'ws_customerspecialty` cs
|
||||||
|
INNER JOIN `' . _DB_PREFIX_ . 'ws_customerspecialty_lang` csl
|
||||||
|
ON csl.`id_ws_customerspecialty` = cs.`id_ws_customerspecialty`
|
||||||
|
AND csl.`id_lang` = ' . $idLang . '
|
||||||
|
' . ($includeInactive ? '' : 'WHERE cs.`active` = 1') . '
|
||||||
|
ORDER BY cs.`position` ASC
|
||||||
|
';
|
||||||
|
|
||||||
|
$rows = Db::getInstance()->executeS($sql);
|
||||||
|
$choices = [];
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$choices[$row['title']] = (int) $row['id_ws_customerspecialty'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChoicesAttributes(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Form\DataHandler;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\FormDataHandlerInterface;
|
||||||
|
use Websmid\CustomerSpecialty\Command\SaveCustomerSpecialtyCommand;
|
||||||
|
use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
|
||||||
|
|
||||||
|
final class CustomerSpecialtyDataHandler implements FormDataHandlerInterface
|
||||||
|
{
|
||||||
|
private $commandBus;
|
||||||
|
|
||||||
|
public function __construct(CommandBusInterface $commandBus)
|
||||||
|
{
|
||||||
|
$this->commandBus = $commandBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(array $data)
|
||||||
|
{
|
||||||
|
return $this->save(0, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($id, array $data)
|
||||||
|
{
|
||||||
|
return $this->save((int) $id, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function save(int $id, array $data)
|
||||||
|
{
|
||||||
|
return $this->commandBus->handle(new SaveCustomerSpecialtyCommand(
|
||||||
|
$id,
|
||||||
|
(bool) ($data['active'] ?? false),
|
||||||
|
$data['title'] ?? []
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Form\DataProvider;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\FormDataProviderInterface;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialty;
|
||||||
|
use Websmid\CustomerSpecialty\Entity\CustomerSpecialtyLang;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
|
||||||
|
|
||||||
|
final class CustomerSpecialtyDataProvider implements FormDataProviderInterface
|
||||||
|
{
|
||||||
|
public function getDefaultData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => [],
|
||||||
|
'active' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData($id): array
|
||||||
|
{
|
||||||
|
$entityManager = SymfonyContainer::getInstance()->get('doctrine.orm.entity_manager');
|
||||||
|
|
||||||
|
$customerSpecialty = $entityManager->getRepository(CustomerSpecialty::class)->find((int) $id);
|
||||||
|
|
||||||
|
if (!$customerSpecialty) {
|
||||||
|
return $this->getDefaultData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'title' => $this->loadTitles($entityManager, (int) $id),
|
||||||
|
'active' => $customerSpecialty->isActive(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadTitles(EntityManagerInterface $entityManager, int $idCustomerSpecialty): array
|
||||||
|
{
|
||||||
|
$titles = [];
|
||||||
|
|
||||||
|
foreach ($entityManager->getRepository(CustomerSpecialtyLang::class)->findBy(['idCustomerSpecialty' => $idCustomerSpecialty]) as $lang) {
|
||||||
|
$titles[$lang->getIdLang()] = $lang->getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $titles;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use PrestaShopBundle\Form\Admin\Type\SwitchType;
|
||||||
|
use PrestaShopBundle\Form\Admin\Type\TranslatableType;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class CustomerSpecialtyType extends AbstractType
|
||||||
|
{
|
||||||
|
private $translator;
|
||||||
|
private $locales;
|
||||||
|
|
||||||
|
public function __construct(TranslatorInterface $translator, array $locales)
|
||||||
|
{
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->locales = $locales;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $formBuilder, array $options): void
|
||||||
|
{
|
||||||
|
$formBuilder
|
||||||
|
->add('title', TranslatableType::class, [
|
||||||
|
'type' => TextType::class,
|
||||||
|
'label' => $this->trans('Title'),
|
||||||
|
'required' => true,
|
||||||
|
])
|
||||||
|
->add('active', SwitchType::class, [
|
||||||
|
'label' => $this->trans('Active'),
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function trans(string $label): string
|
||||||
|
{
|
||||||
|
return $this->translator->trans($label, [], 'Modules.Wscustomerspecialty.Admin');
|
||||||
|
}
|
||||||
|
}
|
||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Grid\Definition\Factory;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\AbstractGridDefinitionFactory;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Column\ColumnCollection;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\DataColumn;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ActionColumn;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Action\Row\RowActionCollection;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Action\Row\Type\LinkRowAction;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Action\GridActionCollection;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Action\Type\SimpleGridAction;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Filter\Filter;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Filter\FilterCollection;
|
||||||
|
use PrestaShopBundle\Form\Admin\Type\SearchAndResetType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
|
||||||
|
class CustomerSpecialtyGridDefinitionFactory extends AbstractGridDefinitionFactory
|
||||||
|
{
|
||||||
|
const GRID_ID = 'customerspecialty';
|
||||||
|
|
||||||
|
protected function getId()
|
||||||
|
{
|
||||||
|
return self::GRID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getName()
|
||||||
|
{
|
||||||
|
return $this->trans('Customer Specialties', [], 'Modules.Wscustomerspecialty.Admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getColumns()
|
||||||
|
{
|
||||||
|
return (new ColumnCollection())
|
||||||
|
->add(
|
||||||
|
(new DataColumn('id_ws_customerspecialty'))
|
||||||
|
->setName($this->trans('ID', [], 'Admin.Global'))
|
||||||
|
->setOptions([
|
||||||
|
'field' => 'id_ws_customerspecialty',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new DataColumn('title'))
|
||||||
|
->setName($this->trans('Title', [], 'Modules.Wscustomerspecialty.Admin'))
|
||||||
|
->setOptions([
|
||||||
|
'field' => 'title',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new ToggleColumn('active'))
|
||||||
|
->setName($this->trans('Active', [], 'Admin.Global'))
|
||||||
|
->setOptions([
|
||||||
|
'field' => 'active',
|
||||||
|
'primary_field' => 'id_ws_customerspecialty',
|
||||||
|
'route' => 'customerspecialty_toggle_active',
|
||||||
|
'route_param_name' => 'idCustomerSpecialty',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new ActionColumn('actions'))
|
||||||
|
->setName($this->trans('Actions', [], 'Admin.Global'))
|
||||||
|
->setOptions([
|
||||||
|
'actions' => (new RowActionCollection())
|
||||||
|
->add(
|
||||||
|
(new LinkRowAction('edit'))
|
||||||
|
->setName($this->trans('Edit', [], 'Admin.Actions'))
|
||||||
|
->setIcon('edit')
|
||||||
|
->setOptions([
|
||||||
|
'route' => 'customerspecialty_edit',
|
||||||
|
'route_param_name' => 'idCustomerSpecialty',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new LinkRowAction('move_up'))
|
||||||
|
->setName($this->trans('Move up', [], 'Modules.Wscustomerspecialty.Admin'))
|
||||||
|
->setIcon('arrow_upward')
|
||||||
|
->setOptions([
|
||||||
|
'route' => 'customerspecialty_move_up',
|
||||||
|
'route_param_name' => 'idCustomerSpecialty',
|
||||||
|
])
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new LinkRowAction('move_down'))
|
||||||
|
->setName($this->trans('Move down', [], 'Modules.Wscustomerspecialty.Admin'))
|
||||||
|
->setIcon('arrow_downward')
|
||||||
|
->setOptions([
|
||||||
|
'route' => 'customerspecialty_move_down',
|
||||||
|
'route_param_name' => 'idCustomerSpecialty',
|
||||||
|
])
|
||||||
|
),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFilters()
|
||||||
|
{
|
||||||
|
return (new FilterCollection())
|
||||||
|
->add(
|
||||||
|
(new Filter('title', TextType::class))
|
||||||
|
->setAssociatedColumn('title')
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new Filter('active', ChoiceType::class))
|
||||||
|
->setTypeOptions([
|
||||||
|
'choices' => [
|
||||||
|
$this->trans('Active', [], 'Admin.Global') => 1,
|
||||||
|
$this->trans('Inactive', [], 'Admin.Global') => 0,
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
->setAssociatedColumn('active')
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new Filter('actions', SearchAndResetType::class))
|
||||||
|
->setTypeOptions([
|
||||||
|
'reset_route' => 'customerspecialty_index',
|
||||||
|
'redirect_route' => 'customerspecialty_index',
|
||||||
|
])
|
||||||
|
->setAssociatedColumn('actions')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getGridActions()
|
||||||
|
{
|
||||||
|
return (new GridActionCollection())
|
||||||
|
->add(
|
||||||
|
(new SimpleGridAction('common_refresh_list'))
|
||||||
|
->setName($this->trans('Refresh list', [], 'Admin.Catalog.Feature'))
|
||||||
|
->setIcon('refresh')
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
(new SimpleGridAction('common_show_query'))
|
||||||
|
->setName($this->trans('Show SQL query', [], 'Admin.Catalog.Feature'))
|
||||||
|
->setIcon('code')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Grid\Filters;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Filter\Filters;
|
||||||
|
use Websmid\CustomerSpecialty\Grid\Definition\Factory\CustomerSpecialtyGridDefinitionFactory;
|
||||||
|
|
||||||
|
class CustomerSpecialtyFilters extends Filters
|
||||||
|
{
|
||||||
|
protected $filterId = CustomerSpecialtyGridDefinitionFactory::GRID_ID;
|
||||||
|
|
||||||
|
public static function getDefaults()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'limit' => 50,
|
||||||
|
'offset' => 0,
|
||||||
|
'orderBy' => 'cs.position',
|
||||||
|
'sortOrder' => 'asc',
|
||||||
|
'filters' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Grid\Query;
|
||||||
|
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Query\AbstractDoctrineQueryBuilder;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
|
||||||
|
use Doctrine\DBAL\Connection;
|
||||||
|
use Doctrine\DBAL\Query\QueryBuilder;
|
||||||
|
|
||||||
|
class CustomerSpecialtyQueryBuilder extends AbstractDoctrineQueryBuilder
|
||||||
|
{
|
||||||
|
private $searchCriteriaApplicator;
|
||||||
|
private $contextLanguageId;
|
||||||
|
private $filterApplicator;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Connection $connection,
|
||||||
|
$dbPrefix,
|
||||||
|
$searchCriteriaApplicator,
|
||||||
|
int $contextLanguageId,
|
||||||
|
$filterApplicator
|
||||||
|
) {
|
||||||
|
parent::__construct($connection, $dbPrefix);
|
||||||
|
|
||||||
|
$this->searchCriteriaApplicator = $searchCriteriaApplicator;
|
||||||
|
$this->contextLanguageId = $contextLanguageId;
|
||||||
|
$this->filterApplicator = $filterApplicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria)
|
||||||
|
{
|
||||||
|
$queryBuilder = $this->getBaseQuery();
|
||||||
|
$queryBuilder->select('cs.id_ws_customerspecialty, cs.active, cs.position, csl.title');
|
||||||
|
|
||||||
|
$this->applyFilters($queryBuilder, $searchCriteria);
|
||||||
|
|
||||||
|
$this->searchCriteriaApplicator
|
||||||
|
->applyPagination($searchCriteria, $queryBuilder)
|
||||||
|
->applySorting($searchCriteria, $queryBuilder);
|
||||||
|
|
||||||
|
return $queryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria)
|
||||||
|
{
|
||||||
|
$queryBuilder = $this->getBaseQuery();
|
||||||
|
$queryBuilder->select('COUNT(cs.id_ws_customerspecialty)');
|
||||||
|
|
||||||
|
$this->applyFilters($queryBuilder, $searchCriteria);
|
||||||
|
|
||||||
|
return $queryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBaseQuery(): QueryBuilder
|
||||||
|
{
|
||||||
|
$queryBuilder = $this->connection->createQueryBuilder();
|
||||||
|
|
||||||
|
$queryBuilder
|
||||||
|
->from($this->dbPrefix . 'ws_customerspecialty', 'cs')
|
||||||
|
->leftJoin(
|
||||||
|
'cs',
|
||||||
|
$this->dbPrefix . 'ws_customerspecialty_lang',
|
||||||
|
'csl',
|
||||||
|
'csl.id_ws_customerspecialty = cs.id_ws_customerspecialty AND csl.id_lang = :contextLanguageId'
|
||||||
|
)
|
||||||
|
->setParameter('contextLanguageId', $this->contextLanguageId);
|
||||||
|
|
||||||
|
return $queryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyFilters(QueryBuilder $queryBuilder, SearchCriteriaInterface $searchCriteria): void
|
||||||
|
{
|
||||||
|
foreach ($searchCriteria->getFilters() as $filterName => $filterValue) {
|
||||||
|
if ('' === $filterValue || null === $filterValue) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($filterName) {
|
||||||
|
case 'title':
|
||||||
|
$queryBuilder->andWhere('csl.title LIKE :title')
|
||||||
|
->setParameter('title', '%' . pSQL($filterValue) . '%');
|
||||||
|
break;
|
||||||
|
case 'active':
|
||||||
|
$queryBuilder->andWhere('cs.active = :active')
|
||||||
|
->setParameter('active', (int) $filterValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Module;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Config\Config;
|
||||||
|
use Websmid\CustomerSpecialty\Command\LinkCustomerSpecialtyCommand;
|
||||||
|
use Db;
|
||||||
|
use Configuration;
|
||||||
|
use Tools;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\DataColumn;
|
||||||
|
use PrestaShop\PrestaShop\Core\Grid\Filter\Filter;
|
||||||
|
|
||||||
|
trait AdminHooks
|
||||||
|
{
|
||||||
|
public function isUsingNewTranslationSystem(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
$confirmation = '';
|
||||||
|
|
||||||
|
if (Tools::isSubmit('submitWsCustomerSpecialty')) {
|
||||||
|
Configuration::updateValue(Config::FRONT_ENABLED_CONFIG_KEY, (bool) Tools::getValue('front_enabled'));
|
||||||
|
$confirmation = $this->displayConfirmation($this->trans('Settings saved.', [], 'Admin.Notifications.Success'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$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,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->fetch('module:ws_customerspecialty/views/templates/admin/configuration.tpl');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionCustomerFormBuilderModifier(array $params): void
|
||||||
|
{
|
||||||
|
/** @var FormBuilderInterface $formBuilder */
|
||||||
|
$formBuilder = $params['form_builder'];
|
||||||
|
$idCustomer = (int) $params['id'];
|
||||||
|
|
||||||
|
$formBuilder->add('specialization', ChoiceType::class, [
|
||||||
|
'label' => $this->trans('Specialty', [], 'Modules.Wscustomerspecialty.Admin'),
|
||||||
|
'required' => true,
|
||||||
|
'placeholder' => $this->trans('Please select', [], 'Admin.Global'),
|
||||||
|
'choices' => $this->getCustomerSpecialtyChoiceProvider()->getChoices([
|
||||||
|
'include_inactive' => $idCustomer > 0,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($idCustomer > 0) {
|
||||||
|
$params['data']['specialization'] = $this->loadCustomerSpecialtyId($idCustomer);
|
||||||
|
$formBuilder->setData($params['data']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionAfterCreateCustomerFormHandler(array $params): void
|
||||||
|
{
|
||||||
|
$this->persistBackOfficeCustomerSpecialty($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionAfterUpdateCustomerFormHandler(array $params): void
|
||||||
|
{
|
||||||
|
$this->persistBackOfficeCustomerSpecialty($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionCustomerGridDefinitionModifier(array $params): void
|
||||||
|
{
|
||||||
|
$definition = $params['definition'];
|
||||||
|
|
||||||
|
$definition->getColumns()->addBefore(
|
||||||
|
'social_title',
|
||||||
|
(new DataColumn('specialization'))
|
||||||
|
->setName($this->trans('Specialty', [], 'Modules.Wscustomerspecialty.Admin'))
|
||||||
|
->setOptions([
|
||||||
|
'field' => 'specialization',
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$choices = ['--' => 0] + $this->getCustomerSpecialtyChoiceProvider()->getChoices(['include_inactive' => true]);
|
||||||
|
|
||||||
|
$definition->getFilters()->add(
|
||||||
|
(new Filter('specialization', ChoiceType::class))
|
||||||
|
->setTypeOptions([
|
||||||
|
'choices' => $choices,
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
->setAssociatedColumn('specialization')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionCustomerGridQueryBuilderModifier(array $params): void
|
||||||
|
{
|
||||||
|
$searchQueryBuilder = $params['search_query_builder'];
|
||||||
|
$searchCriteria = $params['search_criteria'];
|
||||||
|
$idLang = (int) $this->context->language->id;
|
||||||
|
|
||||||
|
$searchQueryBuilder->addSelect(
|
||||||
|
'(SELECT csl.title
|
||||||
|
FROM ' . _DB_PREFIX_ . 'ws_customerspecialty_customer cscu
|
||||||
|
INNER JOIN ' . _DB_PREFIX_ . 'ws_customerspecialty_lang csl
|
||||||
|
ON csl.id_ws_customerspecialty = cscu.id_ws_customerspecialty AND csl.id_lang = ' . $idLang . '
|
||||||
|
WHERE cscu.id_customer = c.id_customer
|
||||||
|
) as specialization'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->applyCustomerSpecialtySorting($searchCriteria, $searchQueryBuilder);
|
||||||
|
$this->applyCustomerSpecialtyFilter($searchCriteria, $searchQueryBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookDisplayAdminCustomers(array $params)
|
||||||
|
{
|
||||||
|
$title = $this->loadCustomerSpecialtyTitle((int) $params['id_customer']);
|
||||||
|
|
||||||
|
if (null === $title) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->context->smarty->assign(['specialization' => $title]);
|
||||||
|
|
||||||
|
return $this->fetch('module:ws_customerspecialty/views/templates/hook/display_admin_customers.tpl');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function persistBackOfficeCustomerSpecialty(array $params): void
|
||||||
|
{
|
||||||
|
$idCustomer = (int) $params['id'];
|
||||||
|
$specialization = (int) ($params['form_data']['specialization'] ?? 0);
|
||||||
|
|
||||||
|
if ($idCustomer <= 0 || $specialization <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->get('prestashop.core.command_bus')->handle(
|
||||||
|
new LinkCustomerSpecialtyCommand($idCustomer, $specialization)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyCustomerSpecialtySorting($searchCriteria, $searchQueryBuilder): void
|
||||||
|
{
|
||||||
|
if ('specialization' !== $searchCriteria->getOrderBy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchQueryBuilder->orderBy('specialization', $searchCriteria->getOrderWay());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyCustomerSpecialtyFilter($searchCriteria, $searchQueryBuilder): void
|
||||||
|
{
|
||||||
|
$filters = $searchCriteria->getFilters();
|
||||||
|
|
||||||
|
if (!isset($filters['specialization']) || '' === $filters['specialization']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$idCustomerSpecialty = (int) $filters['specialization'];
|
||||||
|
|
||||||
|
if (0 === $idCustomerSpecialty) {
|
||||||
|
$searchQueryBuilder->andWhere(
|
||||||
|
'NOT EXISTS (SELECT 1 FROM ' . _DB_PREFIX_ . 'ws_customerspecialty_customer cscu WHERE cscu.id_customer = c.id_customer)'
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchQueryBuilder
|
||||||
|
->andWhere(
|
||||||
|
'EXISTS (
|
||||||
|
SELECT 1 FROM ' . _DB_PREFIX_ . 'ws_customerspecialty_customer cscu
|
||||||
|
WHERE cscu.id_customer = c.id_customer AND cscu.id_ws_customerspecialty = :idCustomerSpecialtyFilter
|
||||||
|
)'
|
||||||
|
)
|
||||||
|
->setParameter('idCustomerSpecialtyFilter', $idCustomerSpecialty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadCustomerSpecialtyId(int $idCustomer): int
|
||||||
|
{
|
||||||
|
return (int) Db::getInstance()->getValue(
|
||||||
|
'SELECT `id_ws_customerspecialty` FROM `' . _DB_PREFIX_ . 'ws_customerspecialty_customer`
|
||||||
|
WHERE `id_customer` = ' . $idCustomer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadCustomerSpecialtyTitle(int $idCustomer): ?string
|
||||||
|
{
|
||||||
|
$idLang = (int) $this->context->language->id;
|
||||||
|
|
||||||
|
$title = Db::getInstance()->getValue('
|
||||||
|
SELECT csl.title
|
||||||
|
FROM `' . _DB_PREFIX_ . 'ws_customerspecialty_customer` cscu
|
||||||
|
INNER JOIN `' . _DB_PREFIX_ . 'ws_customerspecialty_lang` csl
|
||||||
|
ON csl.id_ws_customerspecialty = cscu.id_ws_customerspecialty AND csl.id_lang = ' . $idLang . '
|
||||||
|
WHERE cscu.id_customer = ' . $idCustomer . '
|
||||||
|
');
|
||||||
|
|
||||||
|
return false !== $title && null !== $title ? (string) $title : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCustomerSpecialtyChoiceProvider()
|
||||||
|
{
|
||||||
|
return $this->get('websmid.customerspecialty.form.choice_provider.customer_specialty_choice_provider');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Module;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Config\Config;
|
||||||
|
use Websmid\CustomerSpecialty\Command\LinkCustomerSpecialtyCommand;
|
||||||
|
use Configuration;
|
||||||
|
use Tools;
|
||||||
|
use Db;
|
||||||
|
use PrestaShop\PrestaShop\Core\Form\FormField;
|
||||||
|
|
||||||
|
trait DisplayHooks
|
||||||
|
{
|
||||||
|
public function hookAdditionalCustomerFormFields(array $params)
|
||||||
|
{
|
||||||
|
if (!$this->isFrontEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$choices = $this->get('websmid.customerspecialty.form.choice_provider.customer_specialty_choice_provider')->getChoices();
|
||||||
|
|
||||||
|
if (empty($choices)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$specializationField = (new FormField())
|
||||||
|
->setName('specialization')
|
||||||
|
->setType('select')
|
||||||
|
->setLabel($this->trans('Specialty', [], 'Modules.Wscustomerspecialty.Shop'))
|
||||||
|
->setRequired(true)
|
||||||
|
->setAvailableValues($choices);
|
||||||
|
|
||||||
|
if (isset($params['fields'])) {
|
||||||
|
$this->insertFieldAfterEmail($params['fields'], $specializationField);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $specializationField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionObjectCustomerAddAfter(array $params): void
|
||||||
|
{
|
||||||
|
$this->persistFrontOfficeCustomerSpecialty($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionObjectCustomerUpdateAfter(array $params): void
|
||||||
|
{
|
||||||
|
$this->persistFrontOfficeCustomerSpecialty($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookActionGetExtraMailTemplateVars(array $params): void
|
||||||
|
{
|
||||||
|
$specialization = $this->loadOrderCustomerSpecialization((int) $params['template_vars']['{id_order}']);
|
||||||
|
|
||||||
|
if (null === $specialization) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['extra_template_vars']['{specialization}'] = $specialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insertFieldAfterEmail(array &$fields, FormField $field): void
|
||||||
|
{
|
||||||
|
$keys = array_keys($fields);
|
||||||
|
$emailPosition = array_search('email', $keys, true);
|
||||||
|
$insertAt = false === $emailPosition ? count($fields) : $emailPosition + 1;
|
||||||
|
|
||||||
|
$before = array_slice($fields, 0, $insertAt, true);
|
||||||
|
$after = array_slice($fields, $insertAt, null, true);
|
||||||
|
|
||||||
|
$fields = $before + ['specialization' => $field] + $after;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function persistFrontOfficeCustomerSpecialty(array $params): void
|
||||||
|
{
|
||||||
|
if (!$this->isFrontEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer = $params['object'];
|
||||||
|
$idCustomer = (int) $customer->id;
|
||||||
|
$specialization = (int) Tools::getValue('specialization');
|
||||||
|
|
||||||
|
if ($idCustomer <= 0 || $specialization <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->get('prestashop.core.command_bus')->handle(
|
||||||
|
new LinkCustomerSpecialtyCommand($idCustomer, $specialization)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadOrderCustomerSpecialization(int $idOrder): ?string
|
||||||
|
{
|
||||||
|
$idCustomer = (int) Db::getInstance()->getValue(
|
||||||
|
'SELECT `id_customer` FROM `' . _DB_PREFIX_ . 'orders` WHERE `id_order` = ' . $idOrder
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$idCustomer) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$idLang = (int) $this->context->language->id;
|
||||||
|
|
||||||
|
$title = Db::getInstance()->getValue('
|
||||||
|
SELECT csl.title
|
||||||
|
FROM `' . _DB_PREFIX_ . 'ws_customerspecialty_customer` cscu
|
||||||
|
INNER JOIN `' . _DB_PREFIX_ . 'ws_customerspecialty_lang` csl
|
||||||
|
ON csl.id_ws_customerspecialty = cscu.id_ws_customerspecialty AND csl.id_lang = ' . $idLang . '
|
||||||
|
WHERE cscu.id_customer = ' . $idCustomer . '
|
||||||
|
');
|
||||||
|
|
||||||
|
return false !== $title && null !== $title ? (string) $title : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isFrontEnabled(): bool
|
||||||
|
{
|
||||||
|
return (bool) Configuration::get(Config::FRONT_ENABLED_CONFIG_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\CustomerSpecialty\Module;
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Config\Config;
|
||||||
|
use Db;
|
||||||
|
use Language;
|
||||||
|
use Tab;
|
||||||
|
use Configuration;
|
||||||
|
|
||||||
|
trait Install
|
||||||
|
{
|
||||||
|
public function install()
|
||||||
|
{
|
||||||
|
if (!parent::install()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->createTables()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->registerTabs(Config::TABS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->registerHooks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration::updateValue(Config::FRONT_ENABLED_CONFIG_KEY, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTables(): bool
|
||||||
|
{
|
||||||
|
$sqlToExec = [
|
||||||
|
'
|
||||||
|
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'ws_customerspecialty` (
|
||||||
|
`id_ws_customerspecialty` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`position` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||||
|
`active` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
|
||||||
|
`date_add` DATETIME NOT NULL,
|
||||||
|
`date_upd` DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (`id_ws_customerspecialty`)
|
||||||
|
);
|
||||||
|
',
|
||||||
|
'
|
||||||
|
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'ws_customerspecialty_lang` (
|
||||||
|
`id_ws_customerspecialty_lang` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`id_ws_customerspecialty` INT(11) NOT NULL,
|
||||||
|
`id_lang` INT(11) NOT NULL,
|
||||||
|
`title` VARCHAR(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`id_ws_customerspecialty_lang`),
|
||||||
|
UNIQUE KEY `ws_customerspecialty_lang_unique` (`id_ws_customerspecialty`, `id_lang`)
|
||||||
|
);
|
||||||
|
',
|
||||||
|
'
|
||||||
|
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'ws_customerspecialty_customer` (
|
||||||
|
`id_ws_customerspecialty_customer` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`id_customer` INT(11) NOT NULL,
|
||||||
|
`id_ws_customerspecialty` INT(11) NOT NULL,
|
||||||
|
`date_add` DATETIME NOT NULL,
|
||||||
|
`date_upd` DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (`id_ws_customerspecialty_customer`),
|
||||||
|
UNIQUE KEY `ws_customerspecialty_customer_unique` (`id_customer`),
|
||||||
|
KEY `id_ws_customerspecialty` (`id_ws_customerspecialty`)
|
||||||
|
);
|
||||||
|
',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($sqlToExec as $sql) {
|
||||||
|
if (!Db::getInstance()->execute($sql)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerHooks(): bool
|
||||||
|
{
|
||||||
|
foreach (Config::HOOKS as $hook) {
|
||||||
|
if (!$this->registerHook($hook)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerTabs(array $moduleTabs): bool
|
||||||
|
{
|
||||||
|
$languages = Language::getLanguages(false);
|
||||||
|
|
||||||
|
foreach ($moduleTabs as $moduleTab) {
|
||||||
|
if (Tab::getIdFromClassName($moduleTab['class_name'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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']);
|
||||||
|
|
||||||
|
foreach ($languages as $language) {
|
||||||
|
$tab->name[(int) $language['id_lang']] = $moduleTab['name'][$language['iso_code']]
|
||||||
|
?? $moduleTab['name']['en'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tab->add();
|
||||||
|
|
||||||
|
if (!$tab->id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{if $confirmation}
|
||||||
|
{$confirmation nofilter}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="icon-user"></i>
|
||||||
|
{l s='Front office display' d='Modules.Wscustomerspecialty.Admin'}
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="help-block">
|
||||||
|
{l s='When enabled, a required "Specialty" field is added to the registration and account edit forms on the storefront. Back-office management of specialty values and customer records is unaffected by this setting.' d='Modules.Wscustomerspecialty.Admin'}
|
||||||
|
</p>
|
||||||
|
<form method="post" action="{$form_action|escape:'htmlall':'UTF-8'}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">
|
||||||
|
<input type="checkbox" name="front_enabled" value="1" {if $front_enabled}checked="checked"{/if}>
|
||||||
|
{l s='Show the specialty field on the storefront' d='Modules.Wscustomerspecialty.Admin'}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<button type="submit" name="submitWsCustomerSpecialty" class="btn btn-default pull-right">
|
||||||
|
<i class="process-icon-save"></i>
|
||||||
|
{l s='Save' d='Modules.Wscustomerspecialty.Admin'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{% import '@PrestaShop/Admin/macros.html.twig' as ps %}
|
||||||
|
{% form_theme customerSpecialtyForm '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit.html.twig' %}
|
||||||
|
|
||||||
|
{% block customerspecialty_form_block %}
|
||||||
|
<div class="card">
|
||||||
|
{{ form_start(customerSpecialtyForm) }}
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-header-title">{{ 'Customer specialty'|trans({}, 'Modules.Wscustomerspecialty.Admin') }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{ form_rest(customerSpecialtyForm) }}
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="{{ path('customerspecialty_index') }}" class="btn btn-outline-secondary">
|
||||||
|
{{ 'Cancel'|trans({}, 'Admin.Actions') }}
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-primary float-right">
|
||||||
|
{{ 'Save'|trans({}, 'Admin.Actions') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{ form_end(customerSpecialtyForm) }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends '@PrestaShop/Admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% block customerspecialty_form %}
|
||||||
|
{% include '@Modules/ws_customerspecialty/views/templates/admin/form/blocks/form.html.twig' %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ parent() }}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
window.prestashop.component.initComponents([
|
||||||
|
'TranslatableField',
|
||||||
|
'TranslatableInput',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{% extends '@PrestaShop/Admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include '@PrestaShop/Admin/Common/Grid/grid_panel.html.twig' with {'grid': customerSpecialtyGrid} %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ parent() }}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
new window.prestashop.component.Grid('customerspecialty');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{if $specialization}
|
||||||
|
<div class="panel" id="ws-customerspecialty-panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="icon-user-md"></i>
|
||||||
|
{l s='Specialty' d='Modules.Wscustomerspecialty.Admin'}
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="ws-customerspecialty-title">{$specialization|escape:'htmlall':'UTF-8'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 2007-2026 De Websmid BV
|
||||||
|
*
|
||||||
|
* NOTICE OF LICENSE
|
||||||
|
*
|
||||||
|
* This file is not open source! Each license that you purchased is only available for 1 website only.
|
||||||
|
* If you want to use this file on more websites (or projects), you need to purchase additional licenses.
|
||||||
|
* You are not allowed to redistribute, resell, lease, license, sub-license or offer our resources to any third party.
|
||||||
|
*
|
||||||
|
* DISCLAIMER
|
||||||
|
*
|
||||||
|
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||||
|
* versions in the future. If you wish to customize PrestaShop for your
|
||||||
|
* needs please contact us for extra customization service at an affordable price
|
||||||
|
*
|
||||||
|
* @author Isabelle Oving-Anno | De Websmid <isabelle@dewebsmid.nl>
|
||||||
|
* @copyright 2007-2026 De Websmid BV
|
||||||
|
* @license Valid for 1 website (or project) for each purchase of license
|
||||||
|
* International Registered Trademark & Property of De Websmid BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Websmid\CustomerSpecialty\Module\Install;
|
||||||
|
use Websmid\CustomerSpecialty\Module\AdminHooks;
|
||||||
|
use Websmid\CustomerSpecialty\Module\DisplayHooks;
|
||||||
|
|
||||||
|
if (!defined('_PS_VERSION_')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ws_CustomerSpecialty extends Module
|
||||||
|
{
|
||||||
|
use Install;
|
||||||
|
use AdminHooks;
|
||||||
|
use DisplayHooks;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'ws_customerspecialty';
|
||||||
|
$this->version = '1.0.0';
|
||||||
|
$this->author = 'Isabelle Oving-Anno | De Websmid BV';
|
||||||
|
$this->need_instance = 0;
|
||||||
|
$this->bootstrap = true;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->displayName = $this->trans('Customer Specialty', [], 'Modules.Wscustomerspecialty.Admin');
|
||||||
|
$this->description = $this->trans('Adds a manageable specialty/profession field to customer accounts, shown in the back office and exposed to order confirmation emails.', [], 'Modules.Wscustomerspecialty.Admin');
|
||||||
|
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user