vendor/boldr/shop-bundle/src/Presenter/Order/OrderPresenter.php line 164

Open in your IDE?
  1. <?php
  2. namespace Boldr\Shop\ShopBundle\Presenter\Order;
  3. use Boldr\Shop\ShopBundle\Presenter\Order\ChangeState\{ ChangeStateViewChangeStateStepView };
  4. use Boldr\Shop\ShopBundle\Entity\{ OrderOrderItemOptionDiscountInvoice };
  5. use Boldr\Shop\ShopBundle\OrderFlow\OrderFlowManagerInterface;
  6. use Boldr\Shop\ShopBundle\OrderFlow\ChangeStateSteps;
  7. use Boldr\Shop\ShopBundle\OrderFlow\ChangeStateStep\ChangeStateStepInterface;
  8. use Boldr\Shop\ShopBundle\Presenter\Product\ProductPresenter;
  9. use Boldr\Shop\ShopBundle\Presenter\Customer\CustomerPresenter;
  10. use Boldr\Shop\ShopBundle\Presenter\Currency\CurrencyPresenter;
  11. use Boldr\Shop\ShopBundle\Price\Order\{ OrderPriceCalculatorOrderPriceQueryOrderItemPrice };
  12. use Boldr\Shop\ShopBundle\Price\PriceModifierManager;
  13. use Boldr\Shop\ShopBundle\Presenter\Option\OptionPresenter;
  14. use Boldr\Shop\ShopBundle\Presenter\PriceModifierView;
  15. use Boldr\Cms\CmsBundle\Content\Assets;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  18. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  19. use Symfony\Contracts\Translation\TranslatorInterface;
  20. use Psr\Container\ContainerInterface;
  21. use Boldr\Shop\ShopBundle\Presenter\Price\PricePresenter;
  22. use Boldr\Shop\ShopBundle\DiscountProvider;
  23. use Boldr\Shop\ShopBundle\Presenter\Payment\PaymentOptionPresenter;
  24. class OrderPresenter implements ServiceSubscriberInterface
  25. {
  26.     public static function getSubscribedServices(): array
  27.     {
  28.         return [
  29.             OrderFlowManagerInterface::class,
  30.             ProductPresenter::class,
  31.             CurrencyPresenter::class,
  32.             CustomerPresenter::class,
  33.             OrderPriceCalculator::class,
  34.             PriceModifierManager::class,
  35.             UrlGeneratorInterface::class,
  36.             TranslatorInterface::class,
  37.             OptionPresenter::class,
  38.             EntityManagerInterface::class,
  39.             PricePresenter::class,
  40.             DiscountProvider::class,
  41.             PaymentOptionPresenter::class
  42.         ];
  43.     }
  44.     private ContainerInterface $container;
  45.     /** @var iterable<OrderViewProcessorInterface> */
  46.     private iterable $orderViewProcessors;
  47.     /** @var iterable<OrderItemViewProcessorInterface> */
  48.     private iterable $orderItemViewProcessors;
  49.     private array $priceModifierCategories;
  50.     private iterable $changeStateStepPresenters;
  51.     public function __construct(
  52.         ContainerInterface $container,
  53.         iterable $orderViewProcessors,
  54.         iterable $orderItemViewProcessors,
  55.         iterable $changeStateStepPresenters,
  56.     )
  57.     {
  58.         $this->container $container;
  59.         $this->orderViewProcessors $orderViewProcessors;
  60.         $this->orderItemViewProcessors $orderItemViewProcessors;
  61.         $this->changeStateStepPresenters $changeStateStepPresenters;
  62.     }
  63.     /**
  64.      * Creates a view object for the whole order
  65.      */
  66.     public function createOrderView(Order $orderstring $locale): OrderView
  67.     {
  68.         // Create sub-views
  69.         $orderItemViews array_map(
  70.             fn($orderItem) => $this->createOrderItemView($orderItem$locale),
  71.             $order->getItems()->toArray()
  72.         );
  73.         $customerView $this->container->get(CustomerPresenter::class)->createCustomerView($order->getCustomer(), $locale);
  74.         $currencyView $this->container->get(CurrencyPresenter::class)->createCurrencyView($order->getCurrency(), $locale);
  75.         $orderFlowManager $this->container->get(OrderFlowManagerInterface::class);
  76.         // Calculate dynamic options
  77.         $nextStateViews = [];
  78.         foreach ($orderFlowManager->getNextStates($order) as $nextState)
  79.             $nextStateViews[] = $this->createNextStateView($order$nextState$locale);
  80.         $orderPrice $this->container->get(OrderPriceCalculator::class)->calculateOrderPrice(new OrderPriceQuery($order));
  81.         $stateName $this->container->get(TranslatorInterface::class)->trans('order_states.'$order->getState(), [], 'BoldrShopBundle');
  82.         $canItemsBeModified $this->container->get(OrderFlowManagerInterface::class)->canItemsBeModified($order);
  83.         $priceModifierManager $this->container->get(PriceModifierManager::class);
  84.         $translator $this->container->get(TranslatorInterface::class);
  85.         $priceModifierCategories $priceModifierManager->getCategories();
  86.         $discountViews = [];
  87.         $automaticDiscountViews = [];
  88.         $orderDiscounts $order->getDiscounts()
  89.             ->filter(fn($orderDiscount) => $orderDiscount->getDiscount() !== null)
  90.             ->map(fn($orderDiscount) => $orderDiscount->getDiscount())
  91.         ;
  92.         foreach ($this->container->get(DiscountProvider::class)->getOrderDiscounts($order) as $discount)
  93.         {
  94.             if ($orderDiscounts->contains($discount))
  95.             {
  96.                 $discountViews[] = $this->createDiscountView($discount$locale);
  97.             }
  98.             else
  99.             {
  100.                 $automaticDiscountViews[] = $this->createDiscountView($discount$locale);
  101.             }
  102.         }
  103.         $invoiceAddressView null;
  104.         if ($order->getInvoiceAddress() !== null)
  105.         {
  106.             $invoiceAddressView $this->container->get(CustomerPresenter::class)->createAddressView($order->getInvoiceAddress()->getAddress(), null);
  107.         }
  108.         $invoiceUrls array_map(
  109.             fn($invoice) => $this->container->get(UrlGeneratorInterface::class)->generate('shop_customer_invoice_download', ['invoiceId' => $invoice->getId()]),
  110.             array_filter(
  111.                 $order->getInvoices(),
  112.                 fn($invoice) => $invoice->getStatus() !== Invoice::STATUS_DRAFT && !$invoice->isProForma(),
  113.             )
  114.         );
  115.         $selectedPaymentOptionView $order->getSelectedPaymentOption() === null
  116.             null
  117.             $this->container->get(PaymentOptionPresenter::class)->createPaymentOptionView($order->getSelectedPaymentOption(), $locale);
  118.         $orderView = new OrderView(
  119.             $order->getId(),
  120.             $order->getNumber(),
  121.             $customerView,
  122.             $currencyView,
  123.             $this->container->get(PricePresenter::class)->createOrderPriceView($orderPrice$locale),
  124.             $orderItemViews,
  125.             $stateName,
  126.             $nextStateViews,
  127.             $order->getTimeCustomerConfirmed(),
  128.             $order->getCustomerNote(),
  129.             $canItemsBeModified,
  130.             $discountViews,
  131.             $automaticDiscountViews,
  132.             $invoiceAddressView,
  133.             $invoiceUrls,
  134.             $order->getCustomer()->getLocale(),
  135.             $selectedPaymentOptionView
  136.         );
  137.         // Process views
  138.         return array_reduce(
  139.             iterator_to_array($this->orderViewProcessors),
  140.             fn($orderView$orderViewProcessor) => $orderViewProcessor->processOrderView($orderView$order$locale),
  141.             $orderView
  142.         );
  143.     }
  144.     public function createOrderItemView(OrderItem $orderItemstring $locale)
  145.     {
  146.         // Create sub-views
  147.         $productPresenter $this->container->get(ProductPresenter::class);
  148.         $productView $productPresenter->createProductView($orderItem->getProductVariant()->getProduct(), $locale);
  149.         $productVariantView $productPresenter->createProductVariantView($orderItem->getProductVariant(), $locale);
  150.         // Calculate item price if not determined yet
  151.         $invoiceItem $orderItem->getInvoiceItem();
  152.         if ($invoiceItem)
  153.         {
  154.             $price = new OrderItemPrice($invoiceItem->getUnitPrice(), $orderItem->getQuantity(), $invoiceItem->getModifiers());
  155.         }
  156.         else
  157.         {
  158.             $priceCalculator $this->container->get(OrderPriceCalculator::class);
  159.             $orderPrice $priceCalculator->calculateOrderPrice(new OrderPriceQuery($orderItem->getOrder()));
  160.             $price $orderPrice->getOrderItemPrices()[$orderItem->getId()];
  161.         }
  162.         $em $this->container->get(EntityManagerInterface::class);
  163.         $optionRepository $em->getRepository(Option::class);
  164.         $optionPresenter $this->container->get(OptionPresenter::class);
  165.         $optionValueViews = [];
  166.         $customer $orderItem->getOrder()->getCustomer();
  167.         $productVariant $orderItem->getProductVariant();
  168.         foreach ($orderItem->getOptionValues() as $optionId => $optionValue)
  169.         {
  170.             $option $optionRepository->find($optionId);
  171.             if ($option !== null)
  172.             {
  173.                 $optionValueView $optionPresenter->createOptionValueView($option$productVariant$customer$optionValue$locale);
  174.                 $optionValueViews[] = $optionValueView;
  175.             }
  176.         }
  177.         $priceModifierManager $this->container->get(PriceModifierManager::class);
  178.         $currency $orderItem->getOrder()->getCurrency();
  179.         $customer $orderItem->getOrder()->getCustomer();
  180.         $priceView $this->container->get(PricePresenter::class)->createOrderItemPriceView($price$currency$customer$locale);
  181.         $orderItemView = new OrderItemView(
  182.             $orderItem->getId(),
  183.             $productView,
  184.             $productVariantView,
  185.             $orderItem->getQuantity(),
  186.             $priceView,
  187.             $optionValueViews
  188.         );
  189.         // Process view
  190.         return array_reduce(
  191.             iterator_to_array($this->orderItemViewProcessors),
  192.             fn($orderItemView$orderItemViewProcessor) => $orderItemViewProcessor->processOrderItemView($orderItemView$orderItem$locale),
  193.             $orderItemView
  194.         );
  195.     }
  196.     public function createChangeStateStepView(ChangeStateStepInterface $changeStateStepOrder $orderstring $locale): ?ChangeStateStepView
  197.     {
  198.         foreach ($this->changeStateStepPresenters as $changeStateStepPresenter)
  199.         {
  200.             if ($changeStateStepPresenter->supports($changeStateStep))
  201.             {
  202.                 return $changeStateStepPresenter->createChangeStateStepView($changeStateStep$order$locale);
  203.             }
  204.         }
  205.         throw new \Exception('No presenter supports '.get_class($changeStateStep));
  206.     }
  207.     public function createChangeStateView(string $nextStateChangeStateSteps $changeStateStepsOrder $orderbool $cantConfirmstring $locale): ChangeStateView
  208.     {
  209.         $orderView $this->createOrderView($order$locale);
  210.         $changeStateStepViews = [];
  211.         $assets = new Assets;
  212.         foreach ($changeStateSteps->getSteps() as $changeStateStep)
  213.         {
  214.             $changeStateStepView $this->createChangeStateStepView($changeStateStep$order$locale);
  215.             if ($changeStateStepView !== null)
  216.             {
  217.                 $changeStateStepViews[] = $changeStateStepView;
  218.                 $assets->addAll($changeStateStepView->getAssets());
  219.             }
  220.         }
  221.         $title $this->container->get(TranslatorInterface::class)->trans('next_state_buttons.'$nextState, [], 'BoldrShopBundle'$locale);
  222.         return new ChangeStateView(
  223.             $nextState,
  224.             $title,
  225.             $orderView,
  226.             $changeStateStepViews,
  227.             $assets,
  228.             $cantConfirm
  229.         );
  230.     }
  231.     public function createNextStateView(Order $orderstring $nextStatestring $locale): NextStateView
  232.     {
  233.         $currentOrder $this->container->get(OrderFlowManagerInterface::class)->getCurrentOrder($order->getCustomer());
  234.         $translator $this->container->get(TranslatorInterface::class);
  235.         $name $translator->trans('order_states.'$nextState, [], 'BoldrShopBundle'$locale);
  236.         $key 'next_state_buttons_from.'$order->getState() .'.'.$nextState;
  237.         if ($translator->getCatalogue($locale)->defines($key'BoldrShopBundle'))
  238.         {
  239.             $buttonText $translator->trans($key, [], 'BoldrShopBundle'$locale);
  240.         }
  241.         else
  242.         {
  243.             $buttonText $translator->trans('next_state_buttons.'$nextState, [], 'BoldrShopBundle'$locale);
  244.         }
  245.         $urlGenerator $this->container->get(UrlGeneratorInterface::class);
  246.         if ($currentOrder === $order)
  247.         {
  248.             $url $urlGenerator->generate('shop_change_cart_state', [
  249.                 '_locale' => $locale,
  250.                 'nextState' => $nextState
  251.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  252.         }
  253.         else
  254.         {
  255.             $url $urlGenerator->generate('shop_change_order_state', [
  256.                 '_locale' => $locale,
  257.                 'orderId' => $order->getId(),
  258.                 'nextState' => $nextState
  259.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  260.         }
  261.         return new NextStateView($nextState$name$buttonText$url);
  262.     }
  263.     public function createDiscountView(Discount $discountstring $locale): DiscountView
  264.     {
  265.         $translation $discount->getTranslations()->get($locale);
  266.         return new DiscountView(
  267.             $discount->getId(),
  268.             $translation->getName(),
  269.             $discount->getCode(),
  270.             [
  271.                 Discount::TYPE_AMOUNT => 'amount',
  272.                 Discount::TYPE_PERCENTAGE => 'percentage',
  273.                 Discount::TYPE_N_PLUS_N => 'n_plus_n'
  274.             ][$discount->getType()]
  275.         );
  276.     }
  277. }