<?php
namespace App\Controller\Subscription;
use App\Entity\Category;
use App\Entity\Discount;
use App\Entity\SubjectLevel;
use App\Entity\SubscriptionOrder;
use App\Entity\Teacher;
use App\Entity\User;
use App\Form\SubscriptionPrivateOrderType;
use App\Helper\BookHelper;
use App\Helper\CourseHelper;
use App\Helper\SubscriptionHelper;
use App\Notification\EmailNotification;
use App\Notification\SlackClient;
use App\Repository\DiscountRepository;
use App\Repository\HolidayRepository;
use App\Repository\PaidCourseListRepository;
use App\Repository\PlanRepository;
use App\Repository\SubjectLevelRepository;
use App\Repository\SubjectRepository;
use App\Repository\SubscriptionOrderRepository;
use App\Repository\TeacherScheduleRepository;
use App\Service\Currency\CurrencyChangeService;
use App\Service\Localisation\CountryInfoService;
use App\Service\Localisation\GeoIPService;
use App\StripeClient;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Polyfill\Intl\Icu\Currencies;
use Symfony\Polyfill\Intl\Icu\NumberFormatter;
/**
* @Route("user/subscription")
* @Security("is_granted('ROLE_USER')")
*/
class UserSubscriptionController extends AbstractController
{
private $subscriptionHelper;
private $bookHelper;
//Acheter OK
//Voir
//Editer
//Renouveler OK
//Reactiver
//Supprimer
public function __construct(SubscriptionHelper $subscriptionHelper, BookHelper $bookHelper)
{
$this->subscriptionHelper = $subscriptionHelper;
$this->bookHelper = $bookHelper;
}
/**
* @Route("/{category}/{teacher}/checkout", name="subscription_checkout")
* @ParamConverter("category", options={"mapping": {"category" : "name"}})
* @ParamConverter("teacher", options={"mapping": {"teacher" : "id"}})
*/
public function orderSubscription(Request $request, Category $category, Teacher $teacher, SubscriptionOrderRepository $subscriptionOrderRepository,
SubjectRepository $subjectRepository, DiscountRepository $discountRepository, StripeClient $stripeClient,
SubjectLevelRepository $subjectLevelRepository, CurrencyChangeService $currencyChangeService
) {
/** @var User $user */
$user = $this->getUser();
$parameter = $request->query->get('d');
/** @var Discount $discount */
$discount = $discountRepository->findOneBy([
'urlParameter' => $parameter,
'isForGroup' => false,
]);
if ($discount) {
$couponStripeName = $discount->getStripeName();
$discountType = $discount->getType();
try {
$stripeCoupon = $stripeClient->findCoupon($couponStripeName);
if ($stripeCoupon->valid) {
$isDiscount = true;
$request->getSession()->set('code-subscription', $stripeCoupon);
} else {
$isDiscount = false;
$discountAmount = 0;
$discountType = null;
$stripeCoupon = false;
$this->addFlash(
'error',
' Coupon invalid'
);
}
} catch (\Stripe\Exception\InvalidRequestException $e) {
$isDiscount = false;
$discountAmount = 0;
$discountType = null;
$stripeCoupon = false;
$this->addFlash(
'error',
$e.' Coupon invalid'
);
}
} else {
$stripeCoupon = false;
$isDiscount = false;
$discountAmount = 0;
$discountType = null;
}
//reception possible : beginner, intermediate, advanced
$autoAssignLevel = $request->query->get('level');
if ($autoAssignLevel !== "intermediate" && $autoAssignLevel !== "advanced" && $autoAssignLevel !== "beginner") {
$autoAssignLevel = null;
}
//reception possible: "0", "1"
$isChild = $request->query->get('child');
if ($isChild != "0" && $isChild != "1") {
$isChild = null;
}
$categoryEn = $category->getNameEn();
$error = false;
$currency = $currencyChangeService->getCurrencyChangeForView($request);
//$stripeCoupon = $request->getSession()->get('code-subscription', false);
$subscriptionOrder = new SubscriptionOrder();
$subscriptionOrder->setTeacher($teacher);
$subscriptionOrder->setCategory($category);
$subscriptionOrder->setUser($user);
$form = $this->createForm(SubscriptionPrivateOrderType::class, $subscriptionOrder, [
'locale' => $request->getLocale(),
'isChild' => $isChild,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$request->getSession()->remove('code-subscription');
/** @var SubscriptionOrder $subscriptionOrder */
$subscriptionOrder = $form->getData();
//Reception data possible : all, chafawi, naho, qiraa, sarf, balagha,child-program, quran,tajwid, quran-child
$requestedProgram = $request->get('subscription_private_order') ? $request->get('subscription_private_order')['program'] : null;
$subscriptionOrder->setPurchaseDate(new \DateTimeImmutable())
->setTotalLostMinutes(0)
->setRamadanCreditAmount(0);
foreach ($subscriptionOrder->getSchedules() as $teacherSchedule) {
$repeatedSubscription = $subscriptionOrderRepository->findRepeatedOrder($teacherSchedule);
if ($repeatedSubscription) {
$this->addFlash(
'error',
"Ce Planning vient d'être réservé, si vous venez de le reserver, il se peut que cette erreur vienne du fait que vous ayez cliquez plusieurs fois sur le bouton s'inscrire"
);
return $this->redirectToRoute(
'schedule_list',
[
'category' => $category,
'gender' => $user->getGender()->getName(),
'_locale' => $request->getLocale(),
]
);
}
}
$plan = $subscriptionOrder->getPlan();
if ($stripeCoupon) {
if ($plan->getFrequency() != $discount->getPlan()) {
$stripeCoupon = false;
}
}
$token = $request->get('stripeToken');
$quantity = $subscriptionOrder->getNbOfScheduleChoose();
$participant = $subscriptionOrder->getParticipant();
$schedules = $subscriptionOrder->getSchedules();
try {
$stripeSubscription = $this->subscriptionHelper->chargeCustomer($token, $user, $plan, $quantity, $stripeCoupon, $schedules);
} catch (\Stripe\Exception\CardException $e) {
//error_log("A payment error occurred: {$e->getError()->message}");
$error = 'Il y a un problème pour charger votre carte: '.$e->getError()->message;
} catch (\Stripe\Exception\InvalidRequestException $e) {
$error = 'Il y a un problème pour charger votre carte: '.$e->getError()->message;
} catch (\Exception $e) {
//error_log("Another problem occurred, maybe unrelated to Stripe.");
$error = 'Il y a un problème pour charger votre carte: '.$e;
}
/*catch (\Stripe\Error\Card $e) {
$error = 'Il y a un problème pour charger votre carte: '.$e->getMessage();
}
*/
if ( ! $error) {
if ($stripeSubscription->status == 'active') {
$this->addFlash(
'success',
'Votre inscription a été reçue. Elle sera validée lorsque le paiement sera confirmé. Vous recevrez un email et vos cours seront visibles dans votre espace membre'
);
// $requestedProgram à lier avec les entités Subject dans la BDD avec le tag
//all -> alKunuz
//chafawi -> oral
//naho -> ajromiyah
//qiraa -> texteMedine
//sarf -> sarf-private
//balagha -> balagha
//child-program -> tresorsEnfant
//quran -> coranComplet
//tajwid -> tajweed
//quran-child -> coranCompletChildren
//nouraniyah -> an Nouraniyah
$level = null;
if ($requestedProgram == "all") {
$subject = $subjectRepository->findOneBy(['tagName' => "alKaamil"]);
} elseif ($requestedProgram == "chafawi") {
$subject = $subjectRepository->findOneBy(['tagName' => "oralExpression"]);
} elseif ($requestedProgram == "naho") {
$subject = $subjectRepository->findOneBy(['tagName' => "ajromiyah"]);
/** @var SubjectLevel $level */
$level = $subjectLevelRepository->findOneBy([
'subject' => $subject,
'level' => 1,
]);
} elseif ($requestedProgram == "qiraa") {
$subject = $subjectRepository->findOneBy(['tagName' => "medinaTexte"]);
/** @var SubjectLevel $level */
$level = $subjectLevelRepository->findOneBy([
'subject' => $subject,
'level' => 1,
]);
} elseif ($requestedProgram == "sarf") {
//pas de niveau
$subject = $subjectRepository->findOneBy(['tagName' => "sarf"]);
} elseif ($requestedProgram == "balagha") {
//pas de niveau
$subject = $subjectRepository->findOneBy(['tagName' => "balagha"]);
} elseif ($requestedProgram == "child-program") {
// a des niveaux mais dois passser un test
$subject = $subjectRepository->findOneBy(['tagName' => "tresorEnfant"]);
} elseif ($requestedProgram == "quran") {
$subject = $subjectRepository->findOneBy(['tagName' => "coranComplet"]);
} elseif ($requestedProgram == "tajwid") {
$subject = $subjectRepository->findOneBy(['tagName' => "tajweedBeginner"]);
} elseif ($requestedProgram == "quran-child") {
$subject = $subjectRepository->findOneBy(['tagName' => "coranCompletChildren"]);;
} elseif ($requestedProgram == "nouraniyah") {
$subject = $subjectRepository->findOneBy(['tagName' => "nouraniyah"]);
} else {
if ($subscriptionOrder->getCategory()->getNameEn() == 'Arabic') {
if ($isChild) {
$subject = $subjectRepository->findOneBy(['tagName' => "tresorEnfant"]);
} else {
$subject = $subjectRepository->findOneBy(['tagName' => "alKaamil"]);
}
} else {
if ($isChild) {
$subject = $subjectRepository->findOneBy(['tagName' => "coranCompletChildren"]);
} else {
$subject = $subjectRepository->findOneBy(['tagName' => "coranComplet"]);
}
}
}
if ($requestedProgram == null) {
if ($subscriptionOrder->getCategory()->getNameEn() == 'Arabic') {
if ($isChild) {
$subject = $subjectRepository->findOneBy(['tagName' => "tresorEnfant"]);
} else {
$subject = $subjectRepository->findOneBy(['tagName' => "alKaamil"]);
}
} else {
if ($isChild) {
$subject = $subjectRepository->findOneBy(['tagName' => "coranCompletChildren"]);
} else {
$subject = $subjectRepository->findOneBy(['tagName' => "coranComplet"]);
}
}
}
//TODO utiliser Messenger
$subscriptionOrder = $this->subscriptionHelper->addSubscriptionInBDD(
$subscriptionOrder->getUser(),
$plan,
$schedules,
$category,
$teacher,
$quantity,
$stripeSubscription,
$subject,
$level,
$participant
);
//TODO utiliser Messenger
$this->subscriptionHelper->sendNotificationForNewSubscription($subscriptionOrder);
if ( ! $subject) {
//TODO utiliser Messenger
$this->subscriptionHelper->sendAlertNoSubject($subscriptionOrder);
}
//TODO utiliser Messenger
if ($requestedProgram != "quran" and $requestedProgram != "quran-child") {
$this->bookHelper->getChoosenBookForSubscription($subject, $subscriptionOrder, $level);
}
return $this->redirectToRoute(
'confirmation_purchase',
[
'userId' => $user->getId(),
'orderType' => 'subscription',
'orderId' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
} else {
$this->addFlash('error', "Votre Paiement n'a pas été accepté par votre banque");
return $this->redirectToRoute(
'subscription_checkout',
[
'category' => $category->getName(),
'teacher' => $teacher->getId(),
'_locale' => $request->getLocale(),
]
);
}
} else {
$this->addFlash('error', $error);
return $this->redirectToRoute(
'subscription_checkout',
[
'category' => $category->getName(),
'teacher' => $teacher->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
return $this->render(
'schedule/purchase.html.twig',
[
'form' => $form->createView(),
'categoryName' => $category,
'teacher' => $teacher,
'user' => $user,
'stripe_public_key' => $this->getParameter('stripe_public_key'),
'local' => $this->getParameter('locale'),
'errorCard' => $error,
'categoryEn' => $categoryEn,
'code' => ($stripeCoupon !== false) ? $stripeCoupon->percent_off : 0,
'isChild' => $isChild,
'discount' => $discount,
'isDiscount' => $isDiscount,
'currency' => $currency,
]
);
}
/**
* @Route("/{id}/resubscribe", name="subscription_resubscribe")
* @param SubscriptionOrder $oldSubscriptionOrder
* @param PlanRepository $planRepository
* @param Request $request
* @param Session $sessionSymfo
*
* @return RedirectResponse|Response
*/
public function reSubscribe(SubscriptionOrder $oldSubscriptionOrder, PlanRepository $planRepository, Request $request, Session $sessionSymfo, CurrencyChangeService $currencyChangeService
) {
/** @var User $user */
$user = $oldSubscriptionOrder->getUser();
//Montrer les nouveaux plan qui ne sont pas de la même fréquence. Au cas où l'élève souhaite changer de rythme (il passe au nouveau tarif, je ne montre donc pas les anciens plans)
$activePlan = $planRepository->getPlanToEditFrequencyFromOldToNew($oldSubscriptionOrder->getCategory(), $oldSubscriptionOrder->getPlan()->getFrequency());
$error = false;
if ($sessionSymfo->get('code-subscription')) {
$stripeCoupon = $sessionSymfo->get('code-subscription');
$code = $stripeCoupon->percent_off;
} else {
$stripeCoupon = false;
$code = 0;
}
$currency = $currencyChangeService->getCurrencyChangeForView($request);
if ($request->isMethod('POST')) {
$token = $request->request->get('stripeToken');
$quantity = $request->get('quantity');
$planStripeId = $request->get('frequency');
$schedules = $request->get('schedule');
$participant = $oldSubscriptionOrder->getParticipant();
if ( ! $quantity) {
$this->addFlash('error', 'Ne PAS taper sur la touche entrer de votre clavier pour envoyer le formulaire, mais CLIQUEZ sur le boutton "S\'inscrire" avec votre souris ');
return $this->redirectToRoute(
'subscription_resubscribe',
[
'id' => $oldSubscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
if ($planStripeId == null) {
$this->addFlash('error', "Merci de choisir un rythme d'abonnement");
return $this->redirectToRoute(
'subscription_resubscribe',
[
'id' => $oldSubscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
$plan = $planRepository->findOneBy(
[
'stripeId' => $planStripeId,
]
);
if ($stripeCoupon != false) {
if ($plan->getFrequency() != "mensuel") {
$stripeCoupon = false;
}
}
$subject = $oldSubscriptionOrder->getSubject();
$level = $oldSubscriptionOrder->getSubjectLevel();
try {
$stripeSubscription = $this->subscriptionHelper->chargeCustomer($token, $user, $plan, $quantity, $stripeCoupon, $schedules);
} catch (\Stripe\Exception\CardException $e) {
//error_log("A payment error occurred: {$e->getError()->message}");
$error = 'Il y a un problème pour charger votre carte: '.$e->getError()->message;
} catch (\Stripe\Exception\InvalidRequestException $e) {
$error = 'Il y a un problème pour charger votre carte: '.$e->getError()->message;
} catch (\Exception $e) {
//error_log("Another problem occurred, maybe unrelated to Stripe.");
$error = 'Il y a un problème pour charger votre carte: '.$e;
}
if ( ! $error) {
if ($stripeSubscription->status == 'active') {
$this->addFlash(
'success',
'Votre inscription a été reçue. Elle sera validée lorsque le paiement sera confirmé. Vous recevrez un email et vos cours seront visibles dans votre espace membre'
);
//TODO utiliser Messenger
$newSubscriptionOrder = $this->subscriptionHelper->addSubscriptionInBDD(
$user,
$plan,
$schedules,
$oldSubscriptionOrder->getCategory(),
$oldSubscriptionOrder->getTeacher(),
$quantity,
$stripeSubscription,
$subject,
$level,
$participant,
$oldSubscriptionOrder
);
//TODO utiliser Messenger
$this->subscriptionHelper->sendNotificationForNewSubscription($newSubscriptionOrder);
return $this->redirectToRoute(
'user_courses',
[
'order' => $oldSubscriptionOrder->getCategory()->getName(),
'_locale' => $request->getLocale(),
]
);
} else {
$this->addFlash('error', "Votre Paiement n'a pas été accepté par votre banque");
return $this->redirectToRoute(
'subscription_resubscribe',
[
'id' => $oldSubscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
} else {
$this->addFlash('error', $error);
return $this->redirectToRoute(
'subscription_resubscribe',
[
'id' => $oldSubscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
return $this->render(
'profil/resuscribe.html.twig',
[
'user' => $user,
'subscription' => $oldSubscriptionOrder,
'schedules' => $oldSubscriptionOrder->getSchedules(),
'errorCard' => $error,
'stripe_public_key' => $this->getParameter('stripe_public_key'),
'code' => $code,
'plans' => $activePlan,
'currency' => $currency,
]
);
}
/**
* @Route("/checkout/coupon", name="subscription_checkout_coupon_add", methods={"POST"})
*/
public function addCouponAction(Request $request, StripeClient $stripeClient): Response
{
$code = $request->request->get('code');
if ( ! $code) {
return $this->json(['success' => 0, 'message' => 'Vous n\'avez entré aucun coupon']);
}
try {
$stripeCoupon = $stripeClient->findCoupon($code);
} catch (\Stripe\Error\InvalidRequest $e) {
return $this->json(['success' => 0, 'message' => 'Coupon Invalide']);
}
if ($stripeCoupon->amount_off != null) {
return $this->json(['success' => 0, 'message' => 'Coupon invalide pour ces cours']);
}
if ( ! $stripeCoupon->valid) {
return $this->json(['success' => 0, 'message' => 'Coupon expiré']);
}
$request->getSession()->set('code-subscription', $stripeCoupon);
return $this->json(['success' => 1, 'message' => 'Le coupon a été ajouté', 'amount' => $stripeCoupon->percent_off]);
}
//TODO refacto pour code dupliquer à retravailler
/**
* @Route("/{id}/{teacher}/changeteacher", name="subscription_change_teacher")
* @param SubscriptionOrder $subscriptionOrder
* @param Teacher $teacher
* @param TeacherScheduleRepository $teacherScheduleRepository
* @param Request $request
* @param PaidCourseListRepository $paidCourseListRepository
* @param EntityManagerInterface $em
* @param EmailNotification $emailNotification
* @param SlackClient $slackClient
* @param HolidayRepository $holidayRepository
* @param SubscriptionHelper $subscriptionHelper
* @param CourseHelper $courseHelper
*
* @return RedirectResponse|Response
*/
public function modifySubscriptionSchedulesAndTeacher(SubscriptionOrder $subscriptionOrder, Teacher $teacher, TeacherScheduleRepository $teacherScheduleRepository,
Request $request,
PaidCourseListRepository $paidCourseListRepository, EntityManagerInterface $em, EmailNotification $emailNotification,
SlackClient $slackClient, HolidayRepository $holidayRepository, SubscriptionHelper $subscriptionHelper,
CourseHelper $courseHelper
) {
$freeSchedules = $teacherScheduleRepository->findForStudentFreeSchedulesForOneTeacher($teacher);
$oldTeacher = $subscriptionOrder->getTeacher();
if ( ! $this->isGranted('ROLE_SUPPORT')) {
if ($subscriptionHelper->hasCourseToday($subscriptionOrder)) {
$this->addFlash('error', "Vous avez cours aujourd'hui, vous ne pouvez donc pas changer de planning. Merci de modifier votre planning un jour où vous n'avez pas cours");
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
if ($request->isMethod('POST')) {
$holidays = $holidayRepository->findAll();
//Je compte le nb de cours annulé pour les vacances avant le changement de planning
$arrayCanceledCourseForHoliday = $paidCourseListRepository->findNumberCanceledCourseForHolidayAfterScheduleChangeWithQuery($subscriptionOrder)->getQuery()->getArrayResult();;
$nbCanceledCoursesForHoliday = sizeof($arrayCanceledCourseForHoliday);
$schedules = $request->get('newSchedule');
foreach ($schedules as $oldScheduleId => $newScheduleId) {
if ($newScheduleId) {
$oldSchedule = $teacherScheduleRepository->findOneBy(['id' => $oldScheduleId]);
$remainCourses = $paidCourseListRepository->findAllRemainCourseAfterScheduleChange($subscriptionOrder, $oldSchedule);
if ($remainCourses == null) {
$this->addFlash(
'error',
'Il ne vous reste plus de nouveaux cours à prendre pour pouvoir changer de professeur. Une fois vos nouveaux cours ajoutés (quand une nouvelle mensualité sera débitée) vous pourrez revenir sur cette page et changer de professeur.'
);
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
} else {
$this->addFlash('error', 'Merci de choisir un nouveau planning pour remplacer TOUS vos anciens plannings');
return $this->redirectToRoute(
'subscription_change_teacher',
[
'id' => $subscriptionOrder->getId(),
'teacher' => $teacher->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
foreach ($schedules as $oldScheduleId => $newScheduleId) {
if ($newScheduleId) {
$oldSchedule = $teacherScheduleRepository->findOneBy(['id' => $oldScheduleId]);
$newSchedule = $teacherScheduleRepository->findOneBy(['id' => $newScheduleId]);
//Récupérer tout les cours qui ne seront pas fait :
$remainCourses = $paidCourseListRepository->findAllRemainCourseAfterScheduleChange($subscriptionOrder, $oldSchedule);
//permettre le changement de planning uniquement s'il reste des cours à prendre
if ($remainCourses != null) {
//Récupérer le prochain cours qui aurait du avoir lieu pour en faire la date de libération du oldPlanning (freeDate)
$nextCourse = $paidCourseListRepository->findNextCourseAfterScheduleChange($oldSchedule);
$nextCourseDate = DateTimeImmutable::createFromMutable($nextCourse->getCourseDate());
//Je récupère la date de paiement de ce cours pour le réutiliser pour la nouveau planning, certain abo n'ont pas de paiement date car ce sont des ajout manuel, donc je code en défensive
if ($nextCourse->getPaymentDate() != null) {
$paymentDate = $nextCourse->getPaymentDate();
} else {
$paymentDate = null;
}
//Je récupère le montant du cours pour le réutiliser pour les nouveaux cours de la liste
$priceCourse = $nextCourse->getPrice();
//Libérer l'ancien planning immédiatement
$oldSchedule->setFreeDate($nextCourseDate)
->setIsFree(true)
->setSubscriptionOrder(null)
->setOccupiedUntil(null);
$em->persist($oldSchedule);
//rendre le nouveau planning indisponible si l'abo n'est pas canceled
if ($subscriptionOrder->getIsCancelled() == true) {
$newSchedule->setIsFree(true);
} elseif ($subscriptionOrder->getIsCancelled() == false) {
$newSchedule->setIsFree(false);
} else {
$newSchedule->setIsFree(false);
}
$em->persist($newSchedule);
//ajouter le nouveau planning à l'abonnement
$subscriptionOrder->addSchedule($newSchedule)
->removeSchedule($oldSchedule);
$em->persist($subscriptionOrder);
//je récupère la date à laquelle le nouveau planning était marqué comme libre, ce sera la date du 1er cours de cette liste
$startNewCourse = DateTimeImmutable::createFromMutable($newSchedule->getFreeDate());
$newFreeDateForNewSchedule = DateTimeImmutable::createFromMutable($newSchedule->getFreeDate());
$nbOfCoursesToAdd = sizeof($remainCourses);
//ajouter les nouveaux cours à la table "PaidCoursesList", j'ajoute le même nombre qui est contenu dans le tableau des cours restant à l'abonnement (remainCourses)
for ($i = 0; $i < $nbOfCoursesToAdd; $i++) {
$newCourseDate = $startNewCourse->modify('+'.$i.'weeks');
$newPaidCourse = $courseHelper->createNewCourse($newCourseDate, $newSchedule, $priceCourse);
foreach ($holidays as $holiday) {
if ($newPaidCourse->getCourseDate() > $holiday->getStartAt() and $newPaidCourse->getCourseDate() < $holiday->getEndAt(
) and $newPaidCourse->getIsCanceledForHoliday() === null) {
$newPaidCourse->setIsCanceledForHoliday(true);
$em->persist($newPaidCourse);
}
}
if ($newPaidCourse->getIsCanceledForHoliday() != true) {
$newPaidCourse->setIsCanceledForHoliday(false);
$em->persist($newPaidCourse);
}
$newPaidCourse
->setSubscriptionOrder($subscriptionOrder)
->setIsForGroup(false)
->setSessionGroup(null)
->setPaymentDate($paymentDate);
if ($i == $nbOfCoursesToAdd - 1) {
$nbOfWeekForFreeDate = $nbOfCoursesToAdd + 1;
$newSchedule->setFreeDate($newFreeDateForNewSchedule->modify('+'.$nbOfWeekForFreeDate.'weeks'));
}
$em->persist($newPaidCourse);
$newSchedule->addCourseList($newPaidCourse);
$subscriptionOrder->addCoursesList($newPaidCourse);
$em->persist($newSchedule);
$em->persist($subscriptionOrder);
}
//j'efface les anciens cours du oldPlanning de la table PaidCoursesList
foreach ($remainCourses as $course) {
$em->remove($course);
}
} else {
$this->addFlash(
'error',
'Il ne vous reste plus de nouveaux cours à prendre pour pouvoir changer de professeur. Une fois vos nouveaux cours ajoutés (quand une nouvelle mensualité sera débitée) vous pourrez revenir sur cette page et changer de professeur.'
);
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
} else {
$this->addFlash('error', 'Merci de choisir un nouveau planning pour remplacer TOUS vos anciens plannings');
return $this->redirectToRoute(
'subscription_change_teacher',
[
'id' => $subscriptionOrder->getId(),
'teacher' => $teacher->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
$subscriptionOrder->setUpdateAt(new \DateTimeImmutable())
->setTeacher($teacher);
$em->persist($subscriptionOrder);
$em->flush();
//Je compte le nb de cours annulé pour les vacances APRES le changement de planning
$newArrayCanceledCourseForHoliday = $paidCourseListRepository->findNumberCanceledCourseForHolidayAfterScheduleChangeWithQuery($subscriptionOrder)->getQuery()->getArrayResult();;
$newNbCanceledCoursesForHoliday = sizeof($newArrayCanceledCourseForHoliday);
if ($nbCanceledCoursesForHoliday != $newNbCanceledCoursesForHoliday) {
$slackClient->notifyAdminNbCanceledCoursesForHolidayDoNotMatchAfterScheduleChange($subscriptionOrder, $nbCanceledCoursesForHoliday, $newNbCanceledCoursesForHoliday);
}
$subscriptionHelper->setLastCourse($subscriptionOrder);
$newTeacherEmail = $teacher->getUserId()->getEmail();
$emailNotification->notifyStudentTeacherChange($subscriptionOrder, $oldTeacher);
$slackClient->newSubscriptionNotifyTeacher($subscriptionOrder);
$slackClient->notifyTeacherStudentChangeTeacher($subscriptionOrder, $oldTeacher);
//$slackClient->notifyAdminStudentChangeTeacher($subscriptionOrder, $oldTeacher);
$emailNotification->registrationSubscriptionNotifyTeacher($subscriptionOrder, $newTeacherEmail);
$this->addFlash('success', 'Professeur modifié avec succes !');
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
return $this->render(
'profil/change-teacher.html.twig',
[
'subscription' => $subscriptionOrder,
'freeSchedules' => $freeSchedules,
'teacher' => $teacher,
]
);
}
//TODO refacto pour code dupliquer à retravailler (spécialement avec la précédente méthode)
/**
* @Route("/{id}/schedule/edit", name="subscription_schedule_edit", methods={"POST"})
* @param SubscriptionOrder $subscriptionOrder
* @param Request $request
* @param PaidCourseListRepository $paidCourseListRepository
* @param TeacherScheduleRepository $teacherScheduleRepository
* @param EntityManagerInterface $em
* @param EmailNotification $emailNotification
* @param SlackClient $slackClient
* @param HolidayRepository $holidayRepository
* @param SubscriptionHelper $subscriptionHelper
* @param CourseHelper $courseHelper
*
* @return RedirectResponse
*/
public function changeSubscriptionSchedule(SubscriptionOrder $subscriptionOrder, Request $request, PaidCourseListRepository $paidCourseListRepository,
TeacherScheduleRepository $teacherScheduleRepository, EntityManagerInterface $em, EmailNotification $emailNotification,
SlackClient $slackClient, HolidayRepository $holidayRepository, SubscriptionHelper $subscriptionHelper,
CourseHelper $courseHelper
): RedirectResponse {
if ($request->isMethod('POST')) {
$roles = $this->getUser()->getRoles();
if ($subscriptionHelper->hasCourseToday($subscriptionOrder) and ! in_array('ROLE_FR', $roles)) {
$this->addFlash('error', "Vous avez cours aujourd'hui, vous ne pouvez donc pas changer de planning. Merci de modifier votre planning un jour où vous n'avez pas cours");
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
//Je compte le nb de cours annulé pour les vacances avant le changement de planning
$arrayCanceledCourseForHoliday = $paidCourseListRepository->findNumberCanceledCourseForHolidayAfterScheduleChangeWithQuery($subscriptionOrder)->getQuery()->getArrayResult();;
$nbCanceledCoursesForHoliday = sizeof($arrayCanceledCourseForHoliday);
$holidays = $holidayRepository->findAll();
$schedules = $request->get('newSchedule');
$oldSchedules = [];
foreach ($schedules as $oldScheduleId => $newScheduleId) {
if ($newScheduleId) {
$oldSchedule = $teacherScheduleRepository->findOneBy(['id' => $oldScheduleId]);
$newSchedule = $teacherScheduleRepository->findOneBy(['id' => $newScheduleId]);
//Récupérer tout les cours qui ne seront pas fait :
$remainCourses = $paidCourseListRepository->findAllRemainCourseAfterScheduleChange($subscriptionOrder, $oldSchedule);
//permettre le changement de planning uniquement s'il reste des cours à prendre
if ($remainCourses != null) {
//Récupérer le prochain cours qui aurait du avoir lieu pour en faire la date de libération du oldPlanning (freeDate)
$nextCourse = $paidCourseListRepository->findNextCourseAfterScheduleChange($oldSchedule);
$nextCourseDate = DateTimeImmutable::createFromMutable($nextCourse->getCourseDate());
//Je récupère la date de paiement de ce cours pour le réutiliser pour la nouveau planning, certain abo n'ont pas de paiement date car ce sont des ajout manuel, donc je code en défensive
if ($nextCourse->getPaymentDate() != null) {
$paymentDate = $nextCourse->getPaymentDate();
} else {
$paymentDate = null;
}
//Je récupère le montant du cours pour le réutiliser pour les nouveaux cours de la liste
$priceCourse = $nextCourse->getPrice();
//Je récup les anciens plannings dans un tableau en dehors de la boucle pour pouvoir les envoyer par mail à l'élève.
$oldSchedules[] = $oldSchedule;
//Libérer l'ancien planning immédiatement
$oldSchedule->setFreeDate($nextCourseDate)
->setIsFree(true)
->setSubscriptionOrder(null)
->setOccupiedUntil(null);
$em->persist($oldSchedule);
//rendre le nouveau planning indisponible si l'abo n'est pas canceled
if ($subscriptionOrder->getIsCancelled() == true) {
$newSchedule->setIsFree(true);
} elseif ($subscriptionOrder->getIsCancelled() == false) {
$newSchedule->setIsFree(false);
} else {
$newSchedule->setIsFree(false);
}
$em->persist($newSchedule);
//ajouter le nouveau planning à l'abonnement
$subscriptionOrder->addSchedule($newSchedule)
->removeSchedule($oldSchedule);
$em->persist($subscriptionOrder);
//je récupère la date à laquelle le nouveau planning était marqué comme libre, ce sera la date du 1er cours de cette liste
$startNewCourse = DateTimeImmutable::createFromMutable($newSchedule->getFreeDate());
$newFreeDateForNewSchedule = DateTimeImmutable::createFromMutable($newSchedule->getFreeDate());
$nbOfCoursesToAdd = sizeof($remainCourses);
//ajouter les nouveaux cours à la table "PaidCoursesList", j'ajoute le même nombre qui est contenu dans le tableau des cours restant à l'abonnement (remainCourses)
for ($i = 0; $i < $nbOfCoursesToAdd; $i++) {
$newCourseDate = $startNewCourse->modify('+'.$i.'weeks');
$newPaidCourse = $courseHelper->createNewCourse($newCourseDate, $newSchedule, $priceCourse);
foreach ($holidays as $holiday) {
if ($newPaidCourse->getCourseDate() > $holiday->getStartAt() and $newPaidCourse->getCourseDate() < $holiday->getEndAt(
) and $newPaidCourse->getIsCanceledForHoliday() === null) {
$newPaidCourse->setIsCanceledForHoliday(true);
$em->persist($newPaidCourse);
}
}
if ($newPaidCourse->getIsCanceledForHoliday() != true) {
$newPaidCourse->setIsCanceledForHoliday(false);
$em->persist($newPaidCourse);
}
$newPaidCourse
->setSubscriptionOrder($subscriptionOrder)
->setIsForGroup(false)
->setSessionGroup(null)
->setPaymentDate($paymentDate);
if ($i == $nbOfCoursesToAdd - 1) {
$nbOfWeekForFreeDate = $nbOfCoursesToAdd + 1;
$newSchedule->setFreeDate($newFreeDateForNewSchedule->modify('+'.$nbOfWeekForFreeDate.'weeks'));
}
$em->persist($newPaidCourse);
$newSchedule->addCourseList($newPaidCourse);
$subscriptionOrder->addCoursesList($newPaidCourse);
$em->persist($newSchedule);
$em->persist($subscriptionOrder);
}
//j'efface les anciens cours du oldPlanning de la table PaidCoursesList
foreach ($remainCourses as $course) {
$em->remove($course);
}
} else {
$this->addFlash('error', 'Il ne vous reste plus de nouveaux cours à prendre pour pouvoir changer de planning.');
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
}
$subscriptionOrder->setUpdateAt(new \DateTimeImmutable());
$em->persist($subscriptionOrder);
$em->flush();
//Je compte le nb de cours annulé pour les vacances APRES le changement de planning
$newArrayCanceledCourseForHoliday = $paidCourseListRepository->findNumberCanceledCourseForHolidayAfterScheduleChangeWithQuery($subscriptionOrder)->getQuery()->getArrayResult();;
$newNbCanceledCoursesForHoliday = sizeof($newArrayCanceledCourseForHoliday);
if ($nbCanceledCoursesForHoliday != $newNbCanceledCoursesForHoliday) {
$slackClient->notifyAdminNbCanceledCoursesForHolidayDoNotMatchAfterScheduleChange($subscriptionOrder, $nbCanceledCoursesForHoliday, $newNbCanceledCoursesForHoliday);
}
$subscriptionHelper->setLastCourse($subscriptionOrder);
$emailNotification->notifyStudentSubscriptionSchedulesChange($subscriptionOrder, $oldSchedules);
$emailNotification->notifyTeacherSubscriptionScheduleChange($subscriptionOrder, $oldSchedules);
$slackClient->notifyTeacherChangeScheduleSubscription($subscriptionOrder);
$this->addFlash('success', 'Planning modifié avec succes !');
return $this->redirectToRoute(
'user_subscription_show',
[
'id' => $subscriptionOrder->getId(),
'_locale' => $request->getLocale(),
]
);
}
}
}