clone $i, $activeDeliveries); foreach ($deliveriesList as $deliveryId => $delivery) { $minDeliveryDate = array_reduce($deliveriesDates, function ($min, $deliveries) use ($deliveryId) { $delivery = $deliveries[$deliveryId]; $date = $delivery['date']; return is_null($min) ? $date : min($min, $date); }); $delivery->date = $minDeliveryDate; } return $deliveriesList; } /** * Returns array of three items: * - Array of results for each variation. Result is array with the same structure as for the product. * - Minimal in person date, computed across all variations * - Minimal delivery date, computed across all variations. */ public function calcResultsForEachVariation( array $deliveriesDates, ?array $deliveries, $minDeliveryPrice, array $variationResults, $dateMinInPerson, $dateMinDelivery, ): array { foreach ($deliveriesDates as $variationId => $deliveriesDate) { list($variationDateMinInPerson, $variationDateMinDelivery, $variationDeliveriesList) = $this->calcMinDeliveryDates($deliveries, $deliveriesDate); $variationResults[explode('/', $variationId)[1]] = [ 'list' => $variationDeliveriesList, 'min' => [ 'in_person' => $variationDateMinInPerson, 'delivery' => $variationDateMinDelivery, 'total' => min($variationDateMinInPerson, $variationDateMinDelivery), 'deliveryPrice' => $minDeliveryPrice, ], ]; $dateMinInPerson = is_null($dateMinInPerson) ? $variationDateMinInPerson : min($dateMinInPerson, $variationDateMinInPerson); $dateMinDelivery = is_null($dateMinDelivery) ? $variationDateMinDelivery : min($dateMinDelivery, $variationDateMinDelivery); } return [$variationResults, $dateMinInPerson, $dateMinDelivery]; } /** * Returns array of three items: * - Minimal in person date, computed across all in the person `deliveries` * - Minimal delivery date, computed across all not in the person `deliveries` * - List of all the deliveries with added property `date`. The date is minimum across all the deliveries. */ public function calcMinDeliveryDates(?array $deliveries, array $deliveriesDates): array { // I need to clone the list because its items are modified inside the loop // and the input list needs to be untouched. (The modification is required by // backward compatibility) $deliveriesList = array_map(fn ($i) => clone $i, $deliveries); $dateMinInPerson = null; $dateMinDelivery = null; $groupsByType = []; foreach ($deliveriesList as $id => $delivery) { $date = $deliveriesDates[$id]['date']; if (!$date) { continue; } if ($delivery->isInPerson()) { $dateMinInPerson = is_null($dateMinInPerson) ? $date : min($dateMinInPerson, $date); } else { $dateMinDelivery = is_null($dateMinDelivery) ? $date : min($dateMinDelivery, $date); } $delivery->date = $date; $groupsByType[$delivery->getType()][$id] = &$delivery; unset($delivery); } return [$dateMinInPerson, $dateMinDelivery, $deliveriesList, $groupsByType]; } public function calcMinDeliveryPrice(?array $deliveries) { return array_reduce($deliveries, function ($minDeliveryPrice, $delivery) { if (!$delivery->isInPerson() && ($minDeliveryPrice === null || $delivery->getPrice()->getValue()->lowerThan($minDeliveryPrice->getValue()))) { $minDeliveryPrice = $delivery->getPrice(); } return $minDeliveryPrice; }); } /** * @param \Product|ProductWrapper $product */ public function initPurchaseState($product, $price): PurchaseState { $purchaseState = new PurchaseState([ new ProductPurchaseItem($product->id, $product->variationId ?? null, 1, $price, null), ]); /** @var PurchaseUtil $purchaseUtil */ $purchaseUtil = ServiceContainer::getService(PurchaseUtil::class); $purchaseUtil->recalculateTotalPrices($purchaseState); return $purchaseState; } /** * @param \Product|ProductWrapper|null $product */ public function initializeProductCollection($product, bool $variations): ProductCollection { $productList = new ProductCollection(); if ($product) { if ($variations) { $productList->setEntityType(\FilterParamsBase::ENTITY_VARIATION); if ($product instanceof ProductUnifiedWrapper) { $product = $product->getObject()->getProduct(); } foreach ($product->variationsIds as $variationId) { $variation = new \Variation($product->id, $variationId); $variation->createFromDB(); $productList["{$product->id}/{$variationId}"] = $variation; } } else { if ($product instanceof \Variation) { $productList->setEntityType(\FilterParamsBase::ENTITY_VARIATION); $productList["{$product->id}/{$product->variationId}"] = $product; } else { $productList[$product->id] = $product; } } } return $productList; } public function filterDeliveries(?array $deliveries, bool $only_supported, $productPrice, ?PurchaseState $purchaseState): array { $activeDeliveries = []; foreach ($deliveries as $id => $delivery) { if ($only_supported) { if (!$delivery->accept($productPrice, false)) { continue; } if ($purchaseState) { try { $delivery->checkRestrictions($purchaseState); } catch (\Exception $exception) { continue; } } } $activeDeliveries[$id] = $delivery; } return $activeDeliveries; } }