<?php
namespace App\Controller\Customer;
use App\Controller\BaseController;
use App\Entity\Addressing\Address;
use App\Entity\Addressing\City;
use App\Entity\Addressing\Country;
use App\Entity\Addressing\County;
use App\Entity\Institution\ProductType;
use App\Model\AddressModel;
use App\Model\CountryModel;
use App\Model\CustomerModel;
use App\Model\OrderModel;
use App\Model\ShopUserModel;
use App\Service\AddressService;
use App\Service\CustomerService;
use App\Service\InvoiceApiService;
use App\Validator\AddressFormValidator;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\HttpFoundation\JsonResponse;
use function Sentry\captureException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Contracts\Translation\TranslatorInterface;
class AddressController extends BaseController
{
public function retrieveAddressData(Request $request)
{
$addressId = $request->get('addressId');
$isShippingAddress = false;
if ($request->get('isShippingAddress') && $request->get('isShippingAddress') == true) {
$isShippingAddress = true;
}
$address = null;
$user = $this->getUser();
$isValid = false;
$city = null;
$country = null;
$county = null;
$customerType = null;
$customer = null;
if ($user) {
if ($customer = $user->getCustomer()) {
$customerType = $customer->getType();
if ($customer && $addressId) {
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
if ($address) {
$customerType = $address->getCustomerType();
if ($address->getCustomer()
&& $address->getCustomer()->getId() == $customer->getId()) {
$isValid = true;
if ($address->getCountryCode()) {
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $address->getCountryCode()));
}
if ($address->getCounty()) {
if ($country) {
$county = $this->getDoctrine()->getRepository(County::class)->findByCodeAndCountry($address->getCounty(), $country);
} else {
$county = $this->getDoctrine()->getRepository(County::class)->findByCode($address->getCounty());
}
}
if ($address->getCity() && ctype_digit($address->getCity())) {
$city = $this->getDoctrine()->getRepository(City::class)->find((int) $address->getCity());
}
}
}
}
}
}
$template = json_encode('error');
try {
if (!$isValid) {
$address = null;
}
$country = $country ?: $this->getDoctrine()->getRepository(Country::class)->findOneBy(['code' => $address ? $address->getCountryCode() : $request->getLocale()]);
$counties = null;
if ($country) {
$counties = $this->getDoctrine()->getRepository(County::class)->findBy(['country' => $country->getId()]);
}
$template = json_encode(array(
'$isValid' => $isValid,
'address' => $address ? $address->toArray() : null,
'countries' => $this->getDoctrine()->getRepository(Country::class)->findAll(),
'counties' => $counties ? $counties->toArray() : null,
'selectedCountry' => $country,
'selectedCity' => $city,
'selectedCounty' => $county,
'customerType' => $customerType,
'customer' => $customer,
));
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function editViewAction(Request $request)
{
$render = '@templates/Front/Shop/error404.html.twig';
$addressId = $request->get('id');
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
$data = AddressService::getAddressDataForUserIfIsValid($this->getUser(), $address, $this->getEntityManager());
if ($data) {
$render = '@templates/Account/Address/edit-address.html.twig';
}
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $address->getCountryCode()));
return $this->render($render, [
'data' => $data,
'countries' => $this->getDoctrine()->getRepository(Country::class)->findAll(),
'counties' => $this->getDoctrine()->getRepository(County::class)->findAllCountiesByCountry($country),
]);
}
public function editSubmitAction(Request $request)
{
$session = $request->getSession();
$errors = json_encode(array('unknown' => true));
$addressId = $request->get('id');
$data = $request->request->all();
$data = AddressModel::getDataForCustomerType($data);
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
$user = $this->getUser();
if ($user) {
$customer = $user->getCustomer();
$customerAddress = $address->getCustomer();
$isAdminUser = ShopUserModel::checkIfUserIsAdmin($this->getUser(), $this->getEntityManager());
if ($customer && $customerAddress
&& ($customer->getId() == $customerAddress->getId() || $isAdminUser)) {
$addressFormValidator = new AddressFormValidator($this->getEntityManager(), $this->getSerializer());
if ($addressFormValidator->checkForm($request)) {
$fullAddress = AddressModel::constructAddressDataArray($data, false);
$address = AddressModel::updateAddress($address, $fullAddress, $this->getDoctrine()->getRepository(County::class));
$this->getEntityManager()->persist($address);
$this->getEntityManager()->flush();
if ($isAdminUser) {
$this->addFlash('address_edited', 'Adresa editata cu succes');
}
$errors = json_encode(array('success' => true));
} else {
if ($session->has('addressErrors')) {
$errors = $session->get('addressErrors');
}
}
}
}
return new Response($errors);
}
public function updateAddressVueAction(Request $request): Response
{
$data = $request->request->all();
$addressId = (string) $data["selectedAddressId"];
$isForeignCustomer = false;
if (isset($data["address"])) {
$isForeignCustomer = $data["address"]["country"]["code"] != Country::RO_COUNTRY_CODE;
}
// Mapping array keys to desired keys
$mappedData = [
"customerType" => $data["customer_type"],
"customerCUI" => $data["customer_type"] == 1 ? $data["cif_code"] : null,
"customerCompanyName" => $data["customer_type"] == 1 ? $data["company_name"] : null,
"legalCustomerCountry" => $data["customer_type"] == 1 ? $data["address"]["country"]["code"] : null,
"legalCustomerCounty" => $data["customer_type"] == 1 && !$isForeignCustomer ? $data["address"]["county"]["id"] : null,
"legalCustomerCity" => $data["customer_type"] == 1 ? !$isForeignCustomer ? (string) $data["address"]["city"]["id"] : $data["address"]["city_name"] : null,
"legalCustomerStreet" => $data["customer_type"] == 1 ? $data["address"]["street"] : null,
"legalCustomerStreetNumber" => $data["customer_type"] == 1 ? $data["address"]["street_number"] : null,
"customerName" => $data["customer_type"] == 1 ? null : $data["customer_name"],
"customerPhone" => $data["customer_phone"],
"customerCountry" => $data["customer_type"] == 1 ? null : $data["address"]["country"]["code"],
"customerCounty" => $data["customer_type"] == 1 ? null : $data["address"]["county"]["id"],
"customerCity" => $data["customer_type"] == 1 ? null : (string) $data["address"]["city"]["id"],
"customerStreet" => $data["customer_type"] == 1 ? null : $data["address"]["street"],
"customerStreetNumber" => $data["customer_type"] == 1 ? null : $data["address"]["street_number"],
"customerBuilding" => $data["customer_type"] == 1 ? null : $data["address"]["building"],
"customerEntrance" => $data["customer_type"] == 1 ? null : $data["address"]["entrance"],
"customerApartment" => $data["customer_type"] == 1 ? null : $data["address"]["apartment"]
];
$errors = json_encode(array('unknown' => true));
$data = AddressModel::getDataForCustomerType($mappedData);
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
$user = $this->getUser();
if ($user) {
$customer = $user->getCustomer();
$customerAddress = $address->getCustomer();
if ($customer && $customerAddress
&& ($customer->getId() == $customerAddress->getId())) {
$addressFormValidator = new AddressFormValidator($this->getEntityManager(), $this->getSerializer());
if ($addressFormValidator->checkFormAddressVue($mappedData)) {
$fullAddress = AddressModel::constructAddressDataArray($data, false);
$address = AddressModel::updateAddress($address, $fullAddress, $this->getDoctrine()->getRepository(County::class));
$this->getEntityManager()->persist($address);
$this->getEntityManager()->flush();
$errors = json_encode(array('success' => true));
} else {
$errors = json_encode(array('success' => false));
}
}
}
return new Response($errors);
}
public function delete(Request $request): Response
{
$response = json_encode('error');
$address = AddressModel::getAddressById($request->get('id'), $this->getEntityManager());
if (AddressModel::deleteAddress($address, $this->getUser(), $this->getEntityManager())) {
$response = json_encode('success');
}
return new Response($response);
}
public function updateAdminAddress(Request $request): Response
{
$order = OrderModel::retrieveOrderEntityById($request->get('orderId'), $this->getEntityManager());
$data = AddressModel::getAddressData($order->getBillingAddress(), $this->getEntityManager());
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $order->getBillingAddress()->getCountryCode()));
return $this->render('@templates/AdminCustom/Customer/Address/update.html.twig', [
'order' => $order,
'countries' => $this->getDoctrine()->getRepository(Country::class)->findAll(),
'counties' => $this->getDoctrine()->getRepository(County::class)->findAllCountiesByCountry($country),
'data' => $data,
'lastPath' => $request->get('lastPath'),
]);
}
public function editAdminAddressModal(Request $request): Response
{
$address = AddressModel::getAddressById($request->get('addressId'), $this->getEntityManager());
$addressArray = AddressModel::getAddressInArrayFormatById($request->get('addressId'), $this->getEntityManager());
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $address->getCountryCode()));
return $this->render('@templates/AdminCustom/Customer/Address/Modal/edit.html.twig', [
'address' => $address,
'countries' => $this->getDoctrine()->getRepository(Country::class)->findAll(),
'counties' => $this->getDoctrine()->getRepository(County::class)->findAllCountiesByCountry($country),
'addressArray' => $addressArray,
'orderId' => $request->get('orderId'),
]);
}
public function loadSelectCityBlock(): Response
{
$template = $this->get('twig')
->render('@templates/AdminCustom/Customer/Address/Form/_select_city.html.twig');
return new Response($template);
}
public function loadInputCityBlock(): Response
{
$template = $this->get('twig')
->render('@templates/AdminCustom/Customer/Address/Form/_input_city.html.twig');
return new Response($template);
}
/**
* @param Request $request
* @return Response
* If an address is edited in CMS by an Admin, we will save it as a new Address and the old one will be set as inactive
*/
public function editAdminAddressSubmit(Request $request): Response
{
$response = null;
$authService = $this->getContainer()->get('app.service.security.auth_service');
if ($authService->checkIfLoggedUserIsAdmin()) {
$addressFormValidator = new AddressFormValidator($this->getEntityManager(), $this->getSerializer());
$oldAddress = AddressModel::getAddressById($request->get('addressId'), $this->getEntityManager());
$order = OrderModel::retrieveOrderEntityById($request->get('orderId'), $this->getEntityManager());
if ($addressFormValidator->checkForm($request, true) && $oldAddress && $order) {
$customer = $oldAddress->getCustomer();
$data = $request->request->all();
$data = AddressModel::removeFieldsForCustomerType($data);
$addressData = AddressModel::constructAddressDataArray($data, false);
$address = AddressModel::setNewAddress($addressData, $customer, $this->getEntityManager()->getRepository(County::class));
if ($address) {
$oldAddress->setDeleted(true);
$this->getEntityManager()->persist($address);
$this->getEntityManager()->flush();
$order->setBillingAddress($address);
$this->getEntityManager()->flush();
$response = json_encode('success');
$this->addFlash('success', 'Adresa editata cu succes');
}
}
}
if (!$response) {
$response = json_encode('fail');
$this->addFlash('error', 'A intervenit o eroare!');
}
return new Response($response);
}
/**
* @param Request $request
* @return Response
* @throws InvalidArgumentException
*/
public function verifyCustomerCIFCode(Request $request): Response
{
$cif = $request->get('customerCIF');
$countryCode = $request->get('customerCountryCode');
$invoiceApiService = new InvoiceApiService();
$isValid = $invoiceApiService->verifyVatCode($cif, $countryCode, $this->getEntityManager());
$response = $isValid ? $invoiceApiService->getAugumentedInformationTermene($cif, $countryCode, $invoiceApiService->getLastResponse()) : array();
if ($request->get('isFromRca')) {
$customer = CustomerService::retrieveCustomerFromShopUser($this->getUser());
$rcaTrackerActivityService = $this->getContainer()->get('app.service.rca.tracker_activity');
$rcaTrackerActivityService->setCifInfoRetrieved($customer, array('isValid' => $isValid, 'response' => $response));
}
return new Response(json_encode(array('isValid' => $isValid, 'response' => $response)));
}
public function verifyCustomerPhoneNumber(Request $request, TranslatorInterface $translator)
{
$result = false;
$phone = $request->get('phone');
$locale = $request->get('_locale') ? $request->get('_locale') : 'ro';
if ($phone) {
$result = CustomerModel::verifyPhoneNumber($phone);
}
$message = $translator->trans('app.ui.invalid_phone_for_sms_alert', $parameters = [], $domain = null, $locale);
return new Response(json_encode(array('result' => $result, 'error_message' => $message)));
}
public function loadAddressBlock(Request $request)
{
$addressId = $request->get('addressId');
$isShippingAddress = false;
if ($request->get('isShippingAddress') && $request->get('isShippingAddress') == true) {
$isShippingAddress = true;
}
$address = null;
$user = $this->getUser();
$isValid = false;
$city = null;
$country = null;
$county = null;
$customerType = null;
$customer = null;
if ($user) {
if ($customer = $user->getCustomer()) {
$customerType = $customer->getType();
if ($customer && $addressId) {
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
if ($address) {
$customerType = $address->getCustomerType();
if ($address->getCustomer()
&& $address->getCustomer()->getId() == $customer->getId()) {
$isValid = true;
if ($address->getCountryCode()) {
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $address->getCountryCode()));
}
if ($address->getCounty()) {
if ($country) {
$county = $this->getDoctrine()->getRepository(County::class)->findByCodeAndCountry($address->getCounty(), $country);
} else {
$county = $this->getDoctrine()->getRepository(County::class)->findByCode($address->getCounty());
}
}
if ($address->getCity() && ctype_digit($address->getCity())) {
$city = $this->getDoctrine()->getRepository(City::class)->find((int) $address->getCity());
}
}
}
}
}
}
$template = json_encode('error');
try {
if (!$isValid) {
$address = null;
}
$country = $country ?: $this->getDoctrine()->getRepository(Country::class)->findOneBy(['code' => $address ? $address->getCountryCode() : $request->getLocale()]);
$counties = null;
if ($country) {
$counties = $this->getDoctrine()->getRepository(County::class)->findBy(['country' => $country->getId()]);
}
$templatePath = !$this->isMobile ? '@templates/Front/Checkout/address_block.html.twig'
: '@templates/Mobile/Checkout/address_block.html.twig';
if ($isShippingAddress) {
$templatePath = !$this->isMobile ? '@templates/Front/Checkout/shipping_address_block.html.twig'
: '@templates/Mobile/Checkout/shipping_address_block.html.twig';
}
$template = $this->get('twig')
->render($templatePath, [
'address' => $address,
'countries' => $this->getDoctrine()->getRepository(Country::class)->findAll(),
'counties' => $counties,
'selectedCountry' => $country,
'selectedCity' => $city,
'selectedCounty' => $county,
'customerType' => $customerType,
'customer' => $customer,
]);
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function verifyAddressBlock(Request $request)
{
$addressId = $request->get('addressId');
$user = $this->getUser();
$customer = null;
if ($user) {
if ($customer = $user->getCustomer()) {
$customerType = $customer->getType();
if ($customer && $addressId) {
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
if ($address) {
// Check if required fields are empty or null
if (empty($address->getCountryCode()) || empty($address->getCounty()) || empty($address->getCity()) || empty($address->getStreet()) || empty($address->getStreetNumber()) || (!$customerType && empty($address->getFullName())) || empty($address->getPhoneNumber())) {
// Handle the case where one or more required fields are empty or null
return new JsonResponse(['isValid' => false]);
} else {
// The address has all the required fields populated
return new JsonResponse(['isValid' => true]);
}
}
}
}
}
return new JsonResponse(['isValid' => true]);
}
public function loadShopInputCityBlock(Request $request)
{
$template = json_encode('error');
$isShippingAddress = false;
$customerType = $request->get('customerType');
if ($request->get('isShippingAddress') && $request->get('isShippingAddress') == true) {
$isShippingAddress = true;
}
try {
$template = $this->get('twig')
->render('@templates/Front/Checkout/input_city_block.html.twig',
[
'isShippingAddress' => $isShippingAddress,
'customerType' => $customerType
]);
if ($this->isMobile) {
$template = $this->get('twig')
->render('@templates/Mobile/Checkout/input_city_block.html.twig',
[
'isShippingAddress' => $isShippingAddress,
'customerType' => $customerType
]);
}
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function loadShopSelectCityBlock(Request $request)
{
$template = json_encode('error');
$isShippingAddress = false;
$customerType = $request->get('customerType');
if ($request->get('isShippingAddress') && $request->get('isShippingAddress') == true) {
$isShippingAddress = true;
}
try {
$template = $this->get('twig')
->render('@templates/Front/Checkout/select_city_block.html.twig',
[
'isShippingAddress' => $isShippingAddress,
'customerType' => $customerType
]);
if ($this->isMobile) {
$template = $this->get('twig')
->render('@templates/Mobile/Checkout/select_city_block.html.twig',
[
'isShippingAddress' => $isShippingAddress,
'customerType' => $customerType
]);
}
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function loadSelectCountyBlock()
{
$template = json_encode('error');
try {
$template = $this->get('twig')
->render('@templates/Front/Checkout/select_county_block.html.twig', [
'counties' => $this->getDoctrine()->getRepository(County::class)->findAll(),
]);
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function renderSavedAddressesBlock(Request $request)
{
$template = json_encode('error');
$isShippingAddress = false;
if ($request->get('isShippingAddress') && $request->get('isShippingAddress') == true) {
$isShippingAddress = true;
}
try {
$user = $this->getUser();
if ($user) {
$customer = $user->getCustomer();
if ($customer) {
$render = '@templates/Front/Checkout/saved_addresses_block.html.twig';
if ($isShippingAddress) {
$render = '@templates/Front/Checkout/saved_shipping_addresses_block.html.twig';
}
$template = $this->get('twig')
->render($render, [
'customer' => $customer,
'cityRepository' => $this->getDoctrine()->getRepository(City::class),
'countyRepository' => $this->getDoctrine()->getRepository(County::class),
]);
}
}
} catch (\Throwable $exception) {
captureException($exception);
}
return new Response($template);
}
public function retrieveCitiesByCountyAction(Request $request): Response
{
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$countyId = $request->get('countyId');
$cities = [];
if (is_array($countyId)) {
foreach ($countyId as $item) {
$cities = array_merge($cities, $this->retrieveCitiesByCountry($item));
}
} else {
$cities = $this->retrieveCitiesByCountry($countyId);
}
if (($context = $request->get('context')) && str_starts_with($context, 'institution-product')) {
$type = explode('-', $context)[2];
$productTypeRepo = $this->getDoctrine()->getRepository(ProductType::class);
$lastId = 0;
$filteredCities = [];
$addAll = false;
$productTypeCategories = [ProductType::CATEGORY_FINE, ProductType::CATEGORY_TARIFF];
while (in_array($type, $productTypeCategories) &&
$productTypes = $productTypeRepo->getByCategoryWithOffset($type, $lastId)
) {
foreach ($productTypes as $productType) {
$lastId = $productType['id'];
$ibanData = array_merge(
json_decode($productType['legalIBANs'] ?? '[]', true),
json_decode($productType['physicalIBANs'] ?? '[]', true)
);
foreach ($ibanData as $iban) {
if (empty($iban['county']) || (empty($iban['city']) && $iban['county'] == $countyId)) {
$addAll = true;
break 3;
}
if (!empty($iban['city']) && $iban['county'] == $countyId) {
$filteredCities[] = $iban['city'];
}
}
}
}
if (!$addAll) {
$cities = array_filter($cities, function ($city) use ($filteredCities) {
return in_array($city['id'], $filteredCities);
});
}
}
return new Response($serializer->serialize(array_values($cities), 'json'));
}
public function retrieveCitiesByCountry($countyId): array
{
$cityRepo = $this->getEntityManager()->getRepository(City::class);
$cities = $cityRepo->findAllCitiesByCounty($countyId);
if (!$cities) {
$romania = $this->getEntityManager()->getRepository(Country::class)->findOneBy(['code' => 'RO']);
$county = $this->getEntityManager()->getRepository(County::class)
->findByCodeAndCountry($countyId, $romania);
if ($county) {
$cities = $cityRepo->findAllCitiesByCounty($county);
}
}
return $cities;
}
public function retrieveCountryCounties(Request $request)
{
$countryCode = $request->get('countryCode');
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$country = $this->getDoctrine()->getRepository(Country::class)->findOneBy(array('code' => $countryCode));
$counties = $this->getDoctrine()->getRepository(County::class)->findAllCountiesByCountryWithSpecificFields($country);
$counties = $serializer->serialize($counties, 'json', [
'circular_reference_handler' => function ($object) {
return $object->getId();
},
]);
return new Response($counties);
}
public function deleteSelectedAddress(Request $request)
{
$result = json_encode('error');
$addressId = $request->get('addressId');
$user = $this->getUser();
if ($user) {
if ($customer = $user->getCustomer()) {
if ($customer && $addressId) {
$address = $this->getDoctrine()->getRepository(Address::class)->find($addressId);
if ($address) {
if ($address->getCustomer()
&& $address->getCustomer()->getId() == $customer->getId()) {
$customer->removeAddress($address);
$this->getEntityManager()->persist($address);
$this->getEntityManager()->flush();
$this->addFlash('address-deleted', 'success');
$result = json_encode('success');
}
}
}
}
}
return new Response($result);
}
public function retrieveCountryCodeByName(Request $request)
{
$code = '';
$countryName = $request->get('countryName');
if ($countryName) {
$code = CountryModel::retrieveCountryCodeByName($countryName, $this->getEntityManager());
}
return new Response(json_encode($code));
}
public function checkCNPAction(Request $request)
{
$isNN = !empty($request->get('isNN'));
$cnp = $request->get('customerCNP');
$isValid = CustomerModel::validateCNP($cnp, $isNN);
return new Response(json_encode(array('isValid' => $isValid)));
}
}