src/Service/ProfileService.php line 44

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Constant\Common;
  4. use App\Entity\Notification;
  5. use App\Entity\Role;
  6. use App\Entity\Status;
  7. use App\Entity\Profile;
  8. use App\Entity\ProfileNote;
  9. use App\Entity\Campaign;
  10. use App\Repository\ProfileRepository;
  11. use App\Exception\BadRequestException;
  12. use App\Misc\ArrayHelper;
  13. use Symfony\Component\Security\Http\SecurityEvents;
  14. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  15. use Symfony\Contracts\Translation\TranslatorInterface;
  16. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  17. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  18. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  19. use Symfony\Contracts\HttpClient\HttpClientInterface;
  20. /**
  21.  * Class ProfileService
  22.  * @package App\Service
  23.  */
  24. class ProfileService extends BaseService
  25. {
  26.     /**
  27.      * ProfileService constructor.
  28.      * @param ProfileRepository $repository
  29.      */
  30.     public function __construct(
  31.         ProfileRepository $repository,
  32.         BaseService $baseService,
  33.         SessionInterface $session,
  34.         TranslatorInterface $translator,
  35.         EventDispatcherInterface $dispatcher,
  36.         HttpClientInterface $httpClient
  37.     ) {
  38.         $this->reflectFromParent($baseService);
  39.         $this->repository = $repository;
  40.         $this->session = $session;
  41.         $this->translator = $translator;
  42.         $this->dispatcher = $dispatcher;
  43.         $this->httpClient = $httpClient;
  44.     }
  45.     public function getById($id)
  46.     {
  47.         return $this->repository->getOneBy(
  48.             [
  49.                 'filter_id' => $id
  50.             ]
  51.         );
  52.     }
  53.     public function getProfileByUserId($userId)
  54.     {
  55.         return $this->repository->getProfileByUserId($userId);
  56.     }
  57.     public function addProfile($request, $DTO = null)
  58.     {
  59.         $user = $this->userService->addUser(array_merge(
  60.             $request->get("user"),
  61.             [
  62.                 'password' => $this->container->getParameter('default_user_password'),
  63.                 'subRoles' => [Role::ROLE_USER]
  64.             ]
  65.         ), 'ENTITY');
  66.         if($user && $DTO){
  67.             $this->userService->updateProfileUser($request, $user);
  68.         }
  69.         $request->request->set('user', $user->getId());
  70.         if ($this->session->get('trackingCode')) {
  71.             $mediaChannel = $this->MediaChannelRepo->findOneBy(
  72.                 [
  73.                     'name' => $this->session->get('trackingCode')
  74.                 ]
  75.             );
  76.             if ($mediaChannel) {
  77.                 $input['mediaChannel'] = $mediaChannel;
  78.             }
  79.         }
  80.         // Add Profile
  81.         if($request->get('programs') && is_array($request->get('programs'))){
  82.             $input['selectedProgram'] =  $request->get('programs')[0];
  83.         }
  84.         if($request->get('campus1')){
  85.             $request->request->set('campus', $request->get('campus1'));
  86.             $randCommercial = $this->getRandomComercialOfcampus($request->get('campus1'));
  87.             if($randCommercial){
  88.                 $request->request->set('commercial', $randCommercial);
  89.             }
  90.         }
  91.         $input['status'] = Status::STATUS_NEED_CONTACT;
  92.         $profile = $this->add($request, $input, $DTO, 'ENTITY', false, [], true);
  93.         if ($profile->getCampaign()) {
  94.             if ($profile->getCampaign()->getId() == Campaign::APPLICATION) {
  95.                 $this->userService->sendWelcomeEmail($profile);
  96.             }else if($profile->getCampaign()->getId() == Campaign::DOCUMENT){
  97.                 $this->userService->sendDocumentEmail($profile);
  98.             }
  99.         }
  100.         // set profile sources
  101.         if ($request->get('openDay')) {
  102.             $openDay = $this->openDayRepo->findOneBy(['id' => $request->get('openDay')]);
  103.             if($openDay) {
  104.                 $this->profileSourceService->checkandAddProfileSource($profile, $openDay->getName());
  105.             }
  106.         }else if($request->get('landingpage')) {
  107.             $landingpage = $this->landingpageRepo->findOneBy(['id' => $request->get('landingpage')]);
  108.             if($landingpage) {
  109.                 if($landingpage->isIsAgent()){
  110.                     $this->profileSourceService->checkandAddProfileSource($profile, 'LPA: ' .$landingpage->getName());
  111.                 }else{
  112.                     $this->profileSourceService->checkandAddProfileSource($profile, 'LP: ' .$landingpage->getName());
  113.                 }
  114.             }
  115.         }else if($request->get('campaign')) {
  116.             $campaign = $this->campaignRepo->findOneBy(['id' => $request->get('campaign')]);
  117.             if($campaign) {
  118.                 $this->profileSourceService->checkandAddProfileSource($profile, $campaign->getName());
  119.             }
  120.         }
  121.         // clear tracking code
  122.         $this->session->remove('trackingCode');
  123.         $token = new UsernamePasswordToken($user, null, 'main', $user->getSubRoleNames());
  124.         $this->tokenStorage->setToken($token);
  125.         if(!$DTO){
  126.             $event = new SecurityEvents($request);
  127.             $this->dispatcher->dispatch($event, SecurityEvents::INTERACTIVE_LOGIN);
  128.         }
  129.         return $profile;
  130.     }
  131.     public function updateProfile($request, $DTO = 'App\DTO\Profile\UpdateProfileInput', $step4 = null )
  132.     {
  133.         if($this->getUser()){
  134.             $profile = $this->getUser()->getProfiles()[0];
  135.         }elseif( $request->get('profileId')){
  136.             $profile = $this->get($request->get('profileId'));
  137.         } else {
  138.             throw new NotFoundHttpException($this->translator->trans('profile_not_found'));
  139.         }
  140.         if(!$profile) throw new NotFoundHttpException($this->translator->trans('profile_not_found'));   
  141.         if($step4 && $profile->getStatus()->getId() < Status::STATUS_APPLICATION_RECEIVED){
  142.             $request->request->set('status', Status::STATUS_APPLICATION_RECEIVED);
  143.             if(!$request->get('isSent')){
  144.                 // 0, not 1: step4 is submitted but the campus email is still pending;
  145.                 // sendPendingCampusEmails() (via the app:send-campus-email cron) flips this to 1 once actually sent.
  146.                 $request->request->set('isSent', 0);
  147.                 //set profile sources
  148.                 $campaign = $this->campaignService->get(Campaign::APPLICATION);
  149.                 if($campaign) {
  150.                     $this->profileSourceService->checkandAddProfileSource($profile, $campaign->getName());
  151.                 }
  152.             }
  153.         }
  154.         // set profile sources
  155.         if ($request->get('openDay')) {
  156.             $openDay = $this->openDayRepo->findOneBy(['id' => $request->get('openDay')]);
  157.             if($openDay) {
  158.                 $this->profileSourceService->checkandAddProfileSource($profile, $openDay->getName());
  159.             }
  160.         }else if($request->get('landingpage')) {
  161.             $landingpage = $this->landingpageRepo->findOneBy(['id' => $request->get('landingpage')]);
  162.             if($landingpage) {
  163.                 if($landingpage->isIsAgent()){
  164.                     $this->profileSourceService->checkandAddProfileSource($profile, 'LPA: ' .$landingpage->getName());
  165.                 }else{
  166.                     $this->profileSourceService->checkandAddProfileSource($profile, 'LP: ' .$landingpage->getName());
  167.                 }
  168.             }
  169.         }else if($request->get('campaign')) {
  170.             $campaign = $this->campaignRepo->findOneBy(['id' => $request->get('campaign')]);
  171.             if($campaign) {
  172.                 $this->profileSourceService->checkandAddProfileSource($profile, $campaign->getName());
  173.             }
  174.         }
  175.         if($request->get('campus1') && $request->get('campus1') != $profile->getCampus1()->getId()){
  176.             $request->request->set('campus', $request->get('campus1'));
  177.             $randCommercial = $this->getRandomComercialOfcampus($request->get('campus1'));
  178.             if($randCommercial){
  179.                 $request->request->set('commercial', $randCommercial);
  180.             }
  181.         }
  182.         if($request->get('programs')){
  183.             $request->request->set('selectedProgram', $request->get('programs')[0]);
  184.         }
  185.         if($profile->isIsSent() && $request->get('campus1') != $profile->getCampus1()->getId()){
  186.             //send email change campus
  187.             if(isset(Common::listEmailAdmission()[$request->get('campus1')])){
  188.                 $this->userService->sendCampusEmail($profile, Common::listEmailAdmission()[$request->get('campus1')]);
  189.             }
  190.         }
  191.         return $this->update($profile, $request, null, $DTO, 'ENTITY', false, true);
  192.     }
  193.     public function updateSelectedProgram($request, $DTO = 'App\DTO\Profile\AdminUpdateProfileSelectedProgramInput')
  194.     {
  195.         $profile = $this->get($request->get('id'));
  196.         return $this->update($profile, $request, null, $DTO, 'App\DTO\Profile\ProfileOutput', false, true);
  197.     }
  198.     public function handleSendMail($statusOld, $profile)
  199.     {
  200.         // Send Mail if status update
  201.         if (
  202.             $statusOld != ($profile->status)['id']
  203.             && ($profile->status)['id'] >= Status::STATUS_APPLICATION_RECEIVED
  204.             && !$profile->isAgent
  205.         ) {
  206.             $this->userService->sendNotificationEmailUpdateStatus($profile);
  207.         }
  208.     }
  209.     public function updateProfileAdmin($request)
  210.     {
  211.         $profile = $this->get($request->get('id'));
  212.         if (!$profile) throw new NotFoundHttpException($this->translator->trans('profile_not_found'));
  213.         $statusOld = $profile->getStatus()->getId();
  214.         $input = [];
  215.         if ($request->get('jury')) {
  216.             $input['juryDate'] = new \DateTime('now');
  217.         }
  218.         if ($request->get('oraux')) {
  219.             $input['orauxDate'] = new \DateTime('now');
  220.         }
  221.         if($request->get('status') == Status::STATUS_JURY_ACCEPTED){
  222.             if($profile->getSelectedProgram()->getSpecialityId() && !$profile->getQcmToken()){
  223.                 $user = $profile->getUser();
  224.                 $now = new \DateTime('now');
  225.                 $data = [
  226.                     'civility' => $user->getGender() == 1 ? 'mrs' : 'mr' ,
  227.                     'firstName' => $user->getFirstName(),
  228.                     'lastName' => $user->getLastName(),
  229.                     'email' => $user->getEmail(),
  230.                     'birthDate' => $user->getBirthDay() ? $user->getBirthDay()->format('Y-m-d') : $now->format('Y-m-d'),
  231.                     'phone' => $user->getPhone(),
  232.                     'speciality' => $profile->getSelectedProgram()->getSpecialityId()
  233.                 ];
  234.                 $responseQcm = $this->callQcmApi($data, '/auth/external/register', 'POST');
  235.                 if($responseQcm['success'] == true && $responseQcm['data']){
  236.                     $profile->setQcmToken($responseQcm['data']['password']);
  237.                     $dataQcmResults = [
  238.                         'isDoneTest' => $responseQcm['data']['isDoneTest'],
  239.                         'questions' => $responseQcm['data']['questions']
  240.                     ];
  241.                     $profile->setQcmResults($dataQcmResults);
  242.                 }
  243.             }elseif ($profile->getSelectedProgram()->getSpecialityId() && $profile->getQcmToken()){
  244.                 $data = [
  245.                     'email' => $profile->getUser()->getEmail(),
  246.                     'password' => $profile->getQcmToken(),
  247.                     'speciality' => $profile->getSelectedProgram()->getSpecialityId()
  248.                 ];
  249.                 $responseQcm = $this->callQcmApi($data, '/auth/external/user/update-speciality', 'PATCH');  
  250.                 $dataQcmResults = [
  251.                     'isDoneTest' => $responseQcm['data']['isDoneTest'],
  252.                     'questions' => $responseQcm['data']['questions']
  253.                 ];
  254.                 $profile->setQcmResults($dataQcmResults);
  255.             }
  256.         }
  257.         if($request->get('status') == Status::STATUS_INTERVIEW_INVITED && $profile->getQcmMethod() == Profile::QCM_LOCAL){
  258.             if($profile->getOraux()){
  259.                 $dateStartQCM = $profile->getOraux()->getDate()->format('Y-m-d');
  260.                 $timeStartQCM = $profile->getOraux()->getHour() ? $profile->getOraux()->getHour()->format(' H:i:s') : '';
  261.             }
  262.             if(!isset($timeStartQCM)){
  263.                 $orauxSelected = $this->orauxService->get($request->get('oraux'));
  264.                 $dateStartQCM = $orauxSelected->getDate()->format('Y-m-d');
  265.                 $timeStartQCM = $orauxSelected->getHour() ? $orauxSelected->getHour()->format(' H:i:s') : '';
  266.             }
  267.             $data = [
  268.                 'email' => $profile->getUser()->getEmail(),
  269.                 'password' => $profile->getQcmToken(),
  270.                 'startTestAt' => (new \DateTime($dateStartQCM.$timeStartQCM, new \DateTimeZone($this->container->getParameter('fallback_timezone'))))->format(DATE_ATOM)
  271.             ];
  272.             $this->callQcmApi($data, '/auth/external/user/update-start-test', 'PATCH');
  273.         }
  274.         if( $request->get('status') == Status::STATUS_STUDENT_ENROLLED ) {
  275.             $profile->setEnrolledDate(new \DateTime('now'));
  276.         }
  277.         // Check campus selected in list campus of commercial
  278.         // if ($inputCampus = $request->get('campus')) {
  279.         //     if ($commercial = $profile->getCommercial()) {
  280.         //         $campuses = [];
  281.         //         foreach ($commercial->getCampuses() as $campus) {
  282.         //             $campuses[] = $campus->getId();
  283.         //         }
  284.         //         if (!in_array($inputCampus, $campuses)) {
  285.         //             $input['commercial'] = 'isNull';
  286.         //         }
  287.         //     }
  288.         // }
  289.         $profile = $this->update(
  290.             $profile,
  291.             $request,
  292.             $input,
  293.             'App\DTO\Profile\AdminUpdateProfileInput',
  294.             'App\DTO\Profile\ProfileOutput',
  295.             false,
  296.             true
  297.         );
  298.         $this->handleSendMail($statusOld, $profile);
  299.         if($request->get('campus') && $request->get('campus') != $profile->campus1['id']){
  300.             if(isset(Common::listEmailAdmission()[$request->get('campus')])){
  301.                 $this->userService->sendCampusEmail($profile, Common::listEmailAdmission()[$request->get('campus')]);
  302.             }
  303.         }
  304.         return $profile;
  305.     }
  306.     public function updateProgramsAdmin($request)
  307.     {
  308.         $profile = $this->get($request->get('id'));
  309.         if (!$profile) throw new NotFoundHttpException($this->translator->trans('profile_not_found'));
  310.         $statusOld = $profile->getStatus()->getId();
  311.         $profile = $this->update(
  312.             $profile,
  313.             $request,
  314.             null,
  315.             'App\DTO\Profile\AdminUpdateProgramsProfileInput',
  316.             'App\DTO\Profile\ProfileOutput',
  317.             false,
  318.             true
  319.         );
  320.         $this->handleSendMail($statusOld, $profile);
  321.         return $profile;
  322.     }
  323.     public function duplicateProfile($request){
  324.         $profile = $this->repository->find($request->get('id'));
  325.         $programSelected = $this->programRepo->find($request->get('programId'));
  326.         $campusSelected = $this->campusRepo->find($request->get('campusId'));
  327.         $cloneCV                    = $profile->getFileCv() ? clone $profile->getFileCv() : null;
  328.         $cloneFileContract          = $profile->getFileContract() ? clone $profile->getFileContract() : null;
  329.         $cloneLetter                = $profile->getFileLetter() ? clone $profile->getFileLetter() : null;
  330.         $cloneFileReportCard1       = $profile->getFileReportCard1() ? clone $profile->getFileReportCard1() : null;
  331.         $cloneFileReportCard2       = $profile->getFileReportCard2() ? clone $profile->getFileReportCard2() : null;
  332.         $cloneFileReportCard3       = $profile->getFileReportCard3() ? clone $profile->getFileReportCard3() : null;
  333.         $cloneFileIdentity          = $profile->getFileIdentity() ? clone $profile->getFileIdentity() : null;
  334.         $cloneFileResidencePermit   = $profile->getFileResidencePermit() ? clone $profile->getFileResidencePermit() : null;
  335.         $cloneFilePhoto             = $profile->getFilePhoto() ? clone $profile->getFilePhoto() : null;
  336.         $cloneFileHandicap          = $profile->getFileHandicap() ? clone $profile->getFileHandicap() : null;
  337.         $profileDuplicate = clone $profile;
  338.         $profileDuplicate->setFileCv($cloneCV);
  339.         $profileDuplicate->setFileContract($cloneFileContract);
  340.         $profileDuplicate->setFileLetter($cloneLetter);
  341.         $profileDuplicate->setFileReportCard1($cloneFileReportCard1);
  342.         $profileDuplicate->setFileReportCard2($cloneFileReportCard2);
  343.         $profileDuplicate->setFileReportCard3($cloneFileReportCard3);
  344.         $profileDuplicate->setFileIdentity($cloneFileIdentity);
  345.         $profileDuplicate->setFileResidencePermit($cloneFileResidencePermit);
  346.         $profileDuplicate->setFilePhoto($cloneFilePhoto);
  347.         $profileDuplicate->setFileHandicap($cloneFileHandicap);
  348.         $profileDuplicate->setSelectedProgram($programSelected);
  349.         $profileDuplicate->addProgram($programSelected);
  350.         $profileDuplicate->setCampus($campusSelected);
  351.         $profileDuplicate->setCampus1($campusSelected);
  352.         $profileDuplicate->setCampus2(null);
  353.         $profileDuplicate->setCampus3(null);
  354.         $year = date("Y");
  355.         if(date("Y-m-d") > date("Y").'-10-01'){
  356.             $session = date('Y', strtotime('+1 year')).'-'. date('Y', strtotime('+2 year'));
  357.         }else{
  358.             $session = $year.'-'. date('Y', strtotime('+1 year'));
  359.         }
  360.         $profileDuplicate->setYear($session);
  361.         if($profile->getProfileNotes()){
  362.             foreach($profile->getProfileNotes() as $note){
  363.                 $profileDuplicate->addProfileNote(clone $note);
  364.             }
  365.         }
  366.         if($profile->getProfileFiles()){
  367.             foreach($profile->getProfileFiles() as $file){
  368.                 $profileDuplicate->addProfileFile(clone $file);
  369.             }
  370.         }
  371.         $profileDuplicate->setIsDuplicate(1);
  372.         $this->repository->save($profileDuplicate);
  373.         return $this->autoMapper->map($profileDuplicate, 'App\DTO\Profile\ProfileOutput');
  374.     }
  375.     public function updateProfileNotesAdmin($request)
  376.     {
  377.         $profile = $this->get($request->get('id'));
  378.         if (!$profile) throw new NotFoundHttpException($this->translator->trans('profile_not_found'));
  379.         $statusOld = $profile->getStatus()->getId();
  380.         $profile = $this->update(
  381.             $profile,
  382.             $request,
  383.             null,
  384.             'App\DTO\Profile\AdminUpdateProfileNotesProfileInput',
  385.             'App\DTO\Profile\ProfileOutput',
  386.             false,
  387.             true
  388.         );
  389.         $this->handleSendMail($statusOld, $profile);
  390.         return $profile;
  391.     }
  392.     public function checkProfileExpired(){
  393.         $profiles = $this->repository->findAll();
  394.         foreach($profiles as $profile){
  395.             if(!$profile->getExpireIdentity() && !$profile->getExpireResidencePermit()) continue;
  396.             if($profile->getExpireIdentity()){
  397.                 $expireIdentity = null;
  398.                 if($profile->getExpireIdentity()->format('Y-m-d') == date('Y-m-d',strtotime('+60 days'))){
  399.                     $expireIdentity = Notification::EXPRIRE_TYPE_TWO_MONTH;
  400.                 } elseif($profile->getExpireIdentity()->format('Y-m-d') == date('Y-m-d',strtotime('+30 days'))){
  401.                     $expireIdentity = Notification::EXPRIRE_TYPE_ONE_MONTH;
  402.                 } elseif($profile->getExpireIdentity()->format('Y-m-d') == date('Y-m-d',strtotime('+21 days'))){
  403.                     $expireIdentity = Notification::EXPRIRE_TYPE_THREE_WEEK;
  404.                 } elseif($profile->getExpireIdentity()->format('Y-m-d') == date('Y-m-d',strtotime('+14 days'))){
  405.                     $expireIdentity = Notification::EXPRIRE_TYPE_TWO_WEEK;
  406.                 } elseif($profile->getExpireIdentity()->format('Y-m-d') == date('Y-m-d',strtotime('+7 days'))){
  407.                     $expireIdentity = Notification::EXPRIRE_TYPE_ONE_WEEK;
  408.                 }
  409.                 if($expireIdentity){
  410.                     $notification = $this->notificationRepo->findOneBy(['profile' => $profile, 'type' => Notification::TYPE_IDENTITY]);
  411.                     if(!$notification){
  412.                         $notification = new Notification;
  413.                         $notification->setProfile($profile);
  414.                     }
  415.                     
  416.                     $notification->setType(Notification::TYPE_IDENTITY);
  417.                     $notification->setExpireType($expireIdentity);
  418.                     $notification->setIsSeen(null);
  419.                     $this->notificationService->repository->save($notification);
  420.                 }
  421.             }
  422.             if($profile->getExpireResidencePermit()){
  423.                 $expireResidencePermit = null;
  424.                 if($profile->getExpireResidencePermit()->format('Y-m-d') == date('Y-m-d',strtotime('+60 days'))){
  425.                     $expireResidencePermit = Notification::EXPRIRE_TYPE_TWO_MONTH;
  426.                 } elseif($profile->getExpireResidencePermit()->format('Y-m-d') == date('Y-m-d',strtotime('+30 days'))){
  427.                     $expireResidencePermit = Notification::EXPRIRE_TYPE_ONE_MONTH;
  428.                 } elseif($profile->getExpireResidencePermit()->format('Y-m-d') == date('Y-m-d',strtotime('+21 days'))){
  429.                     $expireResidencePermit = Notification::EXPRIRE_TYPE_THREE_WEEK;
  430.                 } elseif($profile->getExpireResidencePermit()->format('Y-m-d') == date('Y-m-d',strtotime('+14 days'))){
  431.                     $expireResidencePermit = Notification::EXPRIRE_TYPE_TWO_WEEK;
  432.                 } elseif($profile->getExpireResidencePermit()->format('Y-m-d') == date('Y-m-d',strtotime('+7 days'))){
  433.                     $expireResidencePermit = Notification::EXPRIRE_TYPE_ONE_WEEK;
  434.                 }
  435.                 if($expireResidencePermit){
  436.                     $notification = $this->notificationRepo->findOneBy(['profile' => $profile, 'type' => Notification::TYPE_RESIDENCE_PERMIT]);
  437.                     if(!$notification){
  438.                         $notification = new Notification;
  439.                         $notification->setProfile($profile);
  440.                     }
  441.                     
  442.                     $notification->setType(Notification::TYPE_RESIDENCE_PERMIT);
  443.                     $notification->setExpireType($expireResidencePermit);
  444.                     $notification->setIsSeen(null);
  445.                     $this->notificationService->repository->save($notification);
  446.                 }
  447.             }
  448.         }
  449.     }
  450.     public function checkRegister(){
  451.         $profiles = $this->repository->findAll();
  452.         foreach($profiles as $profile){
  453.             if($profile->getPercent() > 25 ) continue;
  454.             $day = null;
  455.             if($profile->getCreatedDate()->format('Y-m-d') == date('Y-m-d',strtotime('-1 days'))){
  456.                 $day = 1;
  457.             } elseif($profile->getCreatedDate()->format('Y-m-d') == date('Y-m-d',strtotime('-3 days'))){
  458.                 $day = 3;
  459.             } elseif($profile->getCreatedDate()->format('Y-m-d') == date('Y-m-d',strtotime('-7 days'))){
  460.                 $day = 7;
  461.             }
  462.             if($day){
  463.                 $this->userService->sendNotificationRegisterEmail($profile, $day);
  464.             }
  465.         }
  466.     }
  467.     /**
  468.      * Drains profiles submitted (isSent=false) but not yet notified to the campus
  469.      * admin, sends the notification, and marks them isSent=true. Queries strictly
  470.      * isSent === false (not null) since null means step4 was never submitted at all.
  471.      * One profile's failure is isolated so it never blocks the rest of the batch
  472.      * (and doesn't get stuck reprocessing the same failure on every cron run).
  473.      *
  474.      * @return int number of profiles processed (attempted) in this run
  475.      */
  476.     public function sendPendingCampusEmails()
  477.     {
  478.         $profiles = $this->repository->findBy(['isSent' => false]);
  479.         foreach ($profiles as $profile) {
  480.             try {
  481.                 $campus1 = $profile->getCampus1();
  482.                 if ($campus1 && isset(Common::listEmailAdmission()[$campus1->getId()])) {
  483.                     $this->userService->sendCampusEmail($profile, Common::listEmailAdmission()[$campus1->getId()]);
  484.                 }
  485.                 $profile->setIsSent(true);
  486.                 $this->repository->save($profile);
  487.             } catch (\Throwable $e) {
  488.                 $this->logger->error('sendPendingCampusEmails failed for profile', [
  489.                     'profile' => $profile->getId(),
  490.                     'error' => $e->getMessage()
  491.                 ]);
  492.             }
  493.         }
  494.         return count($profiles);
  495.     }
  496.     private function callQcmApi($data, $url, $method){
  497.         $requestJson = json_encode($data, JSON_THROW_ON_ERROR);
  498.         $response = $this->httpClient->request($method, $this->container->getParameter('qcm_api_url').$url, [
  499.             'headers' => [
  500.                 'Content-Type: application/json',
  501.                 'Accept: application/json',
  502.             ],
  503.             'body' => $requestJson,
  504.         ]);
  505.         $responseJson = $response->getContent();
  506.         $responseData = json_decode($responseJson, true);
  507.         return $responseData;
  508.     }
  509.     public function getQcmUrl($profile){
  510.         $data = [
  511.                 'email' => $profile['user']['email'],
  512.                 'password' => $profile['qcmToken']
  513.             ];
  514.         $requestJson = json_encode($data, JSON_THROW_ON_ERROR);
  515.         $response = $this->httpClient->request('POST', $this->container->getParameter('qcm_api_url').'/auth/one-time-token', [
  516.             'headers' => [
  517.                 'Content-Type: application/json',
  518.                 'Accept: application/json',
  519.             ],
  520.             'body' => $requestJson,
  521.         ]);
  522.         $responseJson = $response->getContent();
  523.         $responseData = json_decode($responseJson, true);
  524.         $redirectUrl = null;
  525.         if($responseData['success'] == true){
  526.             $redirectUrl = $responseData['redirectUrl'];
  527.         }
  528.         return $redirectUrl;
  529.     }
  530.     public function getRandomComercialOfcampus($campusId)
  531.     {
  532.         $commercials = $this->campusService->getListUsersActive($campusId);
  533.         if (empty($commercials) || count($commercials->toArray()) == 0) {
  534.             return null;
  535.         }
  536.         $randomKey = array_rand($commercials->toArray());
  537.         $randomCommercial = $commercials[$randomKey];
  538.         return $randomCommercial->getId() ?? null;
  539.     }
  540. }