<?php
namespace App\Controller;
use App\Entity\CardItem;
use App\Entity\StripePrice;
use App\Entity\StripeProduct;
use App\Service\Mailer;
use App\Service\PlatformService;
use App\Service\StripePriceEntityService;
use App\Service\StripeProductEntityService;
use App\Service\StripeService;
use Doctrine\ORM\EntityManagerInterface;
use Stripe\Customer;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class ProductsController extends AbstractController
{
/**
* @Route("/kiosque", name="products", methods={"GET"})
*/
public function index(Request $request, StripeService $stripeService, PlatformService $platformService)
{
if (!$platformService->getConfig()['e_shop']['on']) return $this->redirectToRoute('home');
$categories = $stripeService->getProductsCategories();
return $this->render('product/index.html.twig', [
'recurring' => $request->get('recurring'),
'categories' => $categories
]);
}
/**
* @Route("/index-all-products", name="index_all_products", methods={"GET"})
*/
public function getProducts(Request $request, StripeService $stripeService)
{
// TODO optimiser cette méthode?
$user = $this->getUser();
$products = $stripeService->getAllProducts(true, $request->get('sort_type'), $request->get('sort_category'), $request->get('sort_price'), $user, null, "front");
$total_results_number = count($products);
$page = $request->get('page');
$limit = 20;
$pages = ceil(count($products) / $limit) != 1 ? ceil(count($products) / $limit) : null;
$products = array_slice($products, $limit * ($page - 1), $limit);
$html = $this->renderView('product/products.html.twig', [
'products' => $products
]);
return $this->json([
'html' => $html,
'total_results_number' => $total_results_number,
'pages' => $pages,
]);
}
/**
* @Route("/produits/{price_id}", name="products.details", methods={"GET"})
*/
public function show($price_id, StripeService $stripeService, PlatformService $platformService)
{
if (!$platformService->getConfig()['e_shop']['on']) return $this->redirectToRoute('home');
$price = $stripeService->getPrice($price_id, false);
$user = $this->getUser();
if (!$price) return $this->redirectToRoute('products');
$product = $stripeService->getProduct($price->getStripeProduct()->getStripeId(), true, $price, $user);
if (!$product) return $this->redirectToRoute('products');
$related_products = [];
if (isset($product['metadata']) && isset($product['metadata']['category']))
$related_products = $stripeService->getAllProducts(true, 'all', $product['metadata']['category'], 'all', $user, $product['stripe_id']);
return $this->render('product/details.html.twig', [
'product' => $product,
'related_products' => $related_products
]);
}
/**
* @Route("/products/create-checkout", name="products.create-checkout", methods={"POST"})
*/
public function createCheckout(Request $request, StripeService $stripeService)
{
$user = $this->getUser();
if ($user) {
$customer = $stripeService->getCustomer($user);
if ($customer && !isset($customer['shipping'])) {
$this->addFlash('adresse', "L'adresse de livraison est requise pour passer une commande");
return $this->json([
'route' => '/account',
'unlogged' => false,
'message' => "L'adresse de livraison est requise pour passer une commande"
]);
}
}
$session = $request->getSession();
$price_id = $request->get('price_id');
$session->set('price_id', $price_id);
$mode = $request->get('mode');
$checkout = $stripeService->createCheckout($user, $price_id, $mode);
return $this->json([
'session_id' => $checkout->id
]);
}
/**
* @Route("/products/stripe-payment-succedeed/{priceId}", name="products.stripe.payment-succeeded", methods={"GET"})
*/
public function paymentSucceeded(Request $request, StripeService $stripeService, Mailer $mailer, $priceId)
{
$user = $this->getUser();
$session_id = $request->get('session_id');
$newAdress = [];
$session = $stripeService->getSession($session_id);
if ($user) {
$customer = $stripeService->getCustomer($user);
$shippingCustomer = $customer['shipping'];
$nameCustomer = $customer['name'];
$billingCustomer = $customer['address'];
// save address if address customer is empty
$shipping = isset($session['shipping']['address']) ? $session['shipping']['address'] : [];
$newName = isset($session['shipping']['name']) ? $session['shipping']['name'] : "";
$billing = isset($session['customer_details']['address']) ? $session['customer_details']['address'] : [];
$newNameBilling = $session['customer_details']['name'];
if (!$shippingCustomer) {
$newAdress = $newAdress + [
"shipping" => [
"address" => [
'city' => $shipping['city'],
'country' => $shipping['country'],
'postal_code' => $shipping['postal_code'],
'line1' => $shipping['line1'],
'line2' => $shipping['line2'],
],
'name' => $newName
],
];
}
if (!$billingCustomer) {
$newAdress = $newAdress + [
"address" => [
'city' => $billing['city'],
'country' => $billing['country'],
'postal_code' => $billing['postal_code'],
'line1' => $billing['line1'],
'line2' => $billing['line2'],
],
];
}
if (!$nameCustomer) {
$newAdress = $newAdress + [
'name' => $newNameBilling,
];
}
if ($newAdress) {
$stripeService->persistAddress2($user, $newAdress);
}
}
if (!$session) return $this->redirectToRoute('products');
$price = $stripeService->getPrice($priceId, false);
$charge = null;
if (!$price->getReccuringInterval()) {
$paymentIntent = $stripeService->getPaymentIntent($session->payment_intent);
if (!$paymentIntent) return $this->redirectToRoute('products');
$charge = $stripeService->getChargeByPaymentIntent($paymentIntent->id);
}
$product = $stripeService->getProduct($price->getStripeProduct()->getStripeId(), true, $price);
$invoice = $stripeService->getLastInvoice($user);
$html = $this->renderView('mails/products/product_payment_succeeded.html.twig', [
'user' => $user,
'product' => $product,
'url_docs' => $this->getParameter('app_url') . '/account/confidential-documents',
'url_dashboard' => $this->getParameter('app_url') . '/account',
'receipt_url' => $charge ? $charge->receipt_url : null,
'invoice_pdf' => $invoice ? $invoice->invoice_pdf : null,
'recurring' => $price->getReccuringInterval()
]);
$mailer->sendHTML(
"Merci pour votre achat",
$html,
$user->getEmail()
);
return $this->redirectToRoute('products.payment_succeeded', [
'product_id' => $product ? $product['stripe_id'] : null,
'session_id' => $session_id,
'price_id' => $priceId
]);
}
/**
* @Route("/products/store-stripe-payment-succedeed/{priceId}/{itemCard}/{id}", name="store.products.stripe.payment-succeeded", methods={"GET"})
*/
public function storePaymentSucceeded(Request $request, EntityManagerInterface $manager, StripeService $stripeService, Mailer $mailer, $itemCard, $priceId, $id)
{
$user = $this->getUser();
$session_id = $request->get('session_id');
$newAdress = [];
$session = $stripeService->getSession($session_id);
$total_amount_paid = $this->getTotalAmountPaidByCustomer($id);
$totale_client = number_format($total_amount_paid, 2);
$total_price = $session['amount_total'] / 100;
$intent_payment = $session['payment_intent'];
$discount_value = $session['total_details']['amount_discount'];
if ($user) {
$customer = $stripeService->getCustomer($user);
$shippingCustomer = $customer['shipping'];
$nameCustomer = $customer['name'];
$billingCustomer = $customer['address'];
// save address if address customer is empty
$shipping = isset($session['shipping']['address']) ? $session['shipping']['address'] : [];
$newName = isset($session['shipping']['name']) ? $session['shipping']['name'] : "";
$billing = isset($session['customer_details']['address']) ? $session['customer_details']['address'] : [];
$newNameBilling = $session['customer_details']['name'];
if (!$shippingCustomer) {
$newAdress = $newAdress + [
"shipping" => [
"address" => [
'city' => $shipping['city'],
'country' => $shipping['country'],
'postal_code' => $shipping['postal_code'],
'line1' => $shipping['line1'],
'line2' => $shipping['line2'],
],
'name' => $newName
],
];
}
if (!$billingCustomer) {
$newAdress = $newAdress + [
"address" => [
'city' => $billing['city'],
'country' => $billing['country'],
'postal_code' => $billing['postal_code'],
'line1' => $billing['line1'],
'line2' => $billing['line2'],
],
];
}
if (!$nameCustomer) {
$newAdress = $newAdress + [
'name' => $newNameBilling,
];
}
if ($newAdress) {
$stripeService->persistAddress2($user, $newAdress);
}
}
if (!$session) return $this->redirectToRoute('panier');
$prices = [];
$priceId = explode(',', $priceId);
foreach ($priceId as $id) {
$prices[] = $stripeService->getPrice($id, false);
}
$charge = null;
$products = [];
$data_pay = [];
$data_pay['intent_payment'] = $intent_payment;
$data_pay['total_price'] = $total_price;
$data_pay['revenu'] = $totale_client;
if( $discount_value == 0 ){
$data_pay['product_has_discount'] = false ;
$data_pay['product_discount_value'] = $discount_value ;
}else{
$data_pay['product_has_discount'] = true ;
$data_pay['product_discount_value'] = - $discount_value/100 ;
}
$price = null;
foreach ($prices as $key=>$price) {
if ($price && !$price->getReccuringInterval()) {
$paymentIntent = $stripeService->getPaymentIntent($session->payment_intent);
$data_pay['payment_methode'] = $paymentIntent['payment_method_types'][0];
if (!$paymentIntent) return $this->redirectToRoute('panier');
$charge = $stripeService->getChargeByPaymentIntent($paymentIntent->id);
}
$products[] = $stripeService->getProductSuccess($price->getStripeProduct()->getStripeId(), true, $price, $user);
$reduction_name = $this->getReductionNameFromHtmlData($charge->receipt_url);
$data_pay['purchase_discount_name'] = $reduction_name;
$declancheur[] = array_merge($products[$key], $data_pay);
}
$invoice = $stripeService->getLastInvoice($user);
if ($session) {
$itemIds = explode(",", $itemCard);
foreach ($itemIds as $item) {
$card_items = $manager->getRepository(CardItem::class)->findOneBy(['id' => $item]);
$manager->remove($card_items);
$manager->flush();
}
}
$html = $this->renderView('mails/products/theme-5-product_payment_succeeded.html.twig', [
'user' => $user,
'product' => $products,
'url_docs' => $this->getParameter('app_url') . '/account/confidential-documents',
'url_dashboard' => $this->getParameter('app_url') . '/account',
'receipt_url' => $charge ? $charge->receipt_url : null,
'invoice_pdf' => $invoice ? $invoice->invoice_pdf : null,
'recurring' => $price ? $price->getReccuringInterval() : null
]);
$mailer->sendHTML(
"Merci pour votre achat",
$html,
$user->getEmail()
);
return $this->redirectToRoute('products.payment_succeeded', [
'product_id' => null,
'declancheur' => $declancheur,
'session_id' => $session_id,
'price_id' => $priceId
]);
}
public function getReductionNameFromHtmlData($receipt_url){
$result=[];
$html = file_get_contents($receipt_url);
$dom = new \DOMDocument();
@$dom->loadHTML($html);
$xpath = new \DOMXPath($dom);
$targetClasses = ['Table-description','Table-amount'];
foreach ($targetClasses as $class) {
$elements = $xpath->query("//*[contains(@class, '$class')]");
foreach ($elements as $element) {
$result[] = $element->textContent;
}
}
$cleanedData = array_map(array($this, 'extractNumericValue'), $result);
$searchTerm = "réduction";
$result = null;
foreach ($cleanedData as $value) {
if (strpos($value, $searchTerm) !== false) {
if (preg_match('/^([^ ]+)/', $value, $matches)) {
$result = $matches[1];
}else{
$result = null;
}
}
}
return $result;
}
public function extractNumericValue($str) {
return preg_replace('/^\h*\v+/m', '', trim($str));
}
/**
* @Route("/products/payment-succeeded", name="products.payment_succeeded", methods={"GET"})
*/
public function paymentSucceededView(Request $request, StripeService $stripeService)
{
$declancheur = $request->get('declancheur');
$session_id = $request->get('session_id');
$price_id = $request->get('price_id');
$session = $stripeService->getSession($session_id);
if (!$session) return $this->redirectToRoute('products');
$price = $stripeService->getPrice($price_id, false);
$charge = null;
if ($price && !$price->getReccuringInterval()) {
$paymentIntent = $stripeService->getPaymentIntent($session->payment_intent);
if (!$paymentIntent) return $this->redirectToRoute('products');
$charge = $stripeService->getChargeByPaymentIntent($paymentIntent->id);
}
$invoice = null;
$user = $this->getUser();
if ($user) $invoice = $stripeService->getLastInvoice($user);
return $this->render('product/payment-succeeded.html.twig', [
'declancheur' => $declancheur,
'receipt_url' => $charge ? $charge->receipt_url : null,
'invoice_pdf' => $invoice ? $invoice->invoice_pdf : null,
'recurring' => $price->getReccuringInterval()
]);
}
/**
* @Route("/kiosque/{type}/{numero}", name="products.kiosque", methods={"GET"})
*/
public function kiosque($type, $numero, StripePriceEntityService $entityService, StripeProductEntityService $stripeProductEntityService, Request $request, StripeService $stripeService, StripePriceEntityService $stripePriceEntityService)
{
if (!$type || !$numero || $type == "null" || $numero == "null") return $this->redirectToRoute('homepage');
// fiche produit depuis Immanens
$magazineExistInSubscriptions = false;
$magazineExistInSingleMagazines = false;
$userHasSubscriptions = false;
$magazinesFromSubscriptionsId = [];
$singleMagazinesId = [];
$magazinesFromSubscriptions = [];
$singleMagazines = [];
$user_subscription = [];
$user = $this->getUser();
// verify if $type contains é
if (str_contains($type, "é")) {
$type = str_replace("é", "e", $type);
$type = strtolower($type);
return $this->redirectToRoute('products.kiosque', ["type" => $type, "numero" => $numero]);
}
/** @var StripePrice $price */
$product = $this->getDoctrine()->getRepository(StripeProduct::class)->findOneBy(['type' => $type, "number" => $numero, "active" => true]);
if (!$product) return $this->redirectToRoute('products');
$price = $this->getDoctrine()->getRepository(StripePrice::class)->findOneBy(['stripe_product' => $product, "active" => true]);
$stripe_price = $price->getStripeId();
if ($user) {
$magazinesFromSubscriptions = $stripeService->getMagazinesFromSubscriptions($stripePriceEntityService, $stripeProductEntityService, $user);
$user_subscription = $stripeService->getUserSubscriptions($user);
$singleMagazines = $stripeService->getSingleMagazines($stripePriceEntityService, $stripeProductEntityService, $user);
}
if ($user_subscription) $userHasSubscriptions = true;
foreach ($magazinesFromSubscriptions as $magazineFromSubscription) {
$magazinesFromSubscriptionsId[] = $magazineFromSubscription['price_id'];
}
$magazineExistInSubscriptions = in_array($stripe_price, $magazinesFromSubscriptionsId);
foreach ($singleMagazines as $singleMagazine) {
$singleMagazinesId[] = $singleMagazine['price_id'];
}
$magazineExistInSingleMagazines = in_array($stripe_price, $singleMagazinesId);
$productFormat=$stripeProductEntityService->formatProduct($product);
$image= $productFormat['images'][0] ?? null;
if($image){
$httpClient = \Symfony\Component\HttpClient\HttpClient::create();
$url = $image."_mobile_298_406";
$old_url = $image;
// Create an instance of the HttpClient
$response = $httpClient->request('HEAD', $url);
// Check the response status code
$statusCode = $response->getStatusCode();
if ($statusCode === 200) {
$productFormat['url'] = $url;
} else {
$productFormat['url'] = $old_url;
}
}
if (!$price || $price->getType() == "recurring" || !$price->getDuajQuadriCode()) return $this->redirectToRoute('homepage');
return $this->render('product/kiosque.html.twig',
[
"price" => $entityService->formatPrice($price),
"product" => $productFormat,
"userHasSubscriptions" => $userHasSubscriptions,
"magazineExistInSubscriptions" => $magazineExistInSubscriptions,
"magazineExistInSingleMagazines" => $magazineExistInSingleMagazines,
"user_subscription" => $user_subscription
]
);
}
private function getTotalAmountPaidByCustomer($customer_id)
{
try {
$total_amount = 0;
// Fetch payments associated with the customer from Stripe
$payments = \Stripe\PaymentIntent::all(['customer' => $customer_id]);
// Iterate through the payments and calculate the total amount paid by the customer
foreach ($payments->autoPagingIterator() as $payment) {
if($payment->status === 'succeeded' ){
$total_amount += $payment->amount / 100; // Convert the amount to the correct currency (e.g., dollars)
}
}
return $total_amount;
} catch (\Stripe\Exception\ApiErrorException $e) {
// Handle the exception if the customer is not found or if there's an API error
echo 'Error fetching payments: ' . $e->getMessage();
return 0;
}
}
}