custom/plugins/ProductModelExtension/src/Services/ProductService.php line 668

Open in your IDE?
  1. <?php
  2. namespace Virgin\ProductModelExtension\Services;
  3. use DateInterval;
  4. use DateTime;
  5. use DateTimeImmutable;
  6. use Exception;
  7. use Shopware\Core\Checkout\Promotion\Aggregate\PromotionDiscount\PromotionDiscountEntity;
  8. use Shopware\Core\Checkout\Promotion\Exception\DiscountCalculatorNotFoundException;
  9. use Shopware\Core\Checkout\Promotion\PromotionEntity;
  10. use Shopware\Core\Content\Product\ProductEntity;
  11. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  16. use Shopware\Core\Framework\Rule\Exception\UnsupportedOperatorException;
  17. use Shopware\Core\Framework\Rule\Rule;
  18. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  19. use Swag\PayPal\PayPal\Api\Payment\Transaction\RelatedResource\Sale;
  20. use Symfony\Component\HttpFoundation\Session\Session;
  21. use Symfony\Contracts\Translation\TranslatorInterface;
  22. use Virgin\ProductModelExtension\Custom\ProductType\ProductTypeEntity;
  23. use Virgin\ProductModelExtension\Custom\Service\Configuration\ConfigurationEntity;
  24. use Virgin\ProductModelExtension\Custom\Service\ServiceEntity;
  25. use Virgin\SystemIntegration\Services\RestApiClient;
  26. class ProductService
  27. {
  28. const string ALL_BASE_SERVICES = 'Servizi del Club';
  29. const string ALL_BASE_SERVICES_DESCRIPTION = 'Elenco dei servizi base inclusi';
  30. const string SERVICE_DIGITAL_WORKOUT = 'Allenamento Digitale';
  31. const string SERVICE_BOOKING = 'Priority Booking';
  32. const string SERVICE_ALTER_EGO = 'Alter Ego';
  33. const string SERVICE_MULTICLUB = 'Multiclub';
  34. const string SERVICE_ASCIUGAMANO = 'Asciugamano';
  35. const string SERVICE_KIT_DOCCIA = 'Kit Doccia';
  36. const string SERVICE_GUESTPASS_REVOLUTION = 'Guest Pass Revolution';
  37. const string SERVICE_GUESTPASS_AMICO = 'Guest Pass Amico';
  38. const string BOCCONI_STRING = 'BOCCONI';
  39. /**
  40. * @var EntityRepository
  41. */
  42. private EntityRepository $productRepository;
  43. /**
  44. * @var EntityRepository
  45. */
  46. private EntityRepository $durationRepository;
  47. /**
  48. * @var EntityRepository
  49. */
  50. private EntityRepository $serviceLevelRepository;
  51. /**
  52. * @var EntityRepository
  53. */
  54. private EntityRepository $serviceRepository;
  55. /**
  56. * @var EntityRepository
  57. */
  58. private EntityRepository $mediaRepository;
  59. /**
  60. * @var EntityRepository
  61. */
  62. private EntityRepository $promotionRepository;
  63. /**
  64. * @var EntityRepository
  65. */
  66. private EntityRepository $ruleConditionRepository;
  67. /**
  68. * @var RestApiClient
  69. */
  70. private RestApiClient $restApiClient;
  71. /**
  72. * @var Session
  73. */
  74. private $session;public function __construct(
  75. EntityRepository $productRepository,
  76. EntityRepository $durationRepository,
  77. EntityRepository $serviceLevelRepository,
  78. EntityRepository $serviceRepository,
  79. EntityRepository $mediaRepository,
  80. EntityRepository $promotionRepository,
  81. EntityRepository $ruleConditionRepository,
  82. RestApiClient $restApiClient
  83. ,
  84. Session $session
  85. )
  86. {
  87. $this->productRepository = $productRepository;
  88. $this->durationRepository = $durationRepository;
  89. $this->serviceLevelRepository = $serviceLevelRepository;
  90. $this->serviceRepository = $serviceRepository;
  91. $this->mediaRepository = $mediaRepository;
  92. $this->promotionRepository = $promotionRepository;
  93. $this->ruleConditionRepository = $ruleConditionRepository;
  94. $this->restApiClient = $restApiClient;
  95. $this->session = $session;
  96. }
  97. /**
  98. * @param ProductEntity $product
  99. * @param SalesChannelContext $salesChannelContext
  100. * @param null $duration
  101. * @param null $prorataDate
  102. * @return array
  103. * @throws Exception
  104. */
  105. public function getProductCardInformation(ProductEntity $product, SalesChannelContext $salesChannelContext, $duration = null, $prorataDate = null): array
  106. {
  107. $productConfigurations = $this->getProductConfigurations($product, $salesChannelContext);
  108. $services = $productConfigurations['services'];
  109. $workouts = $productConfigurations['workouts'];
  110. $promo = $this->getPromoInfo($product, $salesChannelContext);
  111. //todo remove session
  112. if (isset($_SESSION['exerp_promotion_code'])) {
  113. unset($_SESSION['exerp_promotion_code']);
  114. }
  115. $prices = $this->getProductPrices($product, $salesChannelContext, $promo, $prorataDate);
  116. $level = $this->serviceLevelRepository->search(new Criteria(array_filter([$product->getExtensions()['foreignKeys']->jsonSerialize()['serviceLevelId']])), $salesChannelContext->getContext())->first();
  117. if ($product->getExtensions() && isset($product->getExtensions()['duration']) && $product->getExtensions()['duration']!=null) {
  118. $durationValue = $product->getExtensions()['duration']->getName();
  119. } else {
  120. $duration = $this->durationRepository->search(new Criteria(array_filter([$product->getExtensions()['foreignKeys']->jsonSerialize()['durationId']])), $salesChannelContext->getContext())->first();
  121. $durationValue = $duration->getName();
  122. }
  123. return [
  124. 'product' => $product,
  125. 'useAdminFee' => array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'],
  126. 'services' => $services,
  127. 'workouts' => $workouts,
  128. 'prices' => $prices,
  129. 'upgrades' => null,
  130. 'level' => $level->getPriority(),
  131. 'levelName' => $level->getName(),
  132. 'promo' => $promo,
  133. 'duration' => $durationValue
  134. ];
  135. }
  136. /**
  137. * @param ProductEntity $product
  138. * @param SalesChannelContext $salesChannelContext
  139. * @return array
  140. */
  141. private function getProductConfigurations(ProductEntity $product, SalesChannelContext $salesChannelContext): array
  142. {
  143. $services = [];
  144. if ($this->isDigital($product)){
  145. $mainServiceList = [self::SERVICE_GUESTPASS_REVOLUTION];
  146. $otherServiceList = [];
  147. } else {
  148. $mainServiceList = [
  149. self::ALL_BASE_SERVICES,
  150. self::SERVICE_DIGITAL_WORKOUT,
  151. self::SERVICE_BOOKING,
  152. self::SERVICE_MULTICLUB,
  153. self::SERVICE_ALTER_EGO,
  154. ];
  155. $otherServiceList = [
  156. self::SERVICE_ASCIUGAMANO,
  157. self::SERVICE_KIT_DOCCIA,
  158. self::SERVICE_GUESTPASS_AMICO,
  159. ];
  160. }
  161. $mainServices = [];
  162. $otherServices = [];
  163. $workouts = [];
  164. foreach ($mainServiceList as $mainServiceName) {
  165. $item = [];
  166. if (self::ALL_BASE_SERVICES == $mainServiceName) {
  167. $item['name'] = self::ALL_BASE_SERVICES;
  168. $item['modalInfo'] = [
  169. 'id' => str_replace(strtolower(self::ALL_BASE_SERVICES), ' ', '-'),
  170. 'title' => self::ALL_BASE_SERVICES,
  171. 'description' => self::ALL_BASE_SERVICES_DESCRIPTION
  172. ];
  173. $item['services'] = [];
  174. $item['active'] = true;
  175. } else {
  176. $service = $this->getServiceByName($mainServiceName, $salesChannelContext);
  177. if ($service){
  178. $item['name'] = $service->getName();
  179. $item['modalInfo'] = [
  180. 'id' => $service->getId(),
  181. 'title' => $service->getTitle(),
  182. 'title2' => $service->getTitle2(),
  183. 'description' => $service->getDescription(),
  184. 'media' => $service->getImage()
  185. ];
  186. $item['position'] = $service->getPosition();
  187. $item['active'] = false;
  188. }
  189. }
  190. $mainServices[$mainServiceName] = $item;
  191. }
  192. foreach ($otherServiceList as $otherServiceName){
  193. $service = $this->getServiceByName($otherServiceName, $salesChannelContext);
  194. if ($service){
  195. $item['name'] = $service->getName();
  196. $item['modalInfo'] = [
  197. 'id' => $service->getId(),
  198. 'title' => $service->getTitle(),
  199. 'title2' => $service->getTitle2(),
  200. 'description' => $service->getDescription(),
  201. 'media' => $service->getImage()
  202. ];
  203. $item['position'] = $service->getPosition();
  204. $item['active'] = false;
  205. $otherServices[$otherServiceName] = $item;
  206. }
  207. }
  208. if ($product->getExtension('configurations')) {
  209. $configurations = $product->getExtension('configurations')->getElements();
  210. /** @var ConfigurationEntity $configuration */
  211. foreach ($configurations as $configuration) {
  212. $service = $this->getServiceById($configuration->getServiceId(), $salesChannelContext);
  213. if ($service) {
  214. if (isset($mainServices[$service->getName()])) {
  215. $mainServices[$service->getName()]['active'] = true;
  216. $mainServices[$service->getName()]['bannerText'] = $configuration->getLabel();
  217. $mainServices[$service->getName()]['name'] = $service->getName();
  218. $mainServices[$service->getName()]['bannerText'] = $configuration->getLabel();
  219. $mainServices[$service->getName()]['modalInfo'] = [
  220. 'id' => $service->getId(),
  221. 'title' => $service->getTitle(),
  222. 'title2' => $service->getTitle2(),
  223. 'description' => $service->getDescription(),
  224. 'media' => $service->getImage()
  225. ];
  226. } else if (isset($otherServices[$service->getName()])) {
  227. $otherServices[$service->getName()]['active'] = true;
  228. $otherServices[$service->getName()]['bannerText'] = $configuration->getLabel();
  229. $otherServices[$service->getName()]['name'] = $service->getName();
  230. $otherServices[$service->getName()]['bannerText'] = $configuration->getLabel();
  231. $otherServices[$service->getName()]['modalInfo'] = [
  232. 'id' => $service->getId(),
  233. 'title' => $service->getTitle(),
  234. 'title2' => $service->getTitle2(),
  235. 'description' => $service->getDescription(),
  236. 'media' => $service->getImage()
  237. ];
  238. } else {
  239. $item = [];
  240. $item['name'] = $service->getName();
  241. $item['bannerText'] = $configuration->getLabel();
  242. $item['modalInfo'] = [
  243. 'id' => $service->getId(),
  244. 'title' => $service->getTitle(),
  245. 'title2' => $service->getTitle2(),
  246. 'description' => $service->getDescription(),
  247. 'media' => $service->getImage()
  248. ];
  249. $item['position'] = $service->getPosition();
  250. $item['active'] = $configuration->getIncluded();
  251. if ($service->getWorkout()) {
  252. $workouts[] = $item;
  253. } else if ($configuration->getBase()) {
  254. $mainServices[self::ALL_BASE_SERVICES]['services'][] = $item;
  255. }
  256. }
  257. }
  258. }
  259. if ($this->isDigital($product)) {
  260. $otherServices = $workouts;
  261. }
  262. $services = ["main" => $mainServices, "otherServices" => $otherServices];
  263. }
  264. if (isset($workouts)) {
  265. uasort($workouts, function ($a, $b) {
  266. return $a['position'] - $b['position'];
  267. });
  268. }
  269. return ["services" => $services, "workouts" => $workouts ?? []];
  270. }
  271. /**
  272. * @param string $name
  273. * @param SalesChannelContext $salesChannelContext
  274. * @return ServiceEntity|null
  275. */
  276. private function getServiceByName(string $name, SalesChannelContext $salesChannelContext): ?ServiceEntity
  277. {
  278. $criteria = new Criteria();
  279. $criteria->addFilter(new EqualsFilter('service.name', $name));
  280. $criteria->addAssociation('image');
  281. return $this->serviceRepository->search($criteria, $salesChannelContext->getContext())->first();
  282. }
  283. /**
  284. * @param string $serviceId
  285. * @param SalesChannelContext $salesChannelContext
  286. * @return ServiceEntity|null
  287. */
  288. private function getServiceById(string $serviceId, SalesChannelContext $salesChannelContext): ?ServiceEntity
  289. {
  290. $criteria = new Criteria();
  291. $criteria->addFilter(new EqualsFilter('service.id', $serviceId));
  292. $criteria->addAssociation('image');
  293. return $this->serviceRepository->search($criteria, $salesChannelContext->getContext())->first();
  294. }
  295. /**
  296. * @param ProductEntity $product
  297. * @param SalesChannelContext $salesChannelContext
  298. * @return array[]
  299. */
  300. public function getPromoInfo(ProductEntity $product, SalesChannelContext $salesChannelContext): array
  301. {
  302. $customerId = $salesChannelContext->getCustomer()?->getId();
  303. $requiredDalAssociations = ['personaRules', 'personaCustomers', 'cartRules', 'orderRules', 'discounts.discountRules', 'discounts.promotionDiscountPrices', 'setgroups', 'setgroups.setGroupRules',];
  304. $criteria = new Criteria();
  305. foreach ($requiredDalAssociations as $association) {
  306. $criteria->addAssociation($association);
  307. }
  308. $criteria->addAssociation('virginPromotionAttributes');
  309. $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [new EqualsFilter('useCodes', 0), new EqualsFilter('useIndividualCodes', 0), new EqualsFilter('active', 1),]));
  310. $promos = $this->promotionRepository->search($criteria, $salesChannelContext->getContext())->getElements();
  311. $exerpPromo = [];
  312. $swPromo = [];
  313. /** @var PromotionEntity $promo */
  314. foreach ($promos as $promo) {
  315. $attributes = $promo->getExtensions()['virginPromotionAttributes']->getElements();
  316. $attributes = reset($attributes);
  317. if ($promo->isActive()
  318. && $this->isPromoValid($promo)
  319. && $promo->isOrderCountValid()
  320. && (
  321. $promo->hasDiscount()
  322. || ($attributes && ($attributes)->getisExerpPromotion()))
  323. && (
  324. ($attributes && $attributes->getIsSpecialPromoFlow())
  325. || ($customerId && $promo->isOrderCountPerCustomerCountValid($customerId)))
  326. ) {
  327. $cartRules = $promo->getCartRules();
  328. $personaRules = $promo->getPersonaRules();
  329. $promoCartValid = true;
  330. $promoUserValid = true;
  331. foreach ($cartRules as $rule) {
  332. $criteria = new Criteria();
  333. $criteria->addFilter(new EqualsFilter('rule_condition.ruleId', $rule->getId()));
  334. $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [new EqualsFilter('rule_condition.type', 'cartLineItemsInCart'), new EqualsFilter('rule_condition.type', 'cartLineItem'), new EqualsFilter('rule_condition.type', 'cartLineItemTag'),]));
  335. $condition = $this->ruleConditionRepository->search($criteria, $salesChannelContext->getContext())->first();
  336. $promoCartValid = false;
  337. if ($condition) {
  338. if ($condition->getType() == 'cartLineItemTag') {
  339. if ($product->getTags() && count($product->getTags()->getElements()) != 0) {
  340. foreach ($product->getTagIds() as $tag) {
  341. if ($this->match($condition->getValue()['operator'], $condition->getValue()['identifiers'], [$tag])) {
  342. $promoCartValid = true;
  343. break;
  344. }
  345. }
  346. }
  347. } else {
  348. if ($this->match($condition->getValue()['operator'], $condition->getValue()['identifiers'], [$product->getId()])) {
  349. $promoCartValid = true;
  350. }
  351. }
  352. }
  353. }
  354. foreach ($personaRules as $rule) {
  355. $criteria = new Criteria();
  356. $criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [new EqualsFilter('rule_condition.type', 'customerCustomerGroup'), new EqualsFilter('rule_condition.ruleId', $rule->getId()),]));
  357. $condition = $this->ruleConditionRepository->search($criteria, $salesChannelContext->getContext())->first();
  358. if ($condition) {
  359. if (isset($_SESSION['gift_user_params']) && str_contains(strtolower($salesChannelContext->getCurrentCustomerGroup()->getName()), strtolower(self::BOCCONI_STRING))) {
  360. $customerGroupHasPromo = $this->match($condition->getValue()['operator'], $condition->getValue()['customerGroupIds'], [$_SESSION['gift_user_params']['customerGroupId']]);
  361. } else {
  362. $customerGroupHasPromo = $this->match($condition->getValue()['operator'], $condition->getValue()['customerGroupIds'], [$salesChannelContext->getCurrentCustomerGroup()->getId()]);
  363. }
  364. if ($customerGroupHasPromo) {
  365. $promoUserValid = true;
  366. } else {
  367. $promoUserValid = false;
  368. }
  369. }
  370. }
  371. if ($promoUserValid && $promoCartValid) {
  372. $attributes = $promo->getExtensions()['virginPromotionAttributes']->getElements();
  373. if (count($attributes) && reset($attributes)->getisExerpPromotion()) {
  374. $exerpPromo[] = $promo;
  375. } else {
  376. $swPromo[] = $promo;
  377. }
  378. }
  379. }
  380. }
  381. return ['exerpPromo' => $exerpPromo, 'swPromo' => $swPromo];
  382. }
  383. /**
  384. * @param PromotionEntity $promo
  385. * @return bool
  386. */
  387. private function isPromoValid(PromotionEntity $promo): bool
  388. {
  389. $now = new DateTime("now");
  390. $dateValid = $promo->getValidFrom() === null || ($promo->getValidFrom() !== null && $now > $promo->getValidFrom());
  391. if ($promo->getValidUntil() !== null) {
  392. $dateValid = $dateValid && $now < $promo->getValidUntil();
  393. }
  394. if ($this->session->get('prorata_date') && $promo->getValidUntil() && $this->session->get('prorata_date') > $promo->getValidUntil()->getTimestamp()) {
  395. return false;
  396. }
  397. return $dateValid;
  398. }
  399. /**
  400. * @param $operator
  401. * @param $identifiers
  402. * @param $target
  403. * @return bool
  404. */
  405. public function match($operator, $identifiers, $target): bool
  406. {
  407. return match ($operator) {
  408. Rule::OPERATOR_EQ => !empty(array_intersect($identifiers, $target)),
  409. Rule::OPERATOR_NEQ => empty(array_intersect($identifiers, $target)),
  410. default => throw new UnsupportedOperatorException($operator, Rule::class),
  411. };
  412. }
  413. /**
  414. * @param ProductEntity $product
  415. * @param SalesChannelContext $salesChannelContext
  416. * @param null $promo
  417. * @param string|null $prorataDate
  418. * @return array
  419. * @throws Exception
  420. */
  421. public function getProductPrices(ProductEntity $product, SalesChannelContext $salesChannelContext, $promo = null, string $prorataDate = null): array
  422. {
  423. $prorataDate = $prorataDate ?? date('Y-m-d');
  424. if (isset($product->getExtensions()['productType']) && $product->getExtensions()['productType']->getName() == ProductTypeEntity::SUBSCRIPTION) {
  425. if (isset($product->getExtensions()['club'])) {
  426. if ($product->getExtensions()['club']->getIsPresale()) {
  427. $prorataDate = $product->getExtensions()['club']->getPurchaseDate()->format('Y-m-d');
  428. }
  429. }
  430. } elseif (isset($product->getExtensions()['productType']) && $product->getExtensions()['productType']->getName() == ProductTypeEntity::REVOLUTION_DIGITALE) {
  431. if (isset($product->getCustomFields()['free_trial_days']) && $product->getCustomFields()['free_trial_days'] > 0) {
  432. $prorataDate = (new DateTimeImmutable())->add(new DateInterval('PT' . ($product->getCustomFields()['free_trial_days'] * 24) . 'H'))->format('Y-m-d');
  433. }
  434. }
  435. $basePrice = $product->getPrice()->getElements()[$salesChannelContext->getCurrency()->getId()]->getGross();
  436. $infoSub = $this->getProrataActivationPrices($product, $prorataDate);
  437. if (!isset($infoSub->status) && $infoSub != null) {
  438. $activationPrices = ['activationBase' => (float)$infoSub->creationPrice, 'activationPromo' => (float)$infoSub->creationNormalPrice];
  439. $prorataPrices = ['prorataBase' => (float)$infoSub->proRataPrice, 'prorataPromo' => (float)$infoSub->proRataSponsoredAmount];
  440. $type = $product->getCustomFields()['virgin_exerp_type'];
  441. if ($type == "CASH") {
  442. if (isset($product->getExtensions()['productType']) && $product->getExtensions()['productType']->getName() == ProductTypeEntity::SUBSCRIPTION) {
  443. if (array_key_exists('use_admin_fee', $product->getCustomFields()) && $product->getCustomFields()['use_admin_fee'] == true) {
  444. $basePrice = (float)$infoSub->totalAmount - (float)$infoSub->creationPrice - (float)$infoSub->adminFeePrice;
  445. } else {
  446. $basePrice = (float)$infoSub->totalAmount - (float)$infoSub->creationPrice;
  447. }
  448. } else {
  449. $basePrice = (float)$infoSub->totalAmount;
  450. }
  451. } else {
  452. $basePrice = (float)($infoSub->startupCampaignPrice ?? $infoSub->normalPeriodPrice);
  453. }
  454. }
  455. if (isset($promo) && (count($promo['swPromo']) > 0 || count($promo['exerpPromo']) > 0)) {
  456. $promoPrices = $this->getPromoPrice($product, $salesChannelContext, $promo, $prorataDate);
  457. if (empty($promoPrices['firstDeductionDate'])) {
  458. $promoPrices['firstDeductionDate'] = $infoSub->firstDeductionDate;
  459. }
  460. } else {
  461. $promoPrices = ['prorata' => $prorataPrices['prorataBase'] ?? 0, 'activation' => $activationPrices['activationBase'] ?? 0, 'adminFee' => $infoSub->adminFeePrice ?? 0, 'product' => $basePrice, 'firstDeductionDate' => $infoSub->firstDeductionDate ?? $prorataDate,];
  462. }
  463. return ['prorataDate' => $prorataDate, 'isPresale' => ($product->getExtensions()['club']??null) && $product->getExtensions()['club']->getIsPresale(),'adminFee' => $infoSub->adminFeePrice ?? 0, 'prorata' => $prorataPrices ?? 0, 'activation' => $activationPrices ?? 0, 'base_price' => $basePrice, 'promo_price' => $promoPrices ?? null, 'first_deduction_date' => $promoPrices['firstDeductionDate'],];
  464. }
  465. /**
  466. * @param ProductEntity $product
  467. * @param $prorataDate
  468. * @param $promoCode
  469. * @return mixed
  470. * @throws \DateMalformedStringException
  471. */
  472. public function getProrataActivationPrices(ProductEntity $product, $prorataDate, $promoCode = null): mixed
  473. {
  474. $prorataDate = $prorataDate < (new DateTime())->format('Y-m-d') ? (new DateTime())->format('Y-m-d') : $prorataDate;
  475. $dateTime = new DateTime($prorataDate);
  476. // presale deve essere false
  477. if (!(($product->getExtensions()['club'] ?? null)?->getIsPresale()) && $dateTime->format('j') === '1'){
  478. $prorataDate = $dateTime->format('Y-m-d');
  479. }
  480. $subReq = ['campainCode' => $promoCode ?? ($_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'],];
  481. return $this->restApiClient->getSubscritionContractDetails($subReq);
  482. }
  483. /**
  484. * @param ProductEntity $product
  485. * @param SalesChannelContext $salesChannelContext
  486. * @param $promotions
  487. * @param $prorataDate
  488. * @return array
  489. */
  490. private function getPromoPrice(ProductEntity $product, SalesChannelContext $salesChannelContext, $promotions, $prorataDate): array
  491. {
  492. $infoSubBase = $this->getProrataActivationPrices($product, $prorataDate);
  493. if (!isset($infoSubBase->status) && $infoSubBase != null) {
  494. $prorataPrice = $infoSubBase->proRataPrice;
  495. $activationPrice = $infoSubBase->creationPrice;
  496. $adminFeePrice = $infoSubBase->adminFeePrice ?? 0;
  497. $productPrice = (float)($infoSubBase->startupCampaignPrice ?? $infoSubBase->normalPeriodPrice);
  498. }
  499. foreach ($promotions['exerpPromo'] as $promo) {
  500. $attributes = $promo->getExtensions()['virginPromotionAttributes']->getElements();
  501. $infoSub = $this->getProrataActivationPrices($product, $prorataDate, reset($attributes)->getExerpCode());
  502. $firstDeductionDate = $infoSub->firstDeductionDate;
  503. if (!isset($infoSub->status) && $infoSub != null) {
  504. $prorataPrice = $infoSub->proRataPrice;
  505. $activationPrice = $infoSub->creationPrice;
  506. $adminFeePrice = $infoSubBase->adminFeePrice ?? 0;
  507. $productPrice = (float)($infoSub->startupCampaignPrice ?? $infoSub->normalPeriodPrice);
  508. }
  509. }
  510. foreach ($promotions['swPromo'] as $promo) {
  511. /** @var PromotionDiscountEntity $discount */
  512. foreach ($promo->getDiscounts() as $discount) {
  513. foreach ($discount->getDiscountRules()->getElements() as $discountRules) {
  514. if (strtolower($discountRules->getName()) == 'attivazione') {
  515. $type = 'activation';
  516. }
  517. if (strtolower($discountRules->getName()) == 'prorata') {
  518. $type = 'prorata';
  519. }
  520. if (strtolower($discountRules->getName()) != 'prorata' && strtolower($discountRules->getName()) != 'attivazione') {
  521. $type = 'product';
  522. }
  523. if (isset($type)) {
  524. switch ($type) {
  525. case 'activation':
  526. $price = $activationPrice;
  527. break;
  528. case 'prorata':
  529. $price = $prorataPrice;
  530. break;
  531. default:
  532. $price = $productPrice;
  533. }
  534. } else {
  535. $price = $productPrice;
  536. }
  537. switch ($discount->getType()) {
  538. case PromotionDiscountEntity::TYPE_ABSOLUTE:
  539. $newPrice = $price - $discount->getValue();
  540. break;
  541. case PromotionDiscountEntity::TYPE_PERCENTAGE:
  542. $discountPrice = ($price * $discount->getValue()) / 100;
  543. if (!is_null($discount->getMaxValue())) {
  544. if (abs($discountPrice) > abs($discount->getMaxValue())) {
  545. $newPrice = $price - $discount->getMaxValue();
  546. } else {
  547. $newPrice = $price - $discountPrice;
  548. }
  549. } else {
  550. $newPrice = $price - $discountPrice;
  551. }
  552. break;
  553. case PromotionDiscountEntity::TYPE_FIXED_UNIT:
  554. case PromotionDiscountEntity::TYPE_FIXED:
  555. $newPrice = $discount->getValue();
  556. break;
  557. default:
  558. throw new DiscountCalculatorNotFoundException($discount->getType());
  559. }
  560. if (isset($type)) {
  561. switch ($type) {
  562. case 'activation':
  563. $activationPrice = $newPrice;
  564. break;
  565. case 'prorata':
  566. $prorataPrice = $newPrice;
  567. break;
  568. default:
  569. $productPrice = $newPrice;
  570. }
  571. } else {
  572. $productPrice = $newPrice;
  573. }
  574. }
  575. }
  576. }
  577. return ['adminFee' => (float)$adminFeePrice, 'prorata' => (float)$prorataPrice, 'activation' => (float)$activationPrice, 'product' => (float)$productPrice, 'firstDeductionDate' => $firstDeductionDate ?? "",];
  578. }
  579. /**
  580. * @param string $productId
  581. * @param SalesChannelContext $salesChannelContext
  582. * @return ProductEntity|null
  583. */
  584. public function getProductById(string $productId, SalesChannelContext $salesChannelContext): ?ProductEntity
  585. {
  586. $criteria = new Criteria();
  587. $criteria->addAssociation('configurations');
  588. $criteria->addAssociation('productType');
  589. $criteria->addAssociation('duration');
  590. $criteria->addAssociation('tags');
  591. $criteria->addAssociation('club');
  592. $criteria->addAssociation('serviceLevel');
  593. $criteria->addFilter(new EqualsFilter("id", $productId));
  594. return $this->productRepository->search($criteria, $salesChannelContext->getContext())->first();
  595. }
  596. /**
  597. * @param string $clubId
  598. * @param array $tagIds
  599. * @param SalesChannelContext $salesChannelContext
  600. * @return array
  601. */
  602. public function getProductsByTags(string $clubId, array $tagIds, SalesChannelContext $salesChannelContext): array
  603. {
  604. $realProductCriteria = new Criteria();
  605. $realProductCriteria->addFilter(new EqualsFilter('product.clubId', $clubId));
  606. if ($tagIds) {
  607. $realProductCriteria->addFilter(new EqualsAnyFilter('product.tags.id', $tagIds));
  608. }
  609. $realProductCriteria->addFilter(new EqualsFilter('product.active', true));
  610. $realProductCriteria->addAssociation('configurations');
  611. $realProductCriteria->addAssociation('productType');
  612. $realProductCriteria->addAssociation('duration');
  613. $realProductCriteria->addAssociation('tags');
  614. $realProductCriteria->addAssociation('club');
  615. /** @var ProductEntity[] $realProductEntities */
  616. return $this->productRepository->search($realProductCriteria, $salesChannelContext->getContext())->getElements();
  617. }
  618. private function getMediaById(string $imageId, SalesChannelContext $salesChannelContext)
  619. {
  620. $criteria = new Criteria();
  621. $criteria->addFilter(new EqualsFilter('media.id', $imageId));
  622. return $this->mediaRepository->search($criteria, $salesChannelContext->getContext())->first();
  623. }
  624. /**
  625. * @param ProductEntity $productEntity
  626. * @return bool
  627. */
  628. public function isDigital(ProductEntity $productEntity): bool
  629. {
  630. /** @var ProductTypeEntity $productType */
  631. $productType = $productEntity->getExtensions()['productType'];
  632. if ($productType){
  633. return $productType->getName()==ProductTypeEntity::REVOLUTION_DIGITALE;
  634. }
  635. return false;
  636. }
  637. }