From 723b4aaad61890847140a8ee7ebd297f7678321d Mon Sep 17 00:00:00 2001
From: livca-smile <48252963+livca-smile@users.noreply.github.com>
Date: Fri, 3 May 2024 18:27:21 +0200
Subject: [PATCH] 2.0.x (#71)
- Add modal map to product page search
- Fix show product offer price if shop has been selected, even in Retail mode
---
.../Catalog/Product/Retailer/Availability.php | 51 +++++-
CHANGELOG.md | 8 +-
Helper/Config.php | 29 +++
Model/Layer/Filter/Price.php | 2 +
Plugin/ContextPlugin.php | 6 +-
Plugin/ProductPlugin.php | 34 +++-
Ui/Component/Offer/Listing/DataProvider.php | 2 +-
etc/adminhtml/system.xml | 9 +
etc/config.xml | 3 +
i18n/en_US.csv | 1 +
i18n/fr_FR.csv | 1 +
view/frontend/layout/catalog_product_view.xml | 11 +-
.../product/view/retailer/availability.phtml | 21 ++-
view/frontend/web/css/source/_module.less | 170 ++++++++++--------
.../web/js/retailer/product-availability.js | 81 +++++++--
15 files changed, 327 insertions(+), 102 deletions(-)
create mode 100644 Helper/Config.php
diff --git a/Block/Catalog/Product/Retailer/Availability.php b/Block/Catalog/Product/Retailer/Availability.php
index 11db07a..c320821 100644
--- a/Block/Catalog/Product/Retailer/Availability.php
+++ b/Block/Catalog/Product/Retailer/Availability.php
@@ -8,6 +8,7 @@
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Block\Product\Context;
use Magento\Catalog\Model\Product as ProductModel;
+use Magento\Directory\Model\Region;
use Magento\Framework\DataObject\IdentityInterface;
use Magento\Framework\Registry;
use Magento\Framework\View\Element\Template;
@@ -20,6 +21,10 @@
use Smile\Retailer\Api\Data\RetailerExtensionInterface;
use Smile\Retailer\Api\Data\RetailerInterface;
use Smile\Retailer\Model\ResourceModel\Retailer\CollectionFactory as RetailerCollectionFactory;
+use Smile\RetailerOffer\Helper\Config as HelperConfig;
+use Smile\StoreLocator\Helper\Data;
+use Smile\StoreLocator\Helper\Schedule;
+use Smile\StoreLocator\Model\Retailer\ScheduleManagement;
/**
* Block rendering availability in store for a given product.
@@ -32,13 +37,21 @@ class Availability extends Template implements IdentityInterface
protected Registry $coreRegistry;
protected ?array $storeOffers = null;
+ /**
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ */
public function __construct(
Context $context,
protected ProductRepositoryInterface $productRepository,
protected OfferManagement $offerManagement,
protected RetailerCollectionFactory $retailerCollectionFactory,
protected AddressFormatter $addressFormatter,
+ protected Region $region,
+ protected HelperConfig $helperConfig,
MapProviderInterface $mapProvider,
+ protected ScheduleManagement $scheduleManagement,
+ protected Schedule $scheduleHelper,
+ protected Data $storeLocatorHelper,
array $data = []
) {
$this->map = $mapProvider->getMap();
@@ -59,13 +72,27 @@ public function getJsLayout()
$jsLayout['components']['catalog-product-retailer-availability']['productId'] = $this->getProduct()->getId();
$jsLayout['components']['catalog-product-retailer-availability']['storeOffers'] = $this->getStoreOffers();
- $jsLayout['components']['catalog-product-retailer-availability']['children']['geocoder']['provider'] =
- $this->map->getIdentifier();
+ $jsLayout['components']['catalog-product-retailer-availability']['searchPlaceholderText'] = $this
+ ->helperConfig->getSearchPlaceholder();
+
+ // smile-geocoder child
+ $jsLayout['components']['catalog-product-retailer-availability']['children']['geocoder']['provider']
+ = $this->map->getIdentifier();
$jsLayout['components']['catalog-product-retailer-availability']['children']['geocoder'] = array_merge(
$jsLayout['components']['catalog-product-retailer-availability']['children']['geocoder'],
$this->map->getConfig()
);
+ // smile-map child
+ $jsLayout['components']['catalog-product-retailer-availability']['children']['map']['provider'] = $this->map
+ ->getIdentifier();
+ $jsLayout['components']['catalog-product-retailer-availability']['children']['map']['markers']
+ = $this->getStoreOffers();
+ $jsLayout['components']['catalog-product-retailer-availability']['children']['map'] = array_merge(
+ $jsLayout['components']['catalog-product-retailer-availability']['children']['map'],
+ $this->map->getConfig()
+ );
+
return json_encode($jsLayout);
}
@@ -76,7 +103,9 @@ public function getJsLayout()
*/
public function getIdentities(): array
{
- $identities = $this->getProduct()->getIdentities();
+ /** @var ProductModel $product */
+ $product = $this->getProduct();
+ $identities = $product->getIdentities();
foreach ($this->getStoreOffers() as $offer) {
if (isset($offer[OfferInterface::OFFER_ID])) {
@@ -123,16 +152,32 @@ protected function getStoreOffers(): array
/** @var RetailerExtensionInterface $retailerExtensionInterface */
$retailerExtensionInterface = $retailer->getExtensionAttributes();
$address = $retailerExtensionInterface->getAddress();
+ $regionName = $this->region->load($address->getRegionId())->getName() ?: null;
$offer = [
'sellerId' => (int) $retailer->getId(),
'name' => $retailer->getName(),
'address' => $this->addressFormatter->formatAddress($address, AddressFormatter::FORMAT_ONELINE),
+ 'postCode' => $address->getPostcode(),
+ 'region' => $regionName,
+ 'city' => $address->getCity(),
'latitude' => $address->getCoordinates()->getLatitude(),
'longitude' => $address->getCoordinates()->getLongitude(),
'setStoreData' => $this->getSetStorePostData($retailer),
'isAvailable' => false,
+ 'url' => $this->storeLocatorHelper->getRetailerUrl($retailer),
];
+ // phpcs:disable Magento2.Performance.ForeachArrayMerge.ForeachArrayMerge
+ $offer['schedule'] = array_merge(
+ $this->scheduleHelper->getConfig(),
+ [
+ 'calendar' => $this->scheduleManagement->getCalendar($retailer),
+ 'openingHours' => $this->scheduleManagement->getWeekOpeningHours($retailer),
+ 'specialOpeningHours' => $retailerExtensionInterface->getSpecialOpeningHours(),
+ ]
+ );
+ // phpcs:enable
+
if (isset($offerByRetailer[(int) $retailer->getId()])) {
$offer['isAvailable'] = (bool) $offerByRetailer[(int) $retailer->getId()]->isAvailable();
$offer[OfferInterface::OFFER_ID] = $offerByRetailer[(int) $retailer->getId()]->getId();
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e437d2..325a910 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,13 @@
All notable changes to this project will be documented in this file.
-## [2.0.1] - 2023-09-20
+## [2.0.2] - 2024-05-03
+[2.0.2]: https://github.com/Smile-SA/magento2-module-retailer-offer/compare/2.0.1...2.0.2
+
+- Add modal map to product page search
+- Fix show product offer price if shop has been selected, even in Retail mode
+
+## [2.0.1] - 2023-10-05
[2.0.1]: https://github.com/Smile-SA/magento2-module-retailer-offer/compare/2.0.0...2.0.1
- Fix CategoryPlugin closure return type
diff --git a/Helper/Config.php b/Helper/Config.php
new file mode 100644
index 0000000..5c6c56e
--- /dev/null
+++ b/Helper/Config.php
@@ -0,0 +1,29 @@
+scopeConfig->getValue($path, $scope);
+ }
+
+ /**
+ * Get placeholder for search input of store_locator, default: City, Zipcode, Address, ...
+ */
+ public function getSearchPlaceholder(): string
+ {
+ return (string) $this->getConfigByPath(self::SEARCH_PLACEHOLDER_XML_PATH) ?: 'City, Zipcode, Address ...';
+ }
+}
diff --git a/Model/Layer/Filter/Price.php b/Model/Layer/Filter/Price.php
index c1fdb63..effc1a3 100644
--- a/Model/Layer/Filter/Price.php
+++ b/Model/Layer/Filter/Price.php
@@ -92,6 +92,7 @@ public function apply(RequestInterface $request)
if ($filter) {
$this->dataProvider->setInterval($filter);
+ // @phpstan-ignore-next-line
$priorFilters = $this->dataProvider->getPriorFilters($filterParams);
if ($priorFilters) {
$this->dataProvider->setPriorIntervals($priorFilters);
@@ -103,6 +104,7 @@ public function apply(RequestInterface $request)
$this->addQueryFilter($fromValue, $toValue);
$this->getLayer()->getState()->addFilter(
+ // @phpstan-ignore-next-line
$this->_createItem($this->_renderRangeLabel(empty($fromValue) ? 0 : $fromValue, $toValue), $filter)
);
}
diff --git a/Plugin/ContextPlugin.php b/Plugin/ContextPlugin.php
index 0efb35c..b9a8cc1 100644
--- a/Plugin/ContextPlugin.php
+++ b/Plugin/ContextPlugin.php
@@ -34,11 +34,13 @@ public function aroundDispatch(
RequestInterface $request
): mixed {
- if ($this->settingsHelper->isDriveMode()) {
+ // show product offer price if shop has been selected, even in Retail mode
+ if ($this->settingsHelper->isDriveMode() || $this->currentStore->getRetailer()) {
// Set a default value to have common vary for all customers without any chosen retailer.
$retailerId = 'default';
- if ($this->currentStore->getRetailer() && $this->currentStore->getRetailer()->getId()) {
+ if ($this->currentStore->getRetailer()
+ && $this->currentStore->getRetailer()->getId()) {
$retailerId = $this->currentStore->getRetailer()->getId();
}
diff --git a/Plugin/ProductPlugin.php b/Plugin/ProductPlugin.php
index d520aaa..84891c5 100644
--- a/Plugin/ProductPlugin.php
+++ b/Plugin/ProductPlugin.php
@@ -6,16 +6,36 @@
use Closure;
use Magento\Catalog\Model\Product;
+use Smile\Retailer\Api\Data\RetailerInterface;
use Smile\RetailerOffer\Helper\Offer;
use Smile\RetailerOffer\Helper\Settings;
+use Smile\StoreLocator\CustomerData\CurrentStore;
/**
* Replace is in stock native filter on layer.
*/
class ProductPlugin
{
- public function __construct(private Offer $offerHelper, private Settings $settingsHelper)
+
+ public function __construct(
+ private Offer $offerHelper,
+ private Settings $settingsHelper,
+ protected CurrentStore $currentStore
+ ) {
+ }
+
+ /**
+ * Retrieve current retailer.
+ */
+ private function getRetailer(): ?RetailerInterface
{
+ $retailer = null;
+ if ($this->currentStore->getRetailer() && $this->currentStore->getRetailer()->getId()) {
+ /** @var RetailerInterface $retailer */
+ $retailer = $this->currentStore->getRetailer();
+ }
+
+ return $retailer;
}
/**
@@ -27,7 +47,8 @@ public function aroundIsAvailable(Product $product, Closure $proceed): bool
{
$isAvailable = $proceed();
- if ($this->settingsHelper->useStoreOffers()) {
+ // show product availability if shop has been selected, even in Retail mode
+ if ($this->settingsHelper->useStoreOffers() || $this->getRetailer()) {
$isAvailable = false;
$offer = $this->offerHelper->getCurrentOffer($product);
@@ -46,7 +67,8 @@ public function aroundGetPrice(Product $product, Closure $proceed): mixed
{
$price = $proceed();
- if ($this->settingsHelper->useStoreOffers()) {
+ // show product offer price if shop has been selected, even in Retail mode
+ if ($this->settingsHelper->useStoreOffers() || $this->getRetailer()) {
$offer = $this->offerHelper->getCurrentOffer($product);
if ($offer && $offer->getPrice()) {
@@ -66,7 +88,8 @@ public function aroundGetSpecialPrice(Product $product, Closure $proceed): mixed
{
$price = $proceed();
- if ($this->settingsHelper->useStoreOffers()) {
+ // show product offer price if shop has been selected, even in Retail mode
+ if ($this->settingsHelper->useStoreOffers() || $this->getRetailer()) {
$offer = $this->offerHelper->getCurrentOffer($product);
if ($offer && $offer->getSpecialPrice()) {
@@ -84,7 +107,8 @@ public function aroundGetFinalPrice(Product $product, Closure $proceed, mixed $q
{
$price = $proceed($qty);
- if ($this->settingsHelper->useStoreOffers()) {
+ // show product offer price if shop has been selected, even in Retail mode
+ if ($this->settingsHelper->useStoreOffers() || $this->getRetailer()) {
$offer = $this->offerHelper->getCurrentOffer($product);
if ($offer) {
diff --git a/Ui/Component/Offer/Listing/DataProvider.php b/Ui/Component/Offer/Listing/DataProvider.php
index d226903..de9959e 100644
--- a/Ui/Component/Offer/Listing/DataProvider.php
+++ b/Ui/Component/Offer/Listing/DataProvider.php
@@ -47,7 +47,7 @@ public function addField($field, $alias = null): void
/**
* @inheritdoc
*/
- public function addFilter(Filter $filter): mixed
+ public function addFilter(Filter $filter): void
{
if (isset($this->addFilterStrategies[$filter->getField()])) {
$this->addFilterStrategies[$filter->getField()]
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 79ec74f..7186199 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -9,6 +9,7 @@