<?php
namespace Virgin\SubscriptionsConfigurator\Utils\Services;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Checkout\Promotion\PromotionEntity;
use Shopware\Core\Content\Media\MediaEntity;
use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
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\Routing\Exception\MissingRequestParameterException;
use Shopware\Core\Framework\Util\Random;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Bridge\Monolog\Logger;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Virgin\EmailPlugin\Core\Events\QuotationEmailEvent;
use Virgin\EmailPlugin\Core\Events\WalkinFlowCheckoutRemainderEmail;
use Virgin\LeadManager\Utils\Services\AccountAutoLoginService;
use Virgin\ProductModelExtension\Custom\Age\AgeEntity;
use Virgin\ProductModelExtension\Custom\Club\ClubEntity;
use Virgin\EmailPlugin\Core\Events\UpdateCustomerDataEmailEvent;
use Virgin\ProductModelExtension\Custom\ProductType\ProductTypeEntity;
use Virgin\ProductModelExtension\Services\ProductService;
use Virgin\Promotions\Custom\PromotionAttributes\PromotionAttributesEntity;
use Virgin\Promotions\Custom\PromotionAttributes\PromotionAttributesEntityCollection;
use Virgin\SubscriptionsConfigurator\Core\Framework\DataAbstractionLayer\Search\Filter\DateRangeFilter;
use Virgin\SubscriptionsConfigurator\Custom\Quotation\QuotationEntity;
use Virgin\SystemIntegration\Services\Import\Product\ProductImporter;
use Virgin\SystemIntegration\Services\RestApiClient;
class SubscriptionsConfiguratorService
{
const string BOCCONI_STRING = 'BOCCONI';
/**
* @var EntityRepository
*/
private EntityRepository $clubRepository;
/**
* @var EntityRepository
*/
private EntityRepository $durationRepository;
/**
* @var EntityRepository
*/
private EntityRepository $timeRepository;
/**
* @var EntityRepository
*/
private EntityRepository $ageRepository;
/**
* @var EntityRepository
*/
private EntityRepository $productRepository;
/**
* @var EntityRepository
*/
private EntityRepository $serviceRepository;
/**
* @var EntityRepository
*/
private EntityRepository $mediaRepository;
/**
* @var EntityRepository
*/
private EntityRepository $serviceLevelRepository;
/**
* @var EntityRepository
*/
private EntityRepository $customerRepository;
/**
* @var EventDispatcherInterface
*/
private EventDispatcherInterface $eventDispatcher;
/**
* @var EntityRepository
*/
private EntityRepository $quotationRepository;
/**
* @var EntityRepository
*/
private EntityRepository $zipcodeRepository;
/**
* @var EntityRepository
*/
private EntityRepository $promotionRepository;
/**
* @var RouterInterface
*/
private RouterInterface $router;
/**
* @var RestApiClient
*/
private RestApiClient $restApiClient;
/**
* @var CartService
*/
private CartService $cartService;
/**
* @var array
*/
private array $cashbackPartners = [];
/**
* @var AccountAutoLoginService
*/
private AccountAutoLoginService $accountAutoLoginService;
/**
* @var Logger
*/
private Logger $logger;
/** @var TranslatorInterface */
private TranslatorInterface $translator;
/**
* @var ProductService
*/
private ProductService $productService;
/**
* @var ContainerInterface
*/
private ContainerInterface $container;
public function __construct(
EntityRepository $clubRepository,
EntityRepository $durationRepository,
EntityRepository $timeRepository,
EntityRepository $ageRepository,
EntityRepository $productRepository,
EntityRepository $serviceRepository,
EntityRepository $mediaRepository,
EntityRepository $serviceLevelRepository,
EntityRepository $customerRepository,
EventDispatcherInterface $eventDispatcher,
EntityRepository $quotationRepository,
EntityRepository $zipcodeRepository,
EntityRepository $promotionRepository,
RouterInterface $router,
RestApiClient $restApiClient,
CartService $cartService,
ContainerInterface $container,
AccountAutoLoginService $accountAutoLoginService,
Logger $logger,
TranslatorInterface $translator,
ProductService $productService
) {
$this->clubRepository = $clubRepository;
$this->durationRepository = $durationRepository;
$this->timeRepository = $timeRepository;
$this->ageRepository = $ageRepository;
$this->productRepository = $productRepository;
$this->serviceRepository = $serviceRepository;
$this->mediaRepository = $mediaRepository;
$this->serviceLevelRepository = $serviceLevelRepository;
$this->customerRepository = $customerRepository;
$this->eventDispatcher = $eventDispatcher;
$this->quotationRepository = $quotationRepository;
$this->zipcodeRepository = $zipcodeRepository;
$this->promotionRepository = $promotionRepository;
$this->router = $router;
$this->restApiClient = $restApiClient;
$this->cartService = $cartService;
$this->container = $container;
$this->accountAutoLoginService = $accountAutoLoginService;
$this->logger = $logger;
$this->translator = $translator;
$this->productService = $productService;
}
/**
* @param SalesChannelContext $context
* @return array
*/
public function getClubFacet(SalesChannelContext $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('visible', true));
$criteria->addAssociation('serviceLevels');
$criteria->addAssociation('image');
$criteria->addSorting(new FieldSorting('name'));
return array_values($this->clubRepository->search($criteria, $context->getContext())->getElements());
}
/**
* @param SalesChannelContext $context
* @return array
*/
public function getDurationFacet(SalesChannelContext $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('visible', true));
$criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
return array_values($this->durationRepository->search($criteria, $context->getContext())->getElements());
}
/**
* @param SalesChannelContext $context
* @return array
*/
public function getTimeFacet(SalesChannelContext $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('visible', true));
$criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
return array_values($this->timeRepository->search($criteria, $context->getContext())->getElements());
}
/**
* @param SalesChannelContext $context
* @return array
*/
public function getAgeFacet(SalesChannelContext $context): array
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('visible', true));
$criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
return array_values($this->ageRepository->search($criteria, $context->getContext())->getElements());
}
/**
* @param $zipcode
* @param SalesChannelContext $context
* @return mixed|null
*/
public function getClubByZipcode($zipcode, SalesChannelContext $context)
{
$criteria = new Criteria();
$criteria->addAssociation('zipcodes');
$criteria->addAssociation('serviceLevels');
$criteria->addFilter(new EqualsFilter('club.zipcodes.name', $zipcode));
$criteria->addSorting(new FieldSorting('club.serviceLevels.priority', FieldSorting::DESCENDING));
return $this->clubRepository->search(
$criteria,
$context->getContext()
)->first();
}
/**
* @param null $clubId
* @param SalesChannelContext $salesChannelContext
* @return ClubEntity|null
*/
public function getCustomerClub($clubId = null, SalesChannelContext $salesChannelContext): ?ClubEntity
{
$criteria = new Criteria();
$criteria->addAssociation('serviceLevels');
$criteria->addAssociation('image');
if (isset($clubId)) {
$criteria->addFilter(new EqualsFilter('club.id', $clubId));
} else {
$criteria->addFilter(new EqualsFilter('club.default', true));
}
return $this->clubRepository->search(
$criteria,
$salesChannelContext->getContext()
)->first();
}
/**
* @param $club
* @param $duration
* @param $serviceLevelId
* @param SalesChannelContext $salesChannelContext
* @return array
* @throws \Exception
*/
public function getSubscriptionConfiguratorResult(
$club,
$duration,
$serviceLevelId,
SalesChannelContext $salesChannelContext
): array
{
// search con i tre filtri in AND -> 0 risultati
$products = $this->getConfiguratorProductList($club, $duration, $serviceLevelId, $salesChannelContext);
$cardInfoList = [];
foreach ($products as $product)
{
$cardInfoList[] = $this->productService->getProductCardInformation($product, $salesChannelContext, $duration);
}
return $cardInfoList;
}
public function calculateProrata($price)
{
$timestamp = strtotime(date('D M d'));
$leftDays = ((int) date('t', $timestamp) - (int) date('j', $timestamp)) + 1;
$maxDays = date('t');
$prorata = $leftDays * ($price / $maxDays);
return round($prorata, 2);
}
public function getCartRecapInformation($productId, SalesChannelContext $context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('product.id', $productId));
$criteria->addAssociation('productType');
$criteria->addAssociation('serviceLevel');
$criteria->addAssociation('club');
$criteria->addAssociation('duration');
$criteria->addAssociation('tags');
/** @var ProductEntity $product */
$product = $this->productRepository->search($criteria, $context->getContext())->first();
$descriptionPromo = [];
if($context->getCustomer()) {
$promo = $this->productService->promoinfo($product, $context);
if (count($promo['exerpPromo']) > 0) {
foreach ($promo['exerpPromo'] as $item) {
$attributes = $item->getExtensions()['virginPromotionAttributes']->getElements();
$exerpDescriptionPromo = reset($attributes)->getDescription();
}
} else {
$exerpDescriptionPromo = '';
}
if (count($promo['swPromo']) > 0) {
foreach ($promo['swPromo'] as $item) {
$swDescriptionPromo = $item->getName();
}
} else {
$swDescriptionPromo = '';
}
$prices = $this->productService->getProductPrices($product, $context, $promo);
$prices['activation']['activationPromo'] = (float)$prices['promo_price']['activation'];
$prices['prorata']['prorataPromo'] = (float)$prices['promo_price']['prorata'];
$discount = 0;
$totalAmount = 0;
if ($prices['promo_price']['activation'] == $prices['activation']['activationBase']) {
//$prices['promo_price']['activation'] = 0;
$totalAmount += (float)$prices['activation']['activationBase'];
} else {
$discount += ($prices['activation']['activationBase'] - (float)$prices['promo_price']['activation']);
$totalAmount += (float)$prices['promo_price']['activation'];
}
if ($prices['promo_price']['prorata'] == $prices['prorata']['prorataBase']) {
//$prices['promo_price']['prorata'] = 0;
$totalAmount += (float)$prices['prorata']['prorataBase'];
} else {
$discount += ((float)$prices['prorata']['prorataBase'] - (float)$prices['promo_price']['prorata']);
$totalAmount += (float)$prices['promo_price']['prorata'];
}
if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
if ($prices['promo_price']['adminFee'] == $prices['adminFee']) {
//$prices['promo_price']['activation'] = 0;
$totalAmount += (float)$prices['adminFee'];
} else {
$discount += ($prices['adminFee'] - (float)$prices['promo_price']['adminFee']);
$totalAmount += (float)$prices['promo_price']['adminFee'];
}
}
if ($prices['promo_price']['product'] == $prices['base_price']) {
//$prices['promo_price']['product'] = 0;
} else {
//$discount += ($prices['base_price'] - $prices['promo_price']);
}
$prices['activation']['activationPromo'] = (float)$prices['promo_price']['activation'];
$prices['prorata']['prorataPromo'] = (float)$prices['promo_price']['prorata'];
$prices['adminFeePromo'] = (float)$prices['promo_price']['adminFee'];
$prices['totalDiscount'] = (float)$discount;
$prices['totalAmount'] = (float)$totalAmount;
} else {
$prices = $this->productService->getProductPrices($product, $context);
$prices['totalDiscount'] = (float)0;
$prices['totalAmount'] = (float)$prices['prorata']['prorataBase'] + $prices['activation']['activationBase'];
if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
$prices['totalAmount'] += (float)$prices['adminFee'];
$prices['adminFeePromo'] = (float)$prices['adminFee'];
$prices['promo_price']['adminFee'] = $prices['base_price'];
}
$prices['promo_price']['prorata'] = (float)$prices['prorata']['prorataBase'];
$prices['promo_price']['activation'] = (float)$prices['activation']['activationBase'];
$prices['promo_price']['product'] = $prices['base_price'];
$prices['activation']['activationPromo'] = (float)$prices['activation']['activationBase'];
$prices['prorata']['prorataPromo'] = (float)$prices['prorata']['prorataBase'];
}
/*if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
$prices['totalAmount'] += $prices['adminFee'];
}*/
$club = $this->clubRepository->search(
new Criteria([$product->getExtensions()['foreignKeys']->jsonSerialize()['clubId']]),
$context->getContext())->first();
$level = $this->serviceLevelRepository->search(
new Criteria([$club->getServiceLevelId()]),
$context->getContext())->first();
$date = date('d/m/Y');
if ($club->getIsClosed() || $club->getIsPresale() ){
$date = $club->getPurchaseDate()->format('d/m/Y');
}
$d = strtotime('first day of next month');
$ridDate = date('d/m/Y', $d);
if($club->getIsClosed()) {
if (strtotime($club->getPurchaseDate()->format('d/m/Y')) > strtotime($ridDate)) {
$ridDate = date('d/m/Y', strtotime("+1 months", $d));
}
}
return [
'product' => $product,
'useAdminFee' => array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] ? true : false,
'club' => $club,
'prices' => $prices,
'exerpDescriptionPromo' => isset($exerpDescriptionPromo) ? $exerpDescriptionPromo : '',
'swDescriptionPromo' => isset($swDescriptionPromo) ? $swDescriptionPromo : '',
'level' => $level->getPriority(),
'levelName' => $level->getName(),
'date' => $date,
'ridDate' => $ridDate,
'levelProduct' => $product->getExtensions()['serviceLevel']->getPriority(),
'levelNameProduct' => $product->getExtensions()['serviceLevel']->getName(),
'quotationAvailable' => true
];
}
/**
* @param SalesChannelContext $context
* @param $quotationId
* @param $customerId
* @param string $email
* @param $productId
* @param $timeLeft
* @param null $personalPromoCode
* @param null $mcInfo
* @throws \Exception
*/
public function sendQuotationEmailRecap(SalesChannelContext $context, $quotationId, $customerId, string $email, $productId, $timeLeft, $personalPromoCode = null, $mcInfo=null)
{
/** @var QuotationEntity $quotationEntity */
$quotationEntity = $this->quotationRepository->search(
(new Criteria())->addFilter(new EqualsFilter('id', $quotationId)),
$context->getContext()
)->first();
/** @var CustomerEntity $customerEntity */
$customerEntity = $this->customerRepository->search(
(new Criteria())->addFilter(new EqualsFilter('id', $customerId)),
$context->getContext()
)->first();
/** @var ProductEntity $productEntity */
$productEntity = $this->productService->getProductById($productId, $context);
$url = $this->generateQuotationUrl($productEntity, $customerEntity, $mcInfo);
/** @var ClubEntity $clubEntity */
$clubEntity = $productEntity->getExtension('club');
/** @var PromotionEntity $personalPromoEntity */
$personalPromoEntity = $this->getPersonalPromo($personalPromoCode, $context);
if ($clubEntity && $clubEntity->getIsPresale()) {
$startDate = $clubEntity->getPurchaseDate()->format('d/m/Y');
}
elseif (isset($_SESSION['prorata_date']) and $_SESSION['prorata_date']){
$startDate = (new \DateTime($_SESSION['prorata_date']))->format('d/m/Y');
} else {
$startDate = $quotationEntity->getCreatedAt()->format('d/m/Y');
}
$productCardInformation = $this->productService->getProductCardInformation($productEntity, $context, null, \DateTime::createFromFormat('d/m/Y', $startDate)->format("Y-m-d"));
$prices = $productCardInformation['prices'];
/** @var PromotionEntity $promo */
$virginPromotionAttributes = null;
$promo = $productCardInformation['promo']['exerpPromo'][0] ?? null;
if ($promo) {
/** @var PromotionAttributesEntityCollection $virginPromotionAttributes */
$virginPromotionAttributesCollection = $promo->getExtension('virginPromotionAttributes');
/** @var PromotionAttributesEntity $virginPromotionAttributes */
$virginPromotionAttributes = $virginPromotionAttributesCollection->first();
}
$isDigital = $productEntity->getExtensions()['productType']->getName() == 'revolution_digitale';
$labels = $this->getPricesLabel($productCardInformation, $productEntity, $virginPromotionAttributes, $prices['prorataDate'], $prices['isPresale']);
$prices = $this->getPrices($prices, $promo, $isDigital, $virginPromotionAttributes);
$ridDate = $clubEntity && $clubEntity->getIsPresale() ? $startDate : (\DateTime::createFromFormat('d/m/Y', $startDate))->modify('first day of next month')->format('d/m/Y');
if ($mcInfo){
$emailEvent = new WalkinFlowCheckoutRemainderEmail(
$context,
$customerEntity,
$email,
$mcInfo,
$url,
$quotationEntity,
$productEntity,
$clubEntity,
$prices,
$personalPromoEntity,
$timeLeft,
$labels,
$startDate,
$ridDate
);
} else {
$emailEvent = new QuotationEmailEvent(
$context,
$quotationEntity,
$customerEntity,
$email,
$productEntity,
$clubEntity,
$prices,
$personalPromoEntity,
$url,
$timeLeft,
$labels,
$startDate,
$ridDate
);
}
$this->eventDispatcher->dispatch($emailEvent);
}
public function sendUpdateCustomerDataEmail($context, $customerEntity)
{
// dispatch email event
$emailEvent = new UpdateCustomerDataEmailEvent($context, $customerEntity);
$this->eventDispatcher->dispatch($emailEvent);
}
public function getProrataActivationPrices(ProductEntity $product, $prorataDate, $promoCode = null){
$prorataDate = $prorataDate < (new \DateTime())->format('Y-m-d') ? (new \DateTime())->format('Y-m-d') : $prorataDate;
$subReq = [
'campainCode' => isset($promoCode) ? $promoCode : (isset($_SESSION['exerp_promotion_code']) ? $_SESSION['exerp_promotion_code'] : ''),
'centerId' => $product->getCustomFields()['virgin_exerp_centerid'],
'clearingHouseType' => $this->restApiClient::CLEARING_HOUSE_EFT,
'personType' => $this->restApiClient::PERSONTYPE_PRIVATE,
'starDate' => $prorataDate,
'subscriptionId' => $product->getCustomFields()['virgin_exerp_productid'],
];
return $this->restApiClient->getSubscritionContractDetails($subReq);
}
/**
* @param string $duration
* @param string $productName
* @return string|null
*/
private function getProductDurationLabel(string $duration, string $productName, string $prorataDate = null, bool $isPresale = false): ?string
{
$startDate = $isPresale ? strtotime($prorataDate) : strtotime('+1 month');
if ($productName=="Digitale Mensile"){
return "da ". $this->getItalianMonth((int)date('n', strtotime('+1 month'))) . " ’" . date('y');
} else if (strpos($duration, '12') !== false) {
$endDate = $isPresale ? $prorataDate . '+11 month' : '+12 month';
return $this->getItalianMonth((int)date('n', $startDate)) . " ’" . date('y', $startDate) . ' - ' . $this->getItalianMonth((int)date('n', strtotime($endDate))) . " ’" . date('y', strtotime($endDate));
} elseif (strpos($duration, '3') !== false) {
$endDate = $isPresale ? $prorataDate . '+2 month' : '+3 month';
return $this->getItalianMonth((int)date('n', $startDate)) . " ’" . date('y', $startDate) . ' - ' . $this->getItalianMonth((int)date('n', strtotime($endDate))) . " ’" . date('y', strtotime($endDate));
}
return null;
}
private function getItalianMonth(int $month): string
{
$months = [
"Gennaio",
"Febbraio",
"Marzo",
"Aprile",
"Maggio",
"Giugno",
"Luglio",
"Agosto",
"Settembre",
"Ottobre",
"Novembre",
"Dicembre"
];
return $months[$month-1];
}
public function getProductService(): ProductService
{
return $this->productService;
}
/**
* @param SalesChannelContext $context
* @return string|null
*/
private function getDefaultAgeFilterValue(SalesChannelContext $context): ?string
{
$fullValueCriteria = new Criteria();
$fullValueCriteria->addFilter(new EqualsFilter('age.default', true));
return $this->ageRepository->searchIds($fullValueCriteria,
$context->getContext())->firstId();
}
/**
* @param SalesChannelContext $context
* @return string|null
*/
private function getDefaultFullAgeFilterValue(SalesChannelContext $context): ?string
{
$fullValueCriteria = new Criteria();
$fullValueCriteria->addFilter(new EqualsFilter('age.code', AgeEntity::AGGREGATE_CODE_VALUE));
return $this->ageRepository->searchIds($fullValueCriteria,
$context->getContext())->firstId();
}
/**
* @param SalesChannelContext $context
* @return string|null
*/
private function getDefaultTimeFilterValue(SalesChannelContext $context): ?string
{
$defaultTimeValueCriteria = new Criteria();
$defaultTimeValueCriteria->addFilter(new EqualsFilter('time.default', true));
return $this->timeRepository->searchIds($defaultTimeValueCriteria,
$context->getContext())->firstId();
}
/**
* @param string $clubId
* @param string $durationId
* @param string $serviceLevelId
* @param SalesChannelContext $salesChannelContext
* @return EntitySearchResult
*/
public function getConfiguratorProductList(string $clubId, string $durationId, string $serviceLevelId, SalesChannelContext $salesChannelContext):EntitySearchResult
{
$criteria = new Criteria();
$criteria->addFilter(new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('product.clubId', $clubId),
new EqualsFilter('product.durationId', $durationId),
new EqualsFilter('product.customFields.virgin_exerp_type', ProductImporter::PRODUCT_TYPE_EFT),
new EqualsFilter('product.serviceLevelId', $serviceLevelId),
new EqualsFilter('product.active', true),
new DateRangeFilter('product.customFields.activation_datetime', 'product.customFields.expiring_datetime')
]
));
$criteria->addAssociation('configurations');
$criteria->addAssociation('serviceLevel');
$criteria->addAssociation('club');
$criteria->addAssociation('productType');
$criteria->addAssociation('duration');
$criteria->addAssociation('tags');
// if duration is "Smart"
if ($durationId == $this->getDurationSmartId($salesChannelContext)) {
// show only "Smart Open 12" and "Smart Open Flexi"
$criteria->addFilter(new MultiFilter(
MultiFilter::CONNECTION_OR,
[
new ContainsFilter('product.name', "smart open 12"),
new ContainsFilter('product.name', "smart open flexi"),
]
));
}
$criteria->addSorting(new FieldSorting('product.customFields.config_position',FieldSorting::ASCENDING));
return $this->productRepository->search($criteria, $salesChannelContext->getContext());
}
/**
* @param SalesChannelContext $salesChannelContext
* @return string|null
*/
private function getDurationSmartId(SalesChannelContext $salesChannelContext): ?string
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('name', 'Smart'));
$criteria->addAssociation('duration');
return $this->durationRepository->search($criteria, $salesChannelContext->getContext())->first()->getId();
}
public function getCartInfo($cart, $request, $productId, $context, $cartService, $container, $cartServiceCalculator) {
$lineItems = $request->get('lineItems');
if (!$lineItems) {
throw new MissingRequestParameterException('lineItems');
}
$count = 0;
if(isset($_SESSION['payment_formula'])) unset($_SESSION['payment_formula']);
if(isset($_SESSION['customer_order_data'])) unset($_SESSION['customer_order_data']);
if(isset($_SESSION['payment_holder'])) unset($_SESSION['payment_holder']);
if(isset($_SESSION['customer_order_data_form'])) unset($_SESSION['customer_order_data_form']);
if(isset($_SESSION['customer_payment_data_form'])) unset($_SESSION['customer_payment_data_form']);
if(isset($_SESSION['shipping_address_data_form'])) unset($_SESSION['shipping_address_data_form']);
if(isset($_SESSION['contract_data_form'])) unset($_SESSION['contract_data_form']);
if(isset($_SESSION['super_promo_flow'])) unset($_SESSION['super_promo_flow']);
if(isset($_SESSION['orderId'])) unset($_SESSION['orderId']);
try {
foreach ($lineItems as $lineItemData) {
$lineItem = new LineItem(
$lineItemData['id'],
$lineItemData['type'],
$lineItemData['referencedId'],
$lineItemData['quantity']
);
$lineItem->setStackable($lineItemData['stackable']);
$lineItem->setRemovable($lineItemData['removable']);
$lineItem->setPayloadValue('product_type', $lineItemData['product_type']);
$lineItem->setPayloadValue('virgin_exerp_type', $lineItemData['virgin_exerp_type']);
$lineItem->setPayloadValue('duration_value', $lineItemData['duration_value']);
$lineItem->setPayloadValue('meta_title', $lineItemData['meta_title']);
if(isset($lineItemData['base_price'])){
$lineItem->setPayloadValue('base_price', $lineItemData['base_price']);
}
if(isset($lineItemData['activation_base_price'])){
$lineItem->setPayloadValue('activation_base_price', $lineItemData['activation_base_price']);
}
if(isset($lineItemData['prorata_base_price'])){
$lineItem->setPayloadValue('prorata_base_price', $lineItemData['prorata_base_price']);
}
if(isset($lineItemData['eft_cash_association_code'])){
$lineItem->setPayloadValue('eft_cash_association_code', $lineItemData['eft_cash_association_code']);
}
if(($context->getCustomer() !== null && isset($context->getCustomer()->getCustomFields()['mc_code_customer'])) || isset($_SESSION['mc_code'])){
$lineItem->setPayloadValue('mc_code', isset($_SESSION['mc_code'])? $_SESSION['mc_code'] : $context->getCustomer()->getCustomFields()['mc_code_customer']);
}
$count += $lineItem->getQuantity();
if(isset($lineItemData['navId']) && $lineItemData['navId']!=''){
$lineItem->setPayloadValue('navId', $lineItemData['navId']);
$category = $this->container->get('category.repository')->search((new Criteria())->addFilter(new EqualsFilter('id', $lineItemData['navId'])), $context->getContext())->first();
if($category->getTags()){
foreach ($category->getTags() as $tagActive){
if($tagActive != null){
if($tagActive && strpos($tagActive->getName(), \Virgin\LeadManager\Storefront\Subscriber\StorefrontSubscriber::TAG_DIRECT) !== false){
$_SESSION['isDirectFlow']= true;
continue;
}else{
if(isset($_SESSION['isDirectFlow'])) unset($_SESSION['isDirectFlow']);
}
}
}
}
}
if($lineItemData['product_type'] == ProductTypeEntity::GUEST_PASS){
$_SESSION['isDirectFlow']= true;
}
$newCart = $cartService->add($cart, $lineItem, $context);
}
$cart = $newCart;
} catch (ProductNotFoundException $exception) {
//$this->addFlash('danger', $this->translator->trans('error.addToCartError'));
}
$lineItems = $cart->getLineItems();
$cart->setLineItems($cartServiceCalculator->setExerpPrice($lineItems, $context));
$amount= $cartServiceCalculator->reCalculateCartAmount($context, $cart);
$cart->setPrice($amount);
return $cart;
}
/**
* @param ProductEntity $productOmaggio
* @param $clubCenterId
* @return string
*/
public function getProductOmaggioPrice(ProductEntity $productOmaggio, $clubCenterId)
{
switch($productOmaggio->getExtensions()['productType']->getName()) {
case ProductTypeEntity::PRODUCT:
$params = [
'externalId' => $productOmaggio->getCustomFields()['virgin_exerp_externalid'],
'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid']
];
return json_decode($this->restApiClient->ProductByRef($params),true)['products'][0]['price'];
case ProductTypeEntity::REVOLUTION_DIGITALE:
$subReq = [
'campainCode' => '',
'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid'],
'clearingHouseType' => $this->restApiClient::CLEARING_HOUSE_EFT,
'personType' => $this->restApiClient::PERSONTYPE_PRIVATE,
'starDate' => (new \DateTime())->format('Y-m-d'),
'subscriptionId' => $productOmaggio->getCustomFields()['virgin_exerp_productid'],
];
$response = $this->restApiClient->getSubscritionContractDetails($subReq);
$type = $productOmaggio->getCustomFields()['virgin_exerp_type'];
if ($type == "CASH") {
$exerpPrice = $response->totalAmount;
}
if ($type == "EFT") {
$exerpPrice = ($response->startupCampaignPrice ?? $response->normalPeriodPrice);
}
return $exerpPrice;
case ProductTypeEntity::CLIPCARD:
$params = [
'productId' => $productOmaggio->getCustomFields()['virgin_exerp_productid'],
'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid'],
'sellingCenter' => $clubCenterId,
];
return $this->restApiClient->ClipCardPrice($params);
}
}
/**
* @param $productId
* @param SalesChannelContext $salesChannelContext
* @return mixed|null
*/
private function getProductOmaggio($productId, SalesChannelContext $salesChannelContext)
{
$criteria = new Criteria();
$criteria->addAssociations(
[
'virginPromotionAttributes',
'virginPromotionAttributes.product',
'productType'
]
);
$criteria->addFilter(
new EqualsFilter('id', $productId)
);
return $this->productRepository
->search($criteria, $salesChannelContext->getContext())
->first();
}
private function getCashbackSnippets()
{
$translator = $this->container->get('translator');
return [
'cashbackTitle' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.title'),
'cashbackFirstPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.firstPhrase'),
'cashbackSecondPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.secondPhrase'),
'cashbackThirdPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.thirdPhrase'),
'omaggioValueTitle' => $translator->trans('subscriptions-configurator.promoValoreAggiunto.omaggioValueTitle'),
'cashbackCardTitle' => $translator->trans('subscriptions-configurator.promoValoreAggiunto.cashbackCardTitle'),
];
}
private function getConcatenatedCashbackPartnerNames()
{
$partnerNames = "";
foreach ($this->cashbackPartners as $partner) {
$partnerNames .= $partner['name'] . ", ";
}
return substr_replace($partnerNames, '.', -2, 2);
}
private function getCashbackPartnersLink($context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('tags.name', 'buono_regalo'));
$criteria->addSorting(new FieldSorting('uploadedAt', FieldSorting::DESCENDING));
/** @var MediaEntity $cashbackPdfMedia */
$cashbackPdfMedia = $this->container->get('media.repository')->search($criteria, $context->getContext())->first();
return $cashbackPdfMedia->getUrl();
}
private function getSpecialCardDescription($productEntity, $context) {
$specialCardDescription = null;
$exerpPromo = $this->productService->getPromoInfo($productEntity, $context)['exerpPromo'];
if (!empty($exerpPromo)) {
$virginPromotionAttributes = $exerpPromo[0]->getExtensions()['virginPromotionAttributes']->getElements();
$virginPromotionElements = reset($virginPromotionAttributes);
if (!empty($virginPromotionElements)) {
$specialCardDescription = $virginPromotionElements->getDescription();
}
}
if ($specialCardDescription == null) {
$specialCardDescription = "";
}
return $specialCardDescription;
}
/**
* @param SalesChannelContext $context
* @param CustomerEntity $customer
* @param string $email
* @param $productId
* @param $promoDescription
* @param $totalAmount
* @param $totalDiscount
* @param null $mcInfo
* @return JsonResponse
*/
public function createAndSendQuotation(SalesChannelContext $context, CustomerEntity $customer, string $email, $productId, $promoDescription, $totalAmount, $totalDiscount, $mcInfo=null): JsonResponse
{
$personalPromoCode = null;
if (empty($productId)) {
return new JsonResponse([
'success' => false,
'snippetMessage' => $this->translator->trans('subscriptions-configurator.cartRecap.quotationPopUp.errorMissingData')
]);
}
$this->logger->log(Logger::DEBUG, 'Price quotation ' . $productId);
//create personal promo code to send via email to customer
$this->managePersonalPromoCode($context, $customer);
if (!$totalDiscount) {
$totalDiscount = '0';
}
try {
date_default_timezone_set("Europe/Rome");
$quotation = $this->quotationRepository->create(
[
[
'expirationDate' => date('Y-m-d H:i:s', strtotime('+48 hours')),
'promoCode' => $promoDescription,
'customerId' => $customer->getId(),
'productId' => $productId,
'personalPromoCode' => $personalPromoCode,
'totalAmount' => $totalAmount,
'totalDiscount' => $totalDiscount,
],
],
$context->getContext()
);
$quotationId = $quotation->getEvents()->getElements()[0]->getIds()[0];
$this->sendQuotationEmailRecap($context, $quotationId, $customer->getId(), $email, $productId, '48', $personalPromoCode, $mcInfo);
return new JsonResponse([
'quotationAvailable' => false,
'success' => true,
'snippetMessage' => $this->translator->trans('subscriptions-configurator.cartRecap.quotationPopUp.successMessage')
]);
} catch (\Exception $exception) {
$this->logger->log(Logger::ERROR, $exception->getMessage());
return new JsonResponse([
'success' => false,
'snippetMessage' => $exception->getMessage()
]);
}
return array($discounts, $rules, $conditions, $attributes);
}
/**
* @param $personalPromoCode
* @param SalesChannelContext $salesChannelContext
* @return PromotionEntity|null
*/
private function getPersonalPromo($personalPromoCode, SalesChannelContext $salesChannelContext): ?PromotionEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('code', $personalPromoCode));
$criteria->addAssociation('discounts');
return $this->promotionRepository->search(
($criteria),
$salesChannelContext->getContext()
)->first();
}
/**
* @param ProductEntity $productEntity
* @param CustomerEntity $customerEntity
* @param $mcInfo
* @return string
*/
private function generateQuotationUrl(ProductEntity $productEntity, CustomerEntity $customerEntity, $mcInfo): string
{
if ($mcInfo){
return $this->router->generate('frontend.continue.checkout',
['t' => $customerEntity->getId()],
UrlGeneratorInterface::ABSOLUTE_URL
);
}
$lineitem[$productEntity->getId()] = [
'id' => $productEntity->getId(),
'referencedId' => $productEntity->getId(),
'type' => 'product',
'stackable' => 1,
'removable' => 1,
'quantity' => 1,
'product_type' => $productEntity->getExtensions()['productType']->getName(),
'virgin_exerp_type' => $productEntity->getCustomFields()['virgin_exerp_type'],
'virgin_exerp_name' => $productEntity->getCustomFields()['virgin_exerp_name'],
'eft_cash_association_code' => null, //deprecated
'duration_value' => $productEntity->getExtensions()['duration']->getName(),
'meta_title' => $productEntity->getMetaTitle()
];
$idToken = $this->accountAutoLoginService->addUserAutoAuthToken($customerEntity->getEmail());
$token = $this->accountAutoLoginService->getUserAutoAuthTokenById($idToken);
return $this->router->generate('frontend.checkout.line-item-checkout.add',
[
'lineItems' => $lineitem,
'redirectTo'=> 'frontend.checkout.confirm.page',
'redirectParameters' => [
'autoAuth' => true,
'idToken' => $idToken,
'token' => $token,
]
], UrlGeneratorInterface::ABSOLUTE_URL);
}
/**
* @param $productCardInformation
* @param $productEntity
* @param $virginPromotionAttributes
* @return array
*/
public function getPricesLabel($productCardInformation, $productEntity, $virginPromotionAttributes, $prorataDate, $isPresale): array
{
$labels = [];
if (isset($virginPromotionAttributes)){
$labels['fourthRow'] = $virginPromotionAttributes->getLabelFourthRow();
$labels['duration'] = $virginPromotionAttributes->getLabelThirdRow() ?? $this->getProductDurationLabel($productCardInformation['duration'], $productEntity->getName(), $prorataDate, $isPresale);
$labels['subtextSavings'] = $virginPromotionAttributes->getSubtextSavings();
} else {
$labels['fourthRow'] = null;
$labels['duration'] = $this->getProductDurationLabel($productCardInformation['duration'], $productEntity->getName(), $prorataDate, $isPresale);
$labels['subtextSavings'] = null;
}
return $labels;
}
/**
* @param array $prices
* @param PromotionEntity|null $promo
* @param bool $isDigital
* @param PromotionAttributesEntity|null $virginPromotionAttributes
* @return array
*/
public function getPrices(array $prices, ?PromotionEntity $promo, bool $isDigital, ?PromotionAttributesEntity $virginPromotionAttributes=null): array
{
$mainPrice = ($isDigital && isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $promo->getDiscounts()->first()->getValue() : $prices['base_price'];
if ($prices['activation']['activationBase'] != $prices['promo_price']['activation']){
$prices['activation']['full'] = $prices['activation']['activationBase'];
$prices['activation']['current'] = $prices['promo_price']['activation'];
} else {
$prices['activation']['full'] = null;
$prices['activation']['current'] = $prices['activation']['activationBase'];
}
if ($prices['prorata']['prorataBase'] != $prices['promo_price']['prorata']){
$prices['prorata']['full'] = $prices['prorata']['prorataBase'];
$prices['prorata']['current'] = $prices['promo_price']['prorata'];
} else {
$prices['prorata']['full'] = null;
$prices['prorata']['current'] = $prices['prorata']['prorataBase'];
}
$prices['fourthPrice']['current'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getPriceFourthRow()) ? ($prices['base_price'] * (100-$virginPromotionAttributes->getPriceFourthRow())/100) : $prices['base_price'];
$prices['fourthPrice']['full'] = $prices['base_price'];
$prices['thirdPrice']['current'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $mainPrice : $prices['base_price'];
$prices['thirdPrice']['full'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $prices['base_price'] : null;
$prices['total']['full'] = $prices['prorata']['prorataBase'] + $prices['activation']['activationBase'];
$prices['total']['current'] = $prices['prorata']['prorataPromo'] + $prices['activation']['activationPromo'];
return $prices;
}
private function managePersonalPromoCode(SalesChannelContext $context, CustomerEntity $customer)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('name', 'salva il preventivo'));
$criteria->addAssociation('personaCustomers');
$criteria->addAssociation('discounts.discountRules.conditions');
$criteria->addAssociation('salesChannels');
$criteria->addAssociation('virginPromotionAttributes');
$promo = $this->promotionRepository->search(
$criteria,
$context->getContext()
)->first();
if ($promo) {
$attributes = $promo->getExtensions()['virginPromotionAttributes']->getElements();
$discounts = $promo->getDiscounts()->getElements();
$discount = reset($discounts);
$personalPromoCode = Random::getAlphanumericString(7);
$rules = $discount->getDiscountRules()->getElements();
$rule = reset($rules);
$conditions = $rule->getConditions()->getElements();
$condition = reset($conditions);
$promotionId = Uuid::randomHex();
$this->promotionRepository->create(
[
[
'id' => $promotionId,
'name' => reset($attributes)->getDescription(),
'active' => true,
'validFrom' => null,
'validUntil' => null,
'maxRedemptionsGlobal' => $promo->getMaxRedemptionsGlobal(),
'maxRedemptionsPerCustomer' => $promo->getMaxRedemptionsPerCustomer(),
'exclusive' => $promo->isExclusive(),
'useCodes' => true,
'use_setgroups' => false,
'code' => $personalPromoCode,
'customer_restriction' => true,
'salesChannels' => [
[
'id' => Uuid::randomHex(),
'salesChannelId' => $context->getSalesChannel()->getId(),
'priority' => 1,
],
],
'discounts' => [
[
'id' => Uuid::randomHex(),
'scope' => $discount->getScope(),
'type' => $discount->getType(),
'value' => $discount->getValue(),
'maxValue' => $discount->getMaxValue(),
'sorterKey' => $discount->getSorterKey(),
'applierKey' => $discount->getApplierKey(),
'considerAdvancedRules' => $discount->isConsiderAdvancedRules(),
'graduated' => false,
'discountRules' => [
[
'id' => $rule->getId(),
'name' => $rule->getName(),
'priority' => $rule->getPriority(),
'conditions' => [
[
'id' => $condition->getId(),
'type' => $condition->getType(),
'ruleId' => $condition->getRuleId(),
'value' => $condition->getValue()
]
]
]
]
],
],
'personaCustomers' => [
[
'id' => $customer->getId(),
],
],
],
],
$context->getContext()
);
$promotionAttributesRepository = $this->container->get('virgin_promotion_attributes.repository');
$promotionAttributesRepository->create(
[
[
'id' => Uuid::randomHex(),
'description' => $promo->getName() . ' for customer ' . $customer->getCustomerNumber(),
'promotionId' => $promotionId
],
],
$context->getContext()
);
}
}
}