├── .codeclimate.yml ├── .eslintignore ├── .eslintrc ├── .travis.yml ├── Api └── Data │ ├── RetailerAddressInterface.php │ └── RetailerTimeSlotInterface.php ├── Block ├── AbstractView.php ├── Adminhtml │ └── Retailer │ │ ├── OpeningHours.php │ │ ├── OpeningHours │ │ ├── Container │ │ │ └── Renderer.php │ │ └── Element │ │ │ └── Renderer.php │ │ ├── SpecialOpeningHours.php │ │ └── SpecialOpeningHours │ │ └── Container │ │ └── Renderer.php ├── ContactForm.php ├── Search.php ├── StoreChooser.php ├── View.php └── View │ ├── ContactInformation.php │ ├── Map.php │ ├── OpeningHours.php │ └── SetStoreLink.php ├── Controller ├── Adminhtml │ └── Retailer │ │ ├── MassEditHours.php │ │ └── MassSaveHours.php ├── Index │ └── Index.php ├── Router.php └── Store │ ├── Contact.php │ ├── ContactPost.php │ ├── Search.php │ ├── Set.php │ └── View.php ├── CustomerData └── CurrentStore.php ├── Helper ├── Contact.php ├── Data.php └── Schedule.php ├── ISSUE_TEMPLATE.md ├── Model ├── Data │ ├── RetailerAddress.php │ ├── RetailerAddressConverter.php │ ├── RetailerTimeSlot.php │ └── RetailerTimeSlotConverter.php ├── ResourceModel │ ├── RetailerAddress.php │ ├── RetailerTimeSlot.php │ └── Url.php ├── Retailer │ ├── AddressPostDataHandler.php │ ├── AddressReadHandler.php │ ├── AddressSaveHandler.php │ ├── Attribute │ │ └── Backend │ │ │ └── UrlKey.php │ ├── ContactForm.php │ ├── OpeningHoursPostDataHandler.php │ ├── OpeningHoursReadHandler.php │ ├── OpeningHoursSaveHandler.php │ ├── ScheduleManagement.php │ ├── SpecialOpeningHoursPostDataHandler.php │ ├── SpecialOpeningHoursReadHandler.php │ └── SpecialOpeningHoursSaveHandler.php ├── RetailerAddress.php ├── RetailerAddress │ └── Source │ │ └── Country.php └── Url.php ├── Observer └── CleanStoreLocatorCache.php ├── Plugin ├── RetailerCollectionPlugin.php ├── RetailerEditFormPlugin.php └── RetailerUiComponentFormPlugin.php ├── README.md ├── Setup ├── InstallData.php ├── InstallSchema.php ├── StoreLocatorSetup.php ├── UpgradeData.php └── UpgradeSchema.php ├── Ui └── Component │ └── Retailer │ └── Form │ └── DataProvider.php ├── composer.json ├── etc ├── adminhtml │ ├── events.xml │ ├── routes.xml │ └── system.xml ├── config.xml ├── di.xml ├── extension_attributes.xml ├── frontend │ ├── di.xml │ ├── routes.xml │ └── sections.xml └── module.xml ├── i18n ├── en_US.csv └── fr_FR.csv ├── registration.php └── view ├── adminhtml ├── layout │ └── smile_store_locator_retailer_massedithours.xml ├── requirejs-config.js ├── templates │ └── retailer │ │ └── openinghours │ │ ├── container.phtml │ │ └── element.phtml ├── ui_component │ ├── smile_retailer_form.xml │ ├── smile_retailer_listing.xml │ └── storelocator_retailer_mass_edit_hours_form.xml └── web │ ├── css │ └── source │ │ ├── _module.less │ │ └── elessar │ │ └── elessar.less │ └── js │ ├── component │ └── retailer │ │ └── opening-hours.js │ ├── elessar │ ├── elessar.js │ └── estira.js │ └── opening-hours │ └── rangebar.js └── frontend ├── layout ├── default.xml ├── smile_store_locator_store_contact.xml ├── smile_store_locator_store_search.xml └── smile_store_locator_store_view.xml ├── requirejs-config.js ├── templates ├── chooser.phtml ├── contact-form.phtml ├── search.phtml ├── view.phtml └── view │ ├── contact-information.phtml │ ├── map.phtml │ ├── opening-hours.phtml │ └── setStoreLink.phtml └── web ├── css └── source │ ├── _module.less │ ├── nearby-markers │ └── _nearby-markers.less │ └── store-view │ └── _store-view.less ├── images ├── direction-1.svg ├── direction-details.svg └── location-search.svg ├── js ├── map-mixin.js ├── model │ ├── store.js │ ├── store │ │ └── schedule.js │ └── stores.js └── retailer │ ├── chooser.js │ └── store-map.js └── template └── retailer ├── opening-hours.html ├── search.html ├── search ├── store-detail.html └── store-list.html ├── special-opening-hours.html └── store-view ├── nearby-store.html ├── open-hours-view.html ├── view-baners-wrap.html ├── view-closest-store-wrapper.html └── view-store-details.html /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - javascript 8 | - php 9 | eslint: 10 | enabled: true 11 | fixme: 12 | enabled: true 13 | phan: 14 | enabled: true 15 | config: 16 | file_extensions: php 17 | ignore-undeclared: true 18 | ratings: 19 | paths: 20 | - "**.js" 21 | - "**.php" 22 | exclude_paths: 23 | - src/*/Test 24 | - vendor/* 25 | - Resources/* 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '5.6' 5 | - '7.0' 6 | 7 | install: [ 8 | "mkdir -p app/etc var", 9 | "echo \"{\\\"http-basic\\\":{\\\"repo.magento.com\\\":{\\\"username\\\":\\\"${MAGENTO_USERNAME}\\\",\\\"password\\\":\\\"${MAGENTO_PASSWORD}\\\"}}}\" > auth.json", 10 | "composer install --prefer-dist" 11 | ] 12 | 13 | cache: 14 | directories: 15 | - $HOME/.composer/cache 16 | 17 | script: 18 | - vendor/bin/phpcs --ignore=/vendor/,/app/ --standard=vendor/smile/magento2-smilelab-phpcs/phpcs-standards/SmileLab --extensions=php ./ 19 | - vendor/bin/phpmd ./ text vendor/smile/magento2-smilelab-phpmd/phpmd-rulesets/rulset.xml --exclude vendor 20 | -------------------------------------------------------------------------------- /Api/Data/RetailerAddressInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Api\Data; 14 | 15 | /** 16 | * Retailer Store Locator interface 17 | * 18 | * @category Smile 19 | * @package Smile\StoreLocator 20 | * @author Aurelien FOUCRET 21 | */ 22 | interface RetailerAddressInterface extends \Smile\Map\Api\Data\GeolocalizedAddressInterface 23 | { 24 | /**#@+ 25 | * Constants for keys of data array. Identical to the name of the getter in snake case 26 | */ 27 | const ADDRESS_ID = 'address_id'; 28 | const RETAILER_ID = 'retailer_id'; 29 | /**#@-*/ 30 | 31 | /** 32 | * @return int 33 | */ 34 | public function getId(); 35 | 36 | /** 37 | * @return int 38 | */ 39 | public function getRetailerId(); 40 | 41 | /** 42 | * Set id. 43 | * 44 | * @SuppressWarnings(PHPMD.ShortVariable) 45 | * 46 | * @param int $id Address id. 47 | * 48 | * @return $this 49 | */ 50 | public function setId($id); 51 | 52 | /** 53 | * Set retailer id. 54 | * 55 | * @param int $retailerId Retailer id. 56 | * 57 | * @return $this 58 | */ 59 | public function setRetailerId($retailerId); 60 | } 61 | -------------------------------------------------------------------------------- /Api/Data/RetailerTimeSlotInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Api\Data; 14 | 15 | /** 16 | * Generic Interface for retailer time slots items 17 | * 18 | * @category Smile 19 | * @package Smile\StoreLocator 20 | * @author Romain Ruaud 21 | */ 22 | interface RetailerTimeSlotInterface 23 | { 24 | /** 25 | * The date field 26 | */ 27 | const DATE_FIELD = 'date'; 28 | 29 | /** 30 | * The day of week field 31 | */ 32 | const DAY_OF_WEEK_FIELD = 'day_of_week'; 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getStartTime(); 38 | 39 | /** 40 | * @return string 41 | */ 42 | public function getEndTime(); 43 | 44 | /** 45 | * Set the start time 46 | * 47 | * @param string $time The time 48 | * 49 | * @return mixed 50 | */ 51 | public function setStartTime($time); 52 | 53 | /** 54 | * Set the end time 55 | * 56 | * @param string $time The time 57 | * 58 | * @return mixed 59 | */ 60 | public function setEndTime($time); 61 | } 62 | -------------------------------------------------------------------------------- /Block/AbstractView.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Guillaume Vrac 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Block; 15 | 16 | use Magento\Framework\View\Element\Template; 17 | 18 | /** 19 | * Retailer View Block 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | * @author Guillaume Vrac 25 | */ 26 | class AbstractView extends Template 27 | { 28 | /** 29 | * Constructor. 30 | * 31 | * @param \Magento\Framework\View\Element\Template\Context $context Application context 32 | * @param \Magento\Framework\Registry $coreRegistry Application Registry 33 | * @param array $data Block Data 34 | */ 35 | public function __construct( 36 | \Magento\Framework\View\Element\Template\Context $context, 37 | \Magento\Framework\Registry $coreRegistry, 38 | array $data = [] 39 | ) { 40 | parent::__construct($context, $data); 41 | $this->coreRegistry = $coreRegistry; 42 | } 43 | 44 | /** 45 | * Get the current shop. 46 | * 47 | * @return \Smile\Retailer\Api\Data\RetailerInterface 48 | */ 49 | public function getRetailer() 50 | { 51 | return $this->coreRegistry->registry('current_retailer'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Block/Adminhtml/Retailer/OpeningHours.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Block\Adminhtml\Retailer; 14 | 15 | use Magento\Framework\Stdlib\DateTime; 16 | use Smile\Retailer\Api\Data\RetailerInterface; 17 | 18 | /** 19 | * Opening Hours rendering block 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class OpeningHours extends \Magento\Backend\Block\AbstractBlock 26 | { 27 | /** 28 | * @var \Magento\Framework\Data\FormFactory 29 | */ 30 | private $formFactory; 31 | 32 | /** 33 | * @var \Magento\Framework\Registry 34 | */ 35 | private $registry; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param \Magento\Backend\Block\Context $context Block context. 41 | * @param \Magento\Framework\Data\FormFactory $formFactory Form factory. 42 | * @param \Magento\Framework\Registry $registry Registry. 43 | * @param array $data Additional data. 44 | */ 45 | public function __construct( 46 | \Magento\Backend\Block\Context $context, 47 | \Magento\Framework\Data\FormFactory $formFactory, 48 | \Magento\Framework\Registry $registry, 49 | array $data = [] 50 | ) { 51 | $this->formFactory = $formFactory; 52 | $this->registry = $registry; 53 | parent::__construct($context, $data); 54 | } 55 | 56 | /** 57 | * @SuppressWarnings(PHPMD.CamelCaseMethodName) 58 | * {@inheritDoc} 59 | */ 60 | protected function _toHtml() 61 | { 62 | return $this->escapeJsQuote($this->getForm()->toHtml()); 63 | } 64 | 65 | /** 66 | * Get retailer 67 | * 68 | * @return RetailerInterface 69 | */ 70 | private function getRetailer() 71 | { 72 | return $this->registry->registry('current_seller'); 73 | } 74 | 75 | /** 76 | * Create the form containing the virtual rule field. 77 | * 78 | * @return \Magento\Framework\Data\Form 79 | */ 80 | private function getForm() 81 | { 82 | $form = $this->formFactory->create(); 83 | $form->setHtmlId('opening_hours'); 84 | 85 | $openingHoursFieldset = $form->addFieldset( 86 | 'opening_hours', 87 | ['name' => 'opening_hours', 'label' => __('Opening Hours'), 'container_id' => 'opening_hours'] 88 | ); 89 | 90 | if ($this->getRetailer() && $this->getRetailer()->getOpeningHours()) { 91 | $openingHoursFieldset->setOpeningHours($this->getRetailer()->getOpeningHours()); 92 | } 93 | 94 | $openingHoursRenderer = $this->getLayout()->createBlock('Smile\StoreLocator\Block\Adminhtml\Retailer\OpeningHours\Container\Renderer'); 95 | $openingHoursFieldset->setRenderer($openingHoursRenderer); 96 | 97 | return $form; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Block/Adminhtml/Retailer/OpeningHours/Container/Renderer.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Block\Adminhtml\Retailer\OpeningHours\Container; 14 | 15 | use Magento\Backend\Block\Template; 16 | use Magento\Framework\Data\Form\Element\AbstractElement; 17 | use Magento\Framework\Data\Form\Element\Renderer\RendererInterface; 18 | use Magento\Framework\Stdlib\DateTime; 19 | 20 | /** 21 | * Opening Hours field renderer 22 | * 23 | * @SuppressWarnings(PHPMD.CamelCasePropertyName) 24 | * 25 | * @category Smile 26 | * @package Smile\Retailer 27 | * @author Romain Ruaud 28 | */ 29 | class Renderer extends Template implements RendererInterface 30 | { 31 | /** 32 | * @var \Magento\Framework\Data\Form\Element\Factory 33 | */ 34 | protected $elementFactory; 35 | 36 | /** 37 | * @var AbstractElement 38 | */ 39 | protected $element; 40 | 41 | /** 42 | * @var \Magento\Framework\Data\Form\Element\Text 43 | */ 44 | protected $input; 45 | 46 | /** 47 | * @var string 48 | */ 49 | protected $_template = 'retailer/openinghours/container.phtml'; 50 | 51 | /** 52 | * @var \Magento\Framework\Locale\ListsInterface|null 53 | */ 54 | private $localeList = null; 55 | 56 | /** 57 | * Block constructor. 58 | * 59 | * @param \Magento\Backend\Block\Template\Context $context Templating context. 60 | * @param \Magento\Framework\Data\Form\Element\Factory $elementFactory Form element factory. 61 | * @param \Magento\Framework\Locale\ListsInterface $localeLists Locale List. 62 | * @param array $data Additional data. 63 | */ 64 | public function __construct( 65 | \Magento\Backend\Block\Template\Context $context, 66 | \Magento\Framework\Data\Form\Element\Factory $elementFactory, 67 | \Magento\Framework\Locale\ListsInterface $localeLists, 68 | array $data = [] 69 | ) { 70 | $this->elementFactory = $elementFactory; 71 | $this->localeList = $localeLists; 72 | 73 | parent::__construct($context, $data); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function render(AbstractElement $element) 80 | { 81 | $this->element = $element; 82 | $this->element->addClass("opening-hours-container-fieldset"); 83 | 84 | return $this->toHtml(); 85 | } 86 | 87 | /** 88 | * Get currently edited element. 89 | * 90 | * @return AbstractElement 91 | */ 92 | public function getElement() 93 | { 94 | return $this->element; 95 | } 96 | 97 | /** 98 | * Retrieve element unique container id. 99 | * 100 | * @return string 101 | */ 102 | public function getHtmlId() 103 | { 104 | return $this->getElement()->getContainer()->getHtmlId(); 105 | } 106 | 107 | /** 108 | * Render HTML of the element using the opening hours engine. 109 | * 110 | * @return string 111 | */ 112 | public function getInputHtml() 113 | { 114 | if ($this->element->getOpeningHours()) { 115 | $values = $this->element->getOpeningHours(); 116 | } 117 | 118 | $html = ""; 119 | $days = $this->localeList->getOptionWeekdays(true, true); 120 | 121 | foreach ($days as $key => $day) { 122 | $input = $this->elementFactory->create('text'); 123 | $input->setForm($this->getElement()->getForm()); 124 | 125 | $elementRenderer = $this->getLayout() 126 | ->createBlock('Smile\StoreLocator\Block\Adminhtml\Retailer\OpeningHours\Element\Renderer'); 127 | 128 | $elementRenderer->setDateFormat(DateTime::DATETIME_INTERNAL_FORMAT); 129 | 130 | $input->setLabel(ucfirst($day['label'])); 131 | $input->setName($this->element->getName() . "[$key]"); 132 | $input->setRenderer($elementRenderer); 133 | 134 | if (isset($values[$key])) { 135 | $input->setValue($values[$key]); 136 | } 137 | 138 | $html .= $input->toHtml(); 139 | } 140 | 141 | return $html; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Block/Adminhtml/Retailer/SpecialOpeningHours.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Block\Adminhtml\Retailer; 14 | 15 | use Magento\Framework\Stdlib\DateTime; 16 | use Smile\Retailer\Api\Data\RetailerInterface; 17 | 18 | /** 19 | * Special Opening Hours rendering block 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class SpecialOpeningHours extends \Magento\Backend\Block\AbstractBlock 26 | { 27 | /** 28 | * @var \Magento\Framework\Data\FormFactory 29 | */ 30 | private $formFactory; 31 | 32 | /** 33 | * @var \Magento\Framework\Registry 34 | */ 35 | private $registry; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param \Magento\Backend\Block\Context $context Block context. 41 | * @param \Magento\Framework\Data\FormFactory $formFactory Form factory. 42 | * @param \Magento\Framework\Registry $registry Registry. 43 | * @param array $data Additional data. 44 | */ 45 | public function __construct( 46 | \Magento\Backend\Block\Context $context, 47 | \Magento\Framework\Data\FormFactory $formFactory, 48 | \Magento\Framework\Registry $registry, 49 | array $data = [] 50 | ) { 51 | $this->formFactory = $formFactory; 52 | $this->registry = $registry; 53 | parent::__construct($context, $data); 54 | } 55 | 56 | /** 57 | * @SuppressWarnings(PHPMD.CamelCaseMethodName) 58 | * {@inheritDoc} 59 | */ 60 | protected function _toHtml() 61 | { 62 | return $this->getForm()->toHtml(); 63 | } 64 | 65 | /** 66 | * Get retailer 67 | * 68 | * @return RetailerInterface 69 | */ 70 | private function getRetailer() 71 | { 72 | return $this->registry->registry('current_seller'); 73 | } 74 | 75 | /** 76 | * Create the form containing the virtual rule field. 77 | * 78 | * @return \Magento\Framework\Data\Form 79 | */ 80 | private function getForm() 81 | { 82 | $form = $this->formFactory->create(); 83 | $form->setHtmlId('special_opening_hours'); 84 | 85 | $openingHoursFieldset = $form->addFieldset( 86 | 'special_opening_hours', 87 | ['name' => 'special_opening_hours', 'label' => __('Special Opening Hours'), 'container_id' => 'special_opening_hours'] 88 | ); 89 | 90 | if ($this->getRetailer() && $this->getRetailer()->getSpecialOpeningHours()) { 91 | $openingHoursFieldset->setSpecialOpeningHours($this->getRetailer()->getSpecialOpeningHours()); 92 | } 93 | 94 | $openingHoursRenderer = $this->getLayout()->createBlock('Smile\StoreLocator\Block\Adminhtml\Retailer\SpecialOpeningHours\Container\Renderer'); 95 | $openingHoursFieldset->setRenderer($openingHoursRenderer->setForm($form)); 96 | 97 | return $form; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Block/StoreChooser.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | 14 | namespace Smile\StoreLocator\Block; 15 | 16 | use Magento\Framework\View\Element\Template; 17 | 18 | /** 19 | * Store chooser block. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class StoreChooser extends Template 26 | { 27 | /** 28 | * @var \Smile\StoreLocator\Helper\Data 29 | */ 30 | private $storeLocatorHelper; 31 | 32 | /** 33 | * @var \Smile\Map\Api\MapInterface 34 | */ 35 | private $map; 36 | 37 | /** 38 | * Constructor. 39 | * 40 | * @param \Magento\Framework\View\Element\Template\Context $context Template context. 41 | * @param \Smile\StoreLocator\Helper\Data $storeLocatorHelper Store locator helper. 42 | * @param \Smile\Map\Api\MapProviderInterface $mapProvider Map Provider. 43 | * @param array $data Additional data. 44 | */ 45 | public function __construct( 46 | \Magento\Framework\View\Element\Template\Context $context, 47 | \Smile\StoreLocator\Helper\Data $storeLocatorHelper, 48 | \Smile\Map\Api\MapProviderInterface $mapProvider, 49 | array $data = [] 50 | ) { 51 | parent::__construct($context, $data); 52 | $this->storeLocatorHelper = $storeLocatorHelper; 53 | $this->map = $mapProvider->getMap(); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public function getJsLayout() 60 | { 61 | $jsLayout = $this->jsLayout; 62 | 63 | $jsLayout['components']['top-storelocator-chooser']['storeLocatorHomeUrl'] = $this->getStoreLocatorHomeUrl(); 64 | $jsLayout['components']['top-storelocator-chooser']['children']['geocoder']['provider'] = $this->map->getIdentifier(); 65 | 66 | $jsLayout['components']['top-storelocator-chooser']['children']['geocoder'] = array_merge( 67 | $jsLayout['components']['top-storelocator-chooser']['children']['geocoder'], 68 | $this->map->getConfig() 69 | ); 70 | 71 | return json_encode($jsLayout); 72 | } 73 | 74 | /** 75 | * Get store locator home URL. 76 | * 77 | * @return string 78 | */ 79 | public function getStoreLocatorHomeUrl() 80 | { 81 | return $this->storeLocatorHelper->getHomeUrl(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Block/View/ContactInformation.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Block\View; 14 | 15 | use Magento\Framework\Registry; 16 | use Magento\Framework\View\Element\Template\Context; 17 | use Smile\StoreLocator\Helper\Contact; 18 | 19 | /** 20 | * Contact Information block for StoreLocator page 21 | * 22 | * @category Smile 23 | * @package Smile\StoreLocator 24 | * @author Romain Ruaud 25 | */ 26 | class ContactInformation extends \Smile\StoreLocator\Block\AbstractView 27 | { 28 | /** 29 | * @var \Smile\StoreLocator\Helper\Contact 30 | */ 31 | private $contactHelper; 32 | 33 | /** 34 | * ContactInformation constructor. 35 | * 36 | * @param \Magento\Framework\View\Element\Template\Context $context Application Context 37 | * @param \Magento\Framework\Registry $coreRegistry Core Registry 38 | * @param \Smile\StoreLocator\Helper\Contact $contactHelper Contact Helper 39 | * @param array $data Block data 40 | */ 41 | public function __construct(Context $context, Registry $coreRegistry, Contact $contactHelper, array $data) 42 | { 43 | $this->contactHelper = $contactHelper; 44 | parent::__construct($context, $coreRegistry, $data); 45 | } 46 | 47 | /** 48 | * Check if current retailer has contact information. 49 | * 50 | * @return bool 51 | */ 52 | public function hasContactInformation() 53 | { 54 | return $this->contactHelper->hasContactInformation($this->getRetailer()); 55 | } 56 | 57 | /** 58 | * Check if we can display contact form for current retailer. 59 | * 60 | * @return bool 61 | */ 62 | public function showContactForm() 63 | { 64 | return $this->contactHelper->canDisplayContactForm($this->getRetailer()); 65 | } 66 | 67 | /** 68 | * Retrieve Contact form Url for current retailer 69 | * 70 | * @return string 71 | */ 72 | public function getContactFormUrl() 73 | { 74 | return $this->contactHelper->getContactFormUrl($this->getRetailer()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Block/View/SetStoreLink.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Block\View; 14 | 15 | use Smile\StoreLocator\Block\AbstractView; 16 | 17 | /** 18 | * Set store link block. 19 | * 20 | * @category Smile 21 | * @package Smile\StoreLocator 22 | * @author Aurelien FOUCRET 23 | */ 24 | class SetStoreLink extends AbstractView 25 | { 26 | /** 27 | * Get the JSON post data used to build the set store link. 28 | * 29 | * @return string 30 | */ 31 | public function getSetStorePostJson() 32 | { 33 | $setUrl = $this->_urlBuilder->getUrl('storelocator/store/set', ['_secure' => true]); 34 | $postData = ['id' => $this->getRetailer()->getId()]; 35 | 36 | return json_encode(['action' => $setUrl, 'data' => $postData]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Retailer/MassEditHours.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2019 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | 15 | namespace Smile\StoreLocator\Controller\Adminhtml\Retailer; 16 | 17 | use Magento\Framework\Controller\ResultFactory; 18 | use Magento\Backend\App\Action\Context; 19 | use Smile\Retailer\Controller\Adminhtml\AbstractRetailer; 20 | 21 | /** 22 | * Retailer Adminhtml MassEditHours controller. 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Fanny DECLERCK 27 | */ 28 | class MassEditHours extends AbstractRetailer 29 | { 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public function execute() 34 | { 35 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ 36 | $resultPage = $this->resultPageFactory->create(); 37 | 38 | $retailerIds = $this->getRequest()->getParam('selected', false); 39 | $this->coreRegistry->register('retailer_ids', $retailerIds); 40 | 41 | $resultPage->getConfig()->getTitle()->prepend(__('Edit retailers informations')); 42 | $resultPage->addBreadcrumb(__('Retailer'), __('Retailer')); 43 | 44 | return $resultPage; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Controller/Index/Index.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Guillaume Vrac 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Controller\Index; 15 | 16 | use Magento\Framework\App\Action\Context; 17 | use Magento\Framework\App\Action\Action; 18 | use Smile\StoreLocator\Helper\Data as StoreLocatorHelper; 19 | 20 | /** 21 | * Index action (redirect to the search/index action). 22 | * 23 | * @category Smile 24 | * @package Smile\StoreLocator 25 | * @author Romain Ruaud 26 | * @author Guillaume Vrac 27 | */ 28 | class Index extends Action 29 | { 30 | /** 31 | * @var StoreLocatorHelper 32 | */ 33 | private $storeLocatorHelper; 34 | 35 | /** 36 | * Constructor. 37 | * 38 | * @param Context $context Controller context. 39 | * @param StoreLocatorHelper $storeLocatorHelper Store locator helper. 40 | */ 41 | public function __construct(Context $context, StoreLocatorHelper $storeLocatorHelper) 42 | { 43 | parent::__construct($context); 44 | $this->storeLocatorHelper = $storeLocatorHelper; 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function execute() 51 | { 52 | $resultRedirect = $this->resultRedirectFactory->create(); 53 | $redirectUrl = $this->storeLocatorHelper->getHomeUrl(); 54 | $resultRedirect->setPath($redirectUrl); 55 | 56 | return $resultRedirect; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Controller/Router.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Controller; 14 | 15 | /** 16 | * Store locator routing (handling rewritten URL). 17 | * 18 | * @category Smile 19 | * @package Smile\StoreLocator 20 | * @author Aurelien FOUCRET 21 | */ 22 | class Router implements \Magento\Framework\App\RouterInterface 23 | { 24 | /** 25 | * @var \Magento\Framework\App\ActionFactory 26 | */ 27 | private $actionFactory; 28 | 29 | /** 30 | * @var \Magento\Framework\Event\ManagerInterface 31 | */ 32 | private $eventManager; 33 | 34 | /** 35 | * @var \Smile\StoreLocator\Model\Url 36 | */ 37 | private $urlModel; 38 | 39 | /** 40 | * Constructor. 41 | * 42 | * @param \Magento\Framework\App\ActionFactory $actionFactory Action factory. 43 | * @param \Magento\Framework\Event\ManagerInterface $eventManager Event manager. 44 | * @param \Smile\StoreLocator\Model\Url $urlModel Retailer URL model. 45 | */ 46 | public function __construct( 47 | \Magento\Framework\App\ActionFactory $actionFactory, 48 | \Magento\Framework\Event\ManagerInterface $eventManager, 49 | \Smile\StoreLocator\Model\Url $urlModel 50 | ) { 51 | $this->actionFactory = $actionFactory; 52 | $this->eventManager = $eventManager; 53 | $this->urlModel = $urlModel; 54 | } 55 | 56 | /** 57 | * Validate and Match Cms Page and modify request 58 | * 59 | * @param \Magento\Framework\App\RequestInterface $request Request. 60 | * 61 | * @return NULL|\Magento\Framework\App\ActionInterface 62 | */ 63 | public function match(\Magento\Framework\App\RequestInterface $request) 64 | { 65 | $action = null; 66 | 67 | $requestPath = trim($request->getPathInfo(), '/'); 68 | $condition = new \Magento\Framework\DataObject(['identifier' => $requestPath]); 69 | 70 | if ($this->matchStoreLocatorHome($requestPath)) { 71 | $this->eventManager->dispatch( 72 | 'store_locator_search_controller_router_match_before', 73 | ['router' => $this, 'condition' => $condition] 74 | ); 75 | 76 | $request->setAlias(\Magento\Framework\Url::REWRITE_REQUEST_PATH_ALIAS, $requestPath) 77 | ->setModuleName('storelocator') 78 | ->setControllerName('store') 79 | ->setActionName('search'); 80 | 81 | $action = $this->actionFactory->create('Magento\Framework\App\Action\Forward', ['request' => $request]); 82 | } elseif ($retailerId = $this->matchRetailer($requestPath)) { 83 | $this->eventManager->dispatch( 84 | 'store_locator_view_controller_router_match_before', 85 | ['router' => $this, 'condition' => $condition] 86 | ); 87 | 88 | $request->setAlias(\Magento\Framework\Url::REWRITE_REQUEST_PATH_ALIAS, $requestPath) 89 | ->setModuleName('storelocator') 90 | ->setControllerName('store') 91 | ->setActionName('view') 92 | ->setParam('id', $retailerId); 93 | 94 | $action = $this->actionFactory->create('Magento\Framework\App\Action\Forward', ['request' => $request]); 95 | } 96 | 97 | return $action; 98 | } 99 | 100 | /** 101 | * Check if the current request path match the configured store locator home. 102 | * 103 | * @param string $requestPath Request path. 104 | * 105 | * @return boolean 106 | */ 107 | private function matchStoreLocatorHome($requestPath) 108 | { 109 | return $this->urlModel->getRequestPathPrefix() == $requestPath; 110 | } 111 | 112 | /** 113 | * Check if the current request path match a retailer URL and returns its id. 114 | * 115 | * @param string $requestPath Request path. 116 | * 117 | * @return int|false 118 | */ 119 | private function matchRetailer($requestPath) 120 | { 121 | $retailerId = false; 122 | $requestPathArray = explode('/', $requestPath); 123 | 124 | if (count($requestPathArray) && $this->matchStoreLocatorHome(current($requestPathArray))) { 125 | $retailerId = $this->urlModel->checkIdentifier(end($requestPathArray)); 126 | } 127 | 128 | return $retailerId; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Controller/Store/Contact.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Controller\Store; 14 | 15 | use Magento\Framework\App\Action\Action; 16 | use Magento\Framework\App\Action\Context; 17 | use Magento\Framework\Controller\Result\ForwardFactory; 18 | use Magento\Framework\Registry; 19 | use Magento\Framework\View\Result\PageFactory; 20 | use Magento\Store\Model\StoreManagerInterface; 21 | use Smile\Retailer\Api\RetailerRepositoryInterface; 22 | use \Smile\StoreLocator\Helper\Contact as ContactHelper; 23 | 24 | /** 25 | * Contact Form action for Shops 26 | * 27 | * @category Smile 28 | * @package Smile\StoreLocator 29 | * @author Romain Ruaud 30 | */ 31 | class Contact extends Action 32 | { 33 | /** 34 | * Page factory. 35 | * 36 | * @var PageFactory 37 | */ 38 | private $resultPageFactory; 39 | 40 | /** 41 | * Forward factory. 42 | * 43 | * @var ForwardFactory 44 | */ 45 | private $resultForwardFactory; 46 | 47 | /** 48 | * Core registry. 49 | * 50 | * @var Registry 51 | */ 52 | private $coreRegistry; 53 | 54 | /** 55 | * @var RetailerRepositoryInterface 56 | */ 57 | private $retailerRepository; 58 | 59 | /** 60 | * @var \Smile\StoreLocator\Helper\Contact 61 | */ 62 | private $contactHelper; 63 | 64 | /** 65 | * Constructor. 66 | * 67 | * @param Context $context Application Context 68 | * @param PageFactory $pageFactory Result Page Factory 69 | * @param ForwardFactory $forwardFactory Forward Factory 70 | * @param Registry $coreRegistry Application Registry 71 | * @param RetailerRepositoryInterface $retailerRepository Retailer Repository 72 | * @param ContactHelper $contactHelper Contact Helper 73 | */ 74 | public function __construct( 75 | Context $context, 76 | PageFactory $pageFactory, 77 | ForwardFactory $forwardFactory, 78 | Registry $coreRegistry, 79 | RetailerRepositoryInterface $retailerRepository, 80 | ContactHelper $contactHelper 81 | ) { 82 | parent::__construct($context); 83 | 84 | $this->resultPageFactory = $pageFactory; 85 | $this->resultForwardFactory = $forwardFactory; 86 | $this->coreRegistry = $coreRegistry; 87 | $this->retailerRepository = $retailerRepository; 88 | $this->contactHelper = $contactHelper; 89 | } 90 | 91 | /** 92 | * Dispatch request. Will bind submitted retailer id (if any) to current customer session 93 | * 94 | * @throws \Magento\Framework\Exception\NotFoundException 95 | * 96 | * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface 97 | */ 98 | public function execute() 99 | { 100 | $retailerId = $this->getRequest()->getParam('id'); 101 | $retailer = $this->retailerRepository->get($retailerId); 102 | 103 | if (!$retailer->getId() || !$this->contactHelper->canDisplayContactForm($retailer)) { 104 | $resultForward = $this->resultForwardFactory->create(); 105 | 106 | return $resultForward->forward('noroute'); 107 | } 108 | 109 | $this->coreRegistry->register('current_retailer', $retailer); 110 | 111 | return $this->resultPageFactory->create(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Controller/Store/Search.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Guillaume Vrac 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Controller\Store; 15 | 16 | use Magento\Framework\App\Action\Action; 17 | use Magento\Framework\App\Action\Context; 18 | use Magento\Framework\View\Result\PageFactory; 19 | use Smile\StoreLocator\Api\LocatorInterface; 20 | 21 | /** 22 | * Search action (displays the search page). 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | * @author Guillaume Vrac 28 | */ 29 | class Search extends Action 30 | { 31 | /** 32 | * Page factory. 33 | * 34 | * @var \Magento\Framework\View\Result\PageFactory 35 | */ 36 | protected $resultPageFactory; 37 | 38 | /** 39 | * Store locator. 40 | * 41 | * @var \Smile\StoreLocator\Api\LocatorInterface 42 | */ 43 | protected $retailerLocator; 44 | 45 | /** 46 | * Constructor. 47 | * 48 | * @param \Magento\Framework\App\Action\Context $context Application Context. 49 | * @param \Magento\Framework\View\Result\PageFactory $pageFactory Result Page Factory. 50 | */ 51 | public function __construct(Context $context, PageFactory $pageFactory) 52 | { 53 | parent::__construct($context); 54 | 55 | $this->resultPageFactory = $pageFactory; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function execute() 62 | { 63 | return $this->resultPageFactory->create(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Controller/Store/Set.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Controller\Store; 14 | 15 | use Magento\Framework\App\Action\Action; 16 | use Magento\Framework\Controller\ResultFactory; 17 | 18 | /** 19 | * Frontend Controller meant to set current Retailer to customer session 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class Set extends Action 26 | { 27 | /** 28 | * @var \Smile\StoreLocator\CustomerData\CurrentStore 29 | */ 30 | private $customerData; 31 | 32 | /** 33 | * @var \Smile\Retailer\Api\RetailerRepositoryInterface 34 | */ 35 | private $retailerRepository; 36 | 37 | /** 38 | * Set constructor. 39 | * 40 | * @param \Magento\Framework\App\Action\Context $context Action context. 41 | * @param \Smile\Retailer\Api\RetailerRepositoryInterface $retailerRepository Retailer repository. 42 | * @param \Smile\StoreLocator\CustomerData\CurrentStore $customerData Store customer data. 43 | */ 44 | public function __construct( 45 | \Magento\Framework\App\Action\Context $context, 46 | \Smile\Retailer\Api\RetailerRepositoryInterface $retailerRepository, 47 | \Smile\StoreLocator\CustomerData\CurrentStore $customerData 48 | ) { 49 | parent::__construct($context); 50 | 51 | $this->retailerRepository = $retailerRepository; 52 | $this->customerData = $customerData; 53 | } 54 | 55 | /** 56 | * Dispatch request. Will bind submitted retailer id (if any) to current customer session 57 | * 58 | * @throws \Magento\Framework\Exception\NotFoundException 59 | * 60 | * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface 61 | */ 62 | public function execute() 63 | { 64 | $retailerId = $this->getRequest()->getParam('id', false); 65 | 66 | try { 67 | $retailer = $this->retailerRepository->get($retailerId); 68 | $this->customerData->setRetailer($retailer); 69 | } catch (\Exception $exception) { 70 | $this->messageManager->addExceptionMessage($exception, __("We are sorry, an error occured when switching retailer.")); 71 | } 72 | 73 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 74 | $resultRedirect->setUrl($this->_redirect->getRefererUrl()); 75 | 76 | return $resultRedirect; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Controller/Store/View.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Guillaume Vrac 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Controller\Store; 15 | 16 | use Magento\Framework\App\Action\Action; 17 | use Magento\Framework\App\Action\Context; 18 | use Magento\Framework\Controller\Result\ForwardFactory; 19 | use Magento\Framework\Registry; 20 | use Magento\Framework\View\Result\PageFactory; 21 | use Magento\Store\Model\StoreManagerInterface; 22 | use Smile\Retailer\Api\RetailerRepositoryInterface; 23 | 24 | /** 25 | * Retailer view action (displays the retailer details page). 26 | * 27 | * @category Smile 28 | * @package Smile\StoreLocator 29 | * @author Romain Ruaud 30 | * @author Guillaume Vrac 31 | */ 32 | class View extends Action 33 | { 34 | /** 35 | * Page factory. 36 | * 37 | * @var PageFactory 38 | */ 39 | private $resultPageFactory; 40 | 41 | /** 42 | * Forward factory. 43 | * 44 | * @var ForwardFactory 45 | */ 46 | private $resultForwardFactory; 47 | 48 | /** 49 | * Core registry. 50 | * 51 | * @var Registry 52 | */ 53 | private $coreRegistry; 54 | 55 | /** 56 | * Store manager. 57 | * 58 | * @var \Magento\Store\Model\StoreManagerInterface 59 | */ 60 | private $storeManager; 61 | 62 | /** 63 | * @var RetailerRepositoryInterface 64 | */ 65 | private $retailerRepository; 66 | 67 | /** 68 | * Constructor. 69 | * 70 | * @param Context $context Application Context 71 | * @param PageFactory $pageFactory Result Page Factory 72 | * @param ForwardFactory $forwardFactory Forward Factory 73 | * @param Registry $coreRegistry Application Registry 74 | * @param StoreManagerInterface $storeManager Store Manager 75 | * @param RetailerRepositoryInterface $retailerRepository Retailer Repository 76 | */ 77 | public function __construct( 78 | Context $context, 79 | PageFactory $pageFactory, 80 | ForwardFactory $forwardFactory, 81 | Registry $coreRegistry, 82 | StoreManagerInterface $storeManager, 83 | RetailerRepositoryInterface $retailerRepository 84 | ) { 85 | parent::__construct($context); 86 | 87 | $this->resultPageFactory = $pageFactory; 88 | $this->resultForwardFactory = $forwardFactory; 89 | $this->coreRegistry = $coreRegistry; 90 | $this->storeManager = $storeManager; 91 | $this->retailerRepository = $retailerRepository; 92 | } 93 | 94 | /** 95 | * {@inheritdoc} 96 | */ 97 | public function execute() 98 | { 99 | $retailerId = $this->getRequest()->getParam('id'); 100 | $storeId = $this->storeManager->getStore()->getId(); 101 | $retailer = $this->retailerRepository->get($retailerId, $storeId); 102 | 103 | if (!$retailer->getId()) { 104 | $resultForward = $this->resultForwardFactory->create(); 105 | 106 | return $resultForward->forward('noroute'); 107 | } 108 | 109 | $this->coreRegistry->register('current_retailer', $retailer); 110 | 111 | return $this->resultPageFactory->create(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /CustomerData/CurrentStore.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\CustomerData; 14 | 15 | use Magento\Customer\CustomerData\SectionSourceInterface; 16 | use Magento\Framework\Exception\NoSuchEntityException; 17 | use Smile\Map\Model\AddressFormatter; 18 | use Smile\Retailer\Api\Data\RetailerInterface; 19 | 20 | /** 21 | * Current Store data. 22 | * 23 | * @category Smile 24 | * @package Smile\StoreLocator 25 | * @author Aurelien FOUCRET 26 | */ 27 | class CurrentStore implements SectionSourceInterface 28 | { 29 | /** 30 | * Will be added as a Vary to HTTP Context 31 | */ 32 | const CONTEXT_RETAILER = 'smile_retailer_id'; 33 | 34 | /** 35 | * @var \Magento\Customer\Model\Session 36 | */ 37 | private $customerSession; 38 | 39 | /** 40 | * @var \Smile\Retailer\Api\RetailerRepositoryInterface 41 | */ 42 | private $retailerRepository; 43 | 44 | /** 45 | * @var \Smile\StoreLocator\Model\Url 46 | */ 47 | private $urlModel; 48 | 49 | /** 50 | * @var \Smile\Map\Model\AddressFormatter 51 | */ 52 | private $addressFormatter; 53 | 54 | /** 55 | * @var \Magento\Framework\App\Http\Context 56 | */ 57 | private $httpContext; 58 | 59 | /** 60 | * CurrentStore constructor 61 | * 62 | * @param \Magento\Customer\Model\Session $customerSession Customer session. 63 | * @param \Smile\Retailer\Api\RetailerRepositoryInterface $retailerRepository Retailer repository. 64 | * @param \Smile\Map\Model\AddressFormatter $addressFormatter Address formatter. 65 | * @param \Smile\StoreLocator\Model\Url $urlModel URL model. 66 | * @param \Magento\Framework\App\Http\Context $context The HTTP Context 67 | */ 68 | public function __construct( 69 | \Magento\Customer\Model\Session $customerSession, 70 | \Smile\Retailer\Api\RetailerRepositoryInterface $retailerRepository, 71 | \Smile\Map\Model\AddressFormatter $addressFormatter, 72 | \Smile\StoreLocator\Model\Url $urlModel, 73 | \Magento\Framework\App\Http\Context $context 74 | ) { 75 | $this->customerSession = $customerSession; 76 | $this->retailerRepository = $retailerRepository; 77 | $this->urlModel = $urlModel; 78 | $this->addressFormatter = $addressFormatter; 79 | $this->httpContext = $context; 80 | } 81 | 82 | /** 83 | * {@inheritdoc} 84 | */ 85 | public function getSectionData() 86 | { 87 | $data = []; 88 | $retailer = $this->getRetailer(); 89 | 90 | if ($retailer) { 91 | $data = $retailer->toArray(['entity_id', 'name']); 92 | 93 | $data['url'] = $this->urlModel->getUrl($retailer); 94 | $data['address'] = $this->addressFormatter->formatAddress( 95 | $retailer->getAddress(), 96 | AddressFormatter::FORMAT_HTML 97 | ); 98 | $data['address_data'] = $retailer->getAddress()->toArray(); 99 | } 100 | 101 | return $data; 102 | } 103 | 104 | /** 105 | * Get the current session retailer. 106 | * 107 | * @return \Smile\Retailer\Api\Data\RetailerInterface 108 | */ 109 | public function getRetailer() 110 | { 111 | $retailer = null; 112 | 113 | $retailerId = $this->customerSession->getRetailerId(); 114 | 115 | if (!$retailerId) { 116 | $retailerId = $this->httpContext->getValue(self::CONTEXT_RETAILER); 117 | } 118 | 119 | if ($retailerId) { 120 | try { 121 | $retailer = $this->retailerRepository->get($retailerId); 122 | } catch (NoSuchEntityException $e) { 123 | $this->customerSession->unsRetailerId(); 124 | } 125 | } 126 | 127 | return $retailer; 128 | } 129 | 130 | /** 131 | * Set a new retailer. 132 | * 133 | * @param RetailerInterface $retailer Current retailer. 134 | * 135 | * @return $this 136 | */ 137 | public function setRetailer($retailer) 138 | { 139 | $this->customerSession->setRetailerId($retailer->getId()); 140 | $this->httpContext->setValue(self::CONTEXT_RETAILER, $retailer->getId(), false); 141 | 142 | return $this; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /Helper/Contact.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Helper; 14 | 15 | use Magento\Framework\App\Helper\AbstractHelper; 16 | use Smile\Retailer\Api\Data\RetailerInterface; 17 | 18 | /** 19 | * Contact information Helper 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class Contact extends AbstractHelper 26 | { 27 | /** 28 | * Check if a retailer has contact information. 29 | * 30 | * @param RetailerInterface $retailer The retailer 31 | * 32 | * @return bool 33 | */ 34 | public function hasContactInformation($retailer) 35 | { 36 | return (($retailer->getCustomAttribute('contact_mail') 37 | && $retailer->getCustomAttribute('contact_mail')->getValue()) 38 | || ($retailer->getCustomAttribute('contact_phone') 39 | && $retailer->getCustomAttribute('contact_phone')->getValue()) 40 | || ($retailer->getCustomAttribute('contact_fax') 41 | && $retailer->getCustomAttribute('contact_fax')->getValue()) 42 | ); 43 | } 44 | 45 | /** 46 | * Check if a retailer can display contact form. 47 | * 48 | * @param RetailerInterface $retailer The retailer 49 | * 50 | * @return bool 51 | */ 52 | public function canDisplayContactForm($retailer) 53 | { 54 | return true === (bool) $retailer->getCustomAttribute('show_contact_form')->getValue(); 55 | } 56 | 57 | /** 58 | * Retrieve contact form submit Url. 59 | * 60 | * @param RetailerInterface $retailer The retailer 61 | * 62 | * @return string 63 | */ 64 | public function getContactFormUrl($retailer) 65 | { 66 | return $this->_getUrl('storelocator/store/contact', ['id' => $retailer->getId(), '_secure' => true]); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Helper/Data.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Fanny DECLERCK 11 | * @copyright 2020 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Helper; 15 | 16 | use Smile\Retailer\Api\Data\RetailerInterface; 17 | 18 | /** 19 | * Store locator helper. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | * @author Fanny DECLERCK 25 | */ 26 | class Data extends \Magento\Framework\App\Helper\AbstractHelper 27 | { 28 | /** 29 | * @var \Smile\StoreLocator\Model\Url 30 | */ 31 | private $urlModel; 32 | 33 | /** 34 | * Constructor. 35 | * 36 | * @param \Magento\Framework\App\Helper\Context $context Helper context. 37 | * @param \Smile\StoreLocator\Model\Url $urlModel Retailer URL model. 38 | */ 39 | public function __construct( 40 | \Magento\Framework\App\Helper\Context $context, 41 | \Smile\StoreLocator\Model\Url $urlModel 42 | ) { 43 | parent::__construct($context); 44 | $this->urlModel = $urlModel; 45 | } 46 | 47 | /** 48 | * Store locator home URL. 49 | * 50 | * @param int|NULL $storeId Store id. 51 | * 52 | * @return string 53 | */ 54 | public function getHomeUrl($storeId = null) 55 | { 56 | return $this->urlModel->getHomeUrl($storeId); 57 | } 58 | 59 | /** 60 | * Retailer URL. 61 | * 62 | * @param RetailerInterface $retailer Retailer. 63 | * 64 | * @return string 65 | */ 66 | public function getRetailerUrl(RetailerInterface $retailer) 67 | { 68 | return $this->urlModel->getUrl($retailer); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Helper/Schedule.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Helper; 14 | 15 | use Magento\Framework\App\Helper\AbstractHelper; 16 | use Magento\Framework\App\Helper\Context; 17 | use Magento\Framework\Locale\Resolver; 18 | use Magento\Framework\Stdlib\DateTime; 19 | 20 | /** 21 | * Schedule Helper 22 | * 23 | * @category Smile 24 | * @package Smile\StoreLocator 25 | * @author Romain Ruaud 26 | */ 27 | class Schedule extends AbstractHelper 28 | { 29 | /** 30 | * Default delay (in minutes) before displaying the "Closing soon" message. 31 | */ 32 | const DEFAULT_WARNING_THRESOLD = 60; 33 | 34 | /** 35 | * @var \Magento\Framework\Locale\Resolver 36 | */ 37 | private $localeResolver; 38 | 39 | /** 40 | * @var \Zend_Locale_Format 41 | */ 42 | private $localeFormat; 43 | 44 | /** 45 | * Schedule constructor. 46 | * 47 | * @param \Magento\Framework\App\Helper\Context $context Application Context 48 | * @param \Magento\Framework\Locale\Resolver $localeResolver Locale Resolver 49 | * @param \Zend_Locale_Format $localeFormat Locale Format 50 | */ 51 | public function __construct( 52 | Context $context, 53 | Resolver $localeResolver, 54 | \Zend_Locale_Format $localeFormat 55 | ) { 56 | parent::__construct($context); 57 | 58 | $this->localeResolver = $localeResolver; 59 | $this->localeFormat = $localeFormat; 60 | } 61 | 62 | /** 63 | * Retrieve configuration used by schedule components 64 | * 65 | * @throws \Zend_Locale_Exception 66 | * @return array 67 | */ 68 | public function getConfig() 69 | { 70 | return [ 71 | 'locale' => $this->getLocale(), 72 | 'dateFormat' => $this->getDateFormat(), 73 | 'timeFormat' => $this->getTimeFormat(), 74 | 'closingWarningThresold' => $this->getClosingWarningThresold(), 75 | ]; 76 | } 77 | 78 | /** 79 | * Retrieve current locale 80 | * 81 | * @return null|string 82 | */ 83 | private function getLocale() 84 | { 85 | return $this->localeResolver->getLocale(); 86 | } 87 | 88 | /** 89 | * Retrieve Time Format 90 | * 91 | * @return string 92 | * @throws \Zend_Locale_Exception 93 | */ 94 | private function getTimeFormat() 95 | { 96 | return $this->localeFormat->getTimeFormat($this->localeResolver->getLocale()); 97 | } 98 | 99 | /** 100 | * Return the date format used for schedule component 101 | * 102 | * @return string 103 | */ 104 | private function getDateFormat() 105 | { 106 | return strtoupper(DateTime::DATE_INTERNAL_FORMAT); 107 | } 108 | 109 | /** 110 | * Retrieve default closing warning thresold, in minutes. 111 | * 112 | * @return int 113 | */ 114 | private function getClosingWarningThresold() 115 | { 116 | return self::DEFAULT_WARNING_THRESOLD; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Preconditions 4 | 5 | 6 | 7 | Magento Version : 8 | 9 | 10 | Module Store Locator Version : 11 | 12 | 13 | Environment : 14 | 15 | 16 | Third party modules : 17 | 18 | ### Steps to reproduce 19 | 20 | 1. 21 | 2. 22 | 3. 23 | 24 | ### Expected result 25 | 26 | 1. 27 | 28 | ### Actual result 29 | 30 | 1. [Screenshot, logs] 31 | 32 | 33 | -------------------------------------------------------------------------------- /Model/Data/RetailerAddress.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Data; 14 | 15 | use Smile\Map\Model\GeolocalizedAddress; 16 | use Smile\StoreLocator\Api\Data\RetailerAddressInterface; 17 | 18 | /** 19 | * Retailer address default implementation. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class RetailerAddress extends GeolocalizedAddress implements RetailerAddressInterface 26 | { 27 | /** 28 | * {@inheritDoc} 29 | */ 30 | public function getId() 31 | { 32 | return $this->getData(self::ADDRESS_ID); 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | public function getRetailerId() 39 | { 40 | return $this->getData(self::RETAILER_ID); 41 | } 42 | 43 | /** 44 | * @SuppressWarnings(PHPMD.ShortVariable) 45 | * 46 | * {@inheritDoc} 47 | */ 48 | public function setId($id) 49 | { 50 | return $this->setData(self::ADDRESS_ID, $id); 51 | } 52 | 53 | /** 54 | * {@inheritDoc} 55 | */ 56 | public function setRetailerId($retailerId) 57 | { 58 | return $this->setData(self::RETAILER_ID, $retailerId); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Model/Data/RetailerTimeSlot.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Data; 14 | 15 | use Magento\Framework\DataObject; 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterface; 17 | use Zend\Stdlib\JsonSerializable; 18 | 19 | /** 20 | * Data Object for Time Slot entries. 21 | * 22 | * @category Smile 23 | * @package Smile\StoreLocator 24 | * @author Romain Ruaud 25 | */ 26 | class RetailerTimeSlot extends DataObject implements RetailerTimeSlotInterface, JsonSerializable 27 | { 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | public function getStartTime() 32 | { 33 | return $this->getData('start_time'); 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | public function getEndTime() 40 | { 41 | return $this->getData('end_time'); 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | public function setStartTime($time) 48 | { 49 | $this->setData('start_time', $time); 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * {@inheritDoc} 56 | */ 57 | public function setEndTime($time) 58 | { 59 | $this->setData('end_time', $time); 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Specify data which should be serialized to JSON 66 | * 67 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 68 | * @return mixed data which can be serialized by json_encode, 69 | * which is a value of any type other than a resource. 70 | * @since 5.4.0 71 | */ 72 | public function jsonSerialize(): mixed 73 | { 74 | return [ 75 | 'start_time' => $this->getStartTime(), 76 | 'end_time' => $this->getEndTime(), 77 | ]; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Model/Data/RetailerTimeSlotConverter.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Data; 14 | 15 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterface; 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterfaceFactory; 17 | 18 | /** 19 | * Converter for Time Slot operations 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class RetailerTimeSlotConverter 26 | { 27 | /** 28 | * RetailerTimeSlotConverter constructor. 29 | * 30 | * @param RetailerTimeSlotInterfaceFactory $timeSlotFactory Time Slot Factory 31 | */ 32 | public function __construct(RetailerTimeSlotInterfaceFactory $timeSlotFactory) 33 | { 34 | $this->timeSlotFactory = $timeSlotFactory; 35 | } 36 | 37 | /** 38 | * Convert a set of timeslot entries to a multidimensional array of RetailerTimeSlotInterface 39 | * 40 | * @param array $timeSlots The time slot data 41 | * @param string $dateField The date field to use 42 | * 43 | * @return array 44 | */ 45 | public function toEntity($timeSlots, $dateField = RetailerTimeSlotInterface::DAY_OF_WEEK_FIELD) 46 | { 47 | $openingHours = []; 48 | 49 | if (!empty($timeSlots)) { 50 | foreach ($timeSlots as $row) { 51 | $day = $row[$dateField]; 52 | if (!isset($openingHours[$day])) { 53 | $openingHours[$day] = []; 54 | } 55 | 56 | if (null !== $row['start_time'] && null !== $row['end_time']) { 57 | $timeSlotModel = $this->timeSlotFactory->create( 58 | ['data' => ['start_time' => $row['start_time'], 'end_time' => $row['end_time']]] 59 | ); 60 | $openingHours[$day][] = $timeSlotModel; 61 | } 62 | } 63 | } 64 | 65 | return $openingHours; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Model/ResourceModel/RetailerAddress.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\ResourceModel; 14 | 15 | use Magento\Framework\Model\ResourceModel\Db\AbstractDb; 16 | use Smile\StoreLocator\Api\Data\RetailerAddressInterface; 17 | 18 | /** 19 | * Retailer address resource model. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class RetailerAddress extends AbstractDb 26 | { 27 | /** 28 | * @var \Magento\Framework\EntityManager\EntityManager 29 | */ 30 | private $entityManager; 31 | 32 | /** 33 | * @var \Magento\Framework\EntityManager\MetadataPool 34 | */ 35 | private $metadataPool; 36 | 37 | /** 38 | * 39 | * @param \Magento\Framework\Model\ResourceModel\Db\Context $context DB context. 40 | * @param \Magento\Framework\EntityManager\EntityManager $entityManager Entity manager. 41 | * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool Entity metadata pool. 42 | * @param string $connectionName Connection name. 43 | */ 44 | public function __construct( 45 | \Magento\Framework\Model\ResourceModel\Db\Context $context, 46 | \Magento\Framework\EntityManager\EntityManager $entityManager, 47 | \Magento\Framework\EntityManager\MetadataPool $metadataPool, 48 | $connectionName = null 49 | ) { 50 | $this->entityManager = $entityManager; 51 | $this->metadataPool = $metadataPool; 52 | parent::__construct($context, $connectionName); 53 | } 54 | 55 | /** 56 | * {@inheritDoc} 57 | */ 58 | public function getConnection() 59 | { 60 | return $this->metadataPool->getMetadata(RetailerAddressInterface::class)->getEntityConnection(); 61 | } 62 | 63 | /** 64 | * @SuppressWarnings(PHPMD.CamelCaseMethodName) 65 | * 66 | * {@inheritDoc} 67 | */ 68 | protected function _construct() 69 | { 70 | $metadata = $this->metadataPool->getMetadata(RetailerAddressInterface::class); 71 | $this->_init($metadata->getEntityTable(), $metadata->getIdentifierField()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Model/ResourceModel/Url.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\ResourceModel; 14 | 15 | use Magento\Framework\DB\Select; 16 | 17 | /** 18 | * Retailer URL resource model. 19 | * 20 | * @category Smile 21 | * @package Smile\StoreLocator 22 | * @author Aurelien FOUCRET 23 | */ 24 | class Url extends \Smile\Seller\Model\ResourceModel\Seller 25 | { 26 | /** 27 | * Check an URL key exists and returns the retailer id. False if no retailer found. 28 | * 29 | * @param urlKey $urlKey URL key. 30 | * @param int $storeId Store Id. 31 | * 32 | * @return int|false 33 | */ 34 | public function checkIdentifier($urlKey, $storeId) 35 | { 36 | $urlKeyAttribute = $this->getAttribute('url_key'); 37 | $select = $this->getConnection()->select(); 38 | 39 | $select->from($urlKeyAttribute->getBackendTable(), ['entity_id']) 40 | ->where('attribute_id = ?', $urlKeyAttribute->getAttributeId()) 41 | ->where('value = ?', $urlKey) 42 | ->where('store_id IN(?, 0)', $storeId) 43 | ->order('store_id ' . Select::SQL_DESC) 44 | ->limit(1); 45 | 46 | return $this->getConnection()->fetchOne($select); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Model/Retailer/AddressPostDataHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | /** 16 | * Read addresses from post data. 17 | * 18 | * @category Smile 19 | * @package Smile\StoreLocator 20 | * @author Aurelien FOUCRET 21 | */ 22 | class AddressPostDataHandler implements \Smile\Retailer\Model\Retailer\PostDataHandlerInterface 23 | { 24 | /** 25 | * @var \Smile\StoreLocator\Api\Data\RetailerAddressInterfaceFactory 26 | */ 27 | private $retailerAddressFactory; 28 | 29 | /** 30 | * @var \Smile\Map\Api\Data\GeoPointInterfaceFactory 31 | */ 32 | private $geoPointFactory; 33 | 34 | /** 35 | * Constructor. 36 | * 37 | * @param \Smile\StoreLocator\Api\Data\RetailerAddressInterfaceFactory $retailerAddressFactory Retailer address factory. 38 | * @param \Smile\Map\Api\Data\GeoPointInterfaceFactory $geoPointFactory Geo point factory. 39 | */ 40 | public function __construct( 41 | \Smile\StoreLocator\Api\Data\RetailerAddressInterfaceFactory $retailerAddressFactory, 42 | \Smile\Map\Api\Data\GeoPointInterfaceFactory $geoPointFactory 43 | ) { 44 | $this->retailerAddressFactory = $retailerAddressFactory; 45 | $this->geoPointFactory = $geoPointFactory; 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | public function getData(\Smile\Retailer\Api\Data\RetailerInterface $retailer, $data) 52 | { 53 | if (isset($data['address'])) { 54 | $addressData = $data['address']; 55 | 56 | if (isset($addressData['coordinates'])) { 57 | $addressData['coordinates'] = $this->geoPointFactory->create($addressData['coordinates']); 58 | } 59 | 60 | if (isset($addressData['street']) && !is_array($addressData['street'])) { 61 | $addressData['street'] = explode('\n', $addressData['street']); 62 | } 63 | 64 | $data['address'] = $this->retailerAddressFactory->create(['data' => $addressData]); 65 | } 66 | 67 | return $data; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Model/Retailer/AddressReadHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Api\Data\RetailerAddressInterface; 17 | use Smile\StoreLocator\Model\RetailerAddressFactory as ModelFactory; 18 | use Smile\StoreLocator\Model\ResourceModel\RetailerAddress as ResourceModel; 19 | use Smile\StoreLocator\Model\Data\RetailerAddressConverter as Converter; 20 | 21 | /** 22 | * Retailer address read handler. 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Aurelien FOUCRET 27 | */ 28 | class AddressReadHandler implements ExtensionInterface 29 | { 30 | /** 31 | * @var ModelFactory 32 | */ 33 | private $modelFactory; 34 | 35 | /** 36 | * @var ResourceModel 37 | */ 38 | private $resource; 39 | 40 | /** 41 | * @var Converter 42 | */ 43 | private $converter; 44 | 45 | /** 46 | * Constructor. 47 | * 48 | * @param ModelFactory $modelFactory Address model factory. 49 | * @param ResourceModel $resource Address resource model. 50 | * @param Converter $converter Adress converter. 51 | */ 52 | public function __construct(ModelFactory $modelFactory, ResourceModel $resource, Converter $converter) 53 | { 54 | $this->modelFactory = $modelFactory; 55 | $this->resource = $resource; 56 | $this->converter = $converter; 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | public function execute($entity, $arguments = []) 63 | { 64 | $addressModel = $this->modelFactory->create(); 65 | $addressModel->setRetailerId($entity->getId()); 66 | 67 | $this->resource->load($addressModel, $entity->getId(), RetailerAddressInterface::RETAILER_ID); 68 | 69 | $addressEntity = $this->converter->toEntity($addressModel); 70 | 71 | $entity->getExtensionAttributes()->setAddress($addressEntity); 72 | $entity->setAddress($addressEntity); 73 | 74 | return $entity; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Model/Retailer/AddressSaveHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Model\RetailerAddressFactory as ModelFactory; 17 | use Smile\StoreLocator\Model\ResourceModel\RetailerAddress as ResourceModel; 18 | use Smile\StoreLocator\Model\Data\RetailerAddressConverter as Converter; 19 | use Smile\StoreLocator\Api\Data\RetailerAddressInterface; 20 | 21 | /** 22 | * Retailer address save handler. 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Aurelien FOUCRET 27 | */ 28 | class AddressSaveHandler implements ExtensionInterface 29 | { 30 | /** 31 | * @var ModelFactory 32 | */ 33 | private $modelFactory; 34 | 35 | /** 36 | * @var ResourceModel 37 | */ 38 | private $resource; 39 | 40 | /** 41 | * @var Converter 42 | */ 43 | private $converter; 44 | 45 | /** 46 | * Constructor. 47 | * 48 | * @param ModelFactory $modelFactory Model factory. 49 | * @param ResourceModel $resource Resource model. 50 | * @param Converter $converter Entity / Model converter. 51 | */ 52 | public function __construct(ModelFactory $modelFactory, ResourceModel $resource, Converter $converter) 53 | { 54 | $this->modelFactory = $modelFactory; 55 | $this->resource = $resource; 56 | $this->converter = $converter; 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | public function execute($entity, $arguments = []) 63 | { 64 | $addressEntity = $entity->getAddress(); 65 | $addressEntity->setRetailerId($entity->getId()); 66 | 67 | $addressModel = $this->modelFactory->create(); 68 | $this->resource->load($addressModel, $entity->getId(), RetailerAddressInterface::RETAILER_ID); 69 | 70 | if ($addressModel->getId()) { 71 | $addressEntity->setId($addressModel->getId()); 72 | } 73 | 74 | $addressModel = $this->converter->toModel($addressEntity); 75 | 76 | $this->resource->save($addressModel); 77 | 78 | return $entity; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Model/Retailer/Attribute/Backend/UrlKey.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer\Attribute\Backend; 14 | 15 | use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend; 16 | use Magento\Framework\Exception\CouldNotSaveException; 17 | 18 | /** 19 | * Retailer URL key backend model. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class UrlKey extends AbstractBackend 26 | { 27 | /** 28 | * @var \Smile\StoreLocator\Model\Url 29 | */ 30 | private $urlModel; 31 | 32 | /** 33 | * Constructor. 34 | * 35 | * @param \Smile\StoreLocator\Model\Url $urlModel Retailer URL Model. 36 | */ 37 | public function __construct(\Smile\StoreLocator\Model\Url $urlModel) 38 | { 39 | $this->urlModel = $urlModel; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | public function beforeSave($object) 46 | { 47 | $urlKey = $this->urlModel->getUrlKey($object); 48 | 49 | if ($urlKey !== $object->getUrlKey()) { 50 | $object->setUrlKey($urlKey); 51 | } 52 | 53 | $retailerIdCheck = $this->urlModel->checkIdentifier($urlKey); 54 | 55 | if ($retailerIdCheck !== false && ($object->getId() !== $retailerIdCheck)) { 56 | throw new CouldNotSaveException(__('Retailer url_key "%1" already exists.', $urlKey)); 57 | } 58 | 59 | return $this; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Model/Retailer/OpeningHoursPostDataHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Fanny DECLERCK 11 | * @copyright 2019 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Model\Retailer; 15 | 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterfaceFactory; 17 | use Magento\Framework\Json\Helper\Data as JsonHelper; 18 | use Smile\Retailer\Api\RetailerRepositoryInterface; 19 | use Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot; 20 | 21 | /** 22 | * Post Data Handler for Retailer Opening Hours 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | * @author Fanny DECLERCK 28 | */ 29 | class OpeningHoursPostDataHandler implements \Smile\Retailer\Model\Retailer\PostDataHandlerInterface 30 | { 31 | /** 32 | * @var RetailerTimeSlotInterfaceFactory 33 | */ 34 | private $timeSlotFactory; 35 | 36 | /** 37 | * @var JsonHelper 38 | */ 39 | private $jsonHelper; 40 | 41 | /** 42 | * @var RetailerRepositoryInterface 43 | */ 44 | private $retailerRepository; 45 | 46 | /** 47 | * @var RetailerTimeSlot 48 | */ 49 | private $retailerTimeSlot; 50 | 51 | /** 52 | * OpeningHoursPostDataHandler constructor. 53 | * 54 | * @param RetailerTimeSlotInterfaceFactory $timeSlotFactory Time Slot Factory 55 | * @param JsonHelper $jsonHelper JSON Helper 56 | * @param RetailerRepositoryInterface $retailerRepository Retailer Repository Interface 57 | * @param RetailerTimeSlot $retailerTimeSlot Retailer Time Slot Resource Model 58 | */ 59 | public function __construct( 60 | RetailerTimeSlotInterfaceFactory $timeSlotFactory, 61 | JsonHelper $jsonHelper, 62 | RetailerRepositoryInterface $retailerRepository, 63 | RetailerTimeSlot $retailerTimeSlot 64 | ) { 65 | $this->timeSlotFactory = $timeSlotFactory; 66 | $this->jsonHelper = $jsonHelper; 67 | $this->retailerRepository = $retailerRepository; 68 | $this->retailerTimeSlot = $retailerTimeSlot; 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | public function getData(\Smile\Retailer\Api\Data\RetailerInterface $retailer, $data) 75 | { 76 | if (isset($data['opening_hours'])) { 77 | $openingHours = []; 78 | 79 | foreach ($data['opening_hours'] as $date => &$timeSlotList) { 80 | if (is_string($timeSlotList)) { 81 | try { 82 | $timeSlotList = $this->jsonHelper->jsonDecode($timeSlotList); 83 | } catch (\Zend_Json_Exception $exception) { 84 | $timeSlotList = []; 85 | } 86 | } 87 | 88 | if (!count($timeSlotList)) { 89 | continue; 90 | } 91 | 92 | foreach ($timeSlotList as $timeSlot) { 93 | $timeSlotModel = $this->timeSlotFactory->create( 94 | ['data' => ['start_time' => $timeSlot[0], 'end_time' => $timeSlot[1]]] 95 | ); 96 | $openingHours[$date][] = $timeSlotModel; 97 | } 98 | } 99 | 100 | // If not a single opening hour is saved, we delete existing entry for current retailer 101 | if (empty($openingHours) && isset($data['entity_id'])) { 102 | $this->retailerTimeSlot->deleteByRetailerId($data['entity_id']); 103 | } 104 | 105 | $data['opening_hours'] = $openingHours; 106 | 107 | $this->updateOpeningHoursBySellerIds($data); 108 | } 109 | 110 | return $data; 111 | } 112 | 113 | /** 114 | * Update opening hours by seller ids. 115 | * 116 | * @param array $data Data seller ids / Opening hours by days. 117 | * 118 | * @return void 119 | */ 120 | private function updateOpeningHoursBySellerIds($data) 121 | { 122 | if (isset($data['opening_hours_seller_ids'])) { 123 | foreach ($data['opening_hours_seller_ids'] as $id) { 124 | $model = $this->retailerRepository->get($id); 125 | $model->setData('opening_hours', $data['opening_hours']); 126 | $this->retailerRepository->save($model); 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Model/Retailer/OpeningHoursReadHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterface; 17 | use Smile\StoreLocator\Model\Data\RetailerTimeSlotConverter; 18 | use Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot as TimeSlotResource; 19 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterfaceFactory; 20 | 21 | /** 22 | * Read Handler for Retailer Opening Hours 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | */ 28 | class OpeningHoursReadHandler implements ExtensionInterface 29 | { 30 | /** 31 | * @var \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot 32 | */ 33 | private $resource; 34 | 35 | /** 36 | * @var \Smile\StoreLocator\Model\Data\RetailerTimeSlotConverter 37 | */ 38 | private $converter; 39 | 40 | /** 41 | * OpeningHoursSaveHandler constructor. 42 | * 43 | * @param RetailerTimeSlotConverter $converter Time Slot Factory 44 | * @param TimeSlotResource $resource Resource Model 45 | */ 46 | public function __construct(RetailerTimeSlotConverter $converter, TimeSlotResource $resource) 47 | { 48 | $this->converter = $converter; 49 | $this->resource = $resource; 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | public function execute($entity, $arguments = []) 56 | { 57 | $timeSlots = $this->resource->getTimeSlots($entity->getId(), 'opening_hours'); 58 | 59 | $openingHours = $this->converter->toEntity($timeSlots, RetailerTimeSlotInterface::DAY_OF_WEEK_FIELD); 60 | 61 | $entity->getExtensionAttributes()->setOpeningHours($openingHours); 62 | $entity->setOpeningHours($openingHours); 63 | 64 | return $entity; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Model/Retailer/OpeningHoursSaveHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot as TimeSlotResource; 17 | 18 | /** 19 | * Save Handler for Retailer Opening Hours 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class OpeningHoursSaveHandler implements ExtensionInterface 26 | { 27 | /** 28 | * @var \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot 29 | */ 30 | private $resource; 31 | 32 | /** 33 | * OpeningHoursSaveHandler constructor. 34 | * 35 | * @param \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot $resource Resource Model 36 | */ 37 | public function __construct(TimeSlotResource $resource) 38 | { 39 | $this->resource = $resource; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | public function execute($entity, $arguments = []) 46 | { 47 | if ($entity->getOpeningHours()) { 48 | $this->resource->saveTimeSlots($entity->getId(), 'opening_hours', $entity->getOpeningHours()); 49 | } 50 | 51 | return $entity; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Retailer/ScheduleManagement.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Smile\Retailer\Api\Data\RetailerInterface; 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterface; 17 | use Magento\Framework\Locale\ListsInterface; 18 | use Magento\Framework\Locale\Resolver; 19 | 20 | /** 21 | * Schedule Management class for Retailers 22 | * 23 | * @category Smile 24 | * @package Smile\StoreLocator 25 | * @author Romain Ruaud 26 | */ 27 | class ScheduleManagement 28 | { 29 | /** 30 | * Display calendar up to X days. 31 | */ 32 | const CALENDAR_MAX_DATE = 6; 33 | 34 | /** 35 | * @var \Magento\Framework\Locale\ListsInterface 36 | */ 37 | private $localeList; 38 | 39 | /** 40 | * ScheduleManagement constructor. 41 | * 42 | * @param \Magento\Framework\Locale\ListsInterface $localeList Locale Lists 43 | */ 44 | public function __construct(ListsInterface $localeList) 45 | { 46 | $this->localeList = $localeList; 47 | } 48 | 49 | /** 50 | * Retrieve opening hours for a given date 51 | * 52 | * @SuppressWarnings(PHPMD.StaticAccess) 53 | * 54 | * @param RetailerInterface $retailer The retailer 55 | * @param null $dateTime The date to retrieve opening hours for 56 | * 57 | * @return RetailerTimeSlotInterface[] 58 | */ 59 | public function getOpeningHours($retailer, $dateTime = null) 60 | { 61 | $dayOpening = []; 62 | 63 | if ($dateTime == null) { 64 | $dateTime = new \DateTime(); 65 | } 66 | if (is_string($dateTime)) { 67 | $dateTime = \DateTime::createFromFormat('Y-m-d', $dateTime); 68 | } 69 | 70 | $dayOfWeek = $dateTime->format('w'); 71 | $date = $dateTime->format('Y-m-d'); 72 | 73 | $openingHours = $retailer->getExtensionAttributes()->getOpeningHours(); 74 | $specialOpeningHours = $retailer->getExtensionAttributes()->getSpecialOpeningHours(); 75 | 76 | if (isset($openingHours[$dayOfWeek])) { 77 | $dayOpening = $openingHours[$dayOfWeek]; 78 | } 79 | 80 | if (isset($specialOpeningHours[$date])) { 81 | $dayOpening = $specialOpeningHours[$date]; 82 | } 83 | 84 | return $dayOpening; 85 | } 86 | 87 | 88 | /** 89 | * Get shop calendar : opening hours for the next X days. 90 | * 91 | * @SuppressWarnings(PHPMD.StaticAccess) 92 | * 93 | * @param RetailerInterface $retailer The retailer 94 | * 95 | * @return array 96 | */ 97 | public function getCalendar($retailer) 98 | { 99 | $calendar = []; 100 | $date = $this->getMinDate(); 101 | $calendar[$date->format('Y-m-d')] = $this->getOpeningHours($retailer, $date); 102 | 103 | while ($date < $this->getMaxDate()) { 104 | $date->add(\DateInterval::createFromDateString('+1 day')); 105 | $calendar[$date->format('Y-m-d')] = $this->getOpeningHours($retailer, $date); 106 | } 107 | 108 | return $calendar; 109 | } 110 | 111 | /** 112 | * Retrieve opening hours 113 | * 114 | * @param RetailerInterface $retailer The retailer 115 | * 116 | * @return array 117 | */ 118 | public function getWeekOpeningHours($retailer) 119 | { 120 | $openingHours = []; 121 | 122 | $days = $this->localeList->getOptionWeekdays(true, true); 123 | 124 | foreach (array_keys($days) as $day) { 125 | $openingHours[$day] = []; 126 | } 127 | 128 | foreach ($retailer->getExtensionAttributes()->getOpeningHours() as $day => $hours) { 129 | $openingHours[$day] = $hours; 130 | } 131 | 132 | return $openingHours; 133 | } 134 | 135 | /** 136 | * Get min date to calculate calendar 137 | * 138 | * @return \DateTime 139 | */ 140 | private function getMinDate() 141 | { 142 | $date = new \DateTime(); 143 | 144 | return $date; 145 | } 146 | 147 | /** 148 | * Get max date to calculate calendar 149 | * 150 | * @SuppressWarnings(PHPMD.StaticAccess) 151 | * 152 | * @return \DateTime 153 | */ 154 | private function getMaxDate() 155 | { 156 | $date = $this->getMinDate(); 157 | $date->add(\DateInterval::createFromDateString(sprintf('+%s day', self::CALENDAR_MAX_DATE))); 158 | 159 | return $date; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /Model/Retailer/SpecialOpeningHoursReadHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterface; 17 | use Smile\StoreLocator\Model\Data\RetailerTimeSlotConverter; 18 | use Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot as TimeSlotResource; 19 | use Smile\StoreLocator\Api\Data\RetailerTimeSlotInterfaceFactory; 20 | 21 | /** 22 | * Read Handler for Retailer Special Opening Hours 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | */ 28 | class SpecialOpeningHoursReadHandler implements ExtensionInterface 29 | { 30 | /** 31 | * @var \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot 32 | */ 33 | private $resource; 34 | 35 | /** 36 | * @var \Smile\StoreLocator\Model\Data\RetailerTimeSlotConverter 37 | */ 38 | private $converter; 39 | 40 | /** 41 | * OpeningHoursSaveHandler constructor. 42 | * 43 | * @param RetailerTimeSlotConverter $converter Time Slot Factory 44 | * @param TimeSlotResource $resource Resource Model 45 | */ 46 | public function __construct(RetailerTimeSlotConverter $converter, TimeSlotResource $resource) 47 | { 48 | $this->converter = $converter; 49 | $this->resource = $resource; 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | public function execute($entity, $arguments = []) 56 | { 57 | $timeSlots = $this->resource->getTimeSlots($entity->getId(), 'special_opening_hours'); 58 | 59 | $openingHours = $this->converter->toEntity($timeSlots, RetailerTimeSlotInterface::DATE_FIELD); 60 | 61 | ksort($openingHours); 62 | $entity->getExtensionAttributes()->setSpecialOpeningHours($openingHours); 63 | $entity->setSpecialOpeningHours($openingHours); 64 | 65 | return $entity; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Model/Retailer/SpecialOpeningHoursSaveHandler.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model\Retailer; 14 | 15 | use Magento\Framework\EntityManager\Operation\ExtensionInterface; 16 | use Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot as TimeSlotResource; 17 | 18 | /** 19 | * Save Handler for Retailer Special Opening Hours 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Romain Ruaud 24 | */ 25 | class SpecialOpeningHoursSaveHandler implements ExtensionInterface 26 | { 27 | /** 28 | * @var \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot 29 | */ 30 | private $resource; 31 | 32 | /** 33 | * OpeningHoursSaveHandler constructor. 34 | * 35 | * @param \Smile\StoreLocator\Model\ResourceModel\RetailerTimeSlot $resource Resource Model 36 | */ 37 | public function __construct(TimeSlotResource $resource) 38 | { 39 | $this->resource = $resource; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | public function execute($entity, $arguments = []) 46 | { 47 | if (empty($entity->getSpecialOpeningHours())) { 48 | $this->resource->deleteByRetailerId($entity->getId(), 'special_opening_hours'); 49 | } 50 | 51 | if ($entity->getSpecialOpeningHours()) { 52 | $this->resource->saveTimeSlots($entity->getId(), 'special_opening_hours', $entity->getSpecialOpeningHours()); 53 | } 54 | 55 | return $entity; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Model/RetailerAddress/Source/Country.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Guillaume Vrac 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | namespace Smile\StoreLocator\Model\RetailerAddress\Source; 15 | 16 | use Magento\Directory\Model\ResourceModel\Country\CollectionFactory as CountryCollectionFactory; 17 | use Magento\Eav\Model\Entity\Attribute\Source\Table; 18 | use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory; 19 | use Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory; 20 | 21 | /** 22 | * Country attribute source model. 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | * @author Guillaume Vrac 28 | */ 29 | class Country extends Table 30 | { 31 | /** 32 | * Countries factory. 33 | * 34 | * @var CountryCollectionFactory 35 | */ 36 | protected $countriesFactory; 37 | 38 | /** 39 | * Constructor. 40 | * 41 | * @param CollectionFactory $attrOptionCollectionFactory Attributes options Collection factory 42 | * @param OptionFactory $attrOptionFactory Attribute option factory 43 | * @param CountryCollectionFactory $countriesFactory Countries Factory 44 | */ 45 | public function __construct( 46 | CollectionFactory $attrOptionCollectionFactory, 47 | OptionFactory $attrOptionFactory, 48 | CountryCollectionFactory $countriesFactory 49 | ) { 50 | $this->countriesFactory = $countriesFactory; 51 | parent::__construct($attrOptionCollectionFactory, $attrOptionFactory); 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function getAllOptions($withEmpty = true, $defaultValues = false) 58 | { 59 | if ($this->_options === null) { 60 | $this->_options = $this->countriesFactory->create() 61 | ->loadByStore() 62 | ->toOptionArray(); 63 | } 64 | 65 | return $this->_options; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Model/Url.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Model; 14 | 15 | use Smile\Retailer\Api\Data\RetailerInterface; 16 | use Magento\Store\Model\ScopeInterface; 17 | 18 | /** 19 | * Retailer URL model. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class Url 26 | { 27 | /** 28 | * @var string 29 | */ 30 | const BASE_URL_XML_PATH = 'store_locator/seo/base_url'; 31 | 32 | /** 33 | * @var \Smile\StoreLocator\Model\ResourceModel\Url 34 | */ 35 | private $resourceModel; 36 | 37 | /** 38 | * @var \Magento\Framework\Filter\FilterManager 39 | */ 40 | private $filter; 41 | 42 | /** 43 | * @var \Magento\Framework\UrlInterface 44 | */ 45 | private $urlBuilder; 46 | 47 | /** 48 | * @var \Magento\Store\Model\StoreManagerInterface 49 | */ 50 | private $storeManager; 51 | 52 | /** 53 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 54 | */ 55 | private $scopeConfig; 56 | 57 | /** 58 | * Constructor. 59 | * 60 | * @param \Smile\StoreLocator\Model\ResourceModel\Url $resourceModel ResourceModel. 61 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager Store manager. 62 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig Store config. 63 | * @param \Magento\Framework\UrlInterface $urlBuilder URL builder. 64 | * @param \Magento\Framework\Filter\FilterManager $filter Filters. 65 | */ 66 | public function __construct( 67 | \Smile\StoreLocator\Model\ResourceModel\Url $resourceModel, 68 | \Magento\Store\Model\StoreManagerInterface $storeManager, 69 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 70 | \Magento\Framework\UrlInterface $urlBuilder, 71 | \Magento\Framework\Filter\FilterManager $filter 72 | ) { 73 | $this->resourceModel = $resourceModel; 74 | $this->storeManager = $storeManager; 75 | $this->scopeConfig = $scopeConfig; 76 | $this->urlBuilder = $urlBuilder; 77 | $this->filter = $filter; 78 | } 79 | 80 | /** 81 | * Get retailer URL key. 82 | * 83 | * @param RetailerInterface $retailer Retailer. 84 | * 85 | * @return string 86 | */ 87 | public function getUrlKey(RetailerInterface $retailer) 88 | { 89 | $urlKey = !empty($retailer->getUrlKey()) ? $retailer->getUrlKey() : $retailer->getName(); 90 | 91 | return $urlKey !== null ? $this->filter->translitUrl($urlKey) : null; 92 | } 93 | 94 | /** 95 | * Get retailer URL. 96 | * 97 | * @param RetailerInterface $retailer Retailer. 98 | * 99 | * @return string 100 | */ 101 | public function getUrl(RetailerInterface $retailer) 102 | { 103 | $url = sprintf("%s/%s", $this->getRequestPathPrefix($retailer->getStoreId()), $this->getUrlKey($retailer)); 104 | 105 | return $this->urlBuilder->getUrl(null, ['_direct' => $url]); 106 | } 107 | 108 | /** 109 | * Get store locator home URL. 110 | * 111 | * @param int|NULL $storeId Store Id 112 | * 113 | * @return string 114 | */ 115 | public function getHomeUrl($storeId = null) 116 | { 117 | return $this->urlBuilder->getUrl(null, ['_direct' => $this->getRequestPathPrefix($storeId)]); 118 | } 119 | 120 | /** 121 | * Get URL prefix for the store locator. 122 | * 123 | * @param int|NULL $storeId Store Id 124 | * 125 | * @return string 126 | */ 127 | public function getRequestPathPrefix($storeId = null) 128 | { 129 | if ($storeId === null) { 130 | $storeId = $this->storeManager->getStore()->getId(); 131 | } 132 | 133 | return $this->scopeConfig->getValue(self::BASE_URL_XML_PATH, ScopeInterface::SCOPE_STORE, $storeId); 134 | } 135 | 136 | /** 137 | * Check an URL key exists and returns the retailer id. False if no retailer found. 138 | * 139 | * @param urlKey $urlKey URL key. 140 | * @param int $storeId Store Id. 141 | * 142 | * @return int|false 143 | */ 144 | public function checkIdentifier($urlKey, $storeId = null) 145 | { 146 | if ($storeId == null) { 147 | $storeId = $this->storeManager->getStore()->getId(); 148 | } 149 | 150 | return $this->resourceModel->checkIdentifier($urlKey, $storeId); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /Observer/CleanStoreLocatorCache.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2018 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Observer; 14 | 15 | use Magento\Framework\App\CacheInterface; 16 | use Magento\Framework\Event\ManagerInterface; 17 | use Magento\Framework\Event\Observer; 18 | use Magento\Framework\Event\ObserverInterface; 19 | use Magento\Framework\Indexer\CacheContext; 20 | use Magento\Framework\Indexer\CacheContextFactory; 21 | use Smile\Seller\Api\Data\SellerInterface; 22 | use Smile\StoreLocator\Block\Search; 23 | 24 | /** 25 | * Clean store locator cache observer. 26 | * 27 | * @category Smile 28 | * @package Smile\StoreLocator 29 | */ 30 | class CleanStoreLocatorCache implements ObserverInterface 31 | { 32 | /** 33 | * @var CacheContextFactory 34 | */ 35 | protected $cacheContextFactory; 36 | 37 | /** 38 | * @var ManagerInterface 39 | */ 40 | protected $eventManager; 41 | 42 | /** 43 | * @var CacheInterface 44 | */ 45 | protected $cache; 46 | 47 | /** 48 | * CleanStoreLocatorCache constructor. 49 | * 50 | * @param CacheContextFactory $cacheContextFactory CacheContextFactory. 51 | * @param ManagerInterface $eventManager EventManager. 52 | * @param CacheInterface $cache Cache. 53 | */ 54 | public function __construct(CacheContextFactory $cacheContextFactory, ManagerInterface $eventManager, CacheInterface $cache) 55 | { 56 | $this->cacheContextFactory = $cacheContextFactory; 57 | $this->eventManager = $eventManager; 58 | $this->cache = $cache; 59 | } 60 | 61 | /** 62 | * Clean store locator marker cache when save a seller. 63 | * 64 | * @param Observer $observer Observer. 65 | * 66 | * @return void 67 | * @SuppressWarnings(PHPMD.UnusedFormalParameters) 68 | */ 69 | public function execute(Observer $observer) 70 | { 71 | /** @var SellerInterface $seller */ 72 | $seller = $observer->getEvent()->getSeller(); 73 | 74 | if ($seller->hasDataChanges()) { 75 | /** @var CacheContext $cacheContext */ 76 | $cacheContext = $this->cacheContextFactory->create(); 77 | $cacheContext->registerTags([Search::CACHE_TAG]); 78 | $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $cacheContext]); 79 | 80 | $this->cache->clean([Search::CACHE_TAG]); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Plugin/RetailerEditFormPlugin.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Plugin; 14 | 15 | use Smile\Retailer\Api\Data\RetailerInterface; 16 | use Smile\Seller\Ui\Component\Seller\Form\DataProvider; 17 | 18 | /** 19 | * Retailer form data provider plugin. 20 | * 21 | * @category Smile 22 | * @package Smile\StoreLocator 23 | * @author Aurelien FOUCRET 24 | */ 25 | class RetailerEditFormPlugin 26 | { 27 | /** 28 | * @param DataProvider $subject 29 | * @param array $result 30 | * 31 | * @return array 32 | */ 33 | public function afterGetData(DataProvider $subject, $result) 34 | { 35 | $retailer = $this->getRetailer($subject); 36 | 37 | if ($retailer !== null && $retailer->getExtensionAttributes()->getAddress()) { 38 | $address = $retailer->getExtensionAttributes()->getAddress(); 39 | $result[$retailer->getId()]['address'] = $address->getData(); 40 | 41 | if ($address->getCoordinates()) { 42 | $result[$retailer->getId()]['address']['coordinates'] = [ 43 | 'latitude' => $address->getCoordinates()->getLatitude(), 44 | 'longitude' => $address->getCoordinates()->getLongitude(), 45 | ]; 46 | } 47 | } 48 | 49 | return $result; 50 | } 51 | 52 | /** 53 | * Return the currently edited retailer. 54 | * 55 | * @param DataProvider $dataProvider DataProvider. 56 | * 57 | * @return NULL|RetailerInterface 58 | */ 59 | private function getRetailer(DataProvider $dataProvider) 60 | { 61 | $retailer = $dataProvider->getCollection()->getFirstItem(); 62 | 63 | return $retailer instanceof RetailerInterface ? $retailer : null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Plugin/RetailerUiComponentFormPlugin.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2019 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Plugin; 14 | 15 | use Magento\Ui\Component\Form; 16 | 17 | /** 18 | * Retailer ui component form plugin. 19 | * 20 | * @category Smile 21 | * @package Smile\StoreLocator 22 | * @author Fanny DECLERCK 23 | */ 24 | class RetailerUiComponentFormPlugin 25 | { 26 | /** 27 | * Data source name 28 | */ 29 | const DATA_SOURCE_NAME = 'storelocator_retailer_mass_edit_hours_form_data_source'; 30 | 31 | /** 32 | * @param Form $subject 33 | * @param array $result 34 | * 35 | * @return array 36 | */ 37 | public function afterGetDataSourceData(Form $subject, array $result) 38 | { 39 | $dataProvider = $subject->getContext()->getDataProvider(); 40 | if ($dataProvider->getName() == self::DATA_SOURCE_NAME && empty($result['data'])) { 41 | $result['data'] = $dataProvider->getData(); 42 | } 43 | 44 | return $result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Smile Store Locator 2 | 3 | This module adds a store locator to the website. You can search a retailer on map. 4 | 5 | ### Requirements 6 | 7 | The module requires : 8 | 9 | - [Retailer](https://github.com/Smile-SA/magento2-module-retailer) > 1.2.* 10 | - [Map](https://github.com/Smile-SA/magento2-module-map) > 2.0.* 11 | 12 | ### How to use 13 | 14 | 1. Install the module via Composer : 15 | 16 | ``` composer require smile/module-store-locator ``` 17 | 18 | 2. Enable it 19 | 20 | ``` bin/magento module:enable Smile_StoreLocator ``` 21 | 22 | 3. Install the module and rebuild the DI cache 23 | 24 | ``` bin/magento setup:upgrade ``` 25 | 26 | ### How to configure 27 | 28 | > Stores > Configuration > Services > Smile Map > Map Settings 29 | 30 | Maximum number of visible stores : Above this limit, the list of stores will be not display 31 | 32 | ### Add autocompletion 33 | 34 | To add autocompletion you need to add this module : 35 | 36 | [RetailerSearch](https://github.com/Smile-SA/magento2-module-retailer-elasticsuite-search) 37 | /!\ be careful with dependencies -------------------------------------------------------------------------------- /Setup/InstallData.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Setup; 14 | 15 | use Magento\Eav\Setup\EavSetup; 16 | use Magento\Eav\Setup\EavSetupFactory; 17 | use Magento\Framework\Setup\InstallDataInterface; 18 | use Magento\Framework\Setup\ModuleContextInterface; 19 | use Magento\Framework\Setup\ModuleDataSetupInterface; 20 | use Smile\StoreLocator\Setup\StoreLocatorSetupFactory; 21 | 22 | /** 23 | * Store locator data setup. 24 | * 25 | * @category Smile 26 | * @package Smile\StoreLocator 27 | * @author Aurelien FOUCRET 28 | */ 29 | class InstallData implements InstallDataInterface 30 | { 31 | /** 32 | * @var EavSetupFactory 33 | */ 34 | private $eavSetupFactory; 35 | 36 | /** 37 | * @var \Smile\StoreLocator\Setup\StoreLocatorSetup 38 | */ 39 | private $storeLocatorSetup; 40 | 41 | /** 42 | * Constructor. 43 | * 44 | * @param EavSetupFactory $eavSetupFactory EAV Setup Factory. 45 | * @param StoreLocatorSetupFactory $storeLocatorSetupFactory The Store Locator Setup Factory 46 | */ 47 | public function __construct(EavSetupFactory $eavSetupFactory, StoreLocatorSetupFactory $storeLocatorSetupFactory) 48 | { 49 | $this->eavSetupFactory = $eavSetupFactory; 50 | $this->storeLocatorSetup = $storeLocatorSetupFactory->create(); 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 57 | { 58 | /** @var EavSetup $eavSetup */ 59 | $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); 60 | 61 | $this->storeLocatorSetup->addUrlKeyAttribute($eavSetup); 62 | $this->storeLocatorSetup->addContactInformation($eavSetup); 63 | $this->storeLocatorSetup->addImage($eavSetup); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Setup/InstallSchema.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2016 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Setup; 14 | 15 | use Magento\Framework\Setup\InstallSchemaInterface; 16 | use Magento\Framework\Setup\ModuleContextInterface; 17 | use Magento\Framework\Setup\SchemaSetupInterface; 18 | use Smile\StoreLocator\Setup\StoreLocatorSetup; 19 | use Smile\StoreLocator\Setup\StoreLocatorSetupFactory; 20 | 21 | /** 22 | * Store locator schema setup. 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Aurelien FOUCRET 27 | */ 28 | class InstallSchema implements InstallSchemaInterface 29 | { 30 | /** 31 | * @var StoreLocatorSetup 32 | */ 33 | private $storeLocatorSetup; 34 | 35 | /** 36 | * InstallSchema constructor. 37 | * 38 | * @param StoreLocatorSetupFactory $storeLocatorSetupFactory The Store Locator Setup Factory 39 | */ 40 | public function __construct(StoreLocatorSetupFactory $storeLocatorSetupFactory) 41 | { 42 | $this->storeLocatorSetup = $storeLocatorSetupFactory->create(); 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | * @throws \Zend_Db_Exception 48 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) 49 | */ 50 | public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) 51 | { 52 | $setup->startSetup(); 53 | $this->storeLocatorSetup->createRetailerAddressTable($setup); 54 | $this->storeLocatorSetup->createOpeningHoursTable($setup); 55 | $setup->endSetup(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Setup/UpgradeData.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Setup; 14 | 15 | use Magento\Framework\Exception\LocalizedException; 16 | use Magento\Framework\Setup\ModuleContextInterface; 17 | use Magento\Framework\Setup\ModuleDataSetupInterface; 18 | use Magento\Framework\Setup\UpgradeDataInterface; 19 | use Magento\Eav\Setup\EavSetupFactory; 20 | 21 | /** 22 | * Data Upgrade for Store Locator 23 | * 24 | * @category Smile 25 | * @package Smile\StoreLocator 26 | * @author Romain Ruaud 27 | */ 28 | class UpgradeData implements UpgradeDataInterface 29 | { 30 | /** 31 | * @var EavSetupFactory 32 | */ 33 | private $eavSetupFactory; 34 | 35 | /** 36 | * @var \Smile\StoreLocator\Setup\StoreLocatorSetup 37 | */ 38 | private $storeLocatorSetup; 39 | 40 | /** 41 | * Constructor. 42 | * 43 | * @param EavSetupFactory $eavSetupFactory EAV Setup Factory. 44 | * @param StoreLocatorSetupFactory $storeLocatorSetupFactory The Store Locator Setup Factory 45 | */ 46 | public function __construct(EavSetupFactory $eavSetupFactory, StoreLocatorSetupFactory $storeLocatorSetupFactory) 47 | { 48 | $this->eavSetupFactory = $eavSetupFactory; 49 | $this->storeLocatorSetup = $storeLocatorSetupFactory->create(); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | * @throws LocalizedException 55 | * @throws \Zend_Validate_Exception 56 | */ 57 | public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 58 | { 59 | /** @var EavSetup $eavSetup */ 60 | $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); 61 | 62 | if (version_compare($context->getVersion(), '1.2.0', '<')) { 63 | $this->storeLocatorSetup->addContactInformation($eavSetup); 64 | } 65 | 66 | if (version_compare($context->getVersion(), '1.2.1', '<')) { 67 | $this->storeLocatorSetup->setContactFormRequired($eavSetup); 68 | } 69 | 70 | if (version_compare($context->getVersion(), '2.0.0', '<')) { 71 | $this->storeLocatorSetup->addImage($eavSetup); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Setup/UpgradeSchema.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | namespace Smile\StoreLocator\Setup; 14 | 15 | use Magento\Framework\Setup\ModuleContextInterface; 16 | use Magento\Framework\Setup\SchemaSetupInterface; 17 | use Magento\Framework\Setup\UpgradeSchemaInterface; 18 | 19 | use Smile\StoreLocator\Setup\StoreLocatorSetup; 20 | use Smile\StoreLocator\Setup\StoreLocatorSetupFactory; 21 | 22 | /** 23 | * Upgrade Schema for StoreLocator Module 24 | * 25 | * @category Smile 26 | * @package Smile\StoreLocator 27 | * @author Romain Ruaud 28 | */ 29 | class UpgradeSchema implements UpgradeSchemaInterface 30 | { 31 | /** 32 | * @var StoreLocatorSetup 33 | */ 34 | private $storeLocatorSetup; 35 | 36 | /** 37 | * InstallSchema constructor. 38 | * 39 | * @param StoreLocatorSetupFactory $storeLocatorSetupFactory The Store Locator Setup Factory 40 | */ 41 | public function __construct(StoreLocatorSetupFactory $storeLocatorSetupFactory) 42 | { 43 | $this->storeLocatorSetup = $storeLocatorSetupFactory->create(); 44 | } 45 | 46 | /** 47 | * Installs DB schema for a module 48 | * 49 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 50 | * 51 | * @param SchemaSetupInterface $setup Setup 52 | * @param ModuleContextInterface $context Context 53 | * 54 | * @throws \Zend_Db_Exception 55 | * @return void 56 | */ 57 | public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) 58 | { 59 | $setup->startSetup(); 60 | 61 | if (version_compare($context->getVersion(), '1.1.0', '<')) { 62 | $this->storeLocatorSetup->createOpeningHoursTable($setup); 63 | } 64 | if (version_compare($context->getVersion(), '1.2.2', '<')) { 65 | $this->storeLocatorSetup->updateDecimalDegreesColumns($setup); 66 | } 67 | 68 | $setup->endSetup(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Ui/Component/Retailer/Form/DataProvider.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2019 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | 15 | namespace Smile\StoreLocator\Ui\Component\Retailer\Form; 16 | 17 | use Smile\Retailer\Model\ResourceModel\Retailer\CollectionFactory; 18 | 19 | /** 20 | * Ui DataProvider controller. 21 | * 22 | * @category Smile 23 | * @package Smile\StoreLocator 24 | * @author Fanny DECLERCK 25 | */ 26 | class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider 27 | { 28 | /** 29 | * @var \Magento\Framework\Registry 30 | */ 31 | private $registry; 32 | 33 | /** 34 | * @param string $name Name 35 | * @param string $primaryFieldName PrimaryFieldName 36 | * @param string $requestFieldName RequestFieldName 37 | * @param CollectionFactory $collectionFactory Collection 38 | * @param \Magento\Framework\Registry $registry Registry. 39 | * @param array $meta Meta 40 | * @param array $data Data 41 | */ 42 | public function __construct( 43 | $name, 44 | $primaryFieldName, 45 | $requestFieldName, 46 | CollectionFactory $collectionFactory, 47 | \Magento\Framework\Registry $registry, 48 | array $meta = [], 49 | array $data = [] 50 | ) { 51 | $this->collection = $collectionFactory->create(); 52 | $this->registry = $registry; 53 | 54 | parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); 55 | } 56 | 57 | /** 58 | * Get data 59 | * 60 | * @return array 61 | */ 62 | public function getData() 63 | { 64 | if (!isset($this->loadData)) { 65 | $this->loadData = []; 66 | if ($retailerIds = $this->getRetailerIds()) { 67 | $this->registry->unregister('retailer_ids'); 68 | $this->loadData = [ 69 | 'retailer_ids' => json_encode($retailerIds), 70 | ]; 71 | } 72 | } 73 | 74 | return $this->loadData; 75 | } 76 | 77 | /** 78 | * Get retailer ids 79 | * 80 | * @return int 81 | */ 82 | private function getRetailerIds() 83 | { 84 | return $this->registry->registry('retailer_ids'); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smile/module-store-locator", 3 | "type": "magento2-module", 4 | "description": "Smile Store Locator", 5 | "keywords": ["magento2", "map", "geocoding", "geolocalisation", "retail"], 6 | "repositories": [ 7 | { 8 | "type": "composer", 9 | "url": "https://repo.magento.com/" 10 | } 11 | ], 12 | "require": { 13 | "php": "~8.0", 14 | "magento/framework": "*", 15 | "magento/module-store": "*", 16 | "magento/module-contact": "*", 17 | "smile/module-map": "~1.1.0 || ~2.0", 18 | "smile/module-retailer": "~1.2.0", 19 | "willdurand/geocoder": "^3.3 || ^4.4" 20 | }, 21 | "require-dev": { 22 | "smile/magento2-smilelab-quality-suite": "1.0.0" 23 | }, 24 | "license": "OSL-3.0", 25 | "authors": [ 26 | { 27 | "name": "Aurélien FOUCRET", 28 | "email": "aurelien.foucret@smile.fr" 29 | }, 30 | { 31 | "name": "Romain Ruaud", 32 | "email": "romain.ruaud@smile.fr" 33 | }, 34 | { 35 | "name": "Guillaume Vrac", 36 | "email": "guillaume.vrac@smile.fr" 37 | } 38 | ], 39 | "autoload": { 40 | "files": [ 41 | "registration.php" 42 | ], 43 | "psr-4": { 44 | "Smile\\StoreLocator\\" : "" 45 | } 46 | }, 47 | "minimum-stability": "dev", 48 | "prefer-stable": true 49 | } 50 | -------------------------------------------------------------------------------- /etc/adminhtml/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | For example: © OpenStreetMap contributors 28 | 29 | osm 30 | 31 | 32 | 33 | 34 | For example: https://www.openstreetmap.org/copyright 35 | 36 | osm 37 | 38 | 39 | 40 | 41 | Above this limit, the list of stores will be not display 42 | 43 | 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | © OpenStreetMap contributors 23 | https://www.openstreetmap.org/copyright 24 | 1000 25 | 26 | 27 | 28 | 29 | stores 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | smile_retailer_address 28 | address_id 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Smile\StoreLocator\Model\Retailer\AddressSaveHandler 40 | Smile\StoreLocator\Model\Retailer\OpeningHoursSaveHandler 41 | Smile\StoreLocator\Model\Retailer\SpecialOpeningHoursSaveHandler 42 | 43 | 44 | Smile\StoreLocator\Model\Retailer\AddressSaveHandler 45 | Smile\StoreLocator\Model\Retailer\OpeningHoursSaveHandler 46 | Smile\StoreLocator\Model\Retailer\SpecialOpeningHoursSaveHandler 47 | 48 | 49 | Smile\StoreLocator\Model\Retailer\AddressReadHandler 50 | Smile\StoreLocator\Model\Retailer\OpeningHoursReadHandler 51 | Smile\StoreLocator\Model\Retailer\SpecialOpeningHoursReadHandler 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Smile\StoreLocator\Model\Retailer\AddressPostDataHandler 62 | Smile\StoreLocator\Model\Retailer\OpeningHoursPostDataHandler 63 | Smile\StoreLocator\Model\Retailer\SpecialOpeningHoursPostDataHandler 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /etc/extension_attributes.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 25 | street 26 | postcode 27 | city 28 | region 29 | region_id 30 | country_id 31 | latitude 32 | longitude 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | Smile\StoreLocator\Controller\Router 24 | false 25 | 50 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Smile\StoreLocator\CustomerData\CurrentStore 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /etc/frontend/sections.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /i18n/en_US.csv: -------------------------------------------------------------------------------- 1 | "%s result(s)","%s result(s)" 2 | "%s shop(s) nearby","%s shop(s) nearby" 3 | "* Required Fields","* Required Fields" 4 | "Above this limit, the list of stores will be not display","Above this limit, the list of stores will be not display" 5 | "Add Special Opening Hours","Add Special Opening Hours" 6 | "Apply for retailers","Apply for retailers" 7 | "Back to results", "Back to results" 8 | "Choose this store","Choose this store" 9 | "City, Zipcode, Department, ...","City, Zipcode, Department, ..." 10 | "Closed (%1)","Closed (%1)" 11 | "Closing soon (%1)","Closing soon (%1)" 12 | "Contact %1","Contact %1" 13 | "Contact form cannot be empty","Contact form cannot be empty" 14 | "Contact mail cannot be empty","Contact mail cannot be empty" 15 | "Contact Us","Contact Us" 16 | "Double-click on an opening hour range to delete it.","Double-click on an opening hour range to delete it." 17 | "Find a store ...","Find a store ..." 18 | "Find a store :","Find a store :" 19 | "Geolocalize me","Geolocalize me" 20 | "Go there","Go there" 21 | "Go to Home Page","Go to Home Page" 22 | "Maximum number of visible stores","Maximum number of visible stores" 23 | "My store : %s","My store : %s" 24 | "Name cannot be empty","Name cannot be empty" 25 | "Narrow your search to see store details","Narrow your search to see store details" 26 | "Open Today (%1)","Open Today (%1)" 27 | "Open Today","Open Today" 28 | "Opening Hours","Opening Hours" 29 | "Our stores","Our stores" 30 | "Phone Number","Phone Number" 31 | "Retailer url_key ""%1"" already exists.","Retailer url_key ""%1"" already exists." 32 | "Shop Search","Shop Search" 33 | "Shops nearby", "Shops nearby" 34 | "Special Opening Hours","Special Opening Hours" 35 | "Store Address","Store Address" 36 | "Thanks for contacting us with your comments and questions. We'll respond to you very soon.","Thanks for contacting us with your comments and questions. We'll respond to you very soon." 37 | "today","today" 38 | "Unable to retrieve retailer informations","Unable to retrieve retailer informations" 39 | "Unable to validate form","Unable to validate form" 40 | "until","until" 41 | "View all","View all" 42 | "View Shop Page","View Shop Page" 43 | "We are sorry, an error occured when switching retailer.","We are sorry, an error occured when switching retailer." 44 | "We can't process your request right now. Sorry, that's all we know.","We can't process your request right now. Sorry, that's all we know." 45 | "What’s on your mind?","What’s on your mind?" 46 | "Write Us","Write Us" 47 | Address,Address 48 | City,City 49 | Close,Close 50 | Closed,Closed 51 | Contact,Contact 52 | Country,Country 53 | Details,Details 54 | Email,Email 55 | Fax,Fax 56 | Home,Home 57 | Latitude,Latitude 58 | Longitude,Longitude 59 | Mail,Mail 60 | Name,Name 61 | Opened,Opened 62 | Postcode,Postcode 63 | Search,Search 64 | Street,Street 65 | Submit,Submit 66 | Tel,Tel 67 | Telephone,Telephone 68 | -------------------------------------------------------------------------------- /i18n/fr_FR.csv: -------------------------------------------------------------------------------- 1 | "%s result(s)","%s résultat(s)" 2 | "%s shop(s) nearby","%s magasin(s) à proximité" 3 | "* Required Fields","* Champs obligatoires" 4 | "Above this limit, the list of stores will be not display","Au-delà de cette limite, la liste des magasins ne sera pas affichée" 5 | "Add Special Opening Hours","Ajouter une heure d'ouverture exceptionnelle" 6 | "Apply for retailers","Appliquer pour les magasins" 7 | "Back to results","Retourner à la liste" 8 | "Choose this store","Choisir ce magasin" 9 | "City, Zipcode, Department, ...","Ville, Code postal, Département ..." 10 | "Closed (%1)","Fermé (%1)" 11 | "Closing soon (%1)","Fermeture imminente (%1)" 12 | "Contact %1","Contacter %1" 13 | "Contact form cannot be empty","Le formulaire de contact ne peut pas être laissé vide" 14 | "Contact mail cannot be empty","L'adresse email ne peut pas être vide" 15 | "Contact Us","Contactez Nous" 16 | "Double-click on an opening hour range to delete it.","Double-cliquez sur une tranche horaire pour la supprimer." 17 | "Find a store ...","Trouver un magasin ..." 18 | "Find a store :","Trouver un magasin :" 19 | "Geolocalize me","Me géolocaliser" 20 | "Go there","M’y rendre" 21 | "Go to Home Page","Aller à la page d'accueil" 22 | "Maximum number of visible stores","Nombre maximum de magasins visible" 23 | "My store : %s","Mon magasin : %s" 24 | "Name cannot be empty","Le nom ne peut pas être vide" 25 | "Narrow your search to see store details","Affinez votre recherche pour voir le détail des magasins" 26 | "Open Today (%1)","Ouvert aujourd'hui (%1)" 27 | "Open Today","Ouvert aujourd'hui" 28 | "Opening Hours","Horaires d'ouverture" 29 | "Our stores","Nos magasins" 30 | "Phone Number","Numéro de téléphone" 31 | "Retailer url_key ""%1"" already exists.","La clef d'url ""%1"" existe déjà." 32 | "Shop Search","Localiser un magasin" 33 | "Shops nearby", "Commerces à proximité" 34 | "Special Opening Hours","Horaires exceptionnels" 35 | "Store Address","Adresse du magasin" 36 | "Thanks for contacting us with your comments and questions. We'll respond to you very soon.","Merci de nous avoir soumis votre question. Nous vous répondrons très bientôt." 37 | "today","aujourd'hui" 38 | "Unable to retrieve retailer informations","Impossible de récupérer les informations du magasin" 39 | "Unable to validate form","Impossible de valider le formulaire" 40 | "until","jusqu'à" 41 | "View all","Voir tout" 42 | "View Shop Page","Voir la page du magasin" 43 | "We are sorry, an error occured when switching retailer.","Nous sommes désolés, une erreur s'est produite durant le choix du magasin." 44 | "We can't process your request right now. Sorry, that's all we know.","Nous sommes désolés, une erreur s'est produite durant l'envoi du formulaire." 45 | "What’s on your mind?","Que souhaitez-vous nous dire ?" 46 | "Write Us","Nous écrire" 47 | Address,Adresse 48 | City,Ville 49 | Close,Fermer 50 | Closed,Fermé 51 | Contact,Contact 52 | Country,Pays 53 | Details,Détails 54 | Email,Email 55 | Fax,Fax 56 | Home,Accueil 57 | Latitude,Latitude 58 | Longitude,Longitude 59 | Mail,Mail 60 | Name,Name 61 | Opened,Ouvert 62 | Postcode,"Code postal" 63 | Search,Search 64 | Street,Rue 65 | Submit,Envoyer 66 | Tel,Tél 67 | Telephone,Téléphone 68 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | 15 | \Magento\Framework\Component\ComponentRegistrar::register( 16 | \Magento\Framework\Component\ComponentRegistrar::MODULE, 17 | 'Smile_StoreLocator', 18 | __DIR__ 19 | ); 20 | -------------------------------------------------------------------------------- /view/adminhtml/layout/smile_store_locator_retailer_massedithours.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /view/adminhtml/requirejs-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DISCLAIMER 3 | * 4 | * Do not edit or add to this file if you wish to upgrade this module to newer 5 | * versions in the future. 6 | * 7 | * 8 | * @category Smile 9 | * @package Smile\StoreLocator 10 | * @author Romain Ruaud 11 | * @copyright 2017 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | 15 | var config = { 16 | map: { 17 | '*': { 18 | estira: 'Smile_StoreLocator/js/elessar/estira', 19 | elessar: 'Smile_StoreLocator/js/elessar/elessar', 20 | openingHours : 'Smile_StoreLocator/js/opening-hours/rangebar' 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /view/adminhtml/templates/retailer/openinghours/container.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2017 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Opening Hours form element renderer. 15 | */ 16 | ?> 17 | 18 | getElement(); 22 | $fieldId = ($element->getHtmlContainerId()) ? ' id="' . $element->getHtmlContainerId() . '"' : ''; 23 | $fieldClass = "fieldset-{$element->getId()} {$element->getClass()}"; 24 | $fieldClass .= ($element->getRequired()) ? ' required' : ''; 25 | $fieldAttributes = $fieldId . ' class="' . $fieldClass . '" ' . $block->getUiId('form-field', $element->getId()); 26 | ?> 27 | 28 | > 29 |
30 |

31 |
32 | getInputHtml() ?> 33 | 34 | -------------------------------------------------------------------------------- /view/adminhtml/templates/retailer/openinghours/element.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Opening Hours form element renderer. 15 | */ 16 | ?> 17 | 18 | getElement(); 22 | $fieldId = ($element->getHtmlContainerId()) ? ' id="' . $element->getHtmlContainerId() . '"' : ''; 23 | $fieldClass = "field admin__field field-{$element->getId()} {$element->getClass()}"; 24 | $fieldClass .= ($element->getRequired()) ? ' required' : ''; 25 | $fieldAttributes = $fieldId . ' class="' . $fieldClass . '" ' . $block->getUiId('form-field', $element->getId()); 26 | ?> 27 | 28 | > 29 | getLabelHtml() ?> 30 | getHtmlId() ; ?> 31 |
32 |
33 |
34 | getInputHtml() ?> 35 |
36 | 37 | 38 | 73 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/smile_retailer_listing.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | opening_hours 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /view/adminhtml/web/css/source/_module.less: -------------------------------------------------------------------------------- 1 | // /** 2 | // * DISCLAIMER 3 | // * 4 | // * Do not edit or add to this file if you wish to upgrade this module to newer 5 | // * versions in the future. 6 | // * 7 | // * @category Smile 8 | // * @package Smile\Retailer 9 | // * @author Romain Ruaud 10 | // * @copyright 2016 Smile 11 | // * @license Open Software License ("OSL") v. 3.0 12 | // */ 13 | 14 | /** Import the base elessar module stylesheet **/ 15 | @import (inline) 'elessar/elessar.less'; 16 | 17 | @timebar-height: 10px; 18 | 19 | .opening-hours-container-fieldset { 20 | margin-left:70px; 21 | margin-top: -30px; 22 | 23 | .admin__field-tooltip { 24 | max-width: 100%; 25 | width: 100%; 26 | margin-bottom: 20px; 27 | .admin__field-tooltip-action { 28 | &:before { 29 | margin-right: 5px; 30 | } 31 | } 32 | } 33 | } 34 | 35 | .opening-hours-fieldset-wrapper { 36 | .admin__fieldset { 37 | padding-top: 1rem; 38 | } 39 | } 40 | 41 | .elessar-range { 42 | background:@color-phoenix; 43 | height: @timebar-height; 44 | overflow: visible; 45 | } 46 | .elessar-handle { 47 | background-color: @color-gray85; 48 | border-radius: 4px; 49 | border: 1px solid @color-dark-gray; 50 | height: 15px; 51 | top: -3px; 52 | width: 15px; 53 | } 54 | .elessar-rangebar { 55 | height: @timebar-height; 56 | } 57 | div.opening-hours-container { 58 | margin-bottom: 20px; 59 | width: 80%; 60 | label { 61 | margin-top: 20px; 62 | } 63 | } 64 | div.opening-hours-rangebar { 65 | div.elessar-rangebar { 66 | background: #FFFFFF; 67 | border: 1px solid @color-dark-grayish; 68 | margin-left: -1px; 69 | } 70 | } 71 | div.opening-hours-indicator { 72 | margin-top: 40px; 73 | span.elessar-barlabel { 74 | color: @color-dark-gray; 75 | left: -30px; 76 | position:relative; 77 | top:-35px; 78 | &:after { 79 | border-left: 1px solid @color-dark-gray; 80 | content: " "; 81 | display: block; 82 | height: @timebar-height; 83 | left: 29px; 84 | position: relative; 85 | top: -5px; 86 | } 87 | } 88 | .elessar-rangebar { 89 | height: 0; 90 | } 91 | } 92 | span.opening-hours-day { 93 | color: @color-dark-gray; 94 | font-size: 80%; 95 | } 96 | 97 | .admin__control-table td { 98 | .admin__control-text._has-datepicker.smile-special-opening-hours-datepicker { 99 | width: 15rem; 100 | } 101 | .opening-hours-wrapper { 102 | min-width: 90rem; 103 | margin-left: 10%; 104 | .opening-hours-container { 105 | width: 90%; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /view/adminhtml/web/css/source/elessar/elessar.less: -------------------------------------------------------------------------------- 1 | .elessar-handle { 2 | display: block; 3 | background: black; 4 | height: 100%; 5 | width: 5px; 6 | cursor: ew-resize; 7 | position: absolute; 8 | top: 0; 9 | bottom: 0; 10 | } 11 | .elessar-handle:first-child { 12 | left: 0; 13 | } 14 | .elessar-handle:last-child { 15 | right: 0; 16 | } 17 | .elessar-vertical .elessar-handle { 18 | height: 5px; 19 | width: 100%; 20 | left: 0; 21 | right: 0; 22 | top: auto; 23 | bottom: auto; 24 | cursor: ns-resize; 25 | } 26 | .elessar-vertical .elessar-handle:first-child { 27 | top: 0; 28 | } 29 | .elessar-vertical .elessar-handle:last-child { 30 | bottom: 0; 31 | } 32 | .elessar-indicator { 33 | position: absolute; 34 | background: black; 35 | border-color: white; 36 | border-style: solid; 37 | border-width: 0 1px; 38 | width: 2px; 39 | height: 100%; 40 | z-index: 15; 41 | } 42 | .elessar-vertical .elessar-indicator { 43 | width: 100%; 44 | height: 2px; 45 | } 46 | .elessar-range { 47 | position: absolute; 48 | cursor: pointer; 49 | cursor: -webkit-grab; 50 | cursor: -moz-grab; 51 | cursor: grab; 52 | overflow: hidden; 53 | text-overflow: ellipsis; 54 | white-space: nowrap; 55 | background: blue; 56 | width: 0; 57 | z-index: 10; 58 | } 59 | .elessar-vertical .elessar-range { 60 | width: auto; 61 | height: 0; 62 | } 63 | .elessar-label { 64 | position: absolute; 65 | z-index: 5; 66 | pointer-events: none; 67 | border-left: 1px solid #999; 68 | padding-left: 10px; 69 | } 70 | .elessar-readonly { 71 | opacity: 0.6; 72 | cursor: default !important; 73 | } 74 | .elessar-phantom { 75 | background-color: transparent; 76 | background: rgba(0,0,0,0.5); 77 | color: white; 78 | cursor: pointer !important; 79 | } 80 | .elessar-rangebar { 81 | position: relative; 82 | height: 30px; 83 | line-height: 30px; 84 | background: #ccc; 85 | -webkit-touch-callout: none; 86 | -webkit-user-select: none; 87 | -khtml-user-select: none; 88 | -moz-user-select: none; 89 | -ms-user-select: none; 90 | user-select: none; 91 | } 92 | .elessar-delete-confirm { 93 | background: red; 94 | } 95 | body.elessar-resizing, body.elessar-dragging { 96 | -webkit-touch-callout: none; 97 | -webkit-user-select: none; 98 | -khtml-user-select: none; 99 | -moz-user-select: none; 100 | -ms-user-select: none; 101 | user-select: none; 102 | } 103 | body.elessar-resizing, 104 | body.elessar-resizing .bar, 105 | body.elessar-resizing .handle { 106 | cursor: ew-resize !important; 107 | } 108 | body.elessar-resizing.elessar-resizing-vertical, 109 | body.elessar-resizing.elessar-resizing-vertical .bar, 110 | body.elessar-resizing.elessar-resizing-vertical .handle { 111 | cursor: ns-resize !important; 112 | } 113 | body.elessar-dragging, 114 | body.elessar-dragging .bar, 115 | body.elessar-dragging .handle { 116 | cursor: move !important; 117 | cursor: -webkit-grabbing !important; 118 | cursor: -moz-grabbing !important; 119 | cursor: grabbing !important; 120 | } 121 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/component/retailer/opening-hours.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DISCLAIMER 3 | * 4 | * Do not edit or add to this file if you wish to upgrade this module to newer 5 | * versions in the future. 6 | * 7 | * @category Smile 8 | * @package Smile\StoreLocator 9 | * @author Romain Ruaud 10 | * @copyright 2017 Smile 11 | * @license Open Software License ("OSL") v. 3.0 12 | */ 13 | 14 | define([ 15 | 'Magento_Ui/js/form/components/html', 16 | 'jquery' 17 | ], function (Component, $) { 18 | 'use strict'; 19 | 20 | return Component.extend({ 21 | defaults: { 22 | value: {}, 23 | links: { 24 | value: '${ $.provider }:${ $.dataScope }' 25 | }, 26 | additionalClasses: "admin__fieldset" 27 | }, 28 | 29 | /** 30 | * Initialize the component 31 | */ 32 | initialize: function () 33 | { 34 | this._super(); 35 | this.initOpeningHoursListener(); 36 | }, 37 | 38 | /** 39 | * Init Observation on fields 40 | * 41 | * @returns {exports} 42 | */ 43 | initObservable: function () 44 | { 45 | this._super(); 46 | this.openingHoursObject = {}; 47 | this.observe('openingHoursObject value'); 48 | 49 | return this; 50 | }, 51 | 52 | /** 53 | * Init Observer on the opening hours fields. 54 | */ 55 | initOpeningHoursListener: function () 56 | { 57 | var observer = new MutationObserver(function () { 58 | var rootNode = document.getElementById(this.index); 59 | if (rootNode !== null) { 60 | this.rootNode = document.getElementById(this.index); 61 | observer.disconnect(); 62 | var openingHoursObserver = new MutationObserver(this.updateOpeningHours.bind(this)); 63 | var openingHoursObserverConfig = {childList:true, subtree: true, attributes: true}; 64 | openingHoursObserver.observe(rootNode, openingHoursObserverConfig); 65 | this.updateOpeningHours(); 66 | } 67 | }.bind(this)); 68 | var observerConfig = {childList: true, subtree: true}; 69 | observer.observe(document, observerConfig) 70 | }, 71 | 72 | /** 73 | * Update value of the Opening Hours Object 74 | */ 75 | updateOpeningHours: function () 76 | { 77 | var openingHoursObject = {}; 78 | var hashValues = []; 79 | 80 | $(this.rootNode).find("[name*=" + this.index + "]").each(function () { 81 | hashValues.push(this.name + this.value.toString()); 82 | var currentOpeningHoursObject = openingHoursObject; 83 | 84 | var path = this.name.match(/\[([^[\[\]]+)\]/g) 85 | .map(function (pathItem) { return pathItem.substr(1, pathItem.length-2); }); 86 | 87 | while (path.length > 1) { 88 | var currentKey = path.shift(); 89 | 90 | if (currentOpeningHoursObject[currentKey] === undefined) { 91 | currentOpeningHoursObject[currentKey] = {}; 92 | } 93 | 94 | currentOpeningHoursObject = currentOpeningHoursObject[currentKey]; 95 | } 96 | 97 | currentKey = path.shift(); 98 | currentOpeningHoursObject[currentKey] = $(this).val(); 99 | }); 100 | 101 | var newHashValue = hashValues.sort().join(''); 102 | 103 | if (newHashValue !== this.currentHashValue) { 104 | if (this.currentHashValue !== undefined) { 105 | this.bubble('update', true); 106 | } 107 | this.currentHashValue = newHashValue; 108 | this.openingHoursObject(openingHoursObject); 109 | 110 | this.value(openingHoursObject); 111 | } 112 | } 113 | }) 114 | }); 115 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/elessar/estira.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | (function(definition){ 3 | switch (false) { 4 | case !(typeof define === 'function' && define.amd != null): 5 | return define([], definition); 6 | case typeof exports !== 'object': 7 | return module.exports = definition(); 8 | default: 9 | return this.Base = definition(); 10 | } 11 | })(function(){ 12 | var Base; 13 | return Base = (function(){ 14 | Base.displayName = 'Base'; 15 | var attach, prototype = Base.prototype, constructor = Base; 16 | attach = function(obj, name, prop, super$, superclass$){ 17 | return obj[name] = typeof prop === 'function' ? import$(function(){ 18 | var this$ = this; 19 | prop.superclass$ = superclass$; 20 | prop.super$ = function(){ 21 | return super$.apply(this$, arguments); 22 | }; 23 | return prop.apply(this, arguments); 24 | }, prop) : prop; 25 | }; 26 | Base.extend = function(displayName, proto){ 27 | proto == null && (proto = displayName); 28 | return (function(superclass){ 29 | var name, ref$, prop, prototype = extend$(import$(constructor, superclass), superclass).prototype; 30 | import$(constructor, Base); 31 | if (typeof displayName === 'string') { 32 | constructor.displayName = displayName; 33 | } 34 | function constructor(){ 35 | var this$ = this instanceof ctor$ ? this : new ctor$; 36 | this$.initialize.apply(this$, arguments); 37 | return this$; 38 | } function ctor$(){} ctor$.prototype = prototype; 39 | prototype.initialize = function(){ 40 | if (superclass.prototype.initialize != null) { 41 | return superclass.prototype.initialize.apply(this, arguments); 42 | } else { 43 | return superclass.apply(this, arguments); 44 | } 45 | }; 46 | for (name in ref$ = proto) { 47 | prop = ref$[name]; 48 | attach(prototype, name, prop, prototype[name], superclass); 49 | } 50 | return constructor; 51 | }(this)); 52 | }; 53 | Base.meta = function(meta){ 54 | var name, prop; 55 | for (name in meta) { 56 | prop = meta[name]; 57 | attach(this, name, prop, this[name], this); 58 | } 59 | return this; 60 | }; 61 | prototype.initialize = function(){}; 62 | function Base(){} 63 | return Base; 64 | }()); 65 | }); 66 | function import$(obj, src){ 67 | var own = {}.hasOwnProperty; 68 | for (var key in src) if (own.call(src, key)) obj[key] = src[key]; 69 | return obj; 70 | } 71 | function extend$(sub, sup){ 72 | function fun(){} fun.prototype = (sub.superclass = sup).prototype; 73 | (sub.prototype = new fun).constructor = sub; 74 | if (typeof sup.extended == 'function') sup.extended(sub); 75 | return sub; 76 | } 77 | }).call(this); 78 | -------------------------------------------------------------------------------- /view/frontend/layout/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Smile_StoreLocator/js/retailer/chooser 29 | Smile_StoreLocator/retailer/chooser 30 | 31 | 32 | smile-geocoder 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /view/frontend/layout/smile_store_locator_store_contact.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /view/frontend/layout/smile_store_locator_store_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | smile-storelocator-map 27 | Smile_StoreLocator/retailer/search 28 | 29 | 30 | smile-geocoder 31 | Search shop 32 | City, Zipcode, Department, ... 33 | Search 34 | 35 | 36 | uiComponent 37 | Smile_StoreLocator/retailer/search/store-list 38 | Smile_StoreLocator/retailer/search/nearby-store 39 | Smile_StoreLocator/retailer/search/store-detail 40 | %s stores 41 | %s shop(s) nearby 42 | View all 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /view/frontend/layout/smile_store_locator_store_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | itemprop="name" 26 | 27 | 28 | 29 | 30 | itemscope itemtype="http://schema.org/Store" 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | smile-map 41 | Smile_StoreLocator/retailer/store-view/view-baners-wrap 42 | Smile_StoreLocator/retailer/store-view/view-store-details 43 | Smile_StoreLocator/retailer/store-view/open-hours-view 44 | Smile_StoreLocator/retailer/store-view/nearby-store 45 | Smile_StoreLocator/retailer/store-view/view-closest-store-wrapper 46 | 47 | 48 | smile-geocoder 49 | 50 | 51 | uiComponent 52 | baners-container 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /view/frontend/requirejs-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DISCLAIMER 3 | * 4 | * Do not edit or add to this file if you wish to upgrade this module to newer 5 | * versions in the future. 6 | * 7 | * 8 | * @category Smile 9 | * @package Smile\StoreLocator 10 | * @author Romain Ruaud 11 | * @author Guillaume Vrac 12 | * @author Fanny DECLERCK 13 | * @copyright 2020 Smile 14 | * @license Open Software License ("OSL") v. 3.0 15 | */ 16 | 17 | var config = { 18 | map: { 19 | '*': { 20 | 'smile-storelocator-opening-hours': 'Smile_StoreLocator/js/retailer/opening-hours', 21 | 'smile-storelocator-map': 'Smile_StoreLocator/js/retailer/store-map', 22 | 'smile-storelocator-store': 'Smile_StoreLocator/js/model/store', 23 | 'smile-storelocator-store-collection': 'Smile_StoreLocator/js/model/stores', 24 | 'smile-storelocator-store-schedule': 'Smile_StoreLocator/js/model/store/schedule' 25 | } 26 | }, 27 | config: { 28 | mixins: { 29 | 'Smile_Map/js/map': { 30 | 'Smile_StoreLocator/js/map-mixin': true 31 | } 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /view/frontend/templates/chooser.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Retailer picker for front office 15 | */ 16 | ?> 17 | 18 | 21 | 22 | getDataScope(); ?> 23 | 24 |
25 |
26 | 27 |
28 |
42 |
43 |
44 |

45 | 46 |

47 |
48 |

49 |
50 |
51 | 52 |
53 |
54 |
55 |
56 |
57 | 76 |
77 |
78 |
79 |
80 | 81 | -------------------------------------------------------------------------------- /view/frontend/templates/contact-form.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2017 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Retailer contact information frontend view block 15 | */ 16 | ?> 17 | 18 |
24 |
25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 | 38 |
39 | 40 |
41 | 42 |
43 |
44 |
45 | 46 |
47 | 48 |
49 |
50 | getChildHtml('form.additional.info'); ?> 51 |
52 |
53 |
54 | 55 | 56 | 59 |
60 |
61 |
62 | 63 | -------------------------------------------------------------------------------- /view/frontend/templates/search.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @author Guillaume Vrac 12 | * @copyright 2016 Smile 13 | * @license Open Software License ("OSL") v. 3.0 14 | * 15 | * Retailer frontend search block 16 | */ 17 | ?> 18 | 19 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /view/frontend/templates/view.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @author Guillaume Vrac 12 | * @copyright 2016 Smile 13 | * @license Open Software License ("OSL") v. 3.0 14 | * 15 | * Retailer frontend view block 16 | */ 17 | ?> 18 | 19 | getRetailer(); 22 | ?> 23 | 24 |
25 |
26 | getChildHtml(); ?> 27 |
28 |
29 | -------------------------------------------------------------------------------- /view/frontend/templates/view/contact-information.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2017 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Retailer contact information frontend view block 15 | */ 16 | ?> 17 | 18 | hasContactInformation()) :?> 19 |
20 |
21 |

22 | 23 | 24 | getRetailer()->getContactPhone()) :?> 25 | 26 | 27 | 28 | 29 | getRetailer()->getContactFax()) :?> 30 | 31 | 32 | 33 | 34 | getRetailer()->getContactMail()) :?> 35 | 36 | 37 | 38 | 39 | 40 | showContactForm()) :?> 41 | 42 | 43 | 44 | 45 | 46 | 47 |
: escapeHtml($block->getRetailer()->getContactPhone());?>
: escapeHtml($block->getRetailer()->getContactFax());?>
: escapeHtml($block->getRetailer()->getContactMail());?>
48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /view/frontend/templates/view/map.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @author Ihor KVASNYTSKYI 12 | * @copyright 2019 Smile 13 | * @license Open Software License ("OSL") v. 3.0 14 | * 15 | * Retailer frontend view block 16 | */ 17 | ?> 18 | 19 | getRetailer(); 22 | $image = $block->getImage(); 23 | $phone = $block->getPhone(); 24 | $mail = $block->getContactMail(); 25 | $storeName = $block->getStoreName(); 26 | ?> 27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 | 37 | 38 |
39 |
40 |

41 |
42 |
43 |
44 |
45 | getAddressHtml(); ?> 46 |
47 |
48 | 49 | 50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 |
60 | 61 |
62 | . : 63 | 64 |
65 | 66 | 67 |
68 | E-mail. : 69 | 70 |
71 | 72 |
73 | 74 |
75 | 81 | 82 | getChildHtml('setstorelink') ?> 83 | 84 | 85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | 93 | 96 | -------------------------------------------------------------------------------- /view/frontend/templates/view/opening-hours.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2017 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Retailer opening hours frontend view block 15 | */ 16 | ?> 17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 | getWeekOpeningHours()) : ?> 27 | 28 | 29 |
30 | 33 | -------------------------------------------------------------------------------- /view/frontend/templates/view/setStoreLink.phtml: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | * 14 | * Retailer frontend set store link. 15 | */ 16 | ?> 17 | 18 | 21 | 22 | 30 | -------------------------------------------------------------------------------- /view/frontend/web/images/direction-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /view/frontend/web/images/direction-details.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /view/frontend/web/images/location-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /view/frontend/web/js/model/store.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'ko', 3 | 'uiClass', 4 | 'Smile_StoreLocator/js/model/store/schedule' 5 | ], function (ko, Class, Schedule) { 6 | 'use strict'; 7 | 8 | return Class.extend({ 9 | 10 | initialize: function () { 11 | if (this.schedule) { 12 | this.schedule = new Schedule(this.schedule); 13 | } 14 | 15 | this._super().initObservable(); 16 | 17 | return this; 18 | }, 19 | 20 | initObservable: function () { 21 | if (this.schedule) { 22 | this.schedule = ko.observable(new Schedule(this.schedule)); 23 | } 24 | 25 | return this; 26 | }, 27 | 28 | getSchedule: function() { 29 | return this.schedule(); 30 | } 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /view/frontend/web/js/model/stores.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'ko', 3 | 'uiClass', 4 | 'Smile_StoreLocator/js/model/store' 5 | ], function (ko, Class, Store) { 6 | 'use strict'; 7 | 8 | return Class.extend({ 9 | 10 | initialize: function () { 11 | this._super() 12 | .initObservable(); 13 | 14 | return this; 15 | }, 16 | 17 | initObservable: function () { 18 | 19 | this.items = ko.observableArray(ko.utils.arrayMap(this.items, function(store) { 20 | return new Store(store); 21 | })); 22 | 23 | return this; 24 | }, 25 | 26 | getList: function() { 27 | return this.items(); 28 | }, 29 | 30 | filter: function (callback) { 31 | return callback(this.items()); 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /view/frontend/web/js/retailer/chooser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DISCLAIMER 3 | * 4 | * Do not edit or add to this file if you wish to upgrade this module to newer 5 | * versions in the future. 6 | * 7 | * 8 | * @category Smile 9 | * @package Smile\Retailer 10 | * @author Aurelien FOUCRET 11 | * @copyright 2016 Smile 12 | * @license Open Software License ("OSL") v. 3.0 13 | */ 14 | 15 | /*jshint browser:true jquery:true*/ 16 | /*global alert*/ 17 | 18 | define(['jquery', 'uiComponent', 'Magento_Customer/js/customer-data', 'uiRegistry', 'mage/translate'], function ($, Component, storage, registry) { 19 | 20 | "use strict"; 21 | 22 | var retailer = storage.get('current-store'); 23 | 24 | return Component.extend({ 25 | 26 | /** 27 | * Component Constructor 28 | */ 29 | initialize: function () { 30 | this._super(); 31 | this.fulltextSearch = ''; 32 | this.observe(['fulltextSearch']); 33 | }, 34 | 35 | hasStore : function () { 36 | return retailer().entity_id != null; 37 | }, 38 | 39 | getLinkLabel : function () { 40 | var label = $.mage.__('Find a store ...'); 41 | 42 | if (this.hasStore()) { 43 | label = $.mage.__('My store : %s').replace("%s", this.getStoreName()); 44 | } 45 | 46 | return label; 47 | }, 48 | 49 | getStoreUrl : function() { 50 | return retailer().url; 51 | }, 52 | 53 | getStoreName : function () { 54 | return retailer().name; 55 | }, 56 | 57 | getStoreAddress: function () { 58 | return retailer().address; 59 | }, 60 | 61 | geolocalize: function() { 62 | registry.get(this.name + '.geocoder', function (geocoder) { 63 | this.geocoder = geocoder; 64 | this.geocoder.geolocalize(this.geolocationSuccess.bind(this)) 65 | }.bind(this)); 66 | }, 67 | 68 | onSubmit: function() { 69 | if (!this.fulltextSearch() || this.fulltextSearch().trim().length === 0) { 70 | return false; 71 | } 72 | registry.get(this.name + '.geocoder', function (geocoder) { 73 | this.geocoder = geocoder; 74 | this.geocoder.fulltextSearch(this.fulltextSearch()); 75 | this.geocoder.currentResult.subscribe(function (result) { 76 | if (result && result.location) { 77 | this.geolocationSuccess({coords: {latitude: result.location.lat, longitude: result.location.lng}}, this.fulltextSearch()); 78 | } 79 | }.bind(this)); 80 | this.geocoder.onSearch(); 81 | }.bind(this)); 82 | }, 83 | 84 | geolocationSuccess: function(position, query) { 85 | if (position.coords && position.coords.latitude && position.coords.longitude) { 86 | var url = this.storeLocatorHomeUrl; 87 | if (query !== undefined && query.trim !== "") { 88 | url += '?query=' + query; 89 | } 90 | window.location.href = url + "#" + position.coords.latitude + "," + position.coords.longitude; 91 | } 92 | } 93 | }); 94 | }); -------------------------------------------------------------------------------- /view/frontend/web/js/retailer/store-map.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'ko', 3 | 'smile-map', 4 | ], function(ko, SmileMap){ 5 | 6 | return SmileMap.extend({ 7 | 8 | /** 9 | * Check is show copyright info. 10 | */ 11 | isShowCopyrightInfo: function() { 12 | return ((this.provider == "osm") && (this.copyright_text != null) && (this.copyright_link != null)); 13 | }, 14 | 15 | /** 16 | * Get copyright text. 17 | */ 18 | getCopyrightText: function() { 19 | return this.copyright_text; 20 | }, 21 | 22 | /** 23 | * Get copyright link. 24 | */ 25 | getCopyrightLink: function() { 26 | return this.copyright_link; 27 | } 28 | 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/opening-hours.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/search.html: -------------------------------------------------------------------------------- 1 | 75 | 76 |
77 | 78 | 83 | 84 |
85 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/search/store-detail.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

6 |
7 | 8 |
9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 | Tél.: 28 | 29 |
30 |
31 | E-mail: 32 | 33 |
34 |
35 |
36 |
37 |
38 | 39 |
40 | 46 |
47 | 48 |
49 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/search/store-list.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

5 |
6 |
7 |
8 |

9 | 10 |
11 |
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/special-opening-hours.html: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/store-view/nearby-store.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 |

9 |
10 |
11 |

12 | 13 |
14 |
15 | Tél.: 16 | 17 |
18 |
19 | 20 |
21 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/store-view/open-hours-view.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 |
7 |
8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 |
23 |

24 |
25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/store-view/view-baners-wrap.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |
-------------------------------------------------------------------------------- /view/frontend/web/template/retailer/store-view/view-closest-store-wrapper.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |

6 |
    7 |
  • 8 |
9 |

10 | Sed maximum est in amicitia parem esse inferiori. 11 | Saepe enim excellentiae quaedam sunt, qualis erat Scipionis in nostro, 12 | ut ita dicam, grege. Numquam se ille Philo, numquam Rupilio, 13 | numquam Mummio anteposuit, numquam inferioris ordinis amicis. 14 |

15 |
16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /view/frontend/web/template/retailer/store-view/view-store-details.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |
6 |
7 | 8 |
9 | 10 | 11 | --------------------------------------------------------------------------------