<?php
namespace CioBudget\Decorator;
use CioBudget\Service\BudgetLoaderService;
use CioBudget\Service\SessionService;
use Psr\Container\ContainerInterface;
use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
use Shopware\Core\Checkout\Customer\SalesChannel\AccountService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Framework\Page\StorefrontSearchResult;
use Shopware\Storefront\Page\Account\Order\AccountOrderPage;
use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoadedEvent;
use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoader;
use Shopware\Storefront\Page\GenericPageLoaderInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
class OrderRouterDecorator extends AccountOrderPageLoader
{
private AccountOrderPageLoader $decoratedService;
private GenericPageLoaderInterface $genericLoader;
private EventDispatcherInterface $eventDispatcher;
private AccountService $accountService;
private EntityRepositoryInterface $orderRepository;
private SessionService $sessionService;
private BudgetLoaderService $budgetLoaderService;
public function __construct(
AccountOrderPageLoader $decoratedService,
GenericPageLoaderInterface $genericLoader,
EventDispatcherInterface $eventDispatcher,
AccountService $accountService,
EntityRepositoryInterface $orderRepository,
SessionService $sessionService,
BudgetLoaderService $budgetLoaderService
)
{
$this->genericLoader = $genericLoader;
$this->eventDispatcher = $eventDispatcher;
$this->accountService = $accountService;
$this->decoratedService = $decoratedService;
$this->orderRepository = $orderRepository;
$this->sessionService = $sessionService;
$this->budgetLoaderService = $budgetLoaderService;
}
public function load(Request $request, SalesChannelContext $salesChannelContext): AccountOrderPage
{
if (!$salesChannelContext->getCustomer() && $request->get('deepLinkCode', false) === false) {
throw new CustomerNotLoggedInException();
}
$page = $this->genericLoader->load($request, $salesChannelContext);
$page = AccountOrderPage::createFrom($page);
if ($page->getMetaInformation()) {
$page->getMetaInformation()->setRobots('noindex,follow');
}
$page->setOrders(StorefrontSearchResult::createFrom($this->getOrders($request, $salesChannelContext)));
$page->setDeepLinkCode($request->get('deepLinkCode'));
if ($request->get('deepLinkCode') && $page->getOrders()->first() !== null) {
$this->accountService->login(
$page->getOrders()->first()->getOrderCustomer()->getCustomer()->getEmail(),
$salesChannelContext,
true
);
}
$this->eventDispatcher->dispatch(
new AccountOrderPageLoadedEvent($page, $salesChannelContext, $request)
);
return $page;
}
public function getOrders(Request $request, SalesChannelContext $salesChannelContext): EntitySearchResult
{
$orderNumber = $request->query->get('orderNumber');
$budgetId = $request->query->get('budgetId') ?: $this->sessionService->getBudgetIdFromSession();
$showBudgetOrder = $request->query->get('showBudgetOrder') === 'true';
$criteria = $this->createCriteria($request);
$criteria->setTitle(__CLASS__ . '::' . __FUNCTION__);
if ($orderNumber) {
$criteria->addFilter(new EqualsFilter('order.orderNumber', $orderNumber));
}
if ($budgetId && $showBudgetOrder) {
$criteria->addFilter(new EqualsFilter('order.transactions.paymentMethodId', $this->getBudgetPaymentMethodId()));
// get store id of the current budget
$storeId = $this->budgetLoaderService->getStoreIdByBudgetId($budgetId);
// search by store id for including old orders from expired budgets of this store
$criteria->addFilter(new EqualsFilter('order.history.budget.store_id', $storeId));
} elseif (!$budgetId && $showBudgetOrder) {
// if $showBudgetOrder is set, we will only show budget-orders but without budgetId we cant
// to force a zero-search-result, we reset all filters and add an impossible filter
$criteria->resetFilters();
$criteria->resetAggregations();
$criteria->resetAssociations();
$criteria->resetQueries();
$criteria->resetSorting();
$criteria->resetGroupFields();
$criteria->resetPostFilters();
$criteria->addFilter(new EqualsFilter('order.orderNumber', 'DONT.FIND.ANYTHING'));
} else {
$criteria->addFilter(new EqualsFilter('order.orderCustomer.customerId', $salesChannelContext->getCustomer()->getId()));
}
return $this->orderRepository->search($criteria, $salesChannelContext->getContext());
}
private function createCriteria(Request $request): Criteria
{
$limit = $request->get('limit');
$limit = $limit ? (int)$limit : 10;
$page = $request->get('p');
$page = $page ? (int)$page : 1;
$criteria = (new Criteria());
$criteria->setTitle(__CLASS__ . '::' . __FUNCTION__);
$criteria->addSorting(new FieldSorting('order.createdAt', FieldSorting::DESCENDING))
->addAssociation('transactions.paymentMethod')
->addAssociation('deliveries.shippingMethod')
->addAssociation('orderCustomer.customer')
->addAssociation('lineItems')
->addAssociation('lineItems.cover')
->addAssociation('addresses')
->addAssociation('currency')
->addAssociation('documents.documentType')
->addAssociation('order.transactions')
->addAssociation('cio_budget_history')
->addAssociation('cio_budget_history.budget')
->setLimit($limit)
->setOffset(($page - 1) * $limit)
->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT)
->addSorting(new FieldSorting('orderDateTime', FieldSorting::DESCENDING));
$criteria
->getAssociation('transactions')
->addSorting(new FieldSorting('createdAt'));
if ($request->get('deepLinkCode')) {
$criteria->addFilter(new EqualsFilter('deepLinkCode', $request->get('deepLinkCode')));
}
return $criteria;
}
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
private function getBudgetPaymentMethodId(): ?string
{
/** @var EntityRepositoryInterface $paymentRepository */
$paymentRepository = $this->container->get('payment_method_translation.repository');
$paymentCriteria = (new Criteria())->addFilter(new EqualsFilter('payment_method_translation.name', 'Budget'));
$paymentMethodEntity = $paymentRepository->search($paymentCriteria, Context::createDefaultContext())->first();
return $paymentMethodEntity->getPaymentMethodId();
}
}