<?php declare(strict_types=1);
/**
* PremSoft
* Copyright © 2020 Premsoft - Sven Mittreiter
*
* @copyright Copyright (c) 2020, premsoft - Sven Mittreiter (http://www.premsoft.de)
* @author Sven Mittreiter <info@premsoft.de>
*/
namespace Prems\Plugin\PremsIndividualOffer6\Core\Offer\Storefront;
use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\Aggregate\OfferItem\OfferItemEntity;
use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\OfferDefinition;
use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\OfferEntity;
use Prems\Plugin\PremsIndividualOffer6\Core\Media\MediaService;
use Prems\Plugin\PremsIndividualOffer6\Event\OfferCreatedEvent;
use Prems\Plugin\PremsIndividualOffer6\PremsIndividualOffer6;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\Error\ErrorCollection;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\LineItemFactoryHandler\CustomLineItemFactory;
use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Content\Product\Cart\ProductLineItemFactory;
use Shopware\Core\Content\Product\SalesChannel\Detail\AbstractProductDetailRoute;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AndFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\NumberRange\ValueGenerator\NumberRangeValueGeneratorInterface;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Checkout\Customer\Aggregate\CustomerGroup\CustomerGroupEntity;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class OfferService
{
/**
* @var EntityRepositoryInterface
*/
private $offerRepository;
/**
* @var EntityRepositoryInterface
*/
private $offerItemRepository;
/**
* @var EntityRepositoryInterface
*/
private $offerMessageRepository;
/**
* @var SalesChannelRepositoryInterface
*/
private $productRepository;
/**
* @var CartService
*/
private $cartService;
/**
* @var NumberRangeValueGeneratorInterface
*/
private $numberRangeValueGenerator;
/**
* @var ProductLineItemFactory
*/
private $productLineItemFactory;
/**
* @var ConfigService
*/
private $configService;
/**
* @var AbstractProductDetailRoute
*/
private $productLoader;
/**
* @var Session $session
*/
private $session;
private OfferStateService $offerStateService;
/** @var MediaService $mediaService */
private $mediaService;
private EventDispatcherInterface $eventDispatcher;
public function __construct(
EntityRepositoryInterface $offerRepository,
EntityRepositoryInterface $offerItemRepository,
EntityRepositoryInterface $offerMessageRepository,
SalesChannelRepositoryInterface $productRepository,
CartService $cartService,
NumberRangeValueGeneratorInterface $numberRangeValueGenerator,
ProductLineItemFactory $productLineItemFactory,
ConfigService $configService,
AbstractProductDetailRoute $productLoader,
OfferStateService $offerStateService,
MediaService $mediaService,
Session $session,
EventDispatcherInterface $eventDispatcher
) {
$this->offerRepository = $offerRepository;
$this->offerItemRepository = $offerItemRepository;
$this->offerMessageRepository = $offerMessageRepository;
$this->productRepository = $productRepository;
$this->cartService = $cartService;
$this->numberRangeValueGenerator = $numberRangeValueGenerator;
$this->productLineItemFactory = $productLineItemFactory;
$this->configService = $configService;
$this->productLoader = $productLoader;
$this->session = $session;
$this->offerStateService = $offerStateService;
$this->mediaService = $mediaService;
$this->eventDispatcher = $eventDispatcher;
}
/**
* Return all offers for an user
*
* @param SalesChannelContext $salesChannelContext
* @param Request $request
*
* @return EntitySearchResult
*
* @throws InconsistentCriteriaIdsException
*/
public function getOffersForUser(SalesChannelContext $salesChannelContext, Request $request)
{
$criteria = (new Criteria())
->addFilter(new AndFilter([
new EqualsFilter('prems_individual_offer.customerId', $salesChannelContext->getCustomer()->getId()),
new EqualsFilter('prems_individual_offer.salesChannelId', $salesChannelContext->getSalesChannelId())
]))
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')
->addSorting(new FieldSorting('createdAt', FieldSorting::DESCENDING));
$filters = [];
if ($request->query->get('openRequest')) {
$filters[] = new EqualsFilter('prems_individual_offer.offered', 0);
}
if ($request->query->get('received')) {
$filters[] = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('prems_individual_offer.offered', 1),
new EqualsFilter('prems_individual_offer.accepted', 0),
new EqualsFilter('prems_individual_offer.declined', 0)
]
);
}
if ($request->query->get('ordered')) {
$filters[] = new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('prems_individual_offer.offered', 1),
new EqualsFilter('prems_individual_offer.accepted', 1),
new EqualsFilter('prems_individual_offer.declined', 0)
]
);
}
if ($request->query->get('declined')) {
$filters[] = new EqualsFilter('prems_individual_offer.declined', 1);
}
if (!empty($filters)) {
$criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, $filters));
}
$offers = $this->offerRepository->search($criteria, $salesChannelContext->getContext());
if (!empty($offers)) {
foreach ($offers as $offer) {
$currentDate = date('Y-m-d H:i:s');
$offerDays = (int) $offer->getOfferDaysValid();
$offerDate = date('Y-m-d H:i:s', strtotime($offer->getUpdatedAtDateTime() . " +{$offerDays} day"));
if (($offer->getOfferDaysValid() !== null && $offer->getOfferDaysValid() !== '') &&
$offer->getUpdatedAtDateTime() !== null &&
$offerDate <= $currentDate &&
($offer->isOffered() && !$offer->isAccepted() && !$offer->isDeclined())
) {
$offer->setDeclined(true);
$this->offerRepository->update([[
'id' => $offer->getId(),
'declined' => $offer->isDeclined(),
'updated_at' => $offer->getUpdatedAtDateTime()
]], $salesChannelContext->getContext());
}
}
}
$offers = $this->offerRepository->search($criteria, $salesChannelContext->getContext());
if (!empty($offers)) {
foreach ($offers as $offer) {
$criteriaMessages = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer_messages.offerId', $offer->getId()))
->addFilter(new EqualsFilter('prems_individual_offer_messages.customerId', $salesChannelContext->getCustomer()->getId()))
->addAssociation('user')
->addAssociation('customer')
->addSorting(new FieldSorting('prems_individual_offer_messages.createdAt', FieldSorting::DESCENDING));
$messages = $this->offerMessageRepository->search($criteriaMessages, $salesChannelContext->getContext())->getEntities();
$offer->setMessages($messages);
}
}
return $offers;
}
/**
* @param Context $context
*/
public function updateOffersStatus(Context $context)
{
$criteria = new Criteria();
$offers = $this->offerRepository->search($criteria, $context);
if (!empty($offers)) {
foreach ($offers as $offer) {
$currentDate = date('Y-m-d H:i:s');
$offerDays = (int) $offer->getOfferDaysValid();
$offerDate = date('Y-m-d H:i:s', strtotime($offer->getUpdatedAtDateTime() . " +{$offerDays} day"));
if(($offer->getOfferDaysValid() !== null && $offer->getOfferDaysValid() !== '') &&
$offer->getUpdatedAtDateTime() !== null &&
$offerDate <= $currentDate &&
($offer->isOffered() && !$offer->isAccepted() && !$offer->isDeclined())
) {
$offer->setDeclined(true);
$this->offerRepository->update([[
'id' => $offer->getId(),
'declined' => $offer->isDeclined(),
'updated_at' => $offer->getUpdatedAtDateTime()
]], $context);
}
}
}
return $offers;
}
/**
* @param CustomerEntity $customer
* @param Context $context
* @return int
*/
public function getOpenRequestCount(CustomerEntity $customer, Context $context)
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customer->getId()))
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')
->addFilter(new EqualsFilter('prems_individual_offer.offered', 0));
return $this->offerRepository->search($criteria, $context)->getTotal();
}
/**
* @param CustomerEntity $customer
* @param Context $context
* @return int
*/
public function getReceivedCount(CustomerEntity $customer, Context $context)
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customer->getId()))
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')
->addFilter(new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('prems_individual_offer.offered', 1),
new EqualsFilter('prems_individual_offer.accepted', 0),
new EqualsFilter('prems_individual_offer.declined', 0)
]
));
return $this->offerRepository->search($criteria, $context)->getTotal();
}
/**
* @param CustomerEntity $customer
* @param Context $context
* @return int
*/
public function getOrderedCount(CustomerEntity $customer, Context $context)
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customer->getId()))
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')
->addFilter(new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('prems_individual_offer.offered', 1),
new EqualsFilter('prems_individual_offer.accepted', 1),
new EqualsFilter('prems_individual_offer.declined', 0)
]
));
return $this->offerRepository->search($criteria, $context)->getTotal();
}
/**
* @param CustomerEntity $customer
* @param Context $context
* @return int
*/
public function getDeclinedCount(CustomerEntity $customer, Context $context)
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customer->getId()))
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')
->addFilter(new EqualsFilter('prems_individual_offer.declined', 1));
return $this->offerRepository->search($criteria, $context)->getTotal();
}
/**
* Get on offer by offer ID
* @param string $offerId
* @param Context $context
* @param CustomerEntity|null $customer
* @return OfferEntity
*/
public function getOfferById(string $offerId, Context $context, CustomerEntity $customer = null)
{
$criteria = new Criteria([ $offerId ]);
if ($customer) {
$criteria->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customer->getId()));
}
$criteria
->addAssociation('items')
->addAssociation('items.product')
->addAssociation('items.product.prices')
->addAssociation('items.product.cover')
->addAssociation('customer')
->addAssociation('customer.salutation')
->addAssociation('customer.defaultBillingAddress')
->addAssociation('customer.activeBillingAddress')
->addAssociation('customer.defaultBillingAddress.country')
->addAssociation('customer.activeBillingAddress.country')
->addAssociation('shippingMethod.tax')
->addAssociation('currency')
->addAssociation('salesChannel.domains')
->addAssociation('salesChannel.mailHeaderFooter')
->addAssociation('language.locale');
$offer = $this->offerRepository->search($criteria, $context)->first();
if ($offer && $customer != null) {
$criteriaMessages = (new Criteria())
->addFilter(new EqualsFilter('prems_individual_offer_messages.offerId', $offer->getId()))
->addFilter(new EqualsFilter('prems_individual_offer_messages.customerId', $customer->getId()))
->addAssociation('user')
->addAssociation('customer')
->addSorting(new FieldSorting('prems_individual_offer_messages.createdAt', FieldSorting::DESCENDING));
$messages = $this->offerMessageRepository->search($criteriaMessages, $context)->getEntities();
$offer->setMessages($messages);
}
return $offer;
}
/**
* Get on product by product ID
* @param string $productId
* @param Context $context
* @return ProductEntity
*/
public function getProductById(string $productId, SalesChannelContext $context)
{
$criteria = new Criteria([$productId]);
$criteria->addAssociation('cover');
$criteria->addAssociation('prices');
$product = $this->productRepository->search($criteria, $context)->first();
return $product;
}
/**
* @param OfferEntity $offer
* @param ProductEntity $product
* @param Context $context
*/
public function addOfferItem(OfferEntity $offer, ProductEntity $product, Context $context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('offerId', $offer->getId()));
$offerItemsCount = $this->offerItemRepository->search($criteria, $context)->getTotal();
$oldPrice = $offer->getTaxStatus() == OfferEntity::TAX_STATUS_NET ? $product->getPrice()->first()->getNet() : $product->getPrice()->first()->getGross();
$price = $offer->getTaxStatus() == OfferEntity::TAX_STATUS_NET ? $product->getPrice()->first()->getNet() : $product->getPrice()->first()->getGross();
$quantity = 1;
$data = [
'oldPrice' => $oldPrice,
'price' => $price,
'totalPrice' => $price * $quantity,
'quantity' => $quantity,
'position' => $offerItemsCount + 1,
//'lineItem' => \base64_encode(\serialize($product)),
'itemOption' => null,
'productId' => $product->getId(),
'offerId' => $offer->getId(),
//'itemType' => 'swag-customized-products'
];
return $this->offerItemRepository->create([
$data
], $context);
}
/**
* Get and return items of an offer
* @param $offerId
* @param $customerId
* @param SalesChannelContext $context
* @return null|\Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\Aggregate\OfferItem\OfferItemCollection
* @throws InconsistentCriteriaIdsException
*/
public function getItemsFromOffer($offerId, $customerId, SalesChannelContext $context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('id', $offerId))
->addFilter(new EqualsFilter('prems_individual_offer.customerId', $customerId))
->addAssociation('items')
->addAssociation('customer')
//->addAssociation('items.product.prices')
/**->addAssociation('items.product')
->addAssociation('items.product.cover')
->addAssociation('items.product.prices')*/;
/** @var OfferEntity|null $offer */
$offer = $this->offerRepository->search($criteria, $context->getContext())->first();
if (!$offer instanceof OfferEntity) {
throw new NotFoundHttpException();
}
$nestedItems = $offer->getNestedItems();
$elements = $nestedItems->getElements();
$productCriteria = new Criteria();
$productCriteria->addAssociation('options.group');
/** @var OfferItemEntity $element */
foreach($elements as $element) {
$clonedCriteria = clone $productCriteria;
/** @var SalesChannelProductEntity|null $product */
if (!$element->getProductId()) {
continue;
}
$result = $this->productLoader->load($element->getProductId(), new Request(), $context, $clonedCriteria);
/** @var SalesChannelProductEntity|null $product */
$product = $result->getProduct();
if ($product) {
$element->setProduct($product);
$element->setPriceNet();
}
}
return $nestedItems;
}
/**
* Determine if a offer request is generally allowed (Plugin activated for saleschannel, cart amount high enough)
* @param SalesChannelContext $context
*
* @return bool
*/
public function isOfferRequestAllowed(SalesChannelContext $context)
{
$offerSettings = $this->configService->getConfig($context);
$settings = $offerSettings->getVars();
if ($settings['disallowedCustomerGroups'] && is_array($settings['disallowedCustomerGroups'])) {
$customerGroup = $context->getCurrentCustomerGroup();
if (in_array($customerGroup->getId(), $settings['disallowedCustomerGroups'])) {
return false;
}
}
if ($settings['offerMinValueReached'] == true) {
return true;
}
return false;
}
/**
* Creates an offer request for a customer
* @param CustomerEntity $customer
* @param CustomerGroupEntity
* @param SalesChannelContext $context
*
* @throws \Exception
* @return EntityWrittenContainerEvent
*/
public function createOfferRequest(CustomerEntity $customer, CustomerGroupEntity $customerGroup, SalesChannelContext $context)
{
$items = [];
$cart = $this->cartService->getCart($context->getToken(), $context);
$lineItems = $cart->getLineItems()->filter(
function (LineItem $lineItem) {
return in_array($lineItem->getType(), [LineItem::PRODUCT_LINE_ITEM_TYPE, 'customized-products', LineItem::PROMOTION_LINE_ITEM_TYPE]);
}
);
$currencySymbol = $context->getCurrency()->getSymbol();
if ($lineItems) {
//echo "<pre>"; print_R($lineItems); echo "</pre>";die();
$i = 0;
foreach($lineItems as $lineItem) {
$i++;
//$products[] = ['id' => $lineItem->getId()];
$data = [
'productId' => $lineItem->getId(),
'oldPrice' => $lineItem->getPrice()->getUnitPrice(),
'price' => $lineItem->getPrice()->getUnitPrice(),
'totalPrice' => $lineItem->getPrice()->getTotalPrice(),
'quantity' => $lineItem->getQuantity(),
'position' => $i,
'lineItem' => \base64_encode(\serialize($lineItem)),
];
// Possibility to use referencedID instead of productId for third party vendors
if ($lineItem->hasPayloadValue('prems_individual_offer_use_reference_id_instead_of_product_id')) {
$data['productId'] = $lineItem->getReferencedId();
}
if($lineItem->getType() == LineItem::PROMOTION_LINE_ITEM_TYPE) {
$data['productId'] = null;
$data['itemType'] = LineItem::PROMOTION_LINE_ITEM_TYPE;
}
if ($lineItem->getType() == 'customized-products') {
$productId = 0;
$children = $lineItem->getChildren();
$itemOption = [];
foreach($children as $child) {
if ($child->getType() == LineItem::PRODUCT_LINE_ITEM_TYPE) {
$productId = $child->getReferencedId();
}
if ($child->getType() == 'customized-products-option') {
$quantity = '';
$price = '';
$payloadValue = '';
if ($child->getQuantity() > 1) {
$quantity = $child->getQuantity() . ' x ';
}
if ($child->hasChildren()) {
$subChildren = $child->getChildren();
$optionValues = [];
foreach($subChildren as $subChild) {
if ($subChild->getPrice()->getTotalPrice() > 0) {
$price = ' '.$subChild->getPrice()->getTotalPrice() . ' ' . $currencySymbol;
}
$optionValues[] = $subChild->getLabel();
}
$itemOption[] = $quantity.$child->getLabel() . ' (' . implode('; ', $optionValues) . ')'.$payloadValue.$price;
} else {
if ($child->getPrice()->getTotalPrice() > 0) {
$price = ' '.$child->getPrice()->getTotalPrice() . ' ' . $currencySymbol;
}
$payload = $child->getPayload();
if ($payload && array_key_exists('value', $payload) && !is_array($payload['value'])) {
$payloadValue = ': '.$payload['value'];
}
if ($payload && array_key_exists('media', $payload) && is_array($payload['media'])) {
$media = $this->mediaService->getMediaById($payload['media']['0']['mediaId'], $context->getContext());
$payloadValue = ': '.$media->getUrl();
}
$itemOption[] = $quantity.$child->getLabel().$payloadValue.$price ;
}
}
}
//$data['itemOption'] = implode('<br>',$itemOption);
$data['itemOption'] = json_encode($itemOption);
$data['productId'] = $productId;
$data['itemType'] = 'swag-customized-products';
}
$items[] = $data;
}
}
//$this->numberRangeValueGenerator->previewPattern(OfferDefinition::ENTITY_NAME, '{n}', 1);
if ($customerGroup->getDisplayGross()) {
$taxStatus = 'gross';
} else {
$taxStatus = 'net';
}
$cart->setErrors(new ErrorCollection());
$cart->setData(null);
$offerId = Uuid::randomHex();
$offerData = [
'id' => $offerId,
'customerId' => $customer->getId(),
'taxStatus' => $taxStatus,
'offerNumber' => $this->numberRangeValueGenerator->getValue(
OfferDefinition::ENTITY_NAME,
$context->getContext(),
$context->getSalesChannel()->getId()
),
'pdfComment' => $this->configService->getConfig($context)->getDefaultPdfComment(),
'currencyFactor' => $context->getContext()->getCurrencyFactor(),
'currencyId' => $context->getContext()->getCurrencyId(),
'languageId' => $context->getContext()->getLanguageId(),
'salesChannelId' => $context->getSalesChannel()->getId(),
'cart' => \base64_encode(\serialize($cart)),
'items' => $items,
];
if ($this->configService->getConfig($context)->getDefaultOfferDaysValid() > 0) {
$offerData['offer_days_valid'] = (int) $this->configService->getConfig($context)->getDefaultOfferDaysValid();
$offerData['offerExpiration'] = $this->calculateOfferExpirationDate($offerData['offer_days_valid']);
}
$offerCreation = $this->offerRepository->create([
$offerData
], $context->getContext());
$this->eventDispatcher->dispatch(new OfferCreatedEvent($offerId, $context));
return $offerCreation;
}
/**
* Determine if an offer is orderable
* @param OfferEntity $offer
* @return bool
*/
public function isOfferOrderable(OfferEntity $offer): bool
{
if ($offer->isOffered() && !$offer->isAccepted() && !$offer->isDeclined()) {
return true;
}
return false;
}
/**
* Determine if an offer is declineable
* @param OfferEntity $offer
* @return bool
*/
public function isOfferDeclineable(OfferEntity $offer): bool
{
if ($offer->isOffered() && !$offer->isAccepted() && !$offer->isDeclined()) {
return true;
}
return false;
}
/**
* Determine if customer is allowed to access an offer
* @param OfferEntity $offer
* @param CustomerEntity $customer
* @return bool
*/
public function hasAccessToOffer(OfferEntity $offer, CustomerEntity $customer): bool
{
$customerIsOwner = $customer->getId() === $offer->getCustomer()->getId();
return $customerIsOwner;
}
/**
* Determine if basket is in offer mode and then return offer mode
* @param SalesChannelContext $context
* @return string
*/
public function getOfferMode($context): string
{
// compatibility mode for older version with session value. If there is an entry then cancel offer mode.
// Code will be removed in newer versions
if ($this->session->has('prems_individual_offer')) {
$this->session->remove('prems_individual_offer');
$this->cancelOfferMode($context);
}
$cart = $this->cartService->getCart($context->getToken(), $context);
//echo "<pre>"; print_R($cart->getExtensions()); die();
if (!$cart->hasExtension('offer_mode_active')) {
return '';
}
$offerMode = $cart->getExtension('offer_mode_active');
if (!$offerMode || !$offerMode->getId()) {
return '';
}
return $offerMode->getId();
}
/**
* Set flag that basket is in offer mode
*
* @param SalesChannelContext $context
* @param string $offerId
*/
public function activateOfferMode($context, $offerId):void
{
$cart = $this->cartService->getCart($context->getToken(), $context);
$cart->addExtension(PremsIndividualOffer6::OFFER_MODE_EXTENSION_NAME, new ArrayEntity(['id' => $offerId]));
}
/**
* Set flag that basket is no longer in offer mode
*/
public function disableOfferMode($context):void
{
$cart = $this->cartService->getCart($context->getToken(), $context);
// compatibility mode for older version with session value.
if ($cart->hasExtension(PremsIndividualOffer6::OFFER_MODE_EXTENSION_NAME)) {
$cart->removeExtension(PremsIndividualOffer6::OFFER_MODE_EXTENSION_NAME);
}
}
/**
* @param SalesChannelContext $context
*/
public function cancelOfferMode($context): void
{
$this->disableOfferMode($context);
$context->removeState(PremsIndividualOffer6::OFFER_MODE_STATE);
$this->cartService->deleteCart($context);
}
/**
* Add an offer to basket and set basket to offer mode
* @param $offer
* @param SalesChannelContext $context
*/
public function addOfferToBasket($offer, $context)
{
// Empty cart
$cart = $this->cartService->getCart($context->getToken(), $context);
$items = $cart->getLineItems();
foreach($items as $item) {
$this->cartService->remove($cart, $item->getId(), $context);
}
$products = [];
/** @var OfferItemEntity $item */
foreach ($offer->getItems() as $item) {
// Swag Custom Product found?
if ($item->getItemType() == 'swag-customized-products') {
$product = \unserialize(base64_decode((string)$item->getLineItem()));
if ($product && $product instanceof LineItem) {
$product->setStackable(true);
$product->setQuantity($item->getQuantity());
$product->setRemovable(false);
$product->setStackable(false);
$product->addExtension('prems', new ArrayStruct(['originalId' => $item->getId(), 'price' => $product->getPrice()]));
} else {
continue;
}
} elseif($item->getItemType() == LineItem::PROMOTION_LINE_ITEM_TYPE) {
$row = \unserialize(base64_decode((string) $item->getLineItem()));
$product = new LineItem(Uuid::randomHex(), LineItem::CUSTOM_LINE_ITEM_TYPE);
$product->assign($row->getVars());
$product->setType(LineItem::CUSTOM_LINE_ITEM_TYPE);
$product->setPriceDefinition(new QuantityPriceDefinition($product->getPrice()->getTotalPrice(), $product->getPrice()->getTaxRules()));
$product->setGood(true);
$product->setRemovable(false);
$product->addExtension('prems', new ArrayStruct(['originalId' => $item->getId(), 'price' => $product->getPrice()]));
} else {
$product = \unserialize(base64_decode((string) $item->getLineItem()));
if (!$product || !is_object($product)) {
$product = $this->productLineItemFactory->create($item->getProductId());
}
$product->setStackable(true);
$product->setRemovable(false);
$product->setQuantity($item->getQuantity());
$product->setStackable(false);
$product->addExtension('prems', new ArrayStruct(['originalId' => $item->getId(), 'price' => $product->getPrice()]));
}
$products[] = $product;
}
$this->cartService->add($cart, $products, $context);
}
/**
* Declines an offer
* @param OfferEntity $offer
* @param Context $context
* @param int|null $offer_days_valid
*
* @return EntityWrittenContainerEvent
* @throws \Exception
*/
public function declineOffer(OfferEntity $offer, Context $context, $offer_days_valid = null)
{
$offer->setDeclined(true);
return $this->offerRepository->update([[
'id' => $offer->getId(),
'declined' => $offer->isDeclined(),
'offer_days_valid' => $offer_days_valid,
'offerExpiration' => $this->calculateOfferExpirationDate($offer_days_valid, $offer->getUpdatedAt())
]], $context);
}
/**
* Accept an offer
* @param OfferEntity $offer
* @param Context $context
*
* @return EntityWrittenContainerEvent
*/
public function acceptOffer(OfferEntity $offer, Context $context)
{
$offer->setAccepted(true);
return $this->offerRepository->update([[
'id' => $offer->getId(),
'accepted' => $offer->isAccepted()
]], $context);
}
/**
* Creates an offer
* @param OfferEntity $offer
* @param Context $context
* @param int|null $offer_days_valid
*
* @return EntityWrittenContainerEvent
* @throws \Exception
*/
public function createOffer(OfferEntity $offer, Context $context, $offer_days_valid = null)
{
$offer->setOffered(true);
$offer->setAccepted(false);
$offer->setDeclined(false);
return $this->offerRepository->update([[
'id' => $offer->getId(),
'offered' => $offer->isOffered(),
'accepted' => $offer->isAccepted(),
'declined' => $offer->isDeclined(),
'offer_days_valid' => $offer_days_valid,
'offerExpiration' => $this->calculateOfferExpirationDate($offer_days_valid, $offer->getUpdatedAt()),
'admin_updated_at' => date("Y-m-d H:i:s")
]], $context);
}
/**
* Change days an offer
* @param OfferEntity $offer
* @param Context $context
* @param int|null $offer_days_valid
*
* @return EntityWrittenContainerEvent
* @throws \Exception
*/
public function changeOfferDays(OfferEntity $offer, Context $context, $offer_days_valid = null)
{
$offer->setOffered(true);
return $this->offerRepository->update([[
'id' => $offer->getId(),
'offer_days_valid' => $offer_days_valid ?? null,
'offerExpiration' => $this->calculateOfferExpirationDate($offer_days_valid, $offer->getUpdatedAt())
]], $context);
}
public function setOffered(string $offerId, Context $context): bool
{
$this->offerRepository->update([['id' => $offerId, 'offered' => true]], $context);
return true;
}
/**
* Adds Line items to cart
* @param Cart $cart
* @param $items
* @param SalesChannelContext $context
* @return Cart
*/
public function addCartItems(Cart $cart, $items, SalesChannelContext $context): Cart
{
$cart = $this->cartService->add($cart, $items, $context);
return $cart;
}
/**
* @param Cart $cart
* @param string $id
* @param SalesChannelContext $context
* @return Cart
*/
public function removeCartItem(Cart $cart, string $id, SalesChannelContext $context): Cart
{
$cart = $this->cartService->remove($cart, $id, $context);
return $cart;
}
/**
* @param array $items
* @param Context $context
* @return EntityWrittenContainerEvent
*/
public function updateOfferItems(array $items, Context $context): EntityWrittenContainerEvent
{
return $this->offerItemRepository->update($items, $context);
}
/**
* @param $days
* @param $date
* @throws \Exception
* @return \DateTimeImmutable
*/
public function calculateOfferExpirationDate($days, $date = null): \DateTimeImmutable
{
if (!$date) {
$date = new \DateTimeImmutable(date("Y-m-d H:i:s", time()));
}
if (is_string($date)) {
$date = new \DateTimeImmutable($date);
}
$interval = \DateInterval::createFromDateString("{$days} day");
return $date->add($interval);
}
}