Программно получать продукты по специальным ценам, которые активны, проверяя дату окончания?


Как я могу программно получить продукты с активной специальной ценой? (проверив дату окончания).

Author: Siarhey Uchukhlebau, 2017-08-09

1 answers

Вот полные критерии поиска с 4 фильтрами:

  1. $withSpecialPrice - фильтр для товаров со специальной ценой, превышающей 0
  2. $withVisibleStatus - фильтр для продукта с видимым статусом (включенные продукты)
  3. $visibleInCatalog - фильтр для товаров с каталогом видимости, поиском, каталогом и поиском
  4. $specialPriceDate - фильтр для товаров по дате специальной цены, превышающей текущую дату, или нулевой (без указанной даты окончания)

Все условия являются объединены AND (группы фильтров). Условия специальной цены и даты объединяются OR друг с другом (фильтры внутри одной группы фильтров).

Полный код:

/**
 * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
 * @param \Magento\Framework\Api\SearchCriteriaInterface $criteria
 * @param \Magento\Framework\Api\Search\FilterGroupBuilder $filterGroupBuilder
 * @param \Magento\Framework\Api\FilterBuilder $filterBuilder
 * @param \Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus
 * @param \Magento\Catalog\Model\Product\Visibility $productVisibility
 */
public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
    \Magento\Framework\Api\SearchCriteriaInterface $criteria,
    \Magento\Framework\Api\Search\FilterGroupBuilder $filterGroupBuilder,
    \Magento\Framework\Api\FilterBuilder $filterBuilder,
    \Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus,
    \Magento\Catalog\Model\Product\Visibility $productVisibility,
    \Magento\Framework\Stdlib\DateTime\DateTime $date
) {
    $this->productRepository = $productRepository;
    $this->searchCriteria = $criteria;
    $this->filterGroupBuilder = $filterGroupBuilder;
    $this->filterBuilder = $filterBuilder;
    $this->productStatus = $productStatus;
    $this->productVisibility = $productVisibility;
    $this->date = $date;
}

/**
 * @return \Magento\Cms\Model\Block|null
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function getProductData()
{
    /** @var \Magento\Framework\Api\Search\FilterGroup $withSpecialPrice */
    $withSpecialPrice = $this->filterGroupBuilder->create();
    $withSpecialPrice->setFilters(
        [
            $this->filterBuilder
                ->setField('special_price')
                ->setConditionType('gt')
                ->setValue(0)
                ->create(),
        ]
    );

    /** @var \Magento\Framework\Api\Search\FilterGroup $withVisibleStatus */
    $withVisibleStatus = $this->filterGroupBuilder->create();
    $withVisibleStatus->setFilters(
        [
            $this->filterBuilder
                ->setField('status')
                ->setConditionType('in')
                ->setValue($this->productStatus->getVisibleStatusIds())
                ->create(),
        ]
    );

    /** @var \Magento\Framework\Api\Search\FilterGroup $visibleInCatalog */
    $visibleInCatalog = $this->filterGroupBuilder->create();
    $visibleInCatalog->setFilters(
        [
            $this->filterBuilder
                ->setField('visibility')
                ->setConditionType('in')
                ->setValue($this->productVisibility->getVisibleInSiteIds())
                ->create(),
        ]
    );

    /** @var \Magento\Framework\Api\Search\FilterGroup $specialPriceDate */
    $specialPriceDate = $this->filterGroupBuilder->create();
    $specialPriceDate->setFilters(
        [
           $this->filterBuilder
                ->setField('special_to_date')
                ->setConditionType('null')
                ->setValue('')
                ->create(),
            $this->filterBuilder
                ->setField('special_to_date')
                ->setConditionType('gt')
                ->setValue($this->date->gmtDate())
                ->create(),
        ]
    );

    $this->searchCriteria->setFilterGroups([$withSpecialPrice, $withVisibleStatus, $visibleInCatalog, $specialPriceDate]);
    $products = $this->productRepository->getList($this->searchCriteria);
    $productItems = $products->getItems();

    return $productItems;
}

Вот полная строка запроса sql:

SELECT
  `e`.*,
  IF(at_status.value_id > 0, at_status.value, at_status_default.value)                            AS `status`,
  IF(at_visibility.value_id > 0, at_visibility.value, at_visibility_default.value)                AS `visibility`,
  `at_special_price`.`value`                                                                      AS `special_price`,
  IF(at_special_to_date.value_id > 0, at_special_to_date.value, at_special_to_date_default.value) AS `special_to_date`
FROM `catalog_product_entity` AS `e`
  INNER JOIN `catalog_product_entity_int` AS `at_status_default`
    ON (`at_status_default`.`entity_id` = `e`.`entity_id`) AND (`at_status_default`.`attribute_id` = '97') AND
       `at_status_default`.`store_id` = 0
  LEFT JOIN `catalog_product_entity_int` AS `at_status`
    ON (`at_status`.`entity_id` = `e`.`entity_id`) AND (`at_status`.`attribute_id` = '97') AND
       (`at_status`.`store_id` = 1)
  INNER JOIN `catalog_product_entity_int` AS `at_visibility_default`
    ON (`at_visibility_default`.`entity_id` = `e`.`entity_id`) AND (`at_visibility_default`.`attribute_id` = '99') AND
       `at_visibility_default`.`store_id` = 0
  LEFT JOIN `catalog_product_entity_int` AS `at_visibility`
    ON (`at_visibility`.`entity_id` = `e`.`entity_id`) AND (`at_visibility`.`attribute_id` = '99') AND
       (`at_visibility`.`store_id` = 1)
  INNER JOIN `catalog_product_entity_decimal` AS `at_special_price`
    ON (`at_special_price`.`entity_id` = `e`.`entity_id`) AND (`at_special_price`.`attribute_id` = '78') AND
       (`at_special_price`.`store_id` = 0)
  INNER JOIN `catalog_product_entity_datetime` AS `at_special_to_date_default` ON (
                                                                                    `at_special_to_date_default`.`entity_id`
                                                                                    = `e`.`entity_id`) AND (
                                                                                    `at_special_to_date_default`.`attribute_id`
                                                                                    = '80') AND
                                                                                  `at_special_to_date_default`.`store_id`
                                                                                  = 0
  LEFT JOIN `catalog_product_entity_datetime` AS `at_special_to_date`
    ON (`at_special_to_date`.`entity_id` = `e`.`entity_id`) AND (`at_special_to_date`.`attribute_id` = '80') AND
       (`at_special_to_date`.`store_id` = 1)
WHERE
  ((at_special_price.value > 0)) AND ((IF(at_status.value_id > 0, at_status.value, at_status_default.value) IN (1)))
  AND
  ((IF(at_visibility.value_id > 0, at_visibility.value, at_visibility_default.value) IN (3, 2, 4)))
  AND
  (
    (IF(at_special_to_date.value_id > 0, at_special_to_date.value, at_special_to_date_default.value) IS NULL)
    OR
    (IF(at_special_to_date.value_id > 0, at_special_to_date.value, at_special_to_date_default.value) >
     '2017-08-09 12:34:13')
  );

PS: похоже, что Magento не может правильно фильтровать товары, когда не установлена специальная дата цены. Я рекомендую вам заполнить эти данные во всех ваших продуктах, чтобы убедиться, что фильтр работает правильно.

 4
Author: Siarhey Uchukhlebau, 2017-08-09 13:12:22