src/Command/AutomatedFunctionCommand.php line 377

Open in your IDE?
  1. <?php
  2. namespace App\Command;
  3. use App\Entity\Company;
  4. use App\Entity\Appraisal;
  5. use App\Entity\AppraisalQuestionnaire;
  6. use App\Entity\LeaveBankHoliday;
  7. use App\Entity\LeaveEntitlement;
  8. use App\Entity\User;
  9. use App\Entity\PersonalInfo;
  10. use App\Entity\LeaveRequest;
  11. use App\Entity\Project;
  12. use App\Repository\LeaveRequestRepository;
  13. use App\Service\AppraisalService;
  14. use App\Service\DocumentManagementService;
  15. use App\Service\UserService;
  16. use App\Service\LeaveService;
  17. use App\Service\NotificationService;
  18. use App\Service\MailgunService;
  19. use App\Service\LogService;
  20. use App\Service\ObjectiveService;
  21. use App\Service\ProjectService;
  22. use App\Service\CurrencyService;
  23. use App\Service\WebhookService;
  24. use Doctrine\ORM\EntityManagerInterface;
  25. use Symfony\Component\Console\Helper\ProgressBar;
  26. use Symfony\Component\Console\Command\Command;
  27. use Symfony\Component\Console\Input\InputInterface;
  28. use Symfony\Component\Console\Input\InputOption;
  29. use Symfony\Component\Console\Input\InputArgument;
  30. use Symfony\Component\Console\Output\OutputInterface;
  31. use Symfony\Component\Console\Style\SymfonyStyle;
  32. use Symfony\Contracts\Translation\TranslatorInterface;
  33. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  34. use Symfony\Component\Console\Helper\TableSeparator;
  35. use App\Command\Exception;
  36. use App\Entity\ExpenseRequest;
  37. use App\Service\ExpenseRequestService;
  38. use App\Service\ChecklistService;
  39. class AutomatedFunctionCommand extends Command
  40. {
  41.     protected static $defaultName 'app:automated';
  42.     protected static $defaultDescription 'Multiple automated function that need to run reqularly';
  43.     protected function configure()
  44.     {
  45.         $this
  46.             ->setDescription('Various command for automated function')
  47.             ->addArgument('type'nullInputOption::VALUE_NONE,  null)
  48.             ->addOption('force'nullInputOption::VALUE_NONE'force command'null)
  49.             ->addOption('clear'nullInputOption::VALUE_NONE'clear timestamp'null)
  50.             ->addOption('test'nullInputOption::VALUE_NONE'test mode'null);
  51.     }
  52.     private $entityManager;
  53.     private $initiateDay 14;
  54.     private $submitDeadline 7;
  55.     private $appraisalService;
  56.     private $objectiveService;
  57.     private $userService;
  58.     private $WebhookService;
  59.     private $leaveService;
  60.     private $logService;
  61.     private $translator;
  62.     private $params;
  63.     private $documentManagement;
  64.     private $mailgunService;
  65.     private $notificationService;
  66.     private $projectService;
  67.     private $currencyService;
  68.     private $testAccounts;
  69.     private $expenseRequestService;
  70.     private $checklistService;
  71.     public function __construct(EntityManagerInterface $entityManagerAppraisalService $appraisalServiceObjectiveService $objectiveServiceUserService $userServiceLeaveService $leaveServiceLogService $logServiceDocumentManagementService $documentManagementTranslatorInterface $translatorParameterBagInterface $paramsMailgunService $mailgunServiceNotificationService $notificationServiceWebhookService $webhookServiceProjectService $projectServiceCurrencyService $currencyServiceChecklistService $checklistServiceExpenseRequestService $expenseRequestService)
  72.     {
  73.         parent::__construct();
  74.         $this->entityManager $entityManager;
  75.         $this->appraisalService $appraisalService;
  76.         $this->objectiveService $objectiveService;
  77.         $this->userService $userService;
  78.         $this->WebhookService $webhookService;
  79.         $this->leaveService $leaveService;
  80.         $this->logService $logService;
  81.         $this->translator $translator;
  82.         $this->params $params;
  83.         $this->documentManagement $documentManagement;
  84.         $this->mailgunService $mailgunService;
  85.         $this->notificationService $notificationService;
  86.         $this->projectService $projectService;
  87.         $this->currencyService $currencyService;
  88.         $this->testAccounts explode(','str_replace(array("\r""\n"" "), '',$_SERVER['TEST_ACCOUNTS']));
  89.         $this->expenseRequestService $expenseRequestService;
  90.         $this->checklistService $checklistService;
  91.     }
  92.     protected function execute(InputInterface $inputOutputInterface $output): int
  93.     {
  94.         $io = new SymfonyStyle($input$output);
  95.         $type $input->getArgument('type');
  96.         $force $input->getOption('force');
  97.         $clear $input->getOption('clear');
  98.         $test $input->getOption('test');
  99.         // Schedule Probation
  100.         if ($type == null) {
  101.             $type 'help';
  102.         }
  103.         switch ($type) {
  104.             case 'process':
  105.                 // $this->passProbation(false, $input, $output);
  106.                 $this->deactivateUser(false$input$output);
  107.                 $this->processProbationAppraisal(false$input$output);
  108.                 $this->processYearlyAppraisal(false$input$output);
  109.                 $this->leaveProRate(false$input$output);
  110.                 $this->remindLeave($input$output);
  111.                 if (in_array(date('N'), [12345])) {
  112.                     $this->dailyLeave(false$input$output); 
  113.                 }
  114.                 if (date('H') == 14){
  115.                     $this->weeklyLeave(false$input$output);
  116.                     $this->weeklyHoliday(falsefalse$input$output);
  117.                 }
  118.                 // $this->remindExpireLeave(false, $input, $output);
  119.                 $this->remindExpireAnnualLeave(false$input$output);
  120.                 $this->remindExpireCarryForwardLeave(false$input$output);
  121.                 $this->remindExpireAdjustmentLeave(false$input$output);
  122.                 $this->remindExpireBonusLeave(false$input$output);
  123.                 $this->syncStatus($input$output);
  124.                 $this->birthdayNow(false$input$output);
  125.                 $this->projectEndToday(false$input$output);
  126.                 $this->projectVendorPlanningEmpty(false$input$output);
  127.                 $this->remindProjectHosting(falsefalse$input$output);
  128.                 //$this->remindBirthday(false, $input, $output);
  129.                 $this->remindAppraisal(false$input$output);
  130.                 $this->remindObjective(false$input$output);
  131.                 $this->onboardingEmail(false$input$output);
  132.                 $this->offboardingEmail(false$input$output);
  133.                 $this->updateProvisionalRate(falsefalse$input$output);
  134.                 break;
  135.             case 'appraisal':
  136.                 $this->processProbationAppraisal($force$input$output);
  137.                 $this->processYearlyAppraisal($force$input$output);
  138.                 break;
  139.             case 'appraisal:probation':
  140.                 $this->processProbationappraisal($force$input$output);
  141.                 break;
  142.             case 'appraisal:yearly':
  143.                 $this->processYearlyAppraisal($force$input$output);
  144.                 break;
  145.             case 'appraisal:yearly:test':
  146.                 $this->testYearlyAppraisal($force$input$output);
  147.                 break;
  148.             case 'appraisal:probation:all':
  149.                 $this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllProbationer(), true$input$output);
  150.                 break;
  151.             case 'appraisal:probation:active':
  152.                 $this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllActiveProbationer($this->initiateDay), true$input$output);
  153.                 break;
  154.             case 'appraisal:performance:all':
  155.                 $this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllEmployee(), false$input$output);
  156.                 break;
  157.             case 'appraisal:performance:active':
  158.                 $this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllActiveEmployee($this->initiateDay), false$input$output);
  159.                 break;
  160.             case 'appraisal:remind':
  161.                 if ($clear) {
  162.                     $this->clearAppraisalReminder($input$output);
  163.                 } else {
  164.                     $this->remindAppraisal($force$input$output);
  165.                 }
  166.                 break;
  167.             case 'appraisal:remind:all':
  168.                 $this->appraisalList($this->entityManager->getRepository(Appraisal::class)->findAllActiveAppraisal(), $input$output);
  169.                 break;
  170.             case 'user:objective:remind':
  171.                 $this->remindObjective($force$input$output);
  172.                 break;
  173.             case 'user:summary:remind':
  174.                 $this->remindSummary($this->entityManager->getRepository(Appraisal::class)->findAllTodayAppraisal(), $input$output);
  175.                 break;
  176.             case 'user:pass:probation':
  177.                 $this->passProbation(false$input$output);
  178.                 break;
  179.             case 'user:deactivate':
  180.                 $this->deactivateUser(false$input$output);
  181.                 break;
  182.             case 'user:deactivate:all':
  183.                 $this->deactivateUser(true$input$output);
  184.                 break;
  185.             case 'user:onboarding':
  186.                 $this->onboardingEmail($force$input$output);
  187.                 break;
  188.             case 'user:offboarding':
  189.                 $this->offboardingEmail($force$input$output);
  190.                 break;
  191.             case 'user:status':
  192.                 $this->syncStatus($input$output);
  193.                 break;
  194.             case 'user:birthday':
  195.                 $this->birthdayNow($force$input$output);
  196.                 break;
  197.             case 'project:remind:end':
  198.                 $this->projectEndToday($force$input$output);
  199.                 break;
  200.             case 'project:remind:vendorplanning':
  201.                 $this->projectVendorPlanningEmpty($force$input$output);
  202.                 break;
  203.             case 'project:remind:hosting':
  204.                 $this->remindProjectHosting($force$test$input$output);
  205.             break;
  206.             case 'user:birthday:remind':
  207.                 $this->remindBirthday($force$input$output);
  208.                 break;
  209.             case 'leave:prorate':
  210.                 $this->leaveProRate($force$input$output);
  211.                 break;
  212.             case 'leave:remind':
  213.                 if ($clear) {
  214.                     $this->clearLeaveReminder($input$output);
  215.                 } else {
  216.                     $this->remindLeave($input$output);
  217.                 }
  218.                 break;
  219.             case 'leave:remind:daily':
  220.                 $this->dailyLeave($force$input$output);
  221.                 break;
  222.             case 'leave:remind:weekly':
  223.                 $this->weeklyLeave($force$input$output);
  224.                 break;
  225.             case 'leave:remind:holiday':
  226.                 $this->weeklyHoliday($force$test$input$output);
  227.                 break;
  228.             /*
  229.             case 'leave:remind:expire':
  230.                 $this->remindExpireLeave($force, $input, $output);
  231.                 break; */
  232.             case 'leave:remind:expire:annual':
  233.                 $this->remindExpireAnnualLeave($force$input$output);
  234.                 break;
  235.             case 'leave:remind:expire:carryforward':
  236.                 $this->remindExpireCarryForwardLeave($force$input$output);
  237.                 break;
  238.             case 'leave:remind:expire:adjustment':
  239.                 $this->remindExpireAdjustmentLeave($force$input$output);
  240.                 break;
  241.             case 'leave:remind:expire:bonus':
  242.                 $this->remindExpireBonusLeave($force$input$output);
  243.                 break;
  244.             case 'expense:remind:invoice':
  245.                 // $this->remindUploadInvoiceExpense($force, $input, $output);
  246.                 $this->remindUploadInvoiceExpenseRecurring($force$input$output);
  247.                 break;
  248.                 // case 'remind:leave:holiday':
  249.                 //     $this->weeklyHoliday($force, $input, $output);
  250.                 //     break;
  251.                 // case 'remind:leave:expire':
  252.                 //     $this->remindExpireLeave($force, $input, $output);
  253.                 //     break;
  254.                 // case 'employee:birthday':
  255.                 //     $this->birthdayNow($force, $input, $output);;
  256.                 //     break;
  257.                 // case 'employee:remind:birthday':
  258.                 //     $this->remindBirthday($force, $input, $output);
  259.                 //     break;
  260.             case 'currency:provisional':
  261.                 $this->updateProvisionalRate($force$test$input$output);
  262.             break;
  263.             default:
  264.                 $io->title('Automated function command list');
  265.                 $headers = ['Command''Argument''Description'];
  266.                 $rows = [
  267.                     ['process''''Process all required command'],
  268.                     ['appraisal''--force''Initiate scheduling routine for all review'],
  269.                     ['appraisal:probation''--force''Initiate scheduling routine for probation review'],
  270.                     ['appraisal:yearly''--force''Initiate scheduling routine for yearly review'],
  271.                     ['appraisal:probation:all''''List all user that in probation status'],
  272.                     ['appraisal:probation:active''''List all user that active in probation'],
  273.                     ['appraisal:performance:all''''List all user that in employee status'],
  274.                     ['appraisal:performance:active''''List all user that active as employee'],
  275.                     ['appraisal:remind''--clear''Remind all user that has active appraisal'],
  276.                     ['user:objective:remind''''Remind all user that has active objective'],
  277.                     ['user:deactivate:all''''Display all user that scheduled for deactivation'],
  278.                     ['user:onboarding''--force''Initiate onboarding email'],
  279.                     ['user:offboarding''--force''Initiate offboarding email'],
  280.                     ['user:summary:remind''''Remind manager to conclude review'],
  281.                     ['user:pass:probation''''Change user status from probation to permanent after end of probation date'],
  282.                     ['user:deactivate''''Initiate user deactivation'],
  283.                     ['user:status''''Sync status with leave'],
  284.                     ['user:birthday''--force''Send employee birthday'],
  285.                     ['user:birthday:remind''--force''Send reminder for 3 days to come employee birthday'],
  286.                     ['leave:prorate''--force''Calculate leave prorate'],
  287.                     ['leave:remind''--clear''Send reminder for all leave info'],
  288.                     ['leave:remind:daily''--force''Send reminder for daily leave info'],
  289.                     ['leave:remind:weekly''--force''Send reminder for next week leave info'],
  290.                     ['leave:remind:expire''--force''Send reminder for next week expire leave info'],
  291.                     ['leave:remind:expire:annual''--force''Send reminder for annual leave expire info'],
  292.                     ['leave:remind:expire:carryforward''--force''Send reminder for carry forward leave expire info'],
  293.                     ['leave:remind:expire:adjustment''--force''Send a reminder for Adjustment one month before leave expiration'],
  294.                     ['leave:remind:expire:bonus''--force''Send a reminder for Bonus three months before leave expiration'],
  295.                     ['leave:remind:holiday''--force''Send reminder for next week holiday info'],
  296.                     ['currency:provisional''--force''Update provisional rate'],
  297.                     ['project:remind:end''--force''Send project end to pic'],
  298.                     ['project:remind:vendorplanning''--force''Send project vendor planning to pic'],
  299.                     ['project:remind:hosting''--force''Send project hosting reminder to pic'],
  300.                     ['expense:remind:invoice''--force''Send a reminder to the requester to upload the invoice'],
  301.                 ];
  302.                 $io->table($headers$rows);
  303.             break;
  304.         }
  305.         return \Symfony\Component\Console\Command\Command::SUCCESS;
  306.     }
  307.     protected function employeeList($employees$inProbation$input$output)
  308.     {
  309.         $io = new SymfonyStyle($input$output);
  310.         $total 0;
  311.         $io->title($inProbation 'Probationer' 'Performance');
  312.         $headers = ['ID''Full Name''Status''Join Date''Expiry Date''Scheduled''Submit Date''Review Date'];
  313.         $rows = [];
  314.         foreach ($employees as $employee) {
  315.             $user $employee->getUser();
  316.             //if ($user->assignedCompany()->getId() == '4') { // CompanyID
  317.             $total++;
  318.             $joinDate $user->getPersonalInfo()->getJobJoinDate() ? '<options=bold>' $user->getPersonalInfo()->getJobJoinDate()->format('d/m/Y') . '</>' '-';
  319.             $expiryDate $user->getPersonalInfo()->getJobExpiryDate() ? '<options=bold>' $user->getPersonalInfo()->getJobExpiryDate()->format('d/m/Y') . '</>' '-';
  320.             //$submitDate = $user->getPersonalInfo()->getJobSubmitDate() ? '<options=bold>'.$user->getPersonalInfo()->getJobSubmitDate()->format('d/m/Y H:i').'</>' : '-';
  321.             $appraisals $user->activeAppraisals();
  322.             if (count($appraisals) > 0) {
  323.                 $submitDate $appraisals[0]->getSubmitAt() ? $appraisals[0]->getSubmitAt()->format('d/m/Y') : '-';
  324.                 $reviewDate $appraisals[0]->getReviewAt() ? $appraisals[0]->getReviewAt()->format('d/m/Y H:i') : '-';
  325.                 $todayMarker $appraisals[0]->getReviewAt() != null && $appraisals[0]->getReviewAt()->format('Ymd') == date('Ymd') ? '*' '';
  326.                 array_push($rows, [
  327.                     $user->getId(),
  328.                     $user->getPersonalInfo()->getFullName() != null $user->getPersonalInfo()->getFullName() : '<error>' $user->getEmail() . '</error>',
  329.                     $this->translator->trans($user->getPersonalInfo()->getJobStatus()),
  330.                     $joinDate,
  331.                     $expiryDate,
  332.                     isset($appraisals[0]) ? '<fg=black;bg=white>Yes [' $appraisals[0]->getId() . ']</>' '',
  333.                     $submitDate,
  334.                     $reviewDate
  335.                 ]);
  336.                 //$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().$todayMarker.' (Join: '.$joinDate.', Expiry: '.$expiryDate.', <fg=black;bg=white>Submit: '.$submitDate.', Review: '.$reviewDate.'</>)');
  337.             } else {
  338.                 $scheduled 'No';
  339.                 if ($user->getPersonalInfo()->getJobExpiryDate() != null) {
  340.                     $daysRemaining floor((strtotime($user->getPersonalInfo()->getJobExpiryDate()->modify('-' $this->initiateDay ' days')->format('Ymd')) - strtotime(date('Ymd'))) / 60 60 24);
  341.                     if ($daysRemaining 1) {
  342.                         $scheduled $daysRemaining == '<fg=black;bg=green>today</>' '<fg=black;bg=red>due ' $daysRemaining ' day/s</>';
  343.                     } else {
  344.                         $scheduled 'in ' $daysRemaining ' day/s';
  345.                     }
  346.                 };
  347.                 array_push($rows, [
  348.                     $user->getId(),
  349.                     $user->getPersonalInfo()->getFullName() != null $user->getPersonalInfo()->getFullName() : '<error>' $user->getEmail() . '</error>',
  350.                     $this->translator->trans($user->getPersonalInfo()->getJobStatus()),
  351.                     $joinDate,
  352.                     $expiryDate,
  353.                     $scheduled,
  354.                     '-',
  355.                     '-'
  356.                 ]);
  357.                 //$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().' (Join: '.$joinDate.', Expiry: '.$expiryDate.')');
  358.             };
  359.             //};
  360.         };
  361.         $io->table($headers$rows);
  362.         $io->success($inProbation $total ' user in probation!' $total ' user found!');
  363.     }
  364.     protected function passProbation($force false$input$output)
  365.     {
  366.         $total 0;
  367.         $io = new SymfonyStyle($input$output);
  368.         $io->title('User auto-pass probation');
  369.         $headers = ['ID''Full Name''Last Probation Date''Next Review Date'];
  370.         $rows = [];
  371.         $userList $this->entityManager->getRepository(PersonalInfo::class)->findProbationerAutoPass();
  372.         foreach ($userList as $userInfo) {
  373.             $user $userInfo->getUser();
  374.             $this->leaveService->leavePermanent($usertruefalse,'run');
  375.             $attributes =  $user->assignedCompany()->getAttributes();
  376.             if(isset($attributes['appraisalEndAt'])){
  377.                 $apprisalStartAt = new \DateTime($attributes['appraisalStartAt']['date']);
  378.                 $apprisalEndAt = new \DateTime($attributes['appraisalEndAt']['date']);
  379.                 $endDate $apprisalStartAt > new \DateTime('+ 2 months') ? $apprisalEndAt $apprisalEndAt->modify('+ 1 years');
  380.             } else {
  381.                 $endDate = new \DateTime('+ 1 years');
  382.             };
  383.             $oldUserInfo = clone $userInfo;
  384.             $userInfo->setJobStatus('form.job_status.permanent');
  385.             $userInfo->setJobExpiryDate($endDate);
  386.             $userInfo->setJobPermanentDate(new \DateTime());
  387.             $probationAppraisal $user->probationAppraisal();
  388.             if($probationAppraisal$probationAppraisal->setConcludedAt(new \DateTime());
  389.             array_push($rows, [
  390.                 $user->getId(),
  391.                 $userInfo->getFullName(),
  392.                 $oldUserInfo->getJobExpiryDate()->format('d/m/Y'),
  393.                 $userInfo->getJobExpiryDate()->format('d/m/Y'),
  394.             ]);
  395.             $this->logService->save(null, [
  396.                 'owner' => $user,
  397.                 'message' => 'log.automated.pass_probation',
  398.                 'old_data' => $oldUserInfo,
  399.                 'new_data' => $userInfo
  400.             ], falsetrue'UserInfo');
  401.             
  402.             $total++;
  403.         }
  404.         $io->table($headers$rows);
  405.         $this->entityManager->flush();
  406.         if ($total == 0) {
  407.             $io->success('No user passing probation period automatically');
  408.         } else {
  409.             $io->success($total ' user pass probation period automatically!');
  410.         };
  411.     }
  412.     private function changeManager(User $user){
  413.         $attr=$user->getPersonalInfo()->getAttributes();
  414.         if(isset($attr['replacemanager'])){
  415.             if($attr['replacemanager']!=''){
  416.                 $rmanager=$this->entityManager->getRepository(User::class)->find($attr['replacemanager']);
  417.                 $usr=$this->entityManager->getRepository(User::class);
  418.                 $qb=$usr->createQueryBuilder('u');
  419.                 $qb->where('(:sm member of u.subManager ) or (u.manager = :m )')
  420.                 ->setParameter('m'$user)
  421.                 ->setParameter('sm', array($user));
  422.                 $result=$qb->getQuery()->getResult();
  423.                 if(is_array($result)){
  424.                     foreach($result as $r){
  425.                         if($r->getManager()==$user){$r->setManager($rmanager);}
  426.                         $sub=$r->getSubManager();
  427.                         if(!is_null($sub)){
  428.                             if($sub->contains($user)){
  429.                                 $r->removeSubManager($user);
  430.                                 $r->addSubManager($rmanager);
  431.                             }
  432.                         }
  433.                         $this->entityManager->persist($r);
  434.                         $this->entityManager->flush();   
  435.                     }
  436.                     $this->userService->syncManagerStatus();
  437.                 }
  438.             }    
  439.         }    
  440.     }
  441.     protected function deactivateUser($list$input$output)
  442.     {
  443.         $total 0;
  444.         $io = new SymfonyStyle($input$output);
  445.         $io->title('User scheduled for termination');
  446.         $headers = ['ID''Full Name''Termination Date''Termination Reason''Status'];
  447.         $rows = [];
  448.         if ($list) {
  449.             $terminationList $this->entityManager->getRepository(PersonalInfo::class)->findAllScheduledForJobTermination();
  450.             foreach ($terminationList as $userInfo) {
  451.                 $oldUserInfo = clone $userInfo;
  452.                 $user $userInfo->getUser();
  453.                 if ($user->getIsActive()) {
  454.                     $terminationDate $userInfo->getJobTerminateDate();
  455.                     $terminationDateFormatted $terminationDate->format('d/m/Y');
  456.                     $today = new \DateTime();
  457.                     $todayFormatted $today->format('d/m/Y');
  458.                     $terminationDateFormatted $terminationDate <= $today '<fg=black;bg=yellow>' $terminationDateFormatted '</>' $todayFormatted;
  459.        
  460.                     array_push($rows, [
  461.                         $user->getId(),
  462.                         $userInfo->getFullName(),
  463.                         $terminationDateFormatted,
  464.                         $this->translator->trans($userInfo->getJobTerminateReason()),
  465.                         $user->getIsActive() ? 'Active' 'Deactivated'
  466.                     ]);
  467.                     $total++;
  468.                 }; 
  469.             }
  470.             $io->table($headers$rows);
  471.             if ($total == 0) {
  472.                 $io->success('No user scheduled for deactivation');
  473.             } else {
  474.                 $io->success($total ' user scheduled for deactivation!');
  475.             };
  476.         } else {
  477.             $terminationList $this->entityManager->getRepository(PersonalInfo::class)->findJobTerminated();
  478.             foreach ($terminationList as $userInfo) {
  479.                 $oldUserInfo = clone $userInfo;
  480.                 $user $userInfo->getUser();
  481.                 if ($user->getIsActive()) {
  482.                     $this->documentManagement->transferAllUserOwnership($user->getId());
  483.                     $user->setIsActive(false);
  484.                     $this->entityManager->flush();
  485.                     $this->changeManager($user);
  486.                     $this->checklistService->checklistTransferOwnership($user->getId());
  487.                     $result['message'] = $this->WebhookService->checkboxWebhook('users''DELETE'$user->getId());
  488.                     array_push($rows, [
  489.                         $user->getId(),
  490.                         $userInfo->getFullName(),
  491.                         $userInfo->getJobTerminateDate()->format('d/m/Y'),
  492.                         $this->translator->trans($userInfo->getJobTerminateReason()),
  493.                         $user->getIsActive() ? 'Active' 'Deactivated'
  494.                     ]);
  495.                    
  496.                     $total++;
  497.                     $this->logService->save(null, [
  498.                         'owner' => $user,
  499.                         'message' => 'log.automated.deactivate_user',
  500.                         'old_data' => $oldUserInfo,
  501.                         'new_data' => $userInfo
  502.                     ], falsetrue'UserInfo');
  503.                 };
  504.             }
  505.             $io->table($headers$rows);
  506.             if ($total == 0) {
  507.                 $io->success('No user deactivation');
  508.             } else {
  509.                 $io->success($total ' user deactivated!');
  510.             };
  511.         };
  512.     }
  513.     protected function scheduleAppraisal($day false$force false$test false$input$output)
  514.     {
  515.         $io = new SymfonyStyle($input$output);
  516.         $employees $this->entityManager->getRepository(PersonalInfo::class)->findEmployeeForReview($day$force);
  517.         $total 0;
  518.         foreach ($employees as $employee) {
  519.             $user $employee->getUser();
  520.             if ($user->getIsActive() == true && $user->inProbation() == true) {
  521.                 //$this->appraisalService->initiate(false, $user->getManager(), $user, $this->translator->trans('email.appraisal.probation'), $probationer->getJobExpiryDate()->modify('-7 weekday')->setTime(16,0,0)); // Server-side review date calculation
  522.                 if (count($user->activeAppraisals()) == 0) {
  523.                     $expiryDate = new \DateTime($user->getPersonalInfo()->getJobExpiryDate()->format('Y-m-d'));
  524.                     $submitAt $expiryDate->modify('-' $this->submitDeadline ' days');
  525.                     $defaultQuestions $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
  526.                     $this->appraisalService->initiateAppraisal(falsenull$usernull$submitAtnull$defaultQuestions);
  527.                     $io->text('<fg=black;bg=white>Schedule appraisal</> <options=bold>[' $user->getId() . ']</> ' $user->getPersonalInfo()->getFullName());
  528.                     $total++;
  529.                 };
  530.             };
  531.         };
  532.         $io->success($total ' appraisal scheduled!');
  533.         return $total true false;
  534.         //return json_decode($response->getContent(),true);
  535.     }
  536.     protected function processProbationAppraisal($force false$input$output)
  537.     {
  538.         $io = new SymfonyStyle($input$output);
  539.         $users $this->entityManager->getRepository(User::class)->findProbationerForReview($this->initiateDaynull$force);
  540.         $total 0;
  541.         $io->title('Process Probation Appraisal');
  542.         foreach ($users as $user) {
  543.             if (count($user->activeAppraisals()) == 0) {
  544.                 $expiryDate = new \DateTime($user->getPersonalInfo()->getJobExpiryDate()->format('Y-m-d'));
  545.                 $submitAt $expiryDate->modify('-' $this->submitDeadline ' days');
  546.                 $defaultQuestions $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
  547.                 $this->appraisalService->initiateAppraisal(falsenull$usernull$submitAtnull$defaultQuestions);
  548.                 $io->text('<fg=black;bg=white>Schedule probation appraisal</> <options=bold>[' $user->getId() . ']</> ' $user->getPersonalInfo()->getFullName());
  549.                 $total++;
  550.             };
  551.         };
  552.         $io->success($total ' probation appraisal scheduled!');
  553.         return $total true false;
  554.     }
  555.     protected function processYearlyAppraisal($force false$input$output)
  556.     {
  557.         $io = new SymfonyStyle($input$output);
  558.         $io->title('Schedule Appraisal by Settings');
  559.         $emailGroup $this->params->get('systemEmailGroup');
  560.         $companies $this->entityManager->getRepository(Company::class)->findAll();
  561.  
  562.         foreach ($companies as $company) {
  563.             if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
  564.             $attributes $company->getAttributes();
  565.             $startDate = isset($attributes['appraisalStartAt']) ? new \DateTimeImmutable($attributes['appraisalStartAt']['date']) : null;
  566.             $endDate = isset($attributes['appraisalEndAt']) ? new \DateTimeImmutable($attributes['appraisalEndAt']['date']) : null;
  567.             $userSubmitDate = isset($attributes['appraisalUserSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalUserSubmitAt']['date']) : null;
  568.             $managerSubmitDate = isset($attributes['appraisalManagerSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']) : null;
  569.             $latestDate = isset($attributes['appraisalLatest']) ? new \DateTimeImmutable($attributes['appraisalLatest']['date']) : null;
  570.             // Initate new appraisal
  571.             $users $this->entityManager->getRepository(User::class)->findAllEligibleForAppraisal($company$startDate$force);
  572.           
  573.             $io->section($company->getFullName());
  574.            
  575.             if (!$startDate || !$endDate || !$userSubmitDate || !$managerSubmitDate) {
  576.                 $io->text("<fg=white;bg=red>Apraisal settings not complete</>\n");
  577.                 continue;
  578.             }
  579.             if (date('Ymd') < $startDate->format('Ymd')) {
  580.                 $io->text("Appraisal period scheduled for " $startDate->format('d/m/Y') . "\n");
  581.                 continue;
  582.             }
  583.             $io->text("<fg=black;bg=yellow>STEP 1 - Initiate (user)</>\n");
  584.             $appraisalData null;
  585.       
  586.             if ($latestDate == null || $startDate->format('Ymd') == date('Ymd') && $startDate->format('Ymd') != $latestDate->format('Ymd') || $force) {
  587.                 $progressBar = new ProgressBar($outputcount($users));
  588.                 $progressBar->setEmptyBarCharacter('â–‘'); // light shade character \u2591
  589.                 $progressBar->setProgressCharacter('');
  590.                 $progressBar->setBarCharacter('â–“'); // dark shade character \u2593
  591.                 $progressBar->start();
  592.                 $skippedUsers = [];
  593.                 $totalYearly 0;
  594.                 $totalError 0;
  595.                 
  596.                 foreach ($users as $user) {
  597.                     $submitAt $userSubmitDate;
  598.                     if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') {
  599.                         $autoConclude 'No';
  600.                         if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getCreatedAt() < $startDate && $user->activeAppraisals()[0]->getConcludedAt() == null) {
  601.                             $autoConclude 'Yes';
  602.                         };
  603.                         if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
  604.                             $skippedUsers[] = [count($skippedUsers) + 1$user->getEmail(), 'Yes'$autoConclude];
  605.                         } else {
  606.                             $skippedUsers[] = [count($skippedUsers) + 1$user->getEmail(), 'No'$autoConclude];
  607.                         }
  608.                        
  609.                         $progressBar->advance();
  610.                         continue;
  611.                     }
  612.                     try {
  613.                         if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getCreatedAt() < $startDate && $user->activeAppraisals()[0]->getConcludedAt() == null) {
  614.                             $user->activeAppraisals()[0]->setConcludedAt(new \DateTime);
  615.                             $this->appraisalService->syncAppraisalStatus($user);
  616.                             //$totalYearly++;
  617.                         };
  618.                         // if ($user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd') || $user->latestAppraisal() == null) {
  619.                         if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
  620.                             // $io->info($user->latestAppraisal()->getCreatedAt()->format('d-m-Y').' - '.$user->getEmail());
  621.                             $defaultQuestions $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
  622.                             $this->appraisalService->initiateAppraisal(falsenull$usernull$submitAtnull$defaultQuestions);
  623.                             $totalYearly++;
  624.                             
  625.                             if ($appraisalData == null$appraisalData = isset($user->activeAppraisals()[0]) ? $user->activeAppraisals()[0] : null;
  626.                             //    $this->objectiveService->updateOldObjective($user);
  627.                         }
  628.                         $progressBar->advance();
  629.                     } catch (Exception $e) {
  630.                         $totalError++;
  631.                         $progressBar->advance();
  632.                         continue;
  633.                     }
  634.                 };
  635.                 $totalManager 0;
  636.                 $totalManagerError 0;
  637.                 if (!$force && $appraisalData != null) {
  638.                     foreach ($company->getAllManager() as $manager) {
  639.                         if (!in_array($manager->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  640.                         try {
  641.                             $this->mailgunService->sendEmail(
  642.                                 $this->translator->trans('email.appraisal.initiated.objective.manager'),
  643.                                 [$manager->getEmail()],
  644.                                 'email/user-notification/appraisal/initiate-objective.html.twig',
  645.                                 [
  646.                                     'recipient' => $manager,
  647.                                     'appraisal' => $appraisalData,
  648.                                     'group' => 'manager'
  649.                                 ],
  650.                                 false
  651.                             );
  652.                             $totalManager++;
  653.                         } catch (Exception $e) {
  654.                             $totalManagerError++;
  655.                             continue;
  656.                         }
  657.                     };
  658.                 }
  659.                 if (!$force && $appraisalData != null) {
  660.                     foreach ($emailGroup as $groupName => $groupEmail) {
  661.                         if($groupName != 'hr') continue;
  662.                         try {
  663.                             $this->mailgunService->sendEmail(
  664.                                 $this->translator->trans('email.appraisal.initiated.objective.' $groupName),
  665.                                 [$groupEmail],
  666.                                 'email/user-notification/appraisal/initiate-objective.html.twig',
  667.                                 [
  668.                                     'recipient' => strtoupper($groupName) . ' Team',
  669.                                     'appraisal' => $appraisalData,
  670.                                     'group' => $groupName,
  671.                                 ],
  672.                                 false
  673.                             );
  674.                         } catch (Exception $e) {
  675.                             continue;
  676.                         }
  677.                     };
  678.                 }
  679.                 $attributes['appraisalLatest'] = new \DateTimeImmutable;
  680.                 $company->setAttributes($attributes);
  681.                 $this->entityManager->flush();
  682.                 $io->text("\n\n" $totalYearly " yearly appraisal scheduled on " $startDate->format('d/m/Y') . "!\n");
  683.                 $io->text($totalManager " manager informed!\n");
  684.                 if ($totalError 0$io->text("\n <fg=white;bg=red>" $totalError " user  & " $totalManagerError " manager appraisal failed to schedule!</>\n");
  685.                 if (count($skippedUsers) > 0) {
  686.                     $io->text("\n\n<fg=black;bg=white>Skipped Users</>\n");
  687.                     $io->table(['No.''Email''Eligible''Auto Conclude'], $skippedUsers);
  688.                 }
  689.             } else {
  690.                 $io->text("Already done at " $startDate->format('d/m/Y') . "\n");
  691.             }
  692.             // Initiate Manager Step
  693.             $io->text("<fg=black;bg=yellow>STEP 2 - Manager</>\n");
  694.             if (date('Ymd') == $userSubmitDate->modify('+ 1 days')->format('Ymd') && ($latestDate == null || date('Ymd') != $latestDate->format('Ymd'))) {
  695.                 $totalYearly 0;
  696.                 $totalDue 0;
  697.                 foreach ($users as $user) {
  698.                     try {
  699.                         if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  700.                         if (isset($user->activeAppraisals()[0])) {
  701.                             if ($user->activeAppraisals()[0]->getSubmittedAt() == null) {
  702.                                 // $user->activeAppraisals()[0]->setSubmittedAt(new \DateTime);
  703.                                 $this->appraisalService->syncAppraisalStatus($user);
  704.                                 $totalYearly++;
  705.                                 $totalDue++;
  706.                                 foreach ($emailGroup as $groupName => $groupEmail) {
  707.                                     if ($groupName == 'hr') {
  708.                                         try {
  709.                                             $this->mailgunService->sendEmail(
  710.                                                 $this->translator->trans('email.appraisal.missed_notice.user', ['%user%' => $user->getPersonalInfo()->getFullName(), '%manager%' => $user->getManager()->getPersonalInfo()->getFullName()]),
  711.                                                 [$groupEmail],
  712.                                                 'email/user-notification/appraisal/missed.html.twig',
  713.                                                 [
  714.                                                     'recipient' => strtoupper($groupName) . ' Team',
  715.                                                     'appraisal' => $user->activeAppraisals()[0],
  716.                                                     'group' => $groupName,
  717.                                                     'missed' => 'user'
  718.                                                 ],
  719.                                                 false
  720.                                             );
  721.                                         } catch (Exception $e) {
  722.                                             continue;
  723.                                         }
  724.                                     };
  725.                                 };
  726.                             };    
  727.                         };
  728.                     } catch (Exception $e) {
  729.                         continue;
  730.                     }
  731.                 };
  732.                 $attributes['appraisalLatest'] = new \DateTimeImmutable;
  733.                 $company->setAttributes($attributes);
  734.                 $this->entityManager->flush();
  735.                 $io->text("User submit window closed! \n");
  736.                 $io->text($totalDue" user didn't finish its form! \n");
  737.             } elseif (date('Ymd') >  $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
  738.                 $io->text("Already done at " $userSubmitDate->format('d/m/Y') . " \n");
  739.             } else {
  740.                 $io->text("Scheduled a day after " $userSubmitDate->format('d/m/Y') . "\n");
  741.             }
  742.             // Initiate Review Step
  743.             $io->text("<fg=black;bg=yellow>STEP 3 - Review</>\n");
  744.             if (date('Ymd') == $managerSubmitDate->modify('+ 1 days')->format('Ymd')  && ($latestDate == null || date('Ymd') != $latestDate->format('Ymd'))) {
  745.                 $dayReduction = (($managerSubmitDate->diff($endDate)->days 7) * 2) + 1;
  746.                 $totalYearly 0;
  747.                 $totalDue 0;
  748.                 foreach ($users as $user) {
  749.                     try {
  750.                         if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  751.                         if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getSubmittedAt() != null && $user->activeAppraisals()[0]->getReviewedAt() == null) {
  752.                             //$user->activeAppraisals()[0]->setReviewedAt(new \DateTime);
  753.                             //$reviewAt = $endDate->modify("- ".rand(1, $managerSubmitDate->diff($endDate)->days - $dayReduction)." weekdays")->setTime(rand(14,17),0,0);
  754.                             //$user->activeAppraisals()[0]->setReviewAt($reviewAt);
  755.                             //$this->appraisalService->syncAppraisalStatus($user);
  756.                             $totalYearly++;
  757.                             $totalDue++;
  758.                             $this->mailgunService->sendEmail(
  759.                                 $this->translator->trans('email.appraisal.missed.manager',['%user%' => $user->getPersonalInfo()->getFullName()]),
  760.                                 [$user->getManager()->getEmail()],
  761.                                 'email/user-notification/appraisal/missed.html.twig',
  762.                                 [
  763.                                     'recipient' => $user->getManager(),
  764.                                     'appraisal' => $user->activeAppraisals()[0],
  765.                                     'group' => 'manager',
  766.                                     'missed' => 'manager'
  767.                                 ],
  768.                                 false
  769.                             );
  770.                             foreach ($emailGroup as $groupName => $groupEmail) {
  771.                                 if ($groupName == 'hr') {
  772.                                     try {
  773.                                         $this->mailgunService->sendEmail(
  774.                                             $this->translator->trans('email.appraisal.missed_notice.manager', ['%user%' => $user->getPersonalInfo()->getFullName(), '%manager%' => $user->getManager()->getPersonalInfo()->getFirstName()]),
  775.                                             [$groupEmail],
  776.                                             'email/user-notification/appraisal/missed.html.twig',
  777.                                             [
  778.                                                 'recipient' => strtoupper($groupName) . ' Team',
  779.                                                 'appraisal' => $user->activeAppraisals()[0],
  780.                                                 'group' => $groupName,
  781.                                                 'missed' => 'manager'
  782.                                             ],
  783.                                             false
  784.                                         );
  785.                                         
  786.                                     } catch (Exception $e) {
  787.                                         continue;
  788.                                     }
  789.                                 };
  790.                             };
  791.                         };
  792.                     } catch (Exception $e) {
  793.                         continue;
  794.                     }
  795.                 };
  796.                 $attributes['appraisalLatest'] = new \DateTimeImmutable;
  797.                 $company->setAttributes($attributes);
  798.                 $this->entityManager->flush();
  799.                 
  800.                 $io->text("Manager submit window closed! \n");
  801.                 $io->text($totalDue" manager didn't finish its form! \n");
  802.             } elseif (date('Ymd') > $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
  803.                 $io->text("Already done at " $managerSubmitDate->format('d/m/Y') . " \n");
  804.             } else {
  805.                 $io->text("Scheduled a day after " $managerSubmitDate->format('d/m/Y') . "\n");
  806.             }
  807.             // Close Apprasial Period
  808.             $io->text("<fg=black;bg=yellow>STEP 4 - Complete</>\n");
  809.             if (date('Ymd') == $endDate->modify('+ 1 days')->format('Ymd')) {
  810.                 // $this->entityManager->flush();
  811.                 $attributes['appraisalStartAt'] = $startDate->modify("+ 6 months");
  812.                 $attributes['appraisalEndAt'] = $endDate->modify("+ 6 months");
  813.                 $attributes['appraisalUserSubmitAt'] = $userSubmitDate->modify("+ 6 months");
  814.                 $attributes['appraisalManagerSubmitAt'] = $managerSubmitDate->modify("+ 6 months");
  815.                 $totalYearly 0;
  816.                
  817.                 foreach ($users as $user) {
  818.                    // if ($totalYearly > 1 && $_SERVER['APP_ENV'] != 'prod') continue;
  819.                 //    if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  820.                    if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getConcludedAt() == null) {
  821.                         //$user->activeAppraisals()[0]->setConcludedAt(new \DateTime);
  822.                         //$user->activeAppraisals()[0]->setReviewedBy($user->getManager());
  823.                         $user->getPersonalInfo()->setJobExpiryDate($attributes['appraisalEndAt']);
  824.                         //$this->appraisalService->syncAppraisalStatus($user);
  825.                         //$totalYearly++;
  826.                     };
  827.                 };
  828.                 
  829.                 $attributes['appraisalLatest'] = new \DateTimeImmutable;
  830.                 $company->setAttributes($attributes);
  831.                 $this->entityManager->flush();
  832.                 //$io->text("All appraisal automatically concluded \n");
  833.                 $io->text("Appraisal session ended \n");
  834.             } elseif (date('Ymd') >  $endDate->modify('+ 1 days')->format('Ymd')) {
  835.                 $io->text("Already done at " $endDate->format('d/m/Y') . " \n");
  836.             } else {
  837.                 $io->text("Scheduled a day after " $endDate->format('d/m/Y') . "\n");
  838.             }
  839.             if ($force$this->appraisalService->syncAppraisalStatus();
  840.         }
  841.         return true;
  842.         //return json_decode($response->getContent(),true);
  843.     }
  844.     protected function testYearlyAppraisal($force false$input$output)
  845.     {
  846.         $io = new SymfonyStyle($input$output);
  847.         $io->title('[TEST] Schedule Appraisal by Settings');
  848.         $companies $this->entityManager->getRepository(Company::class)->findAll();
  849.         foreach ($companies as $company) {
  850.             if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
  851.             $attributes $company->getAttributes();
  852.             $startDate = isset($attributes['appraisalStartAt']) ? new \DateTimeImmutable($attributes['appraisalStartAt']['date']) : null;
  853.             $endDate = isset($attributes['appraisalEndAt']) ? new \DateTimeImmutable($attributes['appraisalEndAt']['date']) : null;
  854.             $userSubmitDate = isset($attributes['appraisalUserSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalUserSubmitAt']['date']) : null;
  855.             $managerSubmitDate = isset($attributes['appraisalManagerSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']) : null;
  856.             $latestDate = isset($attributes['appraisalLatest']) ? new \DateTimeImmutable($attributes['appraisalLatest']['date']) : null;
  857.             // Initate new appraisal
  858.             $users $this->entityManager->getRepository(User::class)->findAllEligibleForAppraisal($company$startDate$force);
  859.             //$probationers = $this->entityManager->getRepository(User::class)->findProbationerForReview($this->initiateDay, $company,$force);
  860.             $io->section($company->getFullName());
  861.             if (!$startDate || !$endDate || !$userSubmitDate || !$managerSubmitDate) {
  862.                 $io->text("<fg=white;bg=red>Apraisal settings not complete</>\n");
  863.                 continue;
  864.             }
  865.             if (date('Ymd') < $startDate->format('Ymd')) {
  866.                 $io->text("Apprasial period scheduled for " $startDate->format('d/m/Y') . "\n");
  867.                 continue;
  868.             }
  869.             $io->text("<fg=black;bg=yellow>[TEST] STEP 1 - Initiate (user)</>\n");
  870.             if ($latestDate == null || $startDate->format('Ymd') == date('Ymd') && $startDate->format('Ymd') != $latestDate->format('Ymd') || $force) {
  871.                 $progressBar = new ProgressBar($outputcount($users));
  872.                 $progressBar->setEmptyBarCharacter('â–‘'); // light shade character \u2591
  873.                 $progressBar->setProgressCharacter('');
  874.                 $progressBar->setBarCharacter('â–“'); // dark shade character \u2593
  875.                 $progressBar->start();
  876.                 $totalYearly 0;
  877.                 $totalError 0;
  878.                 $elligibleUsers = [];
  879.                 foreach ($users as $user) {
  880.                     try {
  881.                         // if ($force && count($user->activeAppraisals()) == 0) {
  882.                         if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
  883.                             $totalYearly++;
  884.                             $latest $user->latestAppraisal() ? $user->latestAppraisal()->getCreatedAt()->format('Y-m-d H:i:s') : null;
  885.                             $elligibleUsers[] = ['no' => $totalYearly'email' => $user->getEmail(), 'latest' => $latest ];
  886.                             
  887.                         }
  888.                         $progressBar->advance();
  889.                     } catch (Exception $e) {
  890.                         $totalError++;
  891.                         $progressBar->advance();
  892.                         continue;
  893.                     }
  894.                 };
  895.                 $totalManager 0;
  896.                 $totalManagerError 0;
  897.                 if (!$force) {
  898.                     foreach ($company->getAllManager() as $manager) {
  899.                         try {
  900.                             $totalManager++;
  901.                         } catch (Exception $e) {
  902.                             $totalManagerError++;
  903.                             continue;
  904.                         }
  905.                     };
  906.                 }
  907.                 $io->newLine();
  908.                 $io->table(['No''Email''Latest'], $elligibleUsers);
  909.                 $io->newLine();
  910.                 $io->text("\n\n"$totalYearly " yearly appraisal scheduled on " $startDate->format('d/m/Y') . "! \n");
  911.                 //$io->text(count($probationers)." probationer still waiting!\n");
  912.                 $io->text($totalManager " manager informed!\n");
  913.                 
  914.                 if ($totalError 0$io->text("\n <fg=white;bg=red>" $totalError " user  & " $totalManagerError " manager appraisal failed to schedule!</>\n");
  915.             } else {
  916.                 $io->text("Already done at " $startDate->format('d/m/Y') . "\n");
  917.             }
  918.             // Initiate Manager Step
  919.             $io->text("<fg=black;bg=yellow>[TEST] STEP 2 - Manager</>\n");
  920.             if (date('Ymd') == $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
  921.                 $totalYearly 0;
  922.                 $totalDue 0;
  923.                 foreach ($users as $user) {
  924.                     $totalYearly++;
  925.                     $totalDue++;
  926.                 };
  927.                 $io->text("User submit window closed! \n");
  928.                 $io->text($totalDue" user didn't finish its form! \n");
  929.             } elseif (date('Ymd') >  $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
  930.                 $io->text("Already done at " $userSubmitDate->format('d/m/Y') . " \n");
  931.             } else {
  932.                 $io->text("Scheduled a day after " $userSubmitDate->format('d/m/Y') . "\n");
  933.             }
  934.             // Initiate Review Step
  935.             $io->text("<fg=black;bg=yellow>[TEST] STEP 3 - Review</>\n");
  936.             if (date('Ymd') == $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
  937.                 $totalYearly 0;
  938.                 $totalDue 0;
  939.                 foreach ($users as $user) {
  940.                     $totalYearly++;
  941.                     $totalDue++;
  942.                 };
  943.                 $io->text("Manager submit window closed! \n");
  944.                 $io->text($totalDue" manager didn't finish its form! \n");
  945.             } elseif (date('Ymd') > $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
  946.                 $io->text("Already done at " $managerSubmitDate->format('d/m/Y') . " \n");
  947.             } else {
  948.                 $io->text("Scheduled a day after " $managerSubmitDate->format('d/m/Y') . "\n");
  949.             }
  950.             // Close Apprasial Period
  951.             $io->text("<fg=black;bg=yellow>[TEST] STEP 4 - Complete</>\n");
  952.             if (date('Ymd') == $endDate->modify('+ 1 days')->format('Ymd')) {
  953.                 $attributes['appraisalStartAt'] = $startDate->modify("+ 1 years");
  954.                 $attributes['appraisalEndAt'] = $endDate->modify("+ 1 years");
  955.                 $attributes['appraisalUserSubmitAt'] = $userSubmitDate->modify("+ 1 years");
  956.                 $attributes['appraisalManagerSubmitAt'] = $managerSubmitDate->modify("+ 1 years");
  957.                 $totalYearly 0;
  958.                 foreach ($users as $user) {
  959.                     $totalYearly++;
  960.                 };
  961.                 $company->setAttributes($attributes);
  962.                 $this->entityManager->flush();
  963.                 $io->text("All appraisal automatically concluded \n");
  964.             } elseif (date('Ymd') >  $endDate->modify('+ 1 days')->format('Ymd')) {
  965.                 $io->text("Already done at " $endDate->format('d/m/Y') . " \n");
  966.             } else {
  967.                 $io->text("Scheduled a day after " $endDate->format('d/m/Y') . "\n");
  968.             }
  969.         }
  970.         return true;
  971.         //return json_decode($response->getContent(),true);
  972.     }
  973.     protected function appraisalList($appraisals$input$output)
  974.     {
  975.         $io = new SymfonyStyle($input$output);
  976.         $total 0;
  977.         $io->title('Active Appraisal');
  978.         $headers = ['No''ID''Full Name''Title''Submit Deadline''User Filled''Review Date''Manager Filled''Last Reminder''Active'];
  979.         $rows = [];
  980.         foreach ($appraisals as $appraisal) {
  981.             $user $appraisal->getUser();
  982.             $daysRemaining floor((strtotime($appraisal->getSubmitAt()->format('Ymd')) - strtotime(date('Ymd'))) / 60 60 24);
  983.             if ($user->getIsActive() == true && $daysRemaining >= -&& $daysRemaining <= 7) {
  984.                 $total++;
  985.                 $submitted $appraisal->getSubmittedAt() == null 'No' '<fg=black;bg=green>Yes</>';
  986.                 $submitDate '<options=bold>' $appraisal->getSubmitAt()->format('d/m/Y') . '</>';
  987.                 if ($appraisal->getReviewAt() != null) {
  988.                     $activeState $appraisal->getReviewAt()->format('Ymd') >= date('Ymd') ? 'Yes' 'No';
  989.                     $reviewed $appraisal->getReviewedAt() == null 'No' 'Yes';
  990.                     $reviewDate $appraisal->getReviewAt()->format('d/m/Y');
  991.                 } else {
  992.                     $activeState 'Yes';
  993.                     $reviewed '-';
  994.                     $reviewDate '-';
  995.                 }
  996.                 array_push($rows, [
  997.                     count($rows) + 1,
  998.                     $appraisal->getId(),
  999.                     $user->getPersonalInfo()->getFullName(),
  1000.                     $appraisal->getTitle(),
  1001.                     $submitDate ' (in ' $daysRemaining ' day/s)',
  1002.                     $submitted,
  1003.                     '<options=bold>' $reviewDate '</>',
  1004.                     $reviewed,
  1005.                     $appraisal->getlastReminder() == null '-' $appraisal->getlastReminder()->format('d/m/Y H:i:s'),
  1006.                     $activeState
  1007.                 ]);
  1008.                 //$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().$todayMarker.' (Join: '.$joinDate.', Expiry: '.$expiryDate.', <fg=black;bg=white>Submit: '.$submitDate.', Review: '.$reviewDate.'</>)');
  1009.             };
  1010.         };
  1011.         $io->table($headers$rows);
  1012.         $io->success($total ' active appraisal!');
  1013.     }
  1014.     protected function remindAppraisal($force$input$output// TODO: add force
  1015.     {
  1016.         $io = new SymfonyStyle($input$output);
  1017.         $appraisals $this->entityManager->getRepository(Appraisal::class)->findActiveAppraisal();
  1018.         $total 0;
  1019.         $io->title('Appraisal Reminder');
  1020.         $headers = ['ID''Full Name''Title''Status''Deadline''Last Reminder''Sending User''Sending Manager'];
  1021.         $rows = [];
  1022.         foreach ($appraisals as $appraisal) {
  1023.             $user $appraisal->getUser();
  1024.             $sending 'No';
  1025.             $sendingManager false;
  1026.             $deadline false;
  1027.             //$status = $appraisal->getReviewedAt() == null ? 'Need to submit before '.$appraisal->getSubmitAt()->format('Y-m-d');
  1028.             //$daysRemainingUser = floor((strtotime($appraisal->getSubmitAt()->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
  1029.             $daysRemainingUser $this->date_diff_weekdays(date('Ymd'), $appraisal->getSubmitAt()->format('Ymd'));
  1030.             $attributes =  $appraisal->getUser()->assignedCompany()->getAttributes();
  1031.             if (!isset($attributes['appraisalManagerSubmitAt'])) continue;
  1032.             $managerSubmitDate =  new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']);
  1033.             //$daysRemainingManager = floor((strtotime($managerSubmitDate->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
  1034.             $daysRemainingManager $this->date_diff_weekdays(date('Ymd'), $managerSubmitDate->format('Ymd'));
  1035.             if ($user->getIsActive() == true) { // 3 days before deadline
  1036.                 $reminderStatus null;
  1037.                 if ($user->inProbation() == false && $appraisal->getSubmittedAt() != null && $appraisal->getReviewedAt() == null && $daysRemainingManager == 3) { // Manager Turn
  1038.                     $sending false;
  1039.                     $sendingManager $this->appraisalService->remindAppraisal($appraisal'manager');
  1040.                     $reminderStatus 'Manager: submit reminder';
  1041.                     //$deadline = $appraisal->getUser()->getPersonalInfo()->getJobExpiryDate() ? $appraisal->getUser()->getPersonalInfo()->getJobExpiryDate()->format('d/m/Y') : false;
  1042.                     $deadline $managerSubmitDate->format('d/m/Y');
  1043.                 } elseif ($appraisal->getSubmittedAt() == null && $daysRemainingUser == || $appraisal->getSubmittedAt() == null && $daysRemainingUser == -1) { // User turn
  1044.                     if ($appraisal->getSubmitAt()->format('Ymd') < date('Ymd')) { // Missed deadline
  1045.                         $sending $this->appraisalService->missedAppraisal($appraisal'user');
  1046.                         //$sending = true;
  1047.                         $reminderStatus 'User: missed deadline';
  1048.                     } else { // Waiting user fill the form
  1049.                         $sending $this->appraisalService->remindAppraisal($appraisal'user');
  1050.                         //$sending = true;
  1051.                         $reminderStatus 'User: submit reminder';
  1052.                     };
  1053.                     $deadline $appraisal->getSubmitAt()->format('d/m/Y');
  1054.                 }
  1055.                 if ($reminderStatus) {
  1056.                     //$io->text('<fg=black;bg=white>'.$reminderStatus.'</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
  1057.                     array_push($rows, [
  1058.                         $appraisal->getId(),
  1059.                         $user->getPersonalInfo()->getFullName(),
  1060.                         '[' $appraisal->getId() . '] ' $appraisal->getTitle(),
  1061.                         $reminderStatus,
  1062.                         $deadline $deadline ' (in ' $daysRemainingUser ' day/s)' '-',
  1063.                         $appraisal->getlastReminder() ? $appraisal->getlastReminder()->format('d/m/Y H:i:s') : '-',
  1064.                         $sending '<fg=black;bg=green>Yes</>' 'No',
  1065.                         $sendingManager '<fg=black;bg=green>Yes</>' 'No'
  1066.                     ]);
  1067.                     if ($sending || $sendingManager$total++;
  1068.                 };
  1069.                 // if(count($user->activeAppraisals()) == 0){
  1070.                 //     $submitAt = $user->getPersonalInfo()->getJobExpiryDate()->modify('-14 days');
  1071.                 //     $this->appraisalService->initiateAppraisal(false, $user->getManager(), $user, $this->translator->trans('email.appraisal.probation'), $submitAt);
  1072.                 //     $io->text('<fg=black;bg=white>Schedule Probation</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
  1073.                 //     $daysRemaining = floor((strtotime($user->getPersonalInfo()->getJobExpiryDate()->modify('-'.$this->initiateDay.' days')->format('Ymd')) - strtotime(date('Ymd')))/60/60/24);
  1074.                 //     $io->text('<fg=black;bg=white>Remind Appraisal</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
  1075.                 //     $total++;
  1076.                 // };
  1077.             };
  1078.         };
  1079.         $io->table($headers$rows);
  1080.         $io->success($total ' user reminded!');
  1081.         return $total true false;
  1082.         //return json_decode($response->getContent(),true);
  1083.     }
  1084.     protected function clearAppraisalReminder($input$output)
  1085.     {
  1086.         $io = new SymfonyStyle($input$output);
  1087.         $appraisals $this->entityManager->getRepository(Appraisal::class)->findActiveAppraisal();
  1088.         $total 0;
  1089.         foreach ($appraisals as $appraisal) {
  1090.             $user $appraisal->getUser();
  1091.             if ($user->getIsActive() == true and $appraisal->getLastReminder() != null and $appraisal->getLastReminder()->format('Ymd') <= date('Ymd')) {
  1092.                 $appraisal->setLastReminder(null);
  1093.                 $this->entityManager->flush();
  1094.                 $total++;
  1095.             };
  1096.         };
  1097.         $io->success($total ' user reminder cleared!');
  1098.         return $total true false;
  1099.     }
  1100.     protected function remindObjective($force$input$output)
  1101.     {
  1102.         $io = new SymfonyStyle($input$output);
  1103.         $users $this->entityManager->getRepository(User::class)->findAllActive();
  1104.         $total 0;
  1105.         $io->title('Objective Reminder');
  1106.         $headers = ['Full Name''Last Reminder''Sending'];
  1107.         $rows = [];
  1108.         foreach ($users as $user) {
  1109.             $sending 'No';
  1110.             try {
  1111.                 $reminderLog $user->getReminder();
  1112.                 $now = new \DateTime();
  1113.                 $sending $user->getIsActive();
  1114.                 $appraisal $user->latestAppraisal();
  1115.                 // TODO: Need to refactor code below to make it more efficient
  1116.                 if (isset($reminderLog['objective']) && $reminderLog['objective']->format('Ymd') == $now->format('Ymd') && !$force$sending =  false;
  1117.                 if (!isset($appraisal) || $appraisal->getReviewAt() == null) continue;
  1118.                 if ($user->totalObjective() == && $user->inProbation() == false && $appraisal->getReviewAt()->modify('+ 1 weeks')->format('Ymd') == date('Ymd')) {
  1119.                     if ($sending == true) {
  1120.                         $this->mailgunService->sendEmail(
  1121.                             $this->translator->trans('email.appraisal.reminder.objective.user', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
  1122.                             [$user->getEmail()],
  1123.                             'email/user-notification/appraisal/reminder-objective.html.twig',
  1124.                             [
  1125.                                 'recipient' => $user,
  1126.                                 'user' => $user,
  1127.                                 'group' => 'user',
  1128.                                 'appraisal' => $appraisal
  1129.                             ],
  1130.                             false
  1131.                         );
  1132.                         foreach ($user->getAllManager() as $manager) {
  1133.                             $this->mailgunService->sendEmail(
  1134.                                 $this->translator->trans('email.appraisal.reminder.objective.manager', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
  1135.                                 [$manager->getEmail()],
  1136.                                 'email/user-notification/appraisal/reminder-objective.html.twig',
  1137.                                 [
  1138.                                     'recipient' => $manager,
  1139.                                     'user' => $user,
  1140.                                     'group' => 'manager',
  1141.                                     'appraisal' => $appraisal
  1142.                                 ],
  1143.                                 false
  1144.                             );
  1145.                         };
  1146.                     }
  1147.                     if ($sending$total++;
  1148.                     array_push($rows, [
  1149.                         $user->getPersonalInfo()->getFullName() ?  $user->getPersonalInfo()->getFullName() : '-',
  1150.                         isset($reminderLog['objective']) ? $reminderLog['objective']->format('d/m/Y H:i:s') : '-',
  1151.                         $sending 'Yes' 'No'
  1152.                     ]);
  1153.                     $reminderLog['objective'] = $now;
  1154.                     $user->setReminder($reminderLog);
  1155.                 };
  1156.             } catch (Exception $e) {
  1157.                 continue;
  1158.             }
  1159.         };
  1160.         $this->entityManager->flush();
  1161.         $io->table($headers$rows);
  1162.         $io->success($total ' user reminded!');
  1163.         return $total true false;
  1164.         //return json_decode($response->getContent(),true);
  1165.     }
  1166.     protected function remindSummary($appraisals$input$output)
  1167.     {
  1168.         $io = new SymfonyStyle($input$output);
  1169.         $total 0;
  1170.         $io->title('Summary Reminder');
  1171.         $headers = ['Title''User''Manager''Review At'];
  1172.         $rows = [];
  1173.         foreach ($appraisals as $appraisal) {
  1174.             try {
  1175.                 $user $appraisal->getUser();
  1176.                 $manager $user->getManager();
  1177.                 $sent $this->mailgunService->sendEmail(
  1178.                     $this->translator->trans('email.appraisal.reminder.summary', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
  1179.                     [$manager->getEmail()],
  1180.                     'email/user-notification/appraisal/reminder-summary.html.twig',
  1181.                     [
  1182.                         'recipient' => $manager,
  1183.                         'user' => $user,
  1184.                         'appraisal' => $appraisal,
  1185.                         'group' => 'user',
  1186.                     ],
  1187.                     false
  1188.                 );
  1189.                 if ($sent$total++;
  1190.                 array_push($rows, [
  1191.                     $appraisal->getTitle(),
  1192.                     $user->getPersonalInfo()->getFullName() ?  $user->getPersonalInfo()->getFullName() : $user->getEmail(),
  1193.                     $manager && $manager->getPersonalInfo()->getFullName() ? $manager->getPersonalInfo()->getFullName() : '-',
  1194.                     $appraisal->getReviewAt() ? $appraisal->getReviewAt()->format('d/m/Y H:i:s') : '-'
  1195.                 ]);
  1196.             } catch (Exception $e) {
  1197.                 continue;
  1198.             }
  1199.         };
  1200.         $this->entityManager->flush();
  1201.         $io->table($headers$rows);
  1202.         $io->success($total ' manager reminded!');
  1203.         return $total true false;
  1204.         //return json_decode($response->getContent(),true);
  1205.     }
  1206.     protected function onboardingEmail($force false$input$output)
  1207.     {
  1208.         $io = new SymfonyStyle($input$output);
  1209.         $users $this->entityManager->getRepository(User::class)->findByOnboarding();
  1210.         $total 0;
  1211.         $io->title('Onboarding email');
  1212.         $headers = ['Full Name''Email''Join date''E.Inventory''E.Welcome'];
  1213.         $rows = [];
  1214.         $now = new \DateTime();
  1215.         foreach ($users as $user) {
  1216.             $emailInventory false;
  1217.             $emailWelcome false;
  1218.             try {
  1219.                 $reminderLog $user->getReminder();
  1220.                 if (!isset($reminderLog['onboardingEmail']) || $force) {
  1221.                     $emailWelcome $this->userService->welcomeEmail(false$user);
  1222.                     if ($emailWelcome$total++;
  1223.                 };
  1224.                 if (!isset($reminderLog['onboardingInventoryEmail']) || $force) {
  1225.                     $emailInventory $this->userService->notifyInventoryPrior(false$user);
  1226.                     if ($emailInventory$total++;
  1227.                 };
  1228.                 array_push($rows, [
  1229.                     $user->getPersonalInfo()->getFullName(),
  1230.                     $user->getEmail(),
  1231.                     $user->getPersonalInfo()->getJobJoinDate()->format('d/m/Y'),
  1232.                     $emailInventory 'Yes' 'No',
  1233.                     $emailWelcome 'Yes' 'No'
  1234.                 ]);
  1235.             } catch (Exception $e) {
  1236.                 continue;
  1237.             }
  1238.         };
  1239.         $this->entityManager->flush();
  1240.         $io->table($headers$rows);
  1241.         $io->success($total ' onboarding email sent!');
  1242.         return $total true false;
  1243.     }
  1244.     function offboardingEmail($force false$input$output)
  1245.     {
  1246.         $io = new SymfonyStyle($input$output);
  1247.         $users $this->entityManager->getRepository(User::class)->findByOffboarding();
  1248.         $total 0;
  1249.         $io->title('Offboarding email');
  1250.         $headers = ['Full Name''Email''Termination date''E.Prior''E.Day''E.Past'];
  1251.         $rows = [];
  1252.         $emailGroup $this->params->get('systemEmailGroup');
  1253.         $now = new \DateTime();
  1254.         foreach ($users as $user) {
  1255.             $sending false;
  1256.             $emailPrior false;
  1257.             $emailDay false;
  1258.             $emailPast false;
  1259.             try {
  1260.                 $reminderLog $user->getReminder();
  1261.                 $terminateDate $user->getPersonalInfo()->getJobTerminateDate();
  1262.                 if (!isset($reminderLog['offboardingEmailPrior']) || $force) {
  1263.                     $emailPrior $this->userService->notifyTerminationPrior(false$user);
  1264.                     if ($emailPrior$total++;
  1265.                 }
  1266.                 if (!isset($reminderLog['offboardingEmailDay']) || $force) {
  1267.                     $emailDay $this->userService->notifyTerminationDay(false$user);
  1268.                     if ($emailDay$total++;
  1269.                 }
  1270.                 if (!isset($reminderLog['offboardingEmailPast']) || $force) {
  1271.                     $emailPast $this->userService->notifyTerminationPast(false$user);
  1272.                     if ($emailPast$total++;
  1273.                 }
  1274.                 array_push($rows, [
  1275.                     $user->getPersonalInfo()->getFullName(),
  1276.                     $user->getEmail(),
  1277.                     $terminateDate->format('Ymd') < $now->format('Ymd') ? '<fg=white;bg=red>' $terminateDate->format('d/m/Y') . '</>' $terminateDate->format('d/m/Y'),
  1278.                     $emailPrior 'Yes' 'No',
  1279.                     $emailDay 'Yes' 'No',
  1280.                     $emailPast 'Yes' 'No'
  1281.                 ]);
  1282.             } catch (Exception $e) {
  1283.                 continue;
  1284.             }
  1285.         };
  1286.         $this->entityManager->flush();
  1287.         $io->table($headers$rows);
  1288.         $io->success($total ' offboarding email sent!');
  1289.         return $total true false;
  1290.     }
  1291.     protected function remindLeave($input$output)
  1292.     {
  1293.         $io = new SymfonyStyle($input$output);
  1294.         $leaves $this->entityManager->getRepository(LeaveRequest::class)->findUncheckLeaveRequest();
  1295.         $total 0;
  1296.         $io->title('Leave request reminder');
  1297.         $headers = ['Created At''Name''Start''End''Days''Days Left''Last Reminder''Sending'];
  1298.         $rows = [];
  1299.         foreach ($leaves as $leave) {
  1300.             $user $leave->getUser();
  1301.             $sending =  false;
  1302.             try {
  1303.                 if ($user->getIsActive() == true and ($leave->getLastReminder() == null or $leave->getLastReminder()->format('Ymd') < date('Ymd'))) {
  1304.                     $this->leaveService->reminderRequestLeaveEmail($leave$user);
  1305.                     $leave->setLastReminder(new \DateTime());
  1306.                     $this->entityManager->flush();
  1307.                     $sending true;
  1308.                     $total++;
  1309.                 }
  1310.                 array_push($rows, [
  1311.                     $leave->getCreatedAt()->format('d/m/Y'),
  1312.                     $user->getPersonalInfo()->getFullName(),
  1313.                     $leave->getStartDate()->format('d/m/Y'),
  1314.                     $leave->getEndDate()->format('d/m/Y'),
  1315.                     $leave->getDays(),
  1316.                     $leave->getDaysLeft(),
  1317.                     $leave->getlastReminder() ? $leave->getlastReminder()->format('d/m/Y H:i:s') : '-',
  1318.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1319.                 ]);
  1320.             } catch (Exception $e) {
  1321.                 $sending =  false;
  1322.                 continue;
  1323.             }
  1324.         }
  1325.         //$this->entityManager->flush();
  1326.         $io->table($headers$rows);
  1327.         $io->success($total ' leave request reminder email sent!');
  1328.     }
  1329.     protected function clearLeaveReminder($input$output)
  1330.     {
  1331.         $io = new SymfonyStyle($input$output);
  1332.         $leaves $this->entityManager->getRepository(LeaveRequest::class)->findUncheckLeaveRequest();
  1333.         $total 0;
  1334.         foreach ($leaves as $leave) {
  1335.             $user $leave->getUser();
  1336.             if ($user->getIsActive() == true and $leave->getLastReminder() != null and $leave->getLastReminder()->format('Ymd') <= date('Ymd')) {
  1337.                 $leave->setLastReminder(null);
  1338.                 $this->entityManager->flush();
  1339.                 $total++;
  1340.             };
  1341.         };
  1342.         $io->success($total ' leave request reminder cleared!');
  1343.         return $total true false;
  1344.     }
  1345.     protected function dailyLeave($force false$input$output)
  1346.     {
  1347.         $io = new SymfonyStyle($input$output);
  1348.         $total 0;
  1349.         $now = new \DateTime();
  1350.         $companies $this->entityManager->getRepository(Company::class)->findAll();
  1351.         foreach ($companies as $company) {
  1352.             if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
  1353.             $reminderLog $company->getReminder();
  1354.             $leaves $this->entityManager->getRepository(LeaveRequest::class)->findTodayLeaveByCompany($company,-1);            
  1355.             if ($leaves) {
  1356.                 try {
  1357.                     if (isset($reminderLog['dailyLeave']) && $reminderLog['dailyLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1358.                     $io->text('<fg=black;bg=white>' $company->getFullName() . '</>: ' count($leaves) . ' user leave request today');
  1359.                     $leaveData=array();
  1360.                     $c=0;
  1361.                     foreach($leaves as $l){
  1362.                         $ok=false;
  1363.                         if($l->getLeaveType()->getLeaveName()=='sick'){
  1364.                             $ok=true;
  1365.                         }else{
  1366.                             if(!is_null($l->getIsApproved())){
  1367.                                 if(($l->getIsApproved()==1) || ($l->getIsApproved()===true)){
  1368.                                     $ok=true;
  1369.                                 }
  1370.                             }
  1371.                         }
  1372.                         if($ok){    
  1373.                             $c=count($leaveData);
  1374.                             $leaveData[$c]['name']=$l->getUser()->getPersonalInfo()->getFullName();
  1375.                             $leaveData[$c]['User']=$l->getUser();
  1376.                             $leaveData[$c]['leavetype']=$l->getLeaveType()->getLeaveName();
  1377.                             $lattr=$l->getLeaveType()->getAttributes();
  1378.                             if(!is_null($lattr)){
  1379.                                 if(isset($lattr['lable'])){ $leaveData[$c]['leavetype']=$lattr['lable'];}
  1380.                             }
  1381.                             $leaveData[$c]['days']=$l->getDays();
  1382.                             $leaveData[$c]['periode']='';
  1383.                             $txt='';
  1384.                             $attr=$l->getAttributes();
  1385.                             $daterg=array();
  1386.                             if(!is_null($attr)){
  1387.                                 if(isset($attr['historymc'])){
  1388.                                     if(isset($attr['manualapproved']) || isset($attr['manualappoved'])){
  1389.                                     $mcmanual=null;
  1390.                                     foreach($attr['historymc'] as $m){
  1391.                                         $mcmanual=$m;
  1392.                                     }
  1393.                                     if(!is_null($mcmanual)){
  1394.                                         $m=$mcmanual;
  1395.                                         if(isset($m['startDate'])){
  1396.                                             $dtstart=new \DateTime($m['startDate']);
  1397.                                         }else{
  1398.                                             $dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
  1399.                                         }
  1400.                                         if(isset($m['endDate'])){
  1401.                                             $dtend=new \DateTime($m['endDate']);
  1402.                                         }else{
  1403.                                             $dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
  1404.                                         }
  1405.                                         
  1406.                                         $intl=date_diff($dtend,$dtstart);
  1407.                                         if(isset($m['am'])){
  1408.                                             $am=$m['am'];
  1409.                                         }else{
  1410.                                             $am=$l->getIsHalfStart();
  1411.                                             if(is_null($am)){$am=false;}
  1412.                                         }
  1413.                                         if(isset($m['pm'])){
  1414.                                             $pm=$m['pm'];
  1415.                                         }else{
  1416.                                             $pm=$l->getIsHalfEnd();
  1417.                                         }
  1418.                                         
  1419.                                         if(($pm==false) && ($pm==false)){
  1420.                                             $am='';$pm='';
  1421.                                         }else{
  1422.                                             $am=$am?' PM':' AM';
  1423.                                             $pm=$pm?' AM':' PM';
  1424.                                         }
  1425.                                         if((abs($intl->d) + 1) > 1){
  1426.                                             $txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
  1427.                                         }else{
  1428.                                             $txt.=$dtstart->format('d M Y').$pm.', ';
  1429.                                         }
  1430.                                     }
  1431.                                     } else{   
  1432.                                         foreach($attr['historymc'] as $m){
  1433.                                             if(isset($m['startDate'])){
  1434.                                                 $dtstart=new \DateTime($m['startDate']);
  1435.                                             }else{
  1436.                                                 $dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
  1437.                                             }
  1438.                                             if(isset($m['endDate'])){
  1439.                                                 $dtend=new \DateTime($m['endDate']);
  1440.                                             }else{
  1441.                                                 $dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
  1442.                                             }
  1443.                                             $intl=date_diff($dtend,$dtstart);
  1444.                                             if(isset($m['am'])){
  1445.                                                 $am=$m['am'];
  1446.                                             }else{
  1447.                                                 $am=$l->getIsHalfStart();
  1448.                                                 if(is_null($am)){$am=false;}
  1449.                                             }
  1450.                                             if(isset($m['pm'])){
  1451.                                                 $pm=$m['pm'];
  1452.                                             }else{
  1453.                                                 $pm=$l->getIsHalfEnd();
  1454.                                             }
  1455.                                             
  1456.                                             if(($pm==false) && ($pm==false)){
  1457.                                                 $am='';$pm='';
  1458.                                             }else{
  1459.                                                 $am=$am?' PM':' AM';
  1460.                                                 $pm=$pm?' AM':' PM';
  1461.                                             }
  1462.                                             
  1463.                                             if((abs($intl->d) + 1) > 1){
  1464.                                                 $txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
  1465.                                             }else{
  1466.                                                 $txt.=$dtstart->format('d M Y').$pm.', ';
  1467.                                             }
  1468.                                         }
  1469.                                     }   
  1470.                                 }else{
  1471.                                     $dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
  1472.                                     $dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
  1473.                                     
  1474.                                     $intl=date_diff($dtend,$dtstart);
  1475.                                     $am=$l->getIsHalfStart();
  1476.                                     $pm=$l->getIsHalfEnd();
  1477.                                     if(is_null($am)){$am=false;}
  1478.                                     if(is_null($pm)){$pm=false;}
  1479.                                     if(($am==false) && ($pm==false)){
  1480.                                         $am='';$pm='';
  1481.                                     }else{
  1482.                                         $am=$am?' PM':' AM';
  1483.                                         $pm=$pm?' AM':' PM';
  1484.                                     }
  1485.                                     if(abs($intl->d) >= 1){
  1486.                                         $txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
  1487.                                     }else{
  1488.                                         $txt.=$dtstart->format('d M Y').$pm.', ';
  1489.                                     }     
  1490.                                 }
  1491.                             }else{
  1492.                                 $dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
  1493.                                 $dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
  1494.                                 $intl=date_diff($dtend,$dtstart);
  1495.                                 $am=$l->getIsHalfStart();
  1496.                                 $pm=$l->getIsHalfEnd();
  1497.                                 if(is_null($am)){$am=false;}
  1498.                                 if(is_null($pm)){$pm=false;}
  1499.                                 if(($am==false) && ($pm==false)){
  1500.                                     $am='';$pm='';
  1501.                                 }else{
  1502.                                     $am=$am?' PM':' AM';
  1503.                                     $pm=$pm?' AM':' PM';
  1504.                                 }
  1505.                                 if(abs($intl->d) >= 1){
  1506.                                     $txt.=$dtstart->format('d M Y').$am.' - '.$dtend->format('d M Y').$pm.', ';
  1507.                                 }else{
  1508.                                     $txt.=$dtstart->format('d M Y').$pm.', ';
  1509.                                 }   
  1510.                             }
  1511.                             $txt=trim($txt);
  1512.                             $txt=trim($txt,',');
  1513.                             $txt=explode(',',$txt);
  1514.                             $txt=join('<br>',$txt);
  1515.                             
  1516.                             $leaveData[$c]['periode']=$txt;
  1517.                         }    
  1518.                     }          
  1519.                     $this->leaveService->dailyLeaveEmail($leaveData);
  1520.                     $total++;
  1521.                     $reminderLog['dailyLeave'] = $now;
  1522.                     $company->setReminder($reminderLog);
  1523.                     $this->entityManager->flush();
  1524.                 } catch (Exception $e) {
  1525.                     $io->caution('Email sending error!');
  1526.                     continue;
  1527.                 }   
  1528.             };
  1529.         }
  1530.         $io->success($total ' company daily email sent!');
  1531.     }
  1532.     protected function weeklyLeave($force false$input$output)
  1533.     {
  1534.         $io = new SymfonyStyle($input$output);
  1535.         if (date('N') == || $force == true) {
  1536.             $total 0;
  1537.             $now = new \DateTime();
  1538.             $companies $this->entityManager->getRepository(Company::class)->findAll();
  1539.             foreach ($companies as $company) {
  1540.                 if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
  1541.                 $reminderLog $company->getReminder();
  1542.                 $leaves $this->entityManager->getRepository(LeaveRequest::class)->findNextWeekLeaveByCompany($company);
  1543.                 if ($leaves) {
  1544.                     try {
  1545.                         if (isset($reminderLog['weeklyLeave']) && $reminderLog['weeklyLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1546.                         $io->text('<fg=black;bg=white>' $company->getFullName() . '</>: ' count($leaves) . ' user on leave next week');
  1547.                         $this->leaveService->weeklyLeaveEmail($leaves);
  1548.                         $total++;
  1549.                     } catch (Exception $e) {
  1550.                         $io->caution('Email sending error!');
  1551.                         continue;
  1552.                     }
  1553.                     $reminderLog['weeklyLeave'] = $now;
  1554.                     $company->setReminder($reminderLog);
  1555.                 };
  1556.                 $this->entityManager->flush();
  1557.             }
  1558.             $io->success($total ' company weekly leave email sent!');
  1559.         } else {
  1560.             $io->warning('Command only can be run on friday!');
  1561.         };
  1562.     }
  1563.     protected function weeklyHoliday($force false$test false,  $input$output)
  1564.     {
  1565.         $io = new SymfonyStyle($input$output);
  1566.         $email $test 'devops@mediatropy.com' null;
  1567.         if ($test$io->text('[Test Mode]');
  1568.         if (date('N') == || $force == true) {
  1569.             $total 0;
  1570.             $now = new \DateTime();
  1571.             $companies $this->entityManager->getRepository(Company::class)->findAll();
  1572.             foreach ($companies as $company) {
  1573.                 if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
  1574.                 $reminderLog $company->getReminder();
  1575.                 $holidays $this->entityManager->getRepository(LeaveBankHoliday::class)->findNextWeekHolidayByCompany($company);
  1576.                 if ($holidays) {
  1577.                     try {
  1578.                         if (isset($reminderLog['weeklyHoliday']) && $reminderLog['weeklyHoliday']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1579.                         $io->text('<fg=black;bg=white>' $company->getFullName() . '</>: ' count($holidays) . ' public holiday on next week');
  1580.                         $this->leaveService->weeklyHolidayEmail($holidays$email);
  1581.                         $total++;
  1582.                     } catch (Exception $e) {
  1583.                         $io->warning('Email sending error!');
  1584.                         continue;
  1585.                     }
  1586.                     if (!$test$reminderLog['weeklyHoliday'] = $now;
  1587.                     $company->setReminder($reminderLog);
  1588.                 };
  1589.                 $this->entityManager->flush();
  1590.             }
  1591.             $io->success($total ' company weekly holiday email sent!');
  1592.         } else {
  1593.             $io->caution('Command only can be run on friday!');
  1594.         }
  1595.     }
  1596.     protected function remindExpireLeave($force false$input$output)
  1597.     {
  1598.         $io = new SymfonyStyle($input$output);
  1599.         $leaves $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireNextMonth();
  1600.         $total 0;
  1601.         $io->title('Leave expire reminder');
  1602.         $headers = ['Name''leaveType''Days Left''Sending'];
  1603.         $rows = [];
  1604.         foreach ($leaves as $leave) {
  1605.             $user $leave->getUser();
  1606.             $sending =  false;
  1607.             try {
  1608.                 $reminderLog $user->getReminder();
  1609.                 $now = new \DateTime();
  1610.                 if (isset($reminderLog['expireLeave']) && $reminderLog['expireLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1611.                 if ($user->getIsActive() == true) {
  1612.                     $this->leaveService->reminderExpireLeaveEmail($leave);
  1613.                     $sending true;
  1614.                     $total++;
  1615.                 }
  1616.                 array_push($rows, [
  1617.                     $user->getPersonalInfo()->getFullName(),
  1618.                     $leave->getLeaveType()->getAttributes()['label'],
  1619.                     $leave->getLeaveLeft(),
  1620.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1621.                 ]);
  1622.                 $reminderLog['expireLeave'] = $now;
  1623.                 $user->setReminder($reminderLog);
  1624.             } catch (Exception $e) {
  1625.                 $sending =  false;
  1626.                 continue;
  1627.             }
  1628.         }
  1629.         $this->entityManager->flush();
  1630.         $io->table($headers$rows);
  1631.         $io->success($total ' leave expire reminder email sent!');
  1632.     }
  1633.     protected function remindExpireAnnualLeave($force false$input$output)
  1634.     {
  1635.         $io = new SymfonyStyle($input$output);
  1636.         // $now = '0108';
  1637.         $now date('dm');
  1638.         if ($now == '0108' || $now == '0111'  || $force == true) {
  1639.             $leaves $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireAnnualLeave();
  1640.             $total 0;
  1641.             $io->title('Leave expire reminder');
  1642.             $headers = ['Name''leaveType''Days Left''Sending'];
  1643.             $rows = [];
  1644.             foreach ($leaves as $leave) {
  1645.                 $user $leave->getUser();
  1646.                 $sending =  false;
  1647.                 try {
  1648.                     $reminderLog $user->getReminder();
  1649.                     $now = new \DateTime();
  1650.                     if (isset($reminderLog['expireAnnualLeave']) && $reminderLog['expireAnnualLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1651.                     if ($user->getIsActive() == true) {
  1652.                         $this->leaveService->reminderExpireAnnualLeaveEmail($leave);
  1653.                         $sending true;
  1654.                         $total++;
  1655.                     }
  1656.                     array_push($rows, [
  1657.                         $user->getPersonalInfo()->getFullName(),
  1658.                         $leave->getLeaveType()->getAttributes()['label'],
  1659.                         $leave->getLeaveLeft(),
  1660.                         $sending '<fg=black;bg=green>Yes</>' 'No'
  1661.                     ]);
  1662.                     $reminderLog['expireAnnualLeave'] = $now;
  1663.                     $user->setReminder($reminderLog);
  1664.                 } catch (Exception $e) {
  1665.                     $sending =  false;
  1666.                     continue;
  1667.                 }
  1668.             }
  1669.             $this->entityManager->flush();
  1670.             $io->table($headers$rows);
  1671.             $io->success($total ' annual leave expire reminder email sent!');
  1672.         }else{
  1673.             $io->caution('Command only can be run on 1st August & 1st November!');
  1674.         }
  1675.     }
  1676.     protected function remindExpireCarryForwardLeave($force false$input$output)
  1677.     {
  1678.         $io = new SymfonyStyle($input$output);
  1679.             // $now = '0101';
  1680.         $now date('dm');
  1681.         if ($now == '0101' || $now == '0102'  || $force == true) {
  1682.             $leaves $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireCarryForwardLeave();
  1683.             $total 0;
  1684.             $io->title('Leave expire reminder');
  1685.             $headers = ['Name''leaveType''Days Left''Sending'];
  1686.             $rows = [];
  1687.             foreach ($leaves as $leave) {
  1688.                 $user $leave['user'];
  1689.                 $sending =  false;
  1690.                 try {
  1691.                     if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  1692.                     $reminderLog $user->getReminder();
  1693.                     $now = new \DateTime();
  1694.                     if (isset($reminderLog['expireCarryForwardLeave']) && $reminderLog['expireCarryForwardLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1695.                     if ($user->getIsActive() == true) {
  1696.                         $this->leaveService->reminderExpireCarryForwardLeaveEmail($leave);
  1697.                         $sending true;
  1698.                         $total++;
  1699.                     }
  1700.                     array_push($rows, [
  1701.                         $user->getPersonalInfo()->getFullName(),
  1702.                         'Carry Over '.$leave['year'],
  1703.                         $leave['carryLeft'],
  1704.                         $sending '<fg=black;bg=green>Yes</>' 'No'
  1705.                     ]);
  1706.                     $reminderLog['expireCarryForwardLeave'] = $now;
  1707.                     $user->setReminder($reminderLog);
  1708.                 } catch (Exception $e) {
  1709.                     $sending =  false;
  1710.                     continue;
  1711.                 }
  1712.             }
  1713.             $this->entityManager->flush();
  1714.             $io->table($headers$rows);
  1715.             $io->success($total ' carry forward leave expire reminder email sent!');
  1716.         }else{
  1717.             $io->caution('Command only can be run on 1st January & 1st February!');
  1718.         }
  1719.     }
  1720.     protected function remindExpireAdjustmentLeave($force false$input$output)
  1721.     {
  1722.         $io = new SymfonyStyle($input$output);
  1723.         $leaves $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireAdjustment();
  1724.             $total 0;
  1725.             $io->title('Adjustment leave expire reminder');
  1726.             $headers = ['Name''leaveType''Days Left''Sending'];
  1727.             $rows = [];
  1728.             foreach ($leaves as $leave) {
  1729.                 $user $leave->getUser();
  1730.                 $sending =  false;
  1731.                 try {
  1732.                     if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  1733.                     $reminderLog $user->getReminder();
  1734.                     $now = new \DateTime();
  1735.                     if (isset($reminderLog['expireAdjLeave']) && $reminderLog['expireAdjLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1736.                     if ($user->getIsActive() == true) {
  1737.                         $this->leaveService->reminderExpireBonusAdjLeaveEmail($leave);
  1738.                         $notificationData = [
  1739.                             '%user%' => $user->getPersonalInfo()->getFirstName(),
  1740.                         ];
  1741.                         $this->notificationService->push($user'notification.leave.adjustment'null'i-holiday-svg'nulltrue);
  1742.                         $sending true;
  1743.                         $total++;
  1744.                     }
  1745.                     array_push($rows, [
  1746.                         $user->getPersonalInfo()->getFullName(),
  1747.                         $leave->getLeaveType()->getAttributes()['label'],
  1748.                         $leave->getLeaveLeft(),
  1749.                         $sending '<fg=black;bg=green>Yes</>' 'No'
  1750.                     ]);
  1751.                     $reminderLog['expireAdjLeave'] = $now;
  1752.                     $user->setReminder($reminderLog);
  1753.                 } catch (Exception $e) {
  1754.                     $sending =  false;
  1755.                     continue;
  1756.                 }
  1757.             }
  1758.             $this->entityManager->flush();
  1759.             $io->table($headers$rows);
  1760.             $io->success($total ' Adjustment leave expire reminder email sent!');
  1761.     }
  1762.     protected function remindExpireBonusLeave($force false$input$output)
  1763.     {
  1764.         $io = new SymfonyStyle($input$output);
  1765.         $leaves $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireBonus();
  1766.             $total 0;
  1767.             $io->title('Bonus leave expire reminder');
  1768.             $headers = ['Name''leaveType''Days Left''Sending'];
  1769.             $rows = [];
  1770.             foreach ($leaves as $leave) {
  1771.                 $user $leave->getUser();
  1772.                 $sending =  false;
  1773.                 try {
  1774.                     if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
  1775.                     $reminderLog $user->getReminder();
  1776.                     $now = new \DateTime();
  1777.                     if (isset($reminderLog['expireBonusLeave']) && $reminderLog['expireBonusLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1778.                     if ($user->getIsActive() == true) {
  1779.                         $this->leaveService->reminderExpireBonusAdjLeaveEmail($leave);
  1780.                         $notificationData = [
  1781.                             '%user%' => $user->getPersonalInfo()->getFirstName(),
  1782.                         ];
  1783.                         $this->notificationService->push($user'notification.leave.bonus'null'i-holiday-svg'nulltrue);
  1784.                         $sending true;
  1785.                         $total++;
  1786.                     }
  1787.                     array_push($rows, [
  1788.                         $user->getPersonalInfo()->getFullName(),
  1789.                         $leave->getLeaveType()->getAttributes()['label'],
  1790.                         $leave->getLeaveLeft(),
  1791.                         $sending '<fg=black;bg=green>Yes</>' 'No'
  1792.                     ]);
  1793.                     $reminderLog['expireBonusLeave'] = $now;
  1794.                     $user->setReminder($reminderLog);
  1795.                 } catch (Exception $e) {
  1796.                     $sending =  false;
  1797.                     continue;
  1798.                 }
  1799.             }
  1800.             $this->entityManager->flush();
  1801.             $io->table($headers$rows);
  1802.             $io->success($total ' Bonus leave expire reminder email sent!');
  1803.     }
  1804.     protected function birthdayNow($force false$input$output)
  1805.     {
  1806.         $io = new SymfonyStyle($input$output);
  1807.         $users $this->entityManager->getRepository(User::class)->findBirthdayNow();
  1808.         $total 0;
  1809.         $io->title('Today Employee Birthday');
  1810.         $headers = ['Name''Birth Date''Sending'];
  1811.         $rows = [];
  1812.         foreach ($users as $user) {
  1813.             $sending =  false;
  1814.             try {
  1815.                 $reminderLog $user->getReminder();
  1816.                 $permission $user->getPermission();
  1817.                 $now = new \DateTime();
  1818.                 if (isset($reminderLog['birthdayNow']) && $reminderLog['birthdayNow']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1819.                 if ($user->getIsActive() == true && (isset($permission['birthdayAnnouncement']) && $permission['birthdayAnnouncement'] == true)) {
  1820.                     $this->userService->birthdayEmail($user);
  1821.                     $receivers $this->entityManager->getRepository(User::class)->findAllActive();
  1822.                     foreach ($receivers as $receiver) {
  1823.                         $notificationData = [
  1824.                             '%user%' => $user->getPersonalInfo()->getFirstName(),
  1825.                         ];
  1826.                         $this->notificationService->push($receiver'notification.user.birthday'$notificationData'i-cake'nulltrue);
  1827.                     }
  1828.                     $sending true;
  1829.                     $total++;
  1830.                     $reminderLog['birthdayNow'] = $now;
  1831.                     $user->setReminder($reminderLog);
  1832.                 };
  1833.                 array_push($rows, [
  1834.                     $user->getPersonalInfo()->getFullName(),
  1835.                     $user->getPersonalInfo()->getBirthDate()->format('d/m/Y'),
  1836.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1837.                 ]);
  1838.             } catch (Exception $e) {
  1839.                 $sending =  false;
  1840.                 continue;
  1841.             }
  1842.         }
  1843.         $this->entityManager->flush();
  1844.         $io->table($headers$rows);
  1845.         $io->success($total ' employee birthday email sent!');
  1846.     }
  1847.     protected function remindBirthday($force$input$output)
  1848.     {
  1849.         $io = new SymfonyStyle($input$output);
  1850.         $users $this->entityManager->getRepository(User::class)->findIncomingBirthday();
  1851.         $total 0;
  1852.         $io->title('Employee\'s birthday 3 days to come');
  1853.         $headers = ['Name''Birth Date''Sending'];
  1854.         $rows = [];
  1855.         foreach ($users as $user) {
  1856.             $sending =  false;
  1857.             try {
  1858.                 $reminderLog $user->getReminder();
  1859.                 $now = new \DateTime();
  1860.                 if (isset($reminderLog['remindBirthday']) && $reminderLog['remindBirthday']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
  1861.                 if ($user->getIsActive() == true) {
  1862.                     $this->userService->birthdayReminder($user);
  1863.                     $sending true;
  1864.                     $total++;
  1865.                 }
  1866.                 array_push($rows, [
  1867.                     $user->getPersonalInfo()->getFullName(),
  1868.                     $user->getPersonalInfo()->getBirthDate()->format('d/m/Y'),
  1869.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1870.                 ]);
  1871.                 $reminderLog['remindBirthday'] = $now;
  1872.                 $user->setReminder($reminderLog);
  1873.             } catch (Exception $e) {
  1874.                 $sending =  false;
  1875.                 continue;
  1876.             }
  1877.         }
  1878.         $this->entityManager->flush();
  1879.         $io->table($headers$rows);
  1880.         $io->success($total ' employee birthday reminder email sent!');
  1881.     }
  1882.     protected function leaveProRate($force false$input$output)
  1883.     {
  1884.         $io = new SymfonyStyle($input$output);
  1885.         $io->text('<fg=black;bg=white>Processing...</>');
  1886.         $total $this->leaveService->LeaveProRateCron($force);
  1887.         $io->success($total ' leave Pro Rate processed!');
  1888.     }
  1889.     protected function syncStatus($input$output)
  1890.     {
  1891.         $io = new SymfonyStyle($input$output);
  1892.         $io->text('<fg=black;bg=white>Processing...</>');
  1893.         $userLeaveIds $this->userService->syncStatusWithLeave();
  1894.         $affectedUsersId $this->userService->syncStatusWithWFA($userLeaveIds);
  1895.         $users $this->entityManager->getRepository(User::class)->findNotWorking($affectedUsersId);
  1896.         foreach ($users as $user) {
  1897.             if (!in_array($user->getId(), $affectedUsersId)) {
  1898.                 $user->setStatus('status.working_home');
  1899.             };
  1900.         }
  1901.         $this->entityManager->flush();
  1902.         $io->success('User status synced!');
  1903.     }
  1904.     static function date_diff_weekdays($from$to)
  1905.     {
  1906.         if ($from === null || $to === null)
  1907.             return null;
  1908.         $date_from = new \DateTime($from);
  1909.         $date_to = new \DateTime($to);
  1910.         // calculate number of weekdays from start of week - start date
  1911.         $from_day intval($date_from->format('w')); // 0 (for Sunday) through 6 (for Saturday)
  1912.         if ($from_day == 0)
  1913.             $from_day 7;
  1914.         $from_wdays $from_day $from_day;
  1915.         // calculate number of weekdays from start of week - end date
  1916.         $to_day intval($date_to->format('w'));
  1917.         if ($to_day == 0)
  1918.             $to_day 7;
  1919.         $to_wdays $to_day $to_day;
  1920.         // calculate number of days between the two dates
  1921.         $interval $date_from->diff($date_to);
  1922.         $days intval($interval->format('%R%a')); // shows negative values too
  1923.         // calculate number of full weeks between the two dates
  1924.         $weeks_between floor($days 7);
  1925.         if ($to_day >= $from_day)
  1926.             $weeks_between -= 1;
  1927.         // complete calculation of number of working days between
  1928.         $diff_wd * ($weeks_between) + ($from_wdays) + $to_wdays;
  1929.         return $diff_wd;
  1930.     }
  1931.     protected function projectEndToday($force false$input$output)
  1932.     {
  1933.         $io = new SymfonyStyle($input$output);
  1934.         $projectEnds $this->entityManager->getRepository(Project::class)->findProjectEndToday();
  1935.         $total 0;
  1936.         $io->title('Project End Today');
  1937.         $headers = ['Project Name''Start Date''End Date''PIC Name''Last Reminder''Sending'];
  1938.         $rows = [];
  1939.         $sending false;
  1940.         foreach ($projectEnds as $project) {
  1941.             try {
  1942.                 if(($project->getLastReminder() != null) && ($project->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
  1943.                 $this->projectService->projectEndEmail($project);
  1944.                 $sending true;
  1945.                 $project->setLastReminder(new \DateTimeImmutable());
  1946.                 $this->entityManager->flush();
  1947.                 $total++;
  1948.                 
  1949.                 array_push($rows, [
  1950.                     $project->getName(),
  1951.                     $project->getStartDate()->format('d/m/Y'),
  1952.                     $project->getEndDate()->format('d/m/Y'),
  1953.                     $project->getPersonInCharge()->getPersonalInfo()->getFullName(),
  1954.                     $project->getLastReminder()->format('d/m/Y'),
  1955.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1956.                 ]);
  1957.             } catch (Exception $e) {
  1958.                 $sending =  false;
  1959.                 continue;
  1960.             }
  1961.         }
  1962.         $this->entityManager->flush();
  1963.         $io->table($headers$rows);
  1964.         $io->success($total ' project end today email sent!');
  1965.     }
  1966.     protected function projectVendorPlanningEmpty($force false$input$output)
  1967.     {
  1968.         $io = new SymfonyStyle($input$output);
  1969.         $projectVendorPlanningEmpties $this->entityManager->getRepository(Project::class)->findProjectVendorPlanningEmpty();
  1970.         $total 0;
  1971.         $io->title('Project Vendor Planning Empty');
  1972.         $headers = ['Project Name''created At''PIC Name''Last Reminder''Sending'];
  1973.         $rows = [];
  1974.         $sending false;
  1975.         foreach ($projectVendorPlanningEmpties as $project) {
  1976.             try {
  1977.                 if(($project->getLastReminder() != null) && ($project->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
  1978.                 $this->projectService->projectVendorPlanningEmail($project);
  1979.                 $sending true;
  1980.                 $project->setLastReminder(new \DateTimeImmutable());
  1981.                 $this->entityManager->flush();
  1982.                 $total++;
  1983.                 
  1984.                 array_push($rows, [
  1985.                     $project->getName(),
  1986.                     $project->getCreatedAt()->format('d/m/Y'),
  1987.                     $project->getPersonInCharge()->getPersonalInfo()->getFullName(),
  1988.                     $project->getLastReminder()->format('d/m/Y'),
  1989.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  1990.                 ]);
  1991.             } catch (Exception $e) {
  1992.                 $sending =  false;
  1993.                 continue;
  1994.             }
  1995.         }
  1996.         $this->entityManager->flush();
  1997.         $io->table($headers$rows);
  1998.         $io->success($total ' project empty vendor planning email sent!');
  1999.     }
  2000.     protected function remindProjectHosting($force false$test false$input$output)
  2001.     {
  2002.         $io = new SymfonyStyle($input$output);
  2003.         $projectHostings $this->entityManager->getRepository(Project::class)->findExpiringProjectHosting();
  2004.         $total 0;
  2005.         if($test){
  2006.             $io->title('[Test Mode] Project Hosting Renewal Reminder');
  2007.         } else {
  2008.             $io->title('Project Hosting Renewal Reminder');
  2009.         }
  2010.         
  2011.         $headers = ['Project Name''Type''Renewal Date''PIC Email''Last Reminder''Sending'];
  2012.         $rows = [];
  2013.         $sending false;
  2014.         foreach ($projectHostings as $project) {
  2015.             try {
  2016.                 if(($project->getProjectHosting()->getLastReminder() != null) && ($project->getProjectHosting()->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false && $test == false) continue;
  2017.                 if($project->getProjectHosting()->getRenewalDate()->format('d/m/Y') == date('d/m/Y'strtotime('+30 days'))){
  2018.                     array_push($rows, [
  2019.                         $project->getName(),
  2020.                         'Domain',
  2021.                         $project->getProjectHosting()->getRenewalDate()->format('d/m/Y') ,
  2022.                         $project->getPersonInCharge()->getEmail(),
  2023.                         $project->getProjectHosting()->getLastReminder() ? $project->getProjectHosting()->getLastReminder()->format('d/m/Y') : '-',
  2024.                         $sending 'Yes' 'No'
  2025.                     ]);
  2026.                     if(!$test){
  2027.                         $sending true;
  2028.                         $this->projectService->projectHostingEmail($project'domain');
  2029.                         $rows[$total][5] = 'Yes';
  2030.                     } 
  2031.                     $total++;
  2032.                 }
  2033.                 if($project->getProjectHosting()->getPlatformRenewalDate()->format('d/m/Y') == date('d/m/Y'strtotime('+30 days'))){
  2034.                     array_push($rows, [
  2035.                         $project->getName(),
  2036.                         'Platform',
  2037.                         $project->getProjectHosting()->getPlatformRenewalDate()->format('d/m/Y') ,
  2038.                         $project->getPersonInCharge()->getEmail(),
  2039.                         $project->getProjectHosting()->getLastReminder() ? $project->getProjectHosting()->getLastReminder()->format('d/m/Y') : '-',
  2040.                         $sending 'Yes' 'No'
  2041.                     ]);
  2042.                     if(!$test){
  2043.                         $sending true;
  2044.                         $this->projectService->projectHostingEmail($project'platform');
  2045.                         $rows[$total][5] = 'Yes';
  2046.                     } 
  2047.                     $total++;
  2048.                 }
  2049.                 
  2050.                 if(!$test){
  2051.                     $project->getProjectHosting()->setLastReminder(new \DateTimeImmutable());
  2052.                     $this->entityManager->flush();
  2053.                 }
  2054.                
  2055.             } catch (Exception $e) {
  2056.                 $sending =  false;
  2057.                 continue;
  2058.             }
  2059.         }
  2060.        
  2061.         $io->table($headers$rows);
  2062.         if(!$test) {
  2063.             $this->entityManager->flush();
  2064.             $io->success($total ' project hosting expiring email sent!');
  2065.         }
  2066.     }     
  2067.     protected function remindUploadInvoiceExpense($force false$input$output)
  2068.     {
  2069.         $io = new SymfonyStyle($input$output);
  2070.         $todayDate date('Y-m-d');
  2071.         $expenseRequests $this->entityManager->getRepository(ExpenseRequest::class)->findByPage(19999'ASC'""""null3truenull$todayDate);
  2072.         $total 0;
  2073.         $io->title('Expense Request Upload Invoice Reminder');
  2074.         $headers = ['Expense ID''Requester''Amount','Sheduled Payment''Recurring''Sending'];
  2075.         $rows = [];
  2076.         $sending false;
  2077.         foreach ($expenseRequests as $expense) {
  2078.             try {
  2079.                 if(($expense->getLastReminder() != null) && ($expense->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
  2080.                 if (!in_array($expense->getRequester()->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod'){
  2081.                    
  2082.                 }else{
  2083.                     $this->expenseRequestService->reminderUploadInvoiceEmail($expense);
  2084.                     $sending true;
  2085.                     $expense->setLastReminder(new \DateTimeImmutable());
  2086.                     $this->entityManager->flush();
  2087.                 }
  2088.                 $total++;
  2089.                 
  2090.                 array_push($rows, [
  2091.                     $expense->getGeneratedId(),
  2092.                     $expense->getRequester()->getPersonalInfo()->getShortFullName(),
  2093.                     $expense->getAmount(),
  2094.                     $expense->getPaymentScheduled()->format('d/m/Y'),
  2095.                     $expense->getRecurring() ?: 'No',
  2096.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  2097.                 ]);
  2098.             } catch (Exception $e) {
  2099.                 $sending =  false;
  2100.                 continue;
  2101.             }
  2102.         }
  2103.         $this->entityManager->flush();
  2104.         $io->table($headers$rows);
  2105.         $io->success($total ' expense request upload invoice email reminder sent!');;
  2106.     }
  2107.     protected function remindUploadInvoiceExpenseRecurring($force false$input$output)
  2108.     {
  2109.         $io = new SymfonyStyle($input$output);
  2110.         // $todayDate = date('2025-06-28');
  2111.         $todayDate date('Y-m-d');
  2112.         $expenseRequests $this->entityManager->getRepository(ExpenseRequest::class)->findByPage(19999'ASC'""""null"3;4;5"truenull$todayDatetrue);
  2113.         $total 0;
  2114.         $io->title('Expense Request Upload Invoice Reminder (Recurring)');
  2115.         $headers = ['Expense ID''Scheduled Payment''Project End Date''Invoice(s)''interval''Recurring''Sending'];
  2116.         $rows = [];
  2117.         $sending false;
  2118.         foreach ($expenseRequests as $expense) {
  2119.             $interval date_diff($expense->getPaymentScheduled(), new \DateTime($todayDate));
  2120.             $totalInvoices count($expense->getExpenseRequestInvoices()->toArray());
  2121.             try {
  2122.                 if(($expense->getLastReminder() != null) && ($expense->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
  2123.                 if (!in_array($expense->getRequester()->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod'){
  2124.                    
  2125.                 }else{
  2126.                     if($expense->getPaymentScheduled()->format('Y-m-d') == $todayDate){
  2127.                         $this->expenseRequestService->reminderUploadInvoiceEmail($expense);
  2128.                         $sending true;
  2129.                         $expense->setLastReminder(new \DateTimeImmutable());
  2130.                         $this->entityManager->flush();
  2131.                         $total++;
  2132.                     }else{
  2133.                         $sending false;
  2134.                         if($expense->getProject() && $expense->getProject()->getEndDate()){
  2135.                             $meetCondition false;
  2136.                             if($expense->getRecurring() == 'Monthly'){
  2137.                                 if($todayDate <= $expense->getProject()->getEndDate() && $interval->>= && ($totalInvoices $interval->|| ($totalInvoices == $interval->+&& $expense->checkInvoices() == false))) $meetCondition true;
  2138.                             }elseif($expense->getRecurring() == 'Yearly'){
  2139.                                 if($todayDate <= $expense->getProject()->getEndDate() && $interval->>= && ($totalInvoices $interval->|| ($totalInvoices == $interval->+&& $expense->checkInvoices() == false))) $meetCondition true;
  2140.                             }
  2141.                             
  2142.                             if($meetCondition){
  2143.                                 $this->expenseRequestService->reminderUploadInvoiceEmail($expense);
  2144.                                 $sending true;
  2145.                                 $expense->setLastReminder(new \DateTimeImmutable());
  2146.                                 $this->entityManager->flush();
  2147.                                 $total++;
  2148.                             }
  2149.                         }
  2150.                     }
  2151.                 }
  2152.                 
  2153.                 array_push($rows, [
  2154.                     $expense->getGeneratedId(),
  2155.                     $expense->getPaymentScheduled()->format('d/m/Y'),
  2156.                     $expense->getProject() && $expense->getProject()->getEndDate() ? $expense->getProject()->getEndDate()->format('d/m/Y') : '-',
  2157.                     count($expense->getExpenseRequestInvoices()),
  2158.                     $expense->getRecurring() == 'Monthly' $interval->$interval->1,
  2159.                     $expense->getRecurring() ?: 'No',
  2160.                     $sending '<fg=black;bg=green>Yes</>' 'No'
  2161.                 ]);
  2162.             } catch (Exception $e) {
  2163.                 $sending =  false;
  2164.                 continue;
  2165.             }
  2166.         }
  2167.         $this->entityManager->flush();
  2168.         $io->table($headers$rows);
  2169.         $io->success($total ' expense request upload invoice email reminder sent!');;
  2170.     }
  2171.     
  2172.     protected function updateProvisionalRate($force false$test$input$output){
  2173.         $io = new SymfonyStyle($input$output);
  2174.         if($test){
  2175.             $io->text('<fg=black;bg=white>[Test Mode] Processing...</>');
  2176.         } else {
  2177.             $io->text('<fg=black;bg=white>Processing...</>');
  2178.         }
  2179.         $results $this->currencyService->updateProvisionalRate($test);
  2180.         if(count($results['rate']) > 0){
  2181.             $headers = ['ID''Rate Date''Create Date''Currency''Old Rate''New Rate'];
  2182.             $rows = [];
  2183.             
  2184.             foreach ($results['rate'] as $result) {
  2185.                 array_push($rows, [
  2186.                     $result['id'],
  2187.                     $result['rate_date'],
  2188.                     $result['create_date'],
  2189.                     $result['currency'],
  2190.                     $result['old_rate'],
  2191.                     $result['new_rate']
  2192.                 ]);
  2193.             }
  2194.             $io->table($headers$rows);
  2195.         }
  2196.         if($results['total'] > count($results['rate'])){
  2197.             $io->success(count($results['rate']) . ' of '.$results['total'].' Provisional Rate Updated!');
  2198.         } else {
  2199.             $io->success(count($results['rate']) . ' Provisional Rate Updated!');
  2200.         }
  2201.         
  2202.     }
  2203. }