custom/plugins/SubscriptionsConfigurator/src/Utils/Services/SubscriptionsConfiguratorService.php line 320

Open in your IDE?
  1. <?php
  2. namespace Virgin\SubscriptionsConfigurator\Utils\Services;
  3. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  4. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  5. use Shopware\Core\Checkout\Customer\CustomerEntity;
  6. use Shopware\Core\Checkout\Promotion\PromotionEntity;
  7. use Shopware\Core\Content\Media\MediaEntity;
  8. use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
  9. use Shopware\Core\Content\Product\ProductEntity;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  17. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  18. use Shopware\Core\Framework\Util\Random;
  19. use Shopware\Core\Framework\Uuid\Uuid;
  20. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  21. use Symfony\Bridge\Monolog\Logger;
  22. use Symfony\Component\DependencyInjection\ContainerInterface;
  23. use Symfony\Component\HttpFoundation\JsonResponse;
  24. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  25. use Symfony\Component\Routing\RouterInterface;
  26. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  27. use Symfony\Contracts\Translation\TranslatorInterface;
  28. use Virgin\EmailPlugin\Core\Events\QuotationEmailEvent;
  29. use Virgin\EmailPlugin\Core\Events\WalkinFlowCheckoutRemainderEmail;
  30. use Virgin\LeadManager\Utils\Services\AccountAutoLoginService;
  31. use Virgin\ProductModelExtension\Custom\Age\AgeEntity;
  32. use Virgin\ProductModelExtension\Custom\Club\ClubEntity;
  33. use Virgin\EmailPlugin\Core\Events\UpdateCustomerDataEmailEvent;
  34. use Virgin\ProductModelExtension\Custom\ProductType\ProductTypeEntity;
  35. use Virgin\ProductModelExtension\Services\ProductService;
  36. use Virgin\Promotions\Custom\PromotionAttributes\PromotionAttributesEntity;
  37. use Virgin\Promotions\Custom\PromotionAttributes\PromotionAttributesEntityCollection;
  38. use Virgin\SubscriptionsConfigurator\Core\Framework\DataAbstractionLayer\Search\Filter\DateRangeFilter;
  39. use Virgin\SubscriptionsConfigurator\Custom\Quotation\QuotationEntity;
  40. use Virgin\SystemIntegration\Services\Import\Product\ProductImporter;
  41. use Virgin\SystemIntegration\Services\RestApiClient;
  42. class SubscriptionsConfiguratorService
  43. {
  44. const string BOCCONI_STRING = 'BOCCONI';
  45. /**
  46. * @var EntityRepository
  47. */
  48. private EntityRepository $clubRepository;
  49. /**
  50. * @var EntityRepository
  51. */
  52. private EntityRepository $durationRepository;
  53. /**
  54. * @var EntityRepository
  55. */
  56. private EntityRepository $timeRepository;
  57. /**
  58. * @var EntityRepository
  59. */
  60. private EntityRepository $ageRepository;
  61. /**
  62. * @var EntityRepository
  63. */
  64. private EntityRepository $productRepository;
  65. /**
  66. * @var EntityRepository
  67. */
  68. private EntityRepository $serviceRepository;
  69. /**
  70. * @var EntityRepository
  71. */
  72. private EntityRepository $mediaRepository;
  73. /**
  74. * @var EntityRepository
  75. */
  76. private EntityRepository $serviceLevelRepository;
  77. /**
  78. * @var EntityRepository
  79. */
  80. private EntityRepository $customerRepository;
  81. /**
  82. * @var EventDispatcherInterface
  83. */
  84. private EventDispatcherInterface $eventDispatcher;
  85. /**
  86. * @var EntityRepository
  87. */
  88. private EntityRepository $quotationRepository;
  89. /**
  90. * @var EntityRepository
  91. */
  92. private EntityRepository $zipcodeRepository;
  93. /**
  94. * @var EntityRepository
  95. */
  96. private EntityRepository $promotionRepository;
  97. /**
  98. * @var RouterInterface
  99. */
  100. private RouterInterface $router;
  101. /**
  102. * @var RestApiClient
  103. */
  104. private RestApiClient $restApiClient;
  105. /**
  106. * @var CartService
  107. */
  108. private CartService $cartService;
  109. /**
  110. * @var array
  111. */
  112. private array $cashbackPartners = [];
  113. /**
  114. * @var AccountAutoLoginService
  115. */
  116. private AccountAutoLoginService $accountAutoLoginService;
  117. /**
  118. * @var Logger
  119. */
  120. private Logger $logger;
  121. /** @var TranslatorInterface */
  122. private TranslatorInterface $translator;
  123. /**
  124. * @var ProductService
  125. */
  126. private ProductService $productService;
  127. /**
  128. * @var ContainerInterface
  129. */
  130. private ContainerInterface $container;
  131. public function __construct(
  132. EntityRepository $clubRepository,
  133. EntityRepository $durationRepository,
  134. EntityRepository $timeRepository,
  135. EntityRepository $ageRepository,
  136. EntityRepository $productRepository,
  137. EntityRepository $serviceRepository,
  138. EntityRepository $mediaRepository,
  139. EntityRepository $serviceLevelRepository,
  140. EntityRepository $customerRepository,
  141. EventDispatcherInterface $eventDispatcher,
  142. EntityRepository $quotationRepository,
  143. EntityRepository $zipcodeRepository,
  144. EntityRepository $promotionRepository,
  145. RouterInterface $router,
  146. RestApiClient $restApiClient,
  147. CartService $cartService,
  148. ContainerInterface $container,
  149. AccountAutoLoginService $accountAutoLoginService,
  150. Logger $logger,
  151. TranslatorInterface $translator,
  152. ProductService $productService
  153. ) {
  154. $this->clubRepository = $clubRepository;
  155. $this->durationRepository = $durationRepository;
  156. $this->timeRepository = $timeRepository;
  157. $this->ageRepository = $ageRepository;
  158. $this->productRepository = $productRepository;
  159. $this->serviceRepository = $serviceRepository;
  160. $this->mediaRepository = $mediaRepository;
  161. $this->serviceLevelRepository = $serviceLevelRepository;
  162. $this->customerRepository = $customerRepository;
  163. $this->eventDispatcher = $eventDispatcher;
  164. $this->quotationRepository = $quotationRepository;
  165. $this->zipcodeRepository = $zipcodeRepository;
  166. $this->promotionRepository = $promotionRepository;
  167. $this->router = $router;
  168. $this->restApiClient = $restApiClient;
  169. $this->cartService = $cartService;
  170. $this->container = $container;
  171. $this->accountAutoLoginService = $accountAutoLoginService;
  172. $this->logger = $logger;
  173. $this->translator = $translator;
  174. $this->productService = $productService;
  175. }
  176. /**
  177. * @param SalesChannelContext $context
  178. * @return array
  179. */
  180. public function getClubFacet(SalesChannelContext $context): array
  181. {
  182. $criteria = new Criteria();
  183. $criteria->addFilter(new EqualsFilter('visible', true));
  184. $criteria->addAssociation('serviceLevels');
  185. $criteria->addAssociation('image');
  186. $criteria->addSorting(new FieldSorting('name'));
  187. return array_values($this->clubRepository->search($criteria, $context->getContext())->getElements());
  188. }
  189. /**
  190. * @param SalesChannelContext $context
  191. * @return array
  192. */
  193. public function getDurationFacet(SalesChannelContext $context): array
  194. {
  195. $criteria = new Criteria();
  196. $criteria->addFilter(new EqualsFilter('visible', true));
  197. $criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
  198. return array_values($this->durationRepository->search($criteria, $context->getContext())->getElements());
  199. }
  200. /**
  201. * @param SalesChannelContext $context
  202. * @return array
  203. */
  204. public function getTimeFacet(SalesChannelContext $context): array
  205. {
  206. $criteria = new Criteria();
  207. $criteria->addFilter(new EqualsFilter('visible', true));
  208. $criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
  209. return array_values($this->timeRepository->search($criteria, $context->getContext())->getElements());
  210. }
  211. /**
  212. * @param SalesChannelContext $context
  213. * @return array
  214. */
  215. public function getAgeFacet(SalesChannelContext $context): array
  216. {
  217. $criteria = new Criteria();
  218. $criteria->addFilter(new EqualsFilter('visible', true));
  219. $criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
  220. return array_values($this->ageRepository->search($criteria, $context->getContext())->getElements());
  221. }
  222. /**
  223. * @param $zipcode
  224. * @param SalesChannelContext $context
  225. * @return mixed|null
  226. */
  227. public function getClubByZipcode($zipcode, SalesChannelContext $context)
  228. {
  229. $criteria = new Criteria();
  230. $criteria->addAssociation('zipcodes');
  231. $criteria->addAssociation('serviceLevels');
  232. $criteria->addFilter(new EqualsFilter('club.zipcodes.name', $zipcode));
  233. $criteria->addSorting(new FieldSorting('club.serviceLevels.priority', FieldSorting::DESCENDING));
  234. return $this->clubRepository->search(
  235. $criteria,
  236. $context->getContext()
  237. )->first();
  238. }
  239. /**
  240. * @param null $clubId
  241. * @param SalesChannelContext $salesChannelContext
  242. * @return ClubEntity|null
  243. */
  244. public function getCustomerClub($clubId = null, SalesChannelContext $salesChannelContext): ?ClubEntity
  245. {
  246. $criteria = new Criteria();
  247. $criteria->addAssociation('serviceLevels');
  248. $criteria->addAssociation('image');
  249. if (isset($clubId)) {
  250. $criteria->addFilter(new EqualsFilter('club.id', $clubId));
  251. } else {
  252. $criteria->addFilter(new EqualsFilter('club.default', true));
  253. }
  254. return $this->clubRepository->search(
  255. $criteria,
  256. $salesChannelContext->getContext()
  257. )->first();
  258. }
  259. /**
  260. * @param $club
  261. * @param $duration
  262. * @param $serviceLevelId
  263. * @param SalesChannelContext $salesChannelContext
  264. * @return array
  265. * @throws \Exception
  266. */
  267. public function getSubscriptionConfiguratorResult(
  268. $club,
  269. $duration,
  270. $serviceLevelId,
  271. SalesChannelContext $salesChannelContext
  272. ): array
  273. {
  274. // search con i tre filtri in AND -> 0 risultati
  275. $products = $this->getConfiguratorProductList($club, $duration, $serviceLevelId, $salesChannelContext);
  276. $cardInfoList = [];
  277. foreach ($products as $product)
  278. {
  279. $cardInfoList[] = $this->productService->getProductCardInformation($product, $salesChannelContext, $duration);
  280. }
  281. return $cardInfoList;
  282. }
  283. public function calculateProrata($price)
  284. {
  285. $timestamp = strtotime(date('D M d'));
  286. $leftDays = ((int) date('t', $timestamp) - (int) date('j', $timestamp)) + 1;
  287. $maxDays = date('t');
  288. $prorata = $leftDays * ($price / $maxDays);
  289. return round($prorata, 2);
  290. }
  291. public function getCartRecapInformation($productId, SalesChannelContext $context)
  292. {
  293. $criteria = new Criteria();
  294. $criteria->addFilter(new EqualsFilter('product.id', $productId));
  295. $criteria->addAssociation('productType');
  296. $criteria->addAssociation('serviceLevel');
  297. $criteria->addAssociation('club');
  298. $criteria->addAssociation('duration');
  299. $criteria->addAssociation('tags');
  300. /** @var ProductEntity $product */
  301. $product = $this->productRepository->search($criteria, $context->getContext())->first();
  302. $descriptionPromo = [];
  303. if($context->getCustomer()) {
  304. $promo = $this->productService->promoinfo($product, $context);
  305. if (count($promo['exerpPromo']) > 0) {
  306. foreach ($promo['exerpPromo'] as $item) {
  307. $attributes = $item->getExtensions()['virginPromotionAttributes']->getElements();
  308. $exerpDescriptionPromo = reset($attributes)->getDescription();
  309. }
  310. } else {
  311. $exerpDescriptionPromo = '';
  312. }
  313. if (count($promo['swPromo']) > 0) {
  314. foreach ($promo['swPromo'] as $item) {
  315. $swDescriptionPromo = $item->getName();
  316. }
  317. } else {
  318. $swDescriptionPromo = '';
  319. }
  320. $prices = $this->productService->getProductPrices($product, $context, $promo);
  321. $prices['activation']['activationPromo'] = (float)$prices['promo_price']['activation'];
  322. $prices['prorata']['prorataPromo'] = (float)$prices['promo_price']['prorata'];
  323. $discount = 0;
  324. $totalAmount = 0;
  325. if ($prices['promo_price']['activation'] == $prices['activation']['activationBase']) {
  326. //$prices['promo_price']['activation'] = 0;
  327. $totalAmount += (float)$prices['activation']['activationBase'];
  328. } else {
  329. $discount += ($prices['activation']['activationBase'] - (float)$prices['promo_price']['activation']);
  330. $totalAmount += (float)$prices['promo_price']['activation'];
  331. }
  332. if ($prices['promo_price']['prorata'] == $prices['prorata']['prorataBase']) {
  333. //$prices['promo_price']['prorata'] = 0;
  334. $totalAmount += (float)$prices['prorata']['prorataBase'];
  335. } else {
  336. $discount += ((float)$prices['prorata']['prorataBase'] - (float)$prices['promo_price']['prorata']);
  337. $totalAmount += (float)$prices['promo_price']['prorata'];
  338. }
  339. if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
  340. if ($prices['promo_price']['adminFee'] == $prices['adminFee']) {
  341. //$prices['promo_price']['activation'] = 0;
  342. $totalAmount += (float)$prices['adminFee'];
  343. } else {
  344. $discount += ($prices['adminFee'] - (float)$prices['promo_price']['adminFee']);
  345. $totalAmount += (float)$prices['promo_price']['adminFee'];
  346. }
  347. }
  348. if ($prices['promo_price']['product'] == $prices['base_price']) {
  349. //$prices['promo_price']['product'] = 0;
  350. } else {
  351. //$discount += ($prices['base_price'] - $prices['promo_price']);
  352. }
  353. $prices['activation']['activationPromo'] = (float)$prices['promo_price']['activation'];
  354. $prices['prorata']['prorataPromo'] = (float)$prices['promo_price']['prorata'];
  355. $prices['adminFeePromo'] = (float)$prices['promo_price']['adminFee'];
  356. $prices['totalDiscount'] = (float)$discount;
  357. $prices['totalAmount'] = (float)$totalAmount;
  358. } else {
  359. $prices = $this->productService->getProductPrices($product, $context);
  360. $prices['totalDiscount'] = (float)0;
  361. $prices['totalAmount'] = (float)$prices['prorata']['prorataBase'] + $prices['activation']['activationBase'];
  362. if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
  363. $prices['totalAmount'] += (float)$prices['adminFee'];
  364. $prices['adminFeePromo'] = (float)$prices['adminFee'];
  365. $prices['promo_price']['adminFee'] = $prices['base_price'];
  366. }
  367. $prices['promo_price']['prorata'] = (float)$prices['prorata']['prorataBase'];
  368. $prices['promo_price']['activation'] = (float)$prices['activation']['activationBase'];
  369. $prices['promo_price']['product'] = $prices['base_price'];
  370. $prices['activation']['activationPromo'] = (float)$prices['activation']['activationBase'];
  371. $prices['prorata']['prorataPromo'] = (float)$prices['prorata']['prorataBase'];
  372. }
  373. /*if(array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] === true) {
  374. $prices['totalAmount'] += $prices['adminFee'];
  375. }*/
  376. $club = $this->clubRepository->search(
  377. new Criteria([$product->getExtensions()['foreignKeys']->jsonSerialize()['clubId']]),
  378. $context->getContext())->first();
  379. $level = $this->serviceLevelRepository->search(
  380. new Criteria([$club->getServiceLevelId()]),
  381. $context->getContext())->first();
  382. $date = date('d/m/Y');
  383. if ($club->getIsClosed() || $club->getIsPresale() ){
  384. $date = $club->getPurchaseDate()->format('d/m/Y');
  385. }
  386. $d = strtotime('first day of next month');
  387. $ridDate = date('d/m/Y', $d);
  388. if($club->getIsClosed()) {
  389. if (strtotime($club->getPurchaseDate()->format('d/m/Y')) > strtotime($ridDate)) {
  390. $ridDate = date('d/m/Y', strtotime("+1 months", $d));
  391. }
  392. }
  393. return [
  394. 'product' => $product,
  395. 'useAdminFee' => array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] ? true : false,
  396. 'club' => $club,
  397. 'prices' => $prices,
  398. 'exerpDescriptionPromo' => isset($exerpDescriptionPromo) ? $exerpDescriptionPromo : '',
  399. 'swDescriptionPromo' => isset($swDescriptionPromo) ? $swDescriptionPromo : '',
  400. 'level' => $level->getPriority(),
  401. 'levelName' => $level->getName(),
  402. 'date' => $date,
  403. 'ridDate' => $ridDate,
  404. 'levelProduct' => $product->getExtensions()['serviceLevel']->getPriority(),
  405. 'levelNameProduct' => $product->getExtensions()['serviceLevel']->getName(),
  406. 'quotationAvailable' => true
  407. ];
  408. }
  409. /**
  410. * @param SalesChannelContext $context
  411. * @param $quotationId
  412. * @param $customerId
  413. * @param string $email
  414. * @param $productId
  415. * @param $timeLeft
  416. * @param null $personalPromoCode
  417. * @param null $mcInfo
  418. * @throws \Exception
  419. */
  420. public function sendQuotationEmailRecap(SalesChannelContext $context, $quotationId, $customerId, string $email, $productId, $timeLeft, $personalPromoCode = null, $mcInfo=null)
  421. {
  422. /** @var QuotationEntity $quotationEntity */
  423. $quotationEntity = $this->quotationRepository->search(
  424. (new Criteria())->addFilter(new EqualsFilter('id', $quotationId)),
  425. $context->getContext()
  426. )->first();
  427. /** @var CustomerEntity $customerEntity */
  428. $customerEntity = $this->customerRepository->search(
  429. (new Criteria())->addFilter(new EqualsFilter('id', $customerId)),
  430. $context->getContext()
  431. )->first();
  432. /** @var ProductEntity $productEntity */
  433. $productEntity = $this->productService->getProductById($productId, $context);
  434. $url = $this->generateQuotationUrl($productEntity, $customerEntity, $mcInfo);
  435. /** @var ClubEntity $clubEntity */
  436. $clubEntity = $productEntity->getExtension('club');
  437. /** @var PromotionEntity $personalPromoEntity */
  438. $personalPromoEntity = $this->getPersonalPromo($personalPromoCode, $context);
  439. if ($clubEntity && $clubEntity->getIsPresale()) {
  440. $startDate = $clubEntity->getPurchaseDate()->format('d/m/Y');
  441. }
  442. elseif (isset($_SESSION['prorata_date']) and $_SESSION['prorata_date']){
  443. $startDate = (new \DateTime($_SESSION['prorata_date']))->format('d/m/Y');
  444. } else {
  445. $startDate = $quotationEntity->getCreatedAt()->format('d/m/Y');
  446. }
  447. $productCardInformation = $this->productService->getProductCardInformation($productEntity, $context, null, \DateTime::createFromFormat('d/m/Y', $startDate)->format("Y-m-d"));
  448. $prices = $productCardInformation['prices'];
  449. /** @var PromotionEntity $promo */
  450. $virginPromotionAttributes = null;
  451. $promo = $productCardInformation['promo']['exerpPromo'][0] ?? null;
  452. if ($promo) {
  453. /** @var PromotionAttributesEntityCollection $virginPromotionAttributes */
  454. $virginPromotionAttributesCollection = $promo->getExtension('virginPromotionAttributes');
  455. /** @var PromotionAttributesEntity $virginPromotionAttributes */
  456. $virginPromotionAttributes = $virginPromotionAttributesCollection->first();
  457. }
  458. $isDigital = $productEntity->getExtensions()['productType']->getName() == 'revolution_digitale';
  459. $labels = $this->getPricesLabel($productCardInformation, $productEntity, $virginPromotionAttributes, $prices['prorataDate'], $prices['isPresale']);
  460. $prices = $this->getPrices($prices, $promo, $isDigital, $virginPromotionAttributes);
  461. $ridDate = $clubEntity && $clubEntity->getIsPresale() ? $startDate : (\DateTime::createFromFormat('d/m/Y', $startDate))->modify('first day of next month')->format('d/m/Y');
  462. if ($mcInfo){
  463. $emailEvent = new WalkinFlowCheckoutRemainderEmail(
  464. $context,
  465. $customerEntity,
  466. $email,
  467. $mcInfo,
  468. $url,
  469. $quotationEntity,
  470. $productEntity,
  471. $clubEntity,
  472. $prices,
  473. $personalPromoEntity,
  474. $timeLeft,
  475. $labels,
  476. $startDate,
  477. $ridDate
  478. );
  479. } else {
  480. $emailEvent = new QuotationEmailEvent(
  481. $context,
  482. $quotationEntity,
  483. $customerEntity,
  484. $email,
  485. $productEntity,
  486. $clubEntity,
  487. $prices,
  488. $personalPromoEntity,
  489. $url,
  490. $timeLeft,
  491. $labels,
  492. $startDate,
  493. $ridDate
  494. );
  495. }
  496. $this->eventDispatcher->dispatch($emailEvent);
  497. }
  498. public function sendUpdateCustomerDataEmail($context, $customerEntity)
  499. {
  500. // dispatch email event
  501. $emailEvent = new UpdateCustomerDataEmailEvent($context, $customerEntity);
  502. $this->eventDispatcher->dispatch($emailEvent);
  503. }
  504. public function getProrataActivationPrices(ProductEntity $product, $prorataDate, $promoCode = null){
  505. $prorataDate = $prorataDate < (new \DateTime())->format('Y-m-d') ? (new \DateTime())->format('Y-m-d') : $prorataDate;
  506. $subReq = [
  507. 'campainCode' => isset($promoCode) ? $promoCode : (isset($_SESSION['exerp_promotion_code']) ? $_SESSION['exerp_promotion_code'] : ''),
  508. 'centerId' => $product->getCustomFields()['virgin_exerp_centerid'],
  509. 'clearingHouseType' => $this->restApiClient::CLEARING_HOUSE_EFT,
  510. 'personType' => $this->restApiClient::PERSONTYPE_PRIVATE,
  511. 'starDate' => $prorataDate,
  512. 'subscriptionId' => $product->getCustomFields()['virgin_exerp_productid'],
  513. ];
  514. return $this->restApiClient->getSubscritionContractDetails($subReq);
  515. }
  516. /**
  517. * @param string $duration
  518. * @param string $productName
  519. * @return string|null
  520. */
  521. private function getProductDurationLabel(string $duration, string $productName, string $prorataDate = null, bool $isPresale = false): ?string
  522. {
  523. $startDate = $isPresale ? strtotime($prorataDate) : strtotime('+1 month');
  524. if ($productName=="Digitale Mensile"){
  525. return "da ". $this->getItalianMonth((int)date('n', strtotime('+1 month'))) . " ’" . date('y');
  526. } else if (strpos($duration, '12') !== false) {
  527. $endDate = $isPresale ? $prorataDate . '+11 month' : '+12 month';
  528. return $this->getItalianMonth((int)date('n', $startDate)) . " ’" . date('y', $startDate) . ' - ' . $this->getItalianMonth((int)date('n', strtotime($endDate))) . " ’" . date('y', strtotime($endDate));
  529. } elseif (strpos($duration, '3') !== false) {
  530. $endDate = $isPresale ? $prorataDate . '+2 month' : '+3 month';
  531. return $this->getItalianMonth((int)date('n', $startDate)) . " ’" . date('y', $startDate) . ' - ' . $this->getItalianMonth((int)date('n', strtotime($endDate))) . " ’" . date('y', strtotime($endDate));
  532. }
  533. return null;
  534. }
  535. private function getItalianMonth(int $month): string
  536. {
  537. $months = [
  538. "Gennaio",
  539. "Febbraio",
  540. "Marzo",
  541. "Aprile",
  542. "Maggio",
  543. "Giugno",
  544. "Luglio",
  545. "Agosto",
  546. "Settembre",
  547. "Ottobre",
  548. "Novembre",
  549. "Dicembre"
  550. ];
  551. return $months[$month-1];
  552. }
  553. public function getProductService(): ProductService
  554. {
  555. return $this->productService;
  556. }
  557. /**
  558. * @param SalesChannelContext $context
  559. * @return string|null
  560. */
  561. private function getDefaultAgeFilterValue(SalesChannelContext $context): ?string
  562. {
  563. $fullValueCriteria = new Criteria();
  564. $fullValueCriteria->addFilter(new EqualsFilter('age.default', true));
  565. return $this->ageRepository->searchIds($fullValueCriteria,
  566. $context->getContext())->firstId();
  567. }
  568. /**
  569. * @param SalesChannelContext $context
  570. * @return string|null
  571. */
  572. private function getDefaultFullAgeFilterValue(SalesChannelContext $context): ?string
  573. {
  574. $fullValueCriteria = new Criteria();
  575. $fullValueCriteria->addFilter(new EqualsFilter('age.code', AgeEntity::AGGREGATE_CODE_VALUE));
  576. return $this->ageRepository->searchIds($fullValueCriteria,
  577. $context->getContext())->firstId();
  578. }
  579. /**
  580. * @param SalesChannelContext $context
  581. * @return string|null
  582. */
  583. private function getDefaultTimeFilterValue(SalesChannelContext $context): ?string
  584. {
  585. $defaultTimeValueCriteria = new Criteria();
  586. $defaultTimeValueCriteria->addFilter(new EqualsFilter('time.default', true));
  587. return $this->timeRepository->searchIds($defaultTimeValueCriteria,
  588. $context->getContext())->firstId();
  589. }
  590. /**
  591. * @param string $clubId
  592. * @param string $durationId
  593. * @param string $serviceLevelId
  594. * @param SalesChannelContext $salesChannelContext
  595. * @return EntitySearchResult
  596. */
  597. public function getConfiguratorProductList(string $clubId, string $durationId, string $serviceLevelId, SalesChannelContext $salesChannelContext):EntitySearchResult
  598. {
  599. $criteria = new Criteria();
  600. $criteria->addFilter(new MultiFilter(
  601. MultiFilter::CONNECTION_AND,
  602. [
  603. new EqualsFilter('product.clubId', $clubId),
  604. new EqualsFilter('product.durationId', $durationId),
  605. new EqualsFilter('product.customFields.virgin_exerp_type', ProductImporter::PRODUCT_TYPE_EFT),
  606. new EqualsFilter('product.serviceLevelId', $serviceLevelId),
  607. new EqualsFilter('product.active', true),
  608. new DateRangeFilter('product.customFields.activation_datetime', 'product.customFields.expiring_datetime')
  609. ]
  610. ));
  611. $criteria->addAssociation('configurations');
  612. $criteria->addAssociation('serviceLevel');
  613. $criteria->addAssociation('club');
  614. $criteria->addAssociation('productType');
  615. $criteria->addAssociation('duration');
  616. $criteria->addAssociation('tags');
  617. // if duration is "Smart"
  618. if ($durationId == $this->getDurationSmartId($salesChannelContext)) {
  619. // show only "Smart Open 12" and "Smart Open Flexi"
  620. $criteria->addFilter(new MultiFilter(
  621. MultiFilter::CONNECTION_OR,
  622. [
  623. new ContainsFilter('product.name', "smart open 12"),
  624. new ContainsFilter('product.name', "smart open flexi"),
  625. ]
  626. ));
  627. }
  628. $criteria->addSorting(new FieldSorting('product.customFields.config_position',FieldSorting::ASCENDING));
  629. return $this->productRepository->search($criteria, $salesChannelContext->getContext());
  630. }
  631. /**
  632. * @param SalesChannelContext $salesChannelContext
  633. * @return string|null
  634. */
  635. private function getDurationSmartId(SalesChannelContext $salesChannelContext): ?string
  636. {
  637. $criteria = new Criteria();
  638. $criteria->addFilter(new EqualsFilter('name', 'Smart'));
  639. $criteria->addAssociation('duration');
  640. return $this->durationRepository->search($criteria, $salesChannelContext->getContext())->first()->getId();
  641. }
  642. public function getCartInfo($cart, $request, $productId, $context, $cartService, $container, $cartServiceCalculator) {
  643. $lineItems = $request->get('lineItems');
  644. if (!$lineItems) {
  645. throw new MissingRequestParameterException('lineItems');
  646. }
  647. $count = 0;
  648. if(isset($_SESSION['payment_formula'])) unset($_SESSION['payment_formula']);
  649. if(isset($_SESSION['customer_order_data'])) unset($_SESSION['customer_order_data']);
  650. if(isset($_SESSION['payment_holder'])) unset($_SESSION['payment_holder']);
  651. if(isset($_SESSION['customer_order_data_form'])) unset($_SESSION['customer_order_data_form']);
  652. if(isset($_SESSION['customer_payment_data_form'])) unset($_SESSION['customer_payment_data_form']);
  653. if(isset($_SESSION['shipping_address_data_form'])) unset($_SESSION['shipping_address_data_form']);
  654. if(isset($_SESSION['contract_data_form'])) unset($_SESSION['contract_data_form']);
  655. if(isset($_SESSION['super_promo_flow'])) unset($_SESSION['super_promo_flow']);
  656. if(isset($_SESSION['orderId'])) unset($_SESSION['orderId']);
  657. try {
  658. foreach ($lineItems as $lineItemData) {
  659. $lineItem = new LineItem(
  660. $lineItemData['id'],
  661. $lineItemData['type'],
  662. $lineItemData['referencedId'],
  663. $lineItemData['quantity']
  664. );
  665. $lineItem->setStackable($lineItemData['stackable']);
  666. $lineItem->setRemovable($lineItemData['removable']);
  667. $lineItem->setPayloadValue('product_type', $lineItemData['product_type']);
  668. $lineItem->setPayloadValue('virgin_exerp_type', $lineItemData['virgin_exerp_type']);
  669. $lineItem->setPayloadValue('duration_value', $lineItemData['duration_value']);
  670. $lineItem->setPayloadValue('meta_title', $lineItemData['meta_title']);
  671. if(isset($lineItemData['base_price'])){
  672. $lineItem->setPayloadValue('base_price', $lineItemData['base_price']);
  673. }
  674. if(isset($lineItemData['activation_base_price'])){
  675. $lineItem->setPayloadValue('activation_base_price', $lineItemData['activation_base_price']);
  676. }
  677. if(isset($lineItemData['prorata_base_price'])){
  678. $lineItem->setPayloadValue('prorata_base_price', $lineItemData['prorata_base_price']);
  679. }
  680. if(isset($lineItemData['eft_cash_association_code'])){
  681. $lineItem->setPayloadValue('eft_cash_association_code', $lineItemData['eft_cash_association_code']);
  682. }
  683. if(($context->getCustomer() !== null && isset($context->getCustomer()->getCustomFields()['mc_code_customer'])) || isset($_SESSION['mc_code'])){
  684. $lineItem->setPayloadValue('mc_code', isset($_SESSION['mc_code'])? $_SESSION['mc_code'] : $context->getCustomer()->getCustomFields()['mc_code_customer']);
  685. }
  686. $count += $lineItem->getQuantity();
  687. if(isset($lineItemData['navId']) && $lineItemData['navId']!=''){
  688. $lineItem->setPayloadValue('navId', $lineItemData['navId']);
  689. $category = $this->container->get('category.repository')->search((new Criteria())->addFilter(new EqualsFilter('id', $lineItemData['navId'])), $context->getContext())->first();
  690. if($category->getTags()){
  691. foreach ($category->getTags() as $tagActive){
  692. if($tagActive != null){
  693. if($tagActive && strpos($tagActive->getName(), \Virgin\LeadManager\Storefront\Subscriber\StorefrontSubscriber::TAG_DIRECT) !== false){
  694. $_SESSION['isDirectFlow']= true;
  695. continue;
  696. }else{
  697. if(isset($_SESSION['isDirectFlow'])) unset($_SESSION['isDirectFlow']);
  698. }
  699. }
  700. }
  701. }
  702. }
  703. if($lineItemData['product_type'] == ProductTypeEntity::GUEST_PASS){
  704. $_SESSION['isDirectFlow']= true;
  705. }
  706. $newCart = $cartService->add($cart, $lineItem, $context);
  707. }
  708. $cart = $newCart;
  709. } catch (ProductNotFoundException $exception) {
  710. //$this->addFlash('danger', $this->translator->trans('error.addToCartError'));
  711. }
  712. $lineItems = $cart->getLineItems();
  713. $cart->setLineItems($cartServiceCalculator->setExerpPrice($lineItems, $context));
  714. $amount= $cartServiceCalculator->reCalculateCartAmount($context, $cart);
  715. $cart->setPrice($amount);
  716. return $cart;
  717. }
  718. /**
  719. * @param ProductEntity $productOmaggio
  720. * @param $clubCenterId
  721. * @return string
  722. */
  723. public function getProductOmaggioPrice(ProductEntity $productOmaggio, $clubCenterId)
  724. {
  725. switch($productOmaggio->getExtensions()['productType']->getName()) {
  726. case ProductTypeEntity::PRODUCT:
  727. $params = [
  728. 'externalId' => $productOmaggio->getCustomFields()['virgin_exerp_externalid'],
  729. 'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid']
  730. ];
  731. return json_decode($this->restApiClient->ProductByRef($params),true)['products'][0]['price'];
  732. case ProductTypeEntity::REVOLUTION_DIGITALE:
  733. $subReq = [
  734. 'campainCode' => '',
  735. 'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid'],
  736. 'clearingHouseType' => $this->restApiClient::CLEARING_HOUSE_EFT,
  737. 'personType' => $this->restApiClient::PERSONTYPE_PRIVATE,
  738. 'starDate' => (new \DateTime())->format('Y-m-d'),
  739. 'subscriptionId' => $productOmaggio->getCustomFields()['virgin_exerp_productid'],
  740. ];
  741. $response = $this->restApiClient->getSubscritionContractDetails($subReq);
  742. $type = $productOmaggio->getCustomFields()['virgin_exerp_type'];
  743. if ($type == "CASH") {
  744. $exerpPrice = $response->totalAmount;
  745. }
  746. if ($type == "EFT") {
  747. $exerpPrice = ($response->startupCampaignPrice ?? $response->normalPeriodPrice);
  748. }
  749. return $exerpPrice;
  750. case ProductTypeEntity::CLIPCARD:
  751. $params = [
  752. 'productId' => $productOmaggio->getCustomFields()['virgin_exerp_productid'],
  753. 'centerId' => $productOmaggio->getCustomFields()['virgin_exerp_centerid'],
  754. 'sellingCenter' => $clubCenterId,
  755. ];
  756. return $this->restApiClient->ClipCardPrice($params);
  757. }
  758. }
  759. /**
  760. * @param $productId
  761. * @param SalesChannelContext $salesChannelContext
  762. * @return mixed|null
  763. */
  764. private function getProductOmaggio($productId, SalesChannelContext $salesChannelContext)
  765. {
  766. $criteria = new Criteria();
  767. $criteria->addAssociations(
  768. [
  769. 'virginPromotionAttributes',
  770. 'virginPromotionAttributes.product',
  771. 'productType'
  772. ]
  773. );
  774. $criteria->addFilter(
  775. new EqualsFilter('id', $productId)
  776. );
  777. return $this->productRepository
  778. ->search($criteria, $salesChannelContext->getContext())
  779. ->first();
  780. }
  781. private function getCashbackSnippets()
  782. {
  783. $translator = $this->container->get('translator');
  784. return [
  785. 'cashbackTitle' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.title'),
  786. 'cashbackFirstPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.firstPhrase'),
  787. 'cashbackSecondPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.secondPhrase'),
  788. 'cashbackThirdPhrase' => $translator->trans('subscriptions-configurator.popUp.cashbackPopUp.thirdPhrase'),
  789. 'omaggioValueTitle' => $translator->trans('subscriptions-configurator.promoValoreAggiunto.omaggioValueTitle'),
  790. 'cashbackCardTitle' => $translator->trans('subscriptions-configurator.promoValoreAggiunto.cashbackCardTitle'),
  791. ];
  792. }
  793. private function getConcatenatedCashbackPartnerNames()
  794. {
  795. $partnerNames = "";
  796. foreach ($this->cashbackPartners as $partner) {
  797. $partnerNames .= $partner['name'] . ", ";
  798. }
  799. return substr_replace($partnerNames, '.', -2, 2);
  800. }
  801. private function getCashbackPartnersLink($context)
  802. {
  803. $criteria = new Criteria();
  804. $criteria->addFilter(new EqualsFilter('tags.name', 'buono_regalo'));
  805. $criteria->addSorting(new FieldSorting('uploadedAt', FieldSorting::DESCENDING));
  806. /** @var MediaEntity $cashbackPdfMedia */
  807. $cashbackPdfMedia = $this->container->get('media.repository')->search($criteria, $context->getContext())->first();
  808. return $cashbackPdfMedia->getUrl();
  809. }
  810. private function getSpecialCardDescription($productEntity, $context) {
  811. $specialCardDescription = null;
  812. $exerpPromo = $this->productService->getPromoInfo($productEntity, $context)['exerpPromo'];
  813. if (!empty($exerpPromo)) {
  814. $virginPromotionAttributes = $exerpPromo[0]->getExtensions()['virginPromotionAttributes']->getElements();
  815. $virginPromotionElements = reset($virginPromotionAttributes);
  816. if (!empty($virginPromotionElements)) {
  817. $specialCardDescription = $virginPromotionElements->getDescription();
  818. }
  819. }
  820. if ($specialCardDescription == null) {
  821. $specialCardDescription = "";
  822. }
  823. return $specialCardDescription;
  824. }
  825. /**
  826. * @param SalesChannelContext $context
  827. * @param CustomerEntity $customer
  828. * @param string $email
  829. * @param $productId
  830. * @param $promoDescription
  831. * @param $totalAmount
  832. * @param $totalDiscount
  833. * @param null $mcInfo
  834. * @return JsonResponse
  835. */
  836. public function createAndSendQuotation(SalesChannelContext $context, CustomerEntity $customer, string $email, $productId, $promoDescription, $totalAmount, $totalDiscount, $mcInfo=null): JsonResponse
  837. {
  838. $personalPromoCode = null;
  839. if (empty($productId)) {
  840. return new JsonResponse([
  841. 'success' => false,
  842. 'snippetMessage' => $this->translator->trans('subscriptions-configurator.cartRecap.quotationPopUp.errorMissingData')
  843. ]);
  844. }
  845. $this->logger->log(Logger::DEBUG, 'Price quotation ' . $productId);
  846. //create personal promo code to send via email to customer
  847. $this->managePersonalPromoCode($context, $customer);
  848. if (!$totalDiscount) {
  849. $totalDiscount = '0';
  850. }
  851. try {
  852. date_default_timezone_set("Europe/Rome");
  853. $quotation = $this->quotationRepository->create(
  854. [
  855. [
  856. 'expirationDate' => date('Y-m-d H:i:s', strtotime('+48 hours')),
  857. 'promoCode' => $promoDescription,
  858. 'customerId' => $customer->getId(),
  859. 'productId' => $productId,
  860. 'personalPromoCode' => $personalPromoCode,
  861. 'totalAmount' => $totalAmount,
  862. 'totalDiscount' => $totalDiscount,
  863. ],
  864. ],
  865. $context->getContext()
  866. );
  867. $quotationId = $quotation->getEvents()->getElements()[0]->getIds()[0];
  868. $this->sendQuotationEmailRecap($context, $quotationId, $customer->getId(), $email, $productId, '48', $personalPromoCode, $mcInfo);
  869. return new JsonResponse([
  870. 'quotationAvailable' => false,
  871. 'success' => true,
  872. 'snippetMessage' => $this->translator->trans('subscriptions-configurator.cartRecap.quotationPopUp.successMessage')
  873. ]);
  874. } catch (\Exception $exception) {
  875. $this->logger->log(Logger::ERROR, $exception->getMessage());
  876. return new JsonResponse([
  877. 'success' => false,
  878. 'snippetMessage' => $exception->getMessage()
  879. ]);
  880. }
  881. return array($discounts, $rules, $conditions, $attributes);
  882. }
  883. /**
  884. * @param $personalPromoCode
  885. * @param SalesChannelContext $salesChannelContext
  886. * @return PromotionEntity|null
  887. */
  888. private function getPersonalPromo($personalPromoCode, SalesChannelContext $salesChannelContext): ?PromotionEntity
  889. {
  890. $criteria = new Criteria();
  891. $criteria->addFilter(new EqualsFilter('code', $personalPromoCode));
  892. $criteria->addAssociation('discounts');
  893. return $this->promotionRepository->search(
  894. ($criteria),
  895. $salesChannelContext->getContext()
  896. )->first();
  897. }
  898. /**
  899. * @param ProductEntity $productEntity
  900. * @param CustomerEntity $customerEntity
  901. * @param $mcInfo
  902. * @return string
  903. */
  904. private function generateQuotationUrl(ProductEntity $productEntity, CustomerEntity $customerEntity, $mcInfo): string
  905. {
  906. if ($mcInfo){
  907. return $this->router->generate('frontend.continue.checkout',
  908. ['t' => $customerEntity->getId()],
  909. UrlGeneratorInterface::ABSOLUTE_URL
  910. );
  911. }
  912. $lineitem[$productEntity->getId()] = [
  913. 'id' => $productEntity->getId(),
  914. 'referencedId' => $productEntity->getId(),
  915. 'type' => 'product',
  916. 'stackable' => 1,
  917. 'removable' => 1,
  918. 'quantity' => 1,
  919. 'product_type' => $productEntity->getExtensions()['productType']->getName(),
  920. 'virgin_exerp_type' => $productEntity->getCustomFields()['virgin_exerp_type'],
  921. 'virgin_exerp_name' => $productEntity->getCustomFields()['virgin_exerp_name'],
  922. 'eft_cash_association_code' => null, //deprecated
  923. 'duration_value' => $productEntity->getExtensions()['duration']->getName(),
  924. 'meta_title' => $productEntity->getMetaTitle()
  925. ];
  926. $idToken = $this->accountAutoLoginService->addUserAutoAuthToken($customerEntity->getEmail());
  927. $token = $this->accountAutoLoginService->getUserAutoAuthTokenById($idToken);
  928. return $this->router->generate('frontend.checkout.line-item-checkout.add',
  929. [
  930. 'lineItems' => $lineitem,
  931. 'redirectTo'=> 'frontend.checkout.confirm.page',
  932. 'redirectParameters' => [
  933. 'autoAuth' => true,
  934. 'idToken' => $idToken,
  935. 'token' => $token,
  936. ]
  937. ], UrlGeneratorInterface::ABSOLUTE_URL);
  938. }
  939. /**
  940. * @param $productCardInformation
  941. * @param $productEntity
  942. * @param $virginPromotionAttributes
  943. * @return array
  944. */
  945. public function getPricesLabel($productCardInformation, $productEntity, $virginPromotionAttributes, $prorataDate, $isPresale): array
  946. {
  947. $labels = [];
  948. if (isset($virginPromotionAttributes)){
  949. $labels['fourthRow'] = $virginPromotionAttributes->getLabelFourthRow();
  950. $labels['duration'] = $virginPromotionAttributes->getLabelThirdRow() ?? $this->getProductDurationLabel($productCardInformation['duration'], $productEntity->getName(), $prorataDate, $isPresale);
  951. $labels['subtextSavings'] = $virginPromotionAttributes->getSubtextSavings();
  952. } else {
  953. $labels['fourthRow'] = null;
  954. $labels['duration'] = $this->getProductDurationLabel($productCardInformation['duration'], $productEntity->getName(), $prorataDate, $isPresale);
  955. $labels['subtextSavings'] = null;
  956. }
  957. return $labels;
  958. }
  959. /**
  960. * @param array $prices
  961. * @param PromotionEntity|null $promo
  962. * @param bool $isDigital
  963. * @param PromotionAttributesEntity|null $virginPromotionAttributes
  964. * @return array
  965. */
  966. public function getPrices(array $prices, ?PromotionEntity $promo, bool $isDigital, ?PromotionAttributesEntity $virginPromotionAttributes=null): array
  967. {
  968. $mainPrice = ($isDigital && isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $promo->getDiscounts()->first()->getValue() : $prices['base_price'];
  969. if ($prices['activation']['activationBase'] != $prices['promo_price']['activation']){
  970. $prices['activation']['full'] = $prices['activation']['activationBase'];
  971. $prices['activation']['current'] = $prices['promo_price']['activation'];
  972. } else {
  973. $prices['activation']['full'] = null;
  974. $prices['activation']['current'] = $prices['activation']['activationBase'];
  975. }
  976. if ($prices['prorata']['prorataBase'] != $prices['promo_price']['prorata']){
  977. $prices['prorata']['full'] = $prices['prorata']['prorataBase'];
  978. $prices['prorata']['current'] = $prices['promo_price']['prorata'];
  979. } else {
  980. $prices['prorata']['full'] = null;
  981. $prices['prorata']['current'] = $prices['prorata']['prorataBase'];
  982. }
  983. $prices['fourthPrice']['current'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getPriceFourthRow()) ? ($prices['base_price'] * (100-$virginPromotionAttributes->getPriceFourthRow())/100) : $prices['base_price'];
  984. $prices['fourthPrice']['full'] = $prices['base_price'];
  985. $prices['thirdPrice']['current'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $mainPrice : $prices['base_price'];
  986. $prices['thirdPrice']['full'] = (isset($virginPromotionAttributes) && $virginPromotionAttributes->getIsStrikethroughPromo()) ? $prices['base_price'] : null;
  987. $prices['total']['full'] = $prices['prorata']['prorataBase'] + $prices['activation']['activationBase'];
  988. $prices['total']['current'] = $prices['prorata']['prorataPromo'] + $prices['activation']['activationPromo'];
  989. return $prices;
  990. }
  991. private function managePersonalPromoCode(SalesChannelContext $context, CustomerEntity $customer)
  992. {
  993. $criteria = new Criteria();
  994. $criteria->addFilter(new EqualsFilter('name', 'salva il preventivo'));
  995. $criteria->addAssociation('personaCustomers');
  996. $criteria->addAssociation('discounts.discountRules.conditions');
  997. $criteria->addAssociation('salesChannels');
  998. $criteria->addAssociation('virginPromotionAttributes');
  999. $promo = $this->promotionRepository->search(
  1000. $criteria,
  1001. $context->getContext()
  1002. )->first();
  1003. if ($promo) {
  1004. $attributes = $promo->getExtensions()['virginPromotionAttributes']->getElements();
  1005. $discounts = $promo->getDiscounts()->getElements();
  1006. $discount = reset($discounts);
  1007. $personalPromoCode = Random::getAlphanumericString(7);
  1008. $rules = $discount->getDiscountRules()->getElements();
  1009. $rule = reset($rules);
  1010. $conditions = $rule->getConditions()->getElements();
  1011. $condition = reset($conditions);
  1012. $promotionId = Uuid::randomHex();
  1013. $this->promotionRepository->create(
  1014. [
  1015. [
  1016. 'id' => $promotionId,
  1017. 'name' => reset($attributes)->getDescription(),
  1018. 'active' => true,
  1019. 'validFrom' => null,
  1020. 'validUntil' => null,
  1021. 'maxRedemptionsGlobal' => $promo->getMaxRedemptionsGlobal(),
  1022. 'maxRedemptionsPerCustomer' => $promo->getMaxRedemptionsPerCustomer(),
  1023. 'exclusive' => $promo->isExclusive(),
  1024. 'useCodes' => true,
  1025. 'use_setgroups' => false,
  1026. 'code' => $personalPromoCode,
  1027. 'customer_restriction' => true,
  1028. 'salesChannels' => [
  1029. [
  1030. 'id' => Uuid::randomHex(),
  1031. 'salesChannelId' => $context->getSalesChannel()->getId(),
  1032. 'priority' => 1,
  1033. ],
  1034. ],
  1035. 'discounts' => [
  1036. [
  1037. 'id' => Uuid::randomHex(),
  1038. 'scope' => $discount->getScope(),
  1039. 'type' => $discount->getType(),
  1040. 'value' => $discount->getValue(),
  1041. 'maxValue' => $discount->getMaxValue(),
  1042. 'sorterKey' => $discount->getSorterKey(),
  1043. 'applierKey' => $discount->getApplierKey(),
  1044. 'considerAdvancedRules' => $discount->isConsiderAdvancedRules(),
  1045. 'graduated' => false,
  1046. 'discountRules' => [
  1047. [
  1048. 'id' => $rule->getId(),
  1049. 'name' => $rule->getName(),
  1050. 'priority' => $rule->getPriority(),
  1051. 'conditions' => [
  1052. [
  1053. 'id' => $condition->getId(),
  1054. 'type' => $condition->getType(),
  1055. 'ruleId' => $condition->getRuleId(),
  1056. 'value' => $condition->getValue()
  1057. ]
  1058. ]
  1059. ]
  1060. ]
  1061. ],
  1062. ],
  1063. 'personaCustomers' => [
  1064. [
  1065. 'id' => $customer->getId(),
  1066. ],
  1067. ],
  1068. ],
  1069. ],
  1070. $context->getContext()
  1071. );
  1072. $promotionAttributesRepository = $this->container->get('virgin_promotion_attributes.repository');
  1073. $promotionAttributesRepository->create(
  1074. [
  1075. [
  1076. 'id' => Uuid::randomHex(),
  1077. 'description' => $promo->getName() . ' for customer ' . $customer->getCustomerNumber(),
  1078. 'promotionId' => $promotionId
  1079. ],
  1080. ],
  1081. $context->getContext()
  1082. );
  1083. }
  1084. }
  1085. }