Files
kupshop/bundles/KupShop/OrderingBundle/Util/Delivery/DeliveryDatesService.php
2025-08-02 16:30:27 +02:00

206 lines
7.5 KiB
PHP

<?php
namespace KupShop\OrderingBundle\Util\Delivery;
use KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\ContentBundle\Entity\Wrapper\ProductUnifiedWrapper;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use Product;
use Variation;
class DeliveryDatesService
{
/**
* Return list of deliveries.
* Each delivery has new property `date`.
* Added date is minimum for that delivery computed across variations.
*/
public function calcTotalDeliveryListForVariations(array $activeDeliveries, $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, $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;
}
}