<?php
namespace App\Utils;
use App\Entity\Gos\Cart;
use App\Entity\Gos\Language;
use App\Entity\Gos\OrderPart;
use App\Entity\Gos\OrderProductVariant;
use App\Entity\Gos\Orders;
use App\Entity\Gos\PortalSettings;
use App\Entity\Gos\ProductCart;
use App\Entity\Gos\ProductVariant;
use App\Entity\Gos\Term;
use App\Entity\Gos\TermText;
use App\Entity\Gos\User;
use App\Entity\Gos\UserTerms;
use App\Utils\SalesManago\SalesManagoEvent;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
class TermsService
{
private ?Request $request;
private EntityManagerInterface $em;
private EmailPermissionServices $emailPermissionServices;
private SalesManagoEvent $salesManagoEvent;
private LoggerInterface $logger;
private TranslatorInterface $translator;
private $locale;
public function __construct(
RequestStack $requestStack,
EntityManagerInterface $entityManager,
EmailPermissionServices $emailPermissionServices,
SalesManagoEvent $salesManagoEvent,
LoggerInterface $logger,
TranslatorInterface $translator
) {
$this->request = $requestStack->getCurrentRequest();
$this->em = $entityManager;
$this->emailPermissionServices = $emailPermissionServices;
$this->salesManagoEvent = $salesManagoEvent;
$this->logger = $logger;
$this->translator = $translator;
}
/**
* Get Terms from products and portal settings to display in order form
*/
public function getTerms(
PortalSettings $portalSettings,
Cart $cart = null,
$isRequired = false,
$registration = false,
$advertising = true,
$user = null
)
{
$terms = [];
if (empty($user))
{
$user = empty($cart) ? null : $cart->getUser();
}
$myTerms = $this->getMyTerms($user);
// get portal settings terms
foreach ($portalSettings->getTerms() as $term)
{
if ($this->checkIfCorrectLanguage($term) && $this->checkApprovedTerms($term, $myTerms, $user)
&& !in_array($term->getTermType()->getSlug(), ['voucher', 'term-info']))
{
$terms = $this->addTermsToArray($terms, $isRequired, $term, $registration, $advertising);
}
}
// get product variants terms
if (!empty($cart))
{
foreach ($cart->getProductCart() as $productCart)
{
/** @var ProductCart $productCart */
$pv = $productCart->getProductVariant();
if (!empty($pv))
{
$terms = $this->addTerms($terms, $pv, $user, $myTerms, $isRequired, $advertising);
}
elseif (!empty($productCart->getProductPack()))
{
foreach ($productCart->getProductPack()->getProductPackItem() as $productPackItem)
{
$terms = $this->addTerms($terms, $productPackItem->getProductVariant(), $user, $myTerms, $isRequired, $advertising);
}
}
if ($productCart->getIsGift() || $productCart->getGift())
{
$cartLanguage = $cart->getCountry()
? $cart->getCountry()->getLanguage()
: $this->em->getRepository(Language::class)->findOneBySlug('polish');
$voucherTerm = $this->em->getRepository(Term::class)
->findOneVoucherTerm($cartLanguage, $portalSettings);
if ($voucherTerm)
{
$terms = $this->addTermsToArray($terms, $isRequired, $voucherTerm, $registration, $advertising);
}
}
foreach ($productCart->getCartParticipant() as $cartParticipant)
foreach ($cartParticipant->getProductVariantGroupItems() as $productVariantGroupItem)
{
$pv = $productVariantGroupItem->getProductVariant();
$terms = $this->addTerms($terms, $pv, $user, $myTerms, $isRequired, $advertising);
}
}
$address = $cart->getAddress();
if ($address === null && $user !== null)
{
$address = $user->getAddress();
}
if ($address && $address->getClientType())
{
/** @var Term $term */
foreach ($terms as $k => $term)
{
if (!empty($term->getClientTypes()->toArray()))
{
if (!in_array($address->getClientType(), $term->getClientTypes()->toArray()))
{
unset($terms[$k]);
}
}
}
}
foreach ($cart->getAllProductVariants() as $variant)
{
foreach ($variant->getTerms() as $term)
{
if ($term->getTermType()->getSlug() === 'withdrawal')
{
foreach ($terms as $key => $businessTerm)
{
if ($businessTerm->getTermType()->getSlug() === 'business-activity')
{
unset($terms[$key]);
}
}
}
}
}
}
return $terms;
}
public function getInfoTerms(?PortalSettings $portalSettings, ?Cart $cart = null): array
{
$infoTerms = array();
if ($portalSettings !== null)
{
$infoTerm = $this->em->getRepository(Term::class)->findTermInfoForPortal($portalSettings);
if ($infoTerm)
{
$infoTerms[] = $infoTerm;
}
}
if ($cart !== null)
{
$variants = array();
/** @var ProductCart $productCart */
foreach ($cart->getProductCart() as $productCart)
{
if ($productCart->getProductVariant() !== null)
{
$variants[] = $productCart->getProductVariant();
}
elseif ($productCart->getProductPack() !== null)
{
foreach ($productCart->getProductPack()->getProductPackItem() as $packItem)
{
$variants[] = $packItem->getProductVariant();
}
}
}
foreach ($variants as $variant)
{
$infoTerm = $this->em->getRepository(Term::class)->findTermInfoForVariant($variant);
if ($infoTerm)
{
$infoTerms[] = $infoTerm;
}
}
}
return array_unique($infoTerms);
}
/**
* Get Terms from order product variant
*/
public function getTermsFromOrder(Orders $orders)
{
$terms = [];
/** @var OrderPart $op */
foreach ($orders->getOrderPart() as $op)
{
/** @var OrderProductVariant $opv */
foreach ($op->getOrderProductVariant() as $opv)
{
/** @var ProductVariant $pv */
$pv = $opv->getProductVariant();
$terms = $this->addTerms($terms, $pv, null, [], false);
}
}
return $terms;
}
/**
* Get Terms from order product variant for Api
*/
public function getTermsFromOrderForApi(Orders $orders): array
{
$terms = [];
/** @var OrderPart $op */
foreach ($orders->getOrderPart() as $op)
{
/** @var OrderProductVariant $opv */
foreach ($op->getOrderProductVariant() as $opv)
{
/** @var ProductVariant $pv */
$pv = $opv->getProductVariant();
$terms = $this->addTerms($terms, $pv, null, [], false);
}
}
$termsInfo = [];
/** @var Term $term */
foreach ($terms as $term)
{
$termsInfo[] = [
'titleOfShortDescription' => $term->getTitleOfShortDescription(),
'shortDescription' => $term->getShortDescription()
];
}
return $termsInfo;
}
/**
* Check if this terms accepted by user
*/
private function checkApprovedTerms(Term $term, $myTerms, User $user = null): bool
{
if (empty($user))
{
return true;
}
if (in_array($term->getTermType()->getSlug(), ['business-activity', 'withdrawal']))
{
return true;
}
if ($term->getIsReusable())
{
return true;
}
if (!$term->getPortalSettings()->isEmpty())
{
return true;
}
if (
in_array($term->getId(), $myTerms)
|| ($user->getAllowedAdvertising() && $term->getTermType()->getSlug() == 'advertising-agreement')
)
{
return false;
}
else
{
return true;
}
}
/**
* Return array all ID terms this user
*/
private function getMyTerms(User $user = null): array
{
$myTerms = array();
if (empty($user))
{
return $myTerms;
}
/** @var UserTerms $userTerm */
foreach ($user->getUserTerms() as $userTerm)
{
if (!$userTerm->getTermText())
{
$this->logger->critical('GOS-1348.09: $userTerm->getTermText() is null.
User_id passed to function: ' . $user->getId() . '.
Referer url: ' . $this->request->headers->get('referer'));
throw new \Exception($this->translator->trans('errors.order.oops'));
}
if (empty($userTerm->getTermText()->getTerm()))
{
$myTerms[] = $userTerm->getTermText()->getActiveTerm()->getId();
}
else
{
$myTerms[] = $userTerm->getTermText()->getTerm()->getId();
}
}
return $myTerms;
}
private function addTermsToArray($terms, $isRequired, Term $term, $registration = false, $advertising = true)
{
if (
(($isRequired && $term->getIsRequired()) || !$isRequired)
&& !empty($term->getActiveTermText())
&& (($registration && $term->getShowInRegistration()) || !$registration)
&& ((!$advertising && $term->getTermType()->getSlug() != 'advertising-agreement') || $advertising)
)
{
$terms[$term->getId()] = $term;
}
return $terms;
}
/**
* Check if all terms are selected
*/
public function areTermsSelected($form, $terms): bool
{
// check each term is in form
foreach ($terms as $term)
{
if (!isset($form[$term->getId()]))
{
return false;
}
}
return true;
}
/**
* Create or edit term on backend
*/
public function save($form, Term $term): Term
{
if ($form->isSubmitted())
{
if ($form->isValid())
{
$requestTermText = $this->request->request->get('termText', null);
$this->em->persist($term);
if (!empty($requestTermText))
{
if (empty($term->getActiveTermText()))
{
$activeTermText = new TermText();
}
else
{
$activeTermText = $term->getActiveTermText();
if ($requestTermText != $term->getActiveTermText()->getTermText())
{
$oldTermText = $activeTermText;
$activeTermText = clone $oldTermText;
$oldTermText
->setTerm($term)
->setActiveTerm(null)
->setIsActive(false);
$this->em->persist($oldTermText);
$this->em->flush();
}
}
$activeTermText
->setTermText($requestTermText)
->setActiveTerm($term)
->setIsActive(true);
$this->em->persist($activeTermText);
}
$this->em->flush();
$this->em->refresh($term);
$this->request->getSession()->getFlashBag()->add('success', 'Successfully saved');
}
else
{
$this->request->getSession()->getFlashBag()->add('danger', 'Form is not valid');
}
}
return $term;
}
public function saveUserTerms($terms, $termsAccepted, User $user, PortalSettings $portalSettings, Orders $order = null): array
{
$result = [];
if (!empty($terms))
{
$clientHost = $this->request->getHost();
$httpXForwardedFor = $this->request->server->get('HTTP_X_FORWARDED_FOR');
$clientIp = $httpXForwardedFor ?: $this->request->getClientIp();
foreach ($terms as $term)
{
if ($this->checkTermIsSelected($term, $termsAccepted) && !$this->checkTermAlreadyExists($term, $user))
{
$userTerms = (new UserTerms())
->setUser($user)
->setUserHost($clientHost)
->setUserIp($clientIp)
->setTermText($term->getActiveTermText())
->setOrders($order);
if ($term->getCooperatorGroup())
{
$cooperatorsList = '';
foreach ($term->getCooperatorGroup()->getCooperator() as $cooperator) {
$cooperatorsList = $cooperatorsList . $cooperator->getName() . ($cooperator->getNip() ? '('. $cooperator->getNip() . ')' : '') . ';';
}
$userTerms->setCurrentCooperators(trim($cooperatorsList,';'));
}
$this->em->persist($userTerms);
$result[] = $userTerms;
if ($term->getTermType()->getSlug() == 'advertising-agreement')
{
$user->setAllowedAdvertising(true);
$portal = parse_url($portalSettings->getDomain(), PHP_URL_HOST);
$this->emailPermissionServices->setEmailPermissionAndPortal(
$user->getEmail(),
$portal
);
/* Send AllowedAdvertising event to SalesManago */
$this->salesManagoEvent->sendAllowedAdvertising($user);
}
$this->em->persist($user);
}
}
$this->em->flush();
}
return $result;
}
private function checkTermIsSelected($term, $termsAccepted): bool
{
if (
isset($termsAccepted[$term->getId()])
&& $termsAccepted[$term->getId()]
)
{
return true;
}
return false;
}
public function checkTermAlreadyExists(?Term $term, $user): bool
{
$userTerms = $user->getUserTerms();
foreach ($userTerms as $ut)
{
if ($ut->getTermText()
&& $ut->getTermText()->getId() == $term->getActiveTermText()->getId()
&& strpos($ut->getTermText()->getTermText(),'regulamin') !== false
&& !$term->getIsReusable())
{
return true;
}
}
return false;
}
public function addTermsToSB($client, $userTerms)
{
$termIndex = 0;
/** @var UserTerms $value */
foreach ($userTerms as $value)
{
$client['Zgoda_' . $termIndex++] = $value->getTermText()->getTermText();
if ($value->getTermText()->getActiveTerm()
&& $value->getTermText()->getActiveTerm()->getTermType()->getSlug() === 'withdrawal'
)
{
$client['prawo_zwrotu'] = 'nie';
}
}
return $client;
}
public function forceUserRegulationsAccept($user, $hash)
{
if ($user)
{
$termRepo = $this->em->getRepository(Term::class);
$portalSettingsRegulations = $termRepo->findRegulationsTermsForPortal($hash);
$userTerms = $termRepo->findUserTerms($user, $hash);
$foundRegulations = 0;
foreach ($portalSettingsRegulations as $portalSettingsRegulation)
{
if (in_array($portalSettingsRegulation, $userTerms))
{
$foundRegulations++;
}
}
return count($portalSettingsRegulations) == $foundRegulations ? 0 : 1;
}
return false;
}
public function addMarketingTerms(User $user, PortalSettings $portal): void
{
$terms = $this->em->getRepository(Term::class)->findAllByPortalAndType($portal, 'advertising-agreement');
if (empty($terms)) return;
$termsAccepted = [];
foreach ($terms as $term)
{
$termsAccepted[$term->getId()] = $term->getId();
}
$this->saveUserTerms($terms, $termsAccepted, $user, $portal);
}
private function addTerms($terms, $productVariant, $user, $myTerms, $isRequired, $advertising = true)
{
foreach ($productVariant->getTerms() as $term)
{
if ($this->checkIfCorrectLanguage($term)
&& $this->checkApprovedTerms($term, $myTerms, $user)
&& $this->checkTermDateValidity($term, $productVariant)
&& !in_array($term->getTermType()->getSlug(), ['term-info']))
{
$terms = $this->addTermsToArray($terms, $isRequired, $term, false, $advertising);
}
}
// if product variant has not terms, check master product
if (count($productVariant->getTerms()) < 1)
{
foreach ($productVariant->getMasterProduct()->getTerms() as $term)
{
if ($this->checkIfCorrectLanguage($term) && $this->checkApprovedTerms($term, $myTerms, $user)
&& !in_array($term->getTermType()->getSlug(), ['term-info']))
{
$terms = $this->addTermsToArray($terms, $isRequired, $term, false, $advertising);
}
}
}
return $terms;
}
private function checkIfCorrectLanguage(Term $term): bool
{
$this->locale = empty($this->request)
? 'pl'
: $this->request->getSession()->get('userLocale', 'pl');
if ($this->locale == 'pl'
&& (is_null($term->getLanguage()) || $term->getLanguage()->getCode() == 'pl'))
{
return true;
}
if ($this->locale != 'pl'
&& !empty($term->getLanguage())
&& $this->locale == $term->getLanguage()->getCode())
{
return true;
}
return false;
}
private function checkTermDateValidity(Term $term, ProductVariant $productVariant): bool
{
if ($productVariant->getEventDate() && $term->getShowDaysBefore())
{
$eventDate = clone $productVariant->getEventDate();
$daysUntilEvent = (new \DateTime())->diff($eventDate)->days;
if ($eventDate > (new \DateTime()) && $daysUntilEvent > $term->getShowDaysBefore())
{
return false;
}
}
return true;
}
}