Расчет розничной цены товара

Интерфейс показывает, какое правило сработает при наличии склада, поставщиков и минимальной наценки.

Автотесты passed

Входные данные

копейки в домене, рубли в UI

Наш склад

Поставщики a / b / c

Итог

rule #1

Цена для покупателя

1 300 ₽
Берем минимальную рекомендованную цену a+b, но не ниже входной цены с минимальной наценкой.
Минимум склада1 300 ₽
Реком. a+b1 260 ₽
Расчетная c1 390 ₽
Складесть

Алгоритм принятия решения

AND / OR правила сохранены
1

Склад

Если товар есть у нас, сравниваем a+b с нижней границей `purchase * minMarkup`.

2

Удаленные склады

Если нашего остатка нет, показываем минимальную расчетную цену поставщиков типа c.

3

Нет поставщиков

Используем складскую выходную цену и проверяем, что она не ниже минимально допустимой.

PHP: расчет

RetailPriceCalculator
if (!$hasSupplierData) {
    return $this->validatedWarehouseSalePrice(
        $availableOwnLots,
        $input->minMarkupPercent
    );
}

if ($availableOwnLots !== []) {
    $minimalOwnPrice = $this->minimalAllowedOwnStockPrice(
        $availableOwnLots,
        $input->minMarkupPercent
    );
    $minimalRecommended = $this->minimalRecommendedSupplierPrice($input);

    return $minimalRecommended === null
        ? $minimalOwnPrice
        : new Money(max(
            $minimalRecommended->kopecks,
            $minimalOwnPrice->kopecks
        ));
}

SQL: фильтр

OR внутри, AND между
SELECT DISTINCT p.*
FROM product p
WHERE (:manufacturer_ids_empty = 1
       OR p.manufacturer_id IN (:manufacturer_ids))
  AND (:category_ids_empty = 1 OR EXISTS (
      SELECT 1
      FROM product_category pc
      WHERE pc.product_id = p.id
        AND pc.category_id IN (:category_ids)
  ))
  AND (:scale_ids_empty = 1 OR EXISTS (
      SELECT 1
      FROM product_field_value pfv
      INNER JOIN field f ON f.id = pfv.field_id
      WHERE pfv.product_id = p.id
        AND f.code = 'scale'
        AND pfv.value_id IN (:scale_ids)
  ));

Исходники

public links