<?php
namespace App\Command;
use App\Entity\Company;
use App\Entity\Appraisal;
use App\Entity\AppraisalQuestionnaire;
use App\Entity\LeaveBankHoliday;
use App\Entity\LeaveEntitlement;
use App\Entity\User;
use App\Entity\PersonalInfo;
use App\Entity\LeaveRequest;
use App\Entity\Project;
use App\Repository\LeaveRequestRepository;
use App\Service\AppraisalService;
use App\Service\DocumentManagementService;
use App\Service\UserService;
use App\Service\LeaveService;
use App\Service\NotificationService;
use App\Service\MailgunService;
use App\Service\LogService;
use App\Service\ObjectiveService;
use App\Service\ProjectService;
use App\Service\CurrencyService;
use App\Service\WebhookService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Console\Helper\TableSeparator;
use App\Command\Exception;
use App\Entity\ExpenseRequest;
use App\Service\ExpenseRequestService;
use App\Service\ChecklistService;
class AutomatedFunctionCommand extends Command
{
protected static $defaultName = 'app:automated';
protected static $defaultDescription = 'Multiple automated function that need to run reqularly';
protected function configure()
{
$this
->setDescription('Various command for automated function')
->addArgument('type', null, InputOption::VALUE_NONE, null)
->addOption('force', null, InputOption::VALUE_NONE, 'force command', null)
->addOption('clear', null, InputOption::VALUE_NONE, 'clear timestamp', null)
->addOption('test', null, InputOption::VALUE_NONE, 'test mode', null);
}
private $entityManager;
private $initiateDay = 14;
private $submitDeadline = 7;
private $appraisalService;
private $objectiveService;
private $userService;
private $WebhookService;
private $leaveService;
private $logService;
private $translator;
private $params;
private $documentManagement;
private $mailgunService;
private $notificationService;
private $projectService;
private $currencyService;
private $testAccounts;
private $expenseRequestService;
private $checklistService;
public function __construct(EntityManagerInterface $entityManager, AppraisalService $appraisalService, ObjectiveService $objectiveService, UserService $userService, LeaveService $leaveService, LogService $logService, DocumentManagementService $documentManagement, TranslatorInterface $translator, ParameterBagInterface $params, MailgunService $mailgunService, NotificationService $notificationService, WebhookService $webhookService, ProjectService $projectService, CurrencyService $currencyService, ChecklistService $checklistService, ExpenseRequestService $expenseRequestService)
{
parent::__construct();
$this->entityManager = $entityManager;
$this->appraisalService = $appraisalService;
$this->objectiveService = $objectiveService;
$this->userService = $userService;
$this->WebhookService = $webhookService;
$this->leaveService = $leaveService;
$this->logService = $logService;
$this->translator = $translator;
$this->params = $params;
$this->documentManagement = $documentManagement;
$this->mailgunService = $mailgunService;
$this->notificationService = $notificationService;
$this->projectService = $projectService;
$this->currencyService = $currencyService;
$this->testAccounts = explode(',', str_replace(array("\r", "\n", " "), '',$_SERVER['TEST_ACCOUNTS']));
$this->expenseRequestService = $expenseRequestService;
$this->checklistService = $checklistService;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$type = $input->getArgument('type');
$force = $input->getOption('force');
$clear = $input->getOption('clear');
$test = $input->getOption('test');
// Schedule Probation
if ($type == null) {
$type = 'help';
}
switch ($type) {
case 'process':
// $this->passProbation(false, $input, $output);
$this->deactivateUser(false, $input, $output);
$this->processProbationAppraisal(false, $input, $output);
$this->processYearlyAppraisal(false, $input, $output);
$this->leaveProRate(false, $input, $output);
$this->remindLeave($input, $output);
if (in_array(date('N'), [1, 2, 3, 4, 5])) {
$this->dailyLeave(false, $input, $output);
}
if (date('H') == 14){
$this->weeklyLeave(false, $input, $output);
$this->weeklyHoliday(false, false, $input, $output);
}
// $this->remindExpireLeave(false, $input, $output);
$this->remindExpireAnnualLeave(false, $input, $output);
$this->remindExpireCarryForwardLeave(false, $input, $output);
$this->remindExpireAdjustmentLeave(false, $input, $output);
$this->remindExpireBonusLeave(false, $input, $output);
$this->syncStatus($input, $output);
$this->birthdayNow(false, $input, $output);
$this->projectEndToday(false, $input, $output);
$this->projectVendorPlanningEmpty(false, $input, $output);
$this->remindProjectHosting(false, false, $input, $output);
//$this->remindBirthday(false, $input, $output);
$this->remindAppraisal(false, $input, $output);
$this->remindObjective(false, $input, $output);
$this->onboardingEmail(false, $input, $output);
$this->offboardingEmail(false, $input, $output);
$this->updateProvisionalRate(false, false, $input, $output);
break;
case 'appraisal':
$this->processProbationAppraisal($force, $input, $output);
$this->processYearlyAppraisal($force, $input, $output);
break;
case 'appraisal:probation':
$this->processProbationappraisal($force, $input, $output);
break;
case 'appraisal:yearly':
$this->processYearlyAppraisal($force, $input, $output);
break;
case 'appraisal:yearly:test':
$this->testYearlyAppraisal($force, $input, $output);
break;
case 'appraisal:probation:all':
$this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllProbationer(), true, $input, $output);
break;
case 'appraisal:probation:active':
$this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllActiveProbationer($this->initiateDay), true, $input, $output);
break;
case 'appraisal:performance:all':
$this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllEmployee(), false, $input, $output);
break;
case 'appraisal:performance:active':
$this->employeeList($this->entityManager->getRepository(PersonalInfo::class)->findAllActiveEmployee($this->initiateDay), false, $input, $output);
break;
case 'appraisal:remind':
if ($clear) {
$this->clearAppraisalReminder($input, $output);
} else {
$this->remindAppraisal($force, $input, $output);
}
break;
case 'appraisal:remind:all':
$this->appraisalList($this->entityManager->getRepository(Appraisal::class)->findAllActiveAppraisal(), $input, $output);
break;
case 'user:objective:remind':
$this->remindObjective($force, $input, $output);
break;
case 'user:summary:remind':
$this->remindSummary($this->entityManager->getRepository(Appraisal::class)->findAllTodayAppraisal(), $input, $output);
break;
case 'user:pass:probation':
$this->passProbation(false, $input, $output);
break;
case 'user:deactivate':
$this->deactivateUser(false, $input, $output);
break;
case 'user:deactivate:all':
$this->deactivateUser(true, $input, $output);
break;
case 'user:onboarding':
$this->onboardingEmail($force, $input, $output);
break;
case 'user:offboarding':
$this->offboardingEmail($force, $input, $output);
break;
case 'user:status':
$this->syncStatus($input, $output);
break;
case 'user:birthday':
$this->birthdayNow($force, $input, $output);
break;
case 'project:remind:end':
$this->projectEndToday($force, $input, $output);
break;
case 'project:remind:vendorplanning':
$this->projectVendorPlanningEmpty($force, $input, $output);
break;
case 'project:remind:hosting':
$this->remindProjectHosting($force, $test, $input, $output);
break;
case 'user:birthday:remind':
$this->remindBirthday($force, $input, $output);
break;
case 'leave:prorate':
$this->leaveProRate($force, $input, $output);
break;
case 'leave:remind':
if ($clear) {
$this->clearLeaveReminder($input, $output);
} else {
$this->remindLeave($input, $output);
}
break;
case 'leave:remind:daily':
$this->dailyLeave($force, $input, $output);
break;
case 'leave:remind:weekly':
$this->weeklyLeave($force, $input, $output);
break;
case 'leave:remind:holiday':
$this->weeklyHoliday($force, $test, $input, $output);
break;
/*
case 'leave:remind:expire':
$this->remindExpireLeave($force, $input, $output);
break; */
case 'leave:remind:expire:annual':
$this->remindExpireAnnualLeave($force, $input, $output);
break;
case 'leave:remind:expire:carryforward':
$this->remindExpireCarryForwardLeave($force, $input, $output);
break;
case 'leave:remind:expire:adjustment':
$this->remindExpireAdjustmentLeave($force, $input, $output);
break;
case 'leave:remind:expire:bonus':
$this->remindExpireBonusLeave($force, $input, $output);
break;
case 'expense:remind:invoice':
// $this->remindUploadInvoiceExpense($force, $input, $output);
$this->remindUploadInvoiceExpenseRecurring($force, $input, $output);
break;
// case 'remind:leave:holiday':
// $this->weeklyHoliday($force, $input, $output);
// break;
// case 'remind:leave:expire':
// $this->remindExpireLeave($force, $input, $output);
// break;
// case 'employee:birthday':
// $this->birthdayNow($force, $input, $output);;
// break;
// case 'employee:remind:birthday':
// $this->remindBirthday($force, $input, $output);
// break;
case 'currency:provisional':
$this->updateProvisionalRate($force, $test, $input, $output);
break;
default:
$io->title('Automated function command list');
$headers = ['Command', 'Argument', 'Description'];
$rows = [
['process', '', 'Process all required command'],
['appraisal', '--force', 'Initiate scheduling routine for all review'],
['appraisal:probation', '--force', 'Initiate scheduling routine for probation review'],
['appraisal:yearly', '--force', 'Initiate scheduling routine for yearly review'],
['appraisal:probation:all', '', 'List all user that in probation status'],
['appraisal:probation:active', '', 'List all user that active in probation'],
['appraisal:performance:all', '', 'List all user that in employee status'],
['appraisal:performance:active', '', 'List all user that active as employee'],
['appraisal:remind', '--clear', 'Remind all user that has active appraisal'],
['user:objective:remind', '', 'Remind all user that has active objective'],
['user:deactivate:all', '', 'Display all user that scheduled for deactivation'],
['user:onboarding', '--force', 'Initiate onboarding email'],
['user:offboarding', '--force', 'Initiate offboarding email'],
['user:summary:remind', '', 'Remind manager to conclude review'],
['user:pass:probation', '', 'Change user status from probation to permanent after end of probation date'],
['user:deactivate', '', 'Initiate user deactivation'],
['user:status', '', 'Sync status with leave'],
['user:birthday', '--force', 'Send employee birthday'],
['user:birthday:remind', '--force', 'Send reminder for 3 days to come employee birthday'],
['leave:prorate', '--force', 'Calculate leave prorate'],
['leave:remind', '--clear', 'Send reminder for all leave info'],
['leave:remind:daily', '--force', 'Send reminder for daily leave info'],
['leave:remind:weekly', '--force', 'Send reminder for next week leave info'],
['leave:remind:expire', '--force', 'Send reminder for next week expire leave info'],
['leave:remind:expire:annual', '--force', 'Send reminder for annual leave expire info'],
['leave:remind:expire:carryforward', '--force', 'Send reminder for carry forward leave expire info'],
['leave:remind:expire:adjustment', '--force', 'Send a reminder for Adjustment one month before leave expiration'],
['leave:remind:expire:bonus', '--force', 'Send a reminder for Bonus three months before leave expiration'],
['leave:remind:holiday', '--force', 'Send reminder for next week holiday info'],
['currency:provisional', '--force', 'Update provisional rate'],
['project:remind:end', '--force', 'Send project end to pic'],
['project:remind:vendorplanning', '--force', 'Send project vendor planning to pic'],
['project:remind:hosting', '--force', 'Send project hosting reminder to pic'],
['expense:remind:invoice', '--force', 'Send a reminder to the requester to upload the invoice'],
];
$io->table($headers, $rows);
break;
}
return \Symfony\Component\Console\Command\Command::SUCCESS;
}
protected function employeeList($employees, $inProbation, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$total = 0;
$io->title($inProbation ? 'Probationer' : 'Performance');
$headers = ['ID', 'Full Name', 'Status', 'Join Date', 'Expiry Date', 'Scheduled', 'Submit Date', 'Review Date'];
$rows = [];
foreach ($employees as $employee) {
$user = $employee->getUser();
//if ($user->assignedCompany()->getId() == '4') { // CompanyID
$total++;
$joinDate = $user->getPersonalInfo()->getJobJoinDate() ? '<options=bold>' . $user->getPersonalInfo()->getJobJoinDate()->format('d/m/Y') . '</>' : '-';
$expiryDate = $user->getPersonalInfo()->getJobExpiryDate() ? '<options=bold>' . $user->getPersonalInfo()->getJobExpiryDate()->format('d/m/Y') . '</>' : '-';
//$submitDate = $user->getPersonalInfo()->getJobSubmitDate() ? '<options=bold>'.$user->getPersonalInfo()->getJobSubmitDate()->format('d/m/Y H:i').'</>' : '-';
$appraisals = $user->activeAppraisals();
if (count($appraisals) > 0) {
$submitDate = $appraisals[0]->getSubmitAt() ? $appraisals[0]->getSubmitAt()->format('d/m/Y') : '-';
$reviewDate = $appraisals[0]->getReviewAt() ? $appraisals[0]->getReviewAt()->format('d/m/Y H:i') : '-';
$todayMarker = $appraisals[0]->getReviewAt() != null && $appraisals[0]->getReviewAt()->format('Ymd') == date('Ymd') ? '*' : '';
array_push($rows, [
$user->getId(),
$user->getPersonalInfo()->getFullName() != null ? $user->getPersonalInfo()->getFullName() : '<error>' . $user->getEmail() . '</error>',
$this->translator->trans($user->getPersonalInfo()->getJobStatus()),
$joinDate,
$expiryDate,
isset($appraisals[0]) ? '<fg=black;bg=white>Yes [' . $appraisals[0]->getId() . ']</>' : '',
$submitDate,
$reviewDate
]);
//$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().$todayMarker.' (Join: '.$joinDate.', Expiry: '.$expiryDate.', <fg=black;bg=white>Submit: '.$submitDate.', Review: '.$reviewDate.'</>)');
} else {
$scheduled = 'No';
if ($user->getPersonalInfo()->getJobExpiryDate() != null) {
$daysRemaining = floor((strtotime($user->getPersonalInfo()->getJobExpiryDate()->modify('-' . $this->initiateDay . ' days')->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
if ($daysRemaining < 1) {
$scheduled = $daysRemaining == 0 ? '<fg=black;bg=green>today</>' : '<fg=black;bg=red>due ' . $daysRemaining . ' day/s</>';
} else {
$scheduled = 'in ' . $daysRemaining . ' day/s';
}
};
array_push($rows, [
$user->getId(),
$user->getPersonalInfo()->getFullName() != null ? $user->getPersonalInfo()->getFullName() : '<error>' . $user->getEmail() . '</error>',
$this->translator->trans($user->getPersonalInfo()->getJobStatus()),
$joinDate,
$expiryDate,
$scheduled,
'-',
'-'
]);
//$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().' (Join: '.$joinDate.', Expiry: '.$expiryDate.')');
};
//};
};
$io->table($headers, $rows);
$io->success($inProbation ? $total . ' user in probation!' : $total . ' user found!');
}
protected function passProbation($force = false, $input, $output)
{
$total = 0;
$io = new SymfonyStyle($input, $output);
$io->title('User auto-pass probation');
$headers = ['ID', 'Full Name', 'Last Probation Date', 'Next Review Date'];
$rows = [];
$userList = $this->entityManager->getRepository(PersonalInfo::class)->findProbationerAutoPass();
foreach ($userList as $userInfo) {
$user = $userInfo->getUser();
$this->leaveService->leavePermanent($user, true, false,'run');
$attributes = $user->assignedCompany()->getAttributes();
if(isset($attributes['appraisalEndAt'])){
$apprisalStartAt = new \DateTime($attributes['appraisalStartAt']['date']);
$apprisalEndAt = new \DateTime($attributes['appraisalEndAt']['date']);
$endDate = $apprisalStartAt > new \DateTime('+ 2 months') ? $apprisalEndAt : $apprisalEndAt->modify('+ 1 years');
} else {
$endDate = new \DateTime('+ 1 years');
};
$oldUserInfo = clone $userInfo;
$userInfo->setJobStatus('form.job_status.permanent');
$userInfo->setJobExpiryDate($endDate);
$userInfo->setJobPermanentDate(new \DateTime());
$probationAppraisal = $user->probationAppraisal();
if($probationAppraisal) $probationAppraisal->setConcludedAt(new \DateTime());
array_push($rows, [
$user->getId(),
$userInfo->getFullName(),
$oldUserInfo->getJobExpiryDate()->format('d/m/Y'),
$userInfo->getJobExpiryDate()->format('d/m/Y'),
]);
$this->logService->save(null, [
'owner' => $user,
'message' => 'log.automated.pass_probation',
'old_data' => $oldUserInfo,
'new_data' => $userInfo
], false, true, 'UserInfo');
$total++;
}
$io->table($headers, $rows);
$this->entityManager->flush();
if ($total == 0) {
$io->success('No user passing probation period automatically');
} else {
$io->success($total . ' user pass probation period automatically!');
};
}
private function changeManager(User $user){
$attr=$user->getPersonalInfo()->getAttributes();
if(isset($attr['replacemanager'])){
if($attr['replacemanager']!=''){
$rmanager=$this->entityManager->getRepository(User::class)->find($attr['replacemanager']);
$usr=$this->entityManager->getRepository(User::class);
$qb=$usr->createQueryBuilder('u');
$qb->where('(:sm member of u.subManager ) or (u.manager = :m )')
->setParameter('m', $user)
->setParameter('sm', array($user));
$result=$qb->getQuery()->getResult();
if(is_array($result)){
foreach($result as $r){
if($r->getManager()==$user){$r->setManager($rmanager);}
$sub=$r->getSubManager();
if(!is_null($sub)){
if($sub->contains($user)){
$r->removeSubManager($user);
$r->addSubManager($rmanager);
}
}
$this->entityManager->persist($r);
$this->entityManager->flush();
}
$this->userService->syncManagerStatus();
}
}
}
}
protected function deactivateUser($list, $input, $output)
{
$total = 0;
$io = new SymfonyStyle($input, $output);
$io->title('User scheduled for termination');
$headers = ['ID', 'Full Name', 'Termination Date', 'Termination Reason', 'Status'];
$rows = [];
if ($list) {
$terminationList = $this->entityManager->getRepository(PersonalInfo::class)->findAllScheduledForJobTermination();
foreach ($terminationList as $userInfo) {
$oldUserInfo = clone $userInfo;
$user = $userInfo->getUser();
if ($user->getIsActive()) {
$terminationDate = $userInfo->getJobTerminateDate();
$terminationDateFormatted = $terminationDate->format('d/m/Y');
$today = new \DateTime();
$todayFormatted = $today->format('d/m/Y');
$terminationDateFormatted = $terminationDate <= $today ? '<fg=black;bg=yellow>' . $terminationDateFormatted . '</>' : $todayFormatted;
array_push($rows, [
$user->getId(),
$userInfo->getFullName(),
$terminationDateFormatted,
$this->translator->trans($userInfo->getJobTerminateReason()),
$user->getIsActive() ? 'Active' : 'Deactivated'
]);
$total++;
};
}
$io->table($headers, $rows);
if ($total == 0) {
$io->success('No user scheduled for deactivation');
} else {
$io->success($total . ' user scheduled for deactivation!');
};
} else {
$terminationList = $this->entityManager->getRepository(PersonalInfo::class)->findJobTerminated();
foreach ($terminationList as $userInfo) {
$oldUserInfo = clone $userInfo;
$user = $userInfo->getUser();
if ($user->getIsActive()) {
$this->documentManagement->transferAllUserOwnership($user->getId());
$user->setIsActive(false);
$this->entityManager->flush();
$this->changeManager($user);
$this->checklistService->checklistTransferOwnership($user->getId());
$result['message'] = $this->WebhookService->checkboxWebhook('users', 'DELETE', $user->getId());
array_push($rows, [
$user->getId(),
$userInfo->getFullName(),
$userInfo->getJobTerminateDate()->format('d/m/Y'),
$this->translator->trans($userInfo->getJobTerminateReason()),
$user->getIsActive() ? 'Active' : 'Deactivated'
]);
$total++;
$this->logService->save(null, [
'owner' => $user,
'message' => 'log.automated.deactivate_user',
'old_data' => $oldUserInfo,
'new_data' => $userInfo
], false, true, 'UserInfo');
};
}
$io->table($headers, $rows);
if ($total == 0) {
$io->success('No user deactivation');
} else {
$io->success($total . ' user deactivated!');
};
};
}
protected function scheduleAppraisal($day = false, $force = false, $test = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$employees = $this->entityManager->getRepository(PersonalInfo::class)->findEmployeeForReview($day, $force);
$total = 0;
foreach ($employees as $employee) {
$user = $employee->getUser();
if ($user->getIsActive() == true && $user->inProbation() == true) {
//$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
if (count($user->activeAppraisals()) == 0) {
$expiryDate = new \DateTime($user->getPersonalInfo()->getJobExpiryDate()->format('Y-m-d'));
$submitAt = $expiryDate->modify('-' . $this->submitDeadline . ' days');
$defaultQuestions = $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
$this->appraisalService->initiateAppraisal(false, null, $user, null, $submitAt, null, $defaultQuestions);
$io->text('<fg=black;bg=white>Schedule appraisal</> <options=bold>[' . $user->getId() . ']</> ' . $user->getPersonalInfo()->getFullName());
$total++;
};
};
};
$io->success($total . ' appraisal scheduled!');
return $total > 0 ? true : false;
//return json_decode($response->getContent(),true);
}
protected function processProbationAppraisal($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findProbationerForReview($this->initiateDay, null, $force);
$total = 0;
$io->title('Process Probation Appraisal');
foreach ($users as $user) {
if (count($user->activeAppraisals()) == 0) {
$expiryDate = new \DateTime($user->getPersonalInfo()->getJobExpiryDate()->format('Y-m-d'));
$submitAt = $expiryDate->modify('-' . $this->submitDeadline . ' days');
$defaultQuestions = $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
$this->appraisalService->initiateAppraisal(false, null, $user, null, $submitAt, null, $defaultQuestions);
$io->text('<fg=black;bg=white>Schedule probation appraisal</> <options=bold>[' . $user->getId() . ']</> ' . $user->getPersonalInfo()->getFullName());
$total++;
};
};
$io->success($total . ' probation appraisal scheduled!');
return $total > 0 ? true : false;
}
protected function processYearlyAppraisal($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Schedule Appraisal by Settings');
$emailGroup = $this->params->get('systemEmailGroup');
$companies = $this->entityManager->getRepository(Company::class)->findAll();
foreach ($companies as $company) {
if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
$attributes = $company->getAttributes();
$startDate = isset($attributes['appraisalStartAt']) ? new \DateTimeImmutable($attributes['appraisalStartAt']['date']) : null;
$endDate = isset($attributes['appraisalEndAt']) ? new \DateTimeImmutable($attributes['appraisalEndAt']['date']) : null;
$userSubmitDate = isset($attributes['appraisalUserSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalUserSubmitAt']['date']) : null;
$managerSubmitDate = isset($attributes['appraisalManagerSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']) : null;
$latestDate = isset($attributes['appraisalLatest']) ? new \DateTimeImmutable($attributes['appraisalLatest']['date']) : null;
// Initate new appraisal
$users = $this->entityManager->getRepository(User::class)->findAllEligibleForAppraisal($company, $startDate, $force);
$io->section($company->getFullName());
if (!$startDate || !$endDate || !$userSubmitDate || !$managerSubmitDate) {
$io->text("<fg=white;bg=red>Apraisal settings not complete</>\n");
continue;
}
if (date('Ymd') < $startDate->format('Ymd')) {
$io->text("Appraisal period scheduled for " . $startDate->format('d/m/Y') . "\n");
continue;
}
$io->text("<fg=black;bg=yellow>STEP 1 - Initiate (user)</>\n");
$appraisalData = null;
if ($latestDate == null || $startDate->format('Ymd') == date('Ymd') && $startDate->format('Ymd') != $latestDate->format('Ymd') || $force) {
$progressBar = new ProgressBar($output, count($users));
$progressBar->setEmptyBarCharacter('â–‘'); // light shade character \u2591
$progressBar->setProgressCharacter('');
$progressBar->setBarCharacter('â–“'); // dark shade character \u2593
$progressBar->start();
$skippedUsers = [];
$totalYearly = 0;
$totalError = 0;
foreach ($users as $user) {
$submitAt = $userSubmitDate;
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') {
$autoConclude = 'No';
if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getCreatedAt() < $startDate && $user->activeAppraisals()[0]->getConcludedAt() == null) {
$autoConclude = 'Yes';
};
if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
$skippedUsers[] = [count($skippedUsers) + 1, $user->getEmail(), 'Yes', $autoConclude];
} else {
$skippedUsers[] = [count($skippedUsers) + 1, $user->getEmail(), 'No', $autoConclude];
}
$progressBar->advance();
continue;
}
try {
if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getCreatedAt() < $startDate && $user->activeAppraisals()[0]->getConcludedAt() == null) {
$user->activeAppraisals()[0]->setConcludedAt(new \DateTime);
$this->appraisalService->syncAppraisalStatus($user);
//$totalYearly++;
};
// if ($user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd') || $user->latestAppraisal() == null) {
if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
// $io->info($user->latestAppraisal()->getCreatedAt()->format('d-m-Y').' - '.$user->getEmail());
$defaultQuestions = $this->entityManager->getRepository(AppraisalQuestionnaire::class)->findByUser($user);
$this->appraisalService->initiateAppraisal(false, null, $user, null, $submitAt, null, $defaultQuestions);
$totalYearly++;
if ($appraisalData == null) $appraisalData = isset($user->activeAppraisals()[0]) ? $user->activeAppraisals()[0] : null;
// $this->objectiveService->updateOldObjective($user);
}
$progressBar->advance();
} catch (Exception $e) {
$totalError++;
$progressBar->advance();
continue;
}
};
$totalManager = 0;
$totalManagerError = 0;
if (!$force && $appraisalData != null) {
foreach ($company->getAllManager() as $manager) {
if (!in_array($manager->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
try {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.initiated.objective.manager'),
[$manager->getEmail()],
'email/user-notification/appraisal/initiate-objective.html.twig',
[
'recipient' => $manager,
'appraisal' => $appraisalData,
'group' => 'manager'
],
false
);
$totalManager++;
} catch (Exception $e) {
$totalManagerError++;
continue;
}
};
}
if (!$force && $appraisalData != null) {
foreach ($emailGroup as $groupName => $groupEmail) {
if($groupName != 'hr') continue;
try {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.initiated.objective.' . $groupName),
[$groupEmail],
'email/user-notification/appraisal/initiate-objective.html.twig',
[
'recipient' => strtoupper($groupName) . ' Team',
'appraisal' => $appraisalData,
'group' => $groupName,
],
false
);
} catch (Exception $e) {
continue;
}
};
}
$attributes['appraisalLatest'] = new \DateTimeImmutable;
$company->setAttributes($attributes);
$this->entityManager->flush();
$io->text("\n\n" . $totalYearly . " yearly appraisal scheduled on " . $startDate->format('d/m/Y') . "!\n");
$io->text($totalManager . " manager informed!\n");
if ($totalError > 0) $io->text("\n <fg=white;bg=red>" . $totalError . " user & " . $totalManagerError . " manager appraisal failed to schedule!</>\n");
if (count($skippedUsers) > 0) {
$io->text("\n\n<fg=black;bg=white>Skipped Users</>\n");
$io->table(['No.', 'Email', 'Eligible', 'Auto Conclude'], $skippedUsers);
}
} else {
$io->text("Already done at " . $startDate->format('d/m/Y') . "\n");
}
// Initiate Manager Step
$io->text("<fg=black;bg=yellow>STEP 2 - Manager</>\n");
if (date('Ymd') == $userSubmitDate->modify('+ 1 days')->format('Ymd') && ($latestDate == null || date('Ymd') != $latestDate->format('Ymd'))) {
$totalYearly = 0;
$totalDue = 0;
foreach ($users as $user) {
try {
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
if (isset($user->activeAppraisals()[0])) {
if ($user->activeAppraisals()[0]->getSubmittedAt() == null) {
// $user->activeAppraisals()[0]->setSubmittedAt(new \DateTime);
$this->appraisalService->syncAppraisalStatus($user);
$totalYearly++;
$totalDue++;
foreach ($emailGroup as $groupName => $groupEmail) {
if ($groupName == 'hr') {
try {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.missed_notice.user', ['%user%' => $user->getPersonalInfo()->getFullName(), '%manager%' => $user->getManager()->getPersonalInfo()->getFullName()]),
[$groupEmail],
'email/user-notification/appraisal/missed.html.twig',
[
'recipient' => strtoupper($groupName) . ' Team',
'appraisal' => $user->activeAppraisals()[0],
'group' => $groupName,
'missed' => 'user'
],
false
);
} catch (Exception $e) {
continue;
}
};
};
};
};
} catch (Exception $e) {
continue;
}
};
$attributes['appraisalLatest'] = new \DateTimeImmutable;
$company->setAttributes($attributes);
$this->entityManager->flush();
$io->text("User submit window closed! \n");
$io->text($totalDue. " user didn't finish its form! \n");
} elseif (date('Ymd') > $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $userSubmitDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $userSubmitDate->format('d/m/Y') . "\n");
}
// Initiate Review Step
$io->text("<fg=black;bg=yellow>STEP 3 - Review</>\n");
if (date('Ymd') == $managerSubmitDate->modify('+ 1 days')->format('Ymd') && ($latestDate == null || date('Ymd') != $latestDate->format('Ymd'))) {
$dayReduction = (($managerSubmitDate->diff($endDate)->days / 7) * 2) + 1;
$totalYearly = 0;
$totalDue = 0;
foreach ($users as $user) {
try {
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getSubmittedAt() != null && $user->activeAppraisals()[0]->getReviewedAt() == null) {
//$user->activeAppraisals()[0]->setReviewedAt(new \DateTime);
//$reviewAt = $endDate->modify("- ".rand(1, $managerSubmitDate->diff($endDate)->days - $dayReduction)." weekdays")->setTime(rand(14,17),0,0);
//$user->activeAppraisals()[0]->setReviewAt($reviewAt);
//$this->appraisalService->syncAppraisalStatus($user);
$totalYearly++;
$totalDue++;
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.missed.manager',['%user%' => $user->getPersonalInfo()->getFullName()]),
[$user->getManager()->getEmail()],
'email/user-notification/appraisal/missed.html.twig',
[
'recipient' => $user->getManager(),
'appraisal' => $user->activeAppraisals()[0],
'group' => 'manager',
'missed' => 'manager'
],
false
);
foreach ($emailGroup as $groupName => $groupEmail) {
if ($groupName == 'hr') {
try {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.missed_notice.manager', ['%user%' => $user->getPersonalInfo()->getFullName(), '%manager%' => $user->getManager()->getPersonalInfo()->getFirstName()]),
[$groupEmail],
'email/user-notification/appraisal/missed.html.twig',
[
'recipient' => strtoupper($groupName) . ' Team',
'appraisal' => $user->activeAppraisals()[0],
'group' => $groupName,
'missed' => 'manager'
],
false
);
} catch (Exception $e) {
continue;
}
};
};
};
} catch (Exception $e) {
continue;
}
};
$attributes['appraisalLatest'] = new \DateTimeImmutable;
$company->setAttributes($attributes);
$this->entityManager->flush();
$io->text("Manager submit window closed! \n");
$io->text($totalDue. " manager didn't finish its form! \n");
} elseif (date('Ymd') > $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $managerSubmitDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $managerSubmitDate->format('d/m/Y') . "\n");
}
// Close Apprasial Period
$io->text("<fg=black;bg=yellow>STEP 4 - Complete</>\n");
if (date('Ymd') == $endDate->modify('+ 1 days')->format('Ymd')) {
// $this->entityManager->flush();
$attributes['appraisalStartAt'] = $startDate->modify("+ 6 months");
$attributes['appraisalEndAt'] = $endDate->modify("+ 6 months");
$attributes['appraisalUserSubmitAt'] = $userSubmitDate->modify("+ 6 months");
$attributes['appraisalManagerSubmitAt'] = $managerSubmitDate->modify("+ 6 months");
$totalYearly = 0;
foreach ($users as $user) {
// if ($totalYearly > 1 && $_SERVER['APP_ENV'] != 'prod') continue;
// if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
if (isset($user->activeAppraisals()[0]) && $user->activeAppraisals()[0]->getConcludedAt() == null) {
//$user->activeAppraisals()[0]->setConcludedAt(new \DateTime);
//$user->activeAppraisals()[0]->setReviewedBy($user->getManager());
$user->getPersonalInfo()->setJobExpiryDate($attributes['appraisalEndAt']);
//$this->appraisalService->syncAppraisalStatus($user);
//$totalYearly++;
};
};
$attributes['appraisalLatest'] = new \DateTimeImmutable;
$company->setAttributes($attributes);
$this->entityManager->flush();
//$io->text("All appraisal automatically concluded \n");
$io->text("Appraisal session ended \n");
} elseif (date('Ymd') > $endDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $endDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $endDate->format('d/m/Y') . "\n");
}
if ($force) $this->appraisalService->syncAppraisalStatus();
}
return true;
//return json_decode($response->getContent(),true);
}
protected function testYearlyAppraisal($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('[TEST] Schedule Appraisal by Settings');
$companies = $this->entityManager->getRepository(Company::class)->findAll();
foreach ($companies as $company) {
if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
$attributes = $company->getAttributes();
$startDate = isset($attributes['appraisalStartAt']) ? new \DateTimeImmutable($attributes['appraisalStartAt']['date']) : null;
$endDate = isset($attributes['appraisalEndAt']) ? new \DateTimeImmutable($attributes['appraisalEndAt']['date']) : null;
$userSubmitDate = isset($attributes['appraisalUserSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalUserSubmitAt']['date']) : null;
$managerSubmitDate = isset($attributes['appraisalManagerSubmitAt']) ? new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']) : null;
$latestDate = isset($attributes['appraisalLatest']) ? new \DateTimeImmutable($attributes['appraisalLatest']['date']) : null;
// Initate new appraisal
$users = $this->entityManager->getRepository(User::class)->findAllEligibleForAppraisal($company, $startDate, $force);
//$probationers = $this->entityManager->getRepository(User::class)->findProbationerForReview($this->initiateDay, $company,$force);
$io->section($company->getFullName());
if (!$startDate || !$endDate || !$userSubmitDate || !$managerSubmitDate) {
$io->text("<fg=white;bg=red>Apraisal settings not complete</>\n");
continue;
}
if (date('Ymd') < $startDate->format('Ymd')) {
$io->text("Apprasial period scheduled for " . $startDate->format('d/m/Y') . "\n");
continue;
}
$io->text("<fg=black;bg=yellow>[TEST] STEP 1 - Initiate (user)</>\n");
if ($latestDate == null || $startDate->format('Ymd') == date('Ymd') && $startDate->format('Ymd') != $latestDate->format('Ymd') || $force) {
$progressBar = new ProgressBar($output, count($users));
$progressBar->setEmptyBarCharacter('â–‘'); // light shade character \u2591
$progressBar->setProgressCharacter('');
$progressBar->setBarCharacter('â–“'); // dark shade character \u2593
$progressBar->start();
$totalYearly = 0;
$totalError = 0;
$elligibleUsers = [];
foreach ($users as $user) {
try {
// if ($force && count($user->activeAppraisals()) == 0) {
if ($user->latestAppraisal() == null || ($user->latestAppraisal() && $user->latestAppraisal()->getCreatedAt()->format('Ymd') < $startDate->format('Ymd')) ) {
$totalYearly++;
$latest = $user->latestAppraisal() ? $user->latestAppraisal()->getCreatedAt()->format('Y-m-d H:i:s') : null;
$elligibleUsers[] = ['no' => $totalYearly, 'email' => $user->getEmail(), 'latest' => $latest ];
}
$progressBar->advance();
} catch (Exception $e) {
$totalError++;
$progressBar->advance();
continue;
}
};
$totalManager = 0;
$totalManagerError = 0;
if (!$force) {
foreach ($company->getAllManager() as $manager) {
try {
$totalManager++;
} catch (Exception $e) {
$totalManagerError++;
continue;
}
};
}
$io->newLine();
$io->table(['No', 'Email', 'Latest'], $elligibleUsers);
$io->newLine();
$io->text("\n\n". $totalYearly . " yearly appraisal scheduled on " . $startDate->format('d/m/Y') . "! \n");
//$io->text(count($probationers)." probationer still waiting!\n");
$io->text($totalManager . " manager informed!\n");
if ($totalError > 0) $io->text("\n <fg=white;bg=red>" . $totalError . " user & " . $totalManagerError . " manager appraisal failed to schedule!</>\n");
} else {
$io->text("Already done at " . $startDate->format('d/m/Y') . "\n");
}
// Initiate Manager Step
$io->text("<fg=black;bg=yellow>[TEST] STEP 2 - Manager</>\n");
if (date('Ymd') == $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
$totalYearly = 0;
$totalDue = 0;
foreach ($users as $user) {
$totalYearly++;
$totalDue++;
};
$io->text("User submit window closed! \n");
$io->text($totalDue. " user didn't finish its form! \n");
} elseif (date('Ymd') > $userSubmitDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $userSubmitDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $userSubmitDate->format('d/m/Y') . "\n");
}
// Initiate Review Step
$io->text("<fg=black;bg=yellow>[TEST] STEP 3 - Review</>\n");
if (date('Ymd') == $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
$totalYearly = 0;
$totalDue = 0;
foreach ($users as $user) {
$totalYearly++;
$totalDue++;
};
$io->text("Manager submit window closed! \n");
$io->text($totalDue. " manager didn't finish its form! \n");
} elseif (date('Ymd') > $managerSubmitDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $managerSubmitDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $managerSubmitDate->format('d/m/Y') . "\n");
}
// Close Apprasial Period
$io->text("<fg=black;bg=yellow>[TEST] STEP 4 - Complete</>\n");
if (date('Ymd') == $endDate->modify('+ 1 days')->format('Ymd')) {
$attributes['appraisalStartAt'] = $startDate->modify("+ 1 years");
$attributes['appraisalEndAt'] = $endDate->modify("+ 1 years");
$attributes['appraisalUserSubmitAt'] = $userSubmitDate->modify("+ 1 years");
$attributes['appraisalManagerSubmitAt'] = $managerSubmitDate->modify("+ 1 years");
$totalYearly = 0;
foreach ($users as $user) {
$totalYearly++;
};
$company->setAttributes($attributes);
$this->entityManager->flush();
$io->text("All appraisal automatically concluded \n");
} elseif (date('Ymd') > $endDate->modify('+ 1 days')->format('Ymd')) {
$io->text("Already done at " . $endDate->format('d/m/Y') . " \n");
} else {
$io->text("Scheduled a day after " . $endDate->format('d/m/Y') . "\n");
}
}
return true;
//return json_decode($response->getContent(),true);
}
protected function appraisalList($appraisals, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$total = 0;
$io->title('Active Appraisal');
$headers = ['No', 'ID', 'Full Name', 'Title', 'Submit Deadline', 'User Filled', 'Review Date', 'Manager Filled', 'Last Reminder', 'Active'];
$rows = [];
foreach ($appraisals as $appraisal) {
$user = $appraisal->getUser();
$daysRemaining = floor((strtotime($appraisal->getSubmitAt()->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
if ($user->getIsActive() == true && $daysRemaining >= -7 && $daysRemaining <= 7) {
$total++;
$submitted = $appraisal->getSubmittedAt() == null ? 'No' : '<fg=black;bg=green>Yes</>';
$submitDate = '<options=bold>' . $appraisal->getSubmitAt()->format('d/m/Y') . '</>';
if ($appraisal->getReviewAt() != null) {
$activeState = $appraisal->getReviewAt()->format('Ymd') >= date('Ymd') ? 'Yes' : 'No';
$reviewed = $appraisal->getReviewedAt() == null ? 'No' : 'Yes';
$reviewDate = $appraisal->getReviewAt()->format('d/m/Y');
} else {
$activeState = 'Yes';
$reviewed = '-';
$reviewDate = '-';
}
array_push($rows, [
count($rows) + 1,
$appraisal->getId(),
$user->getPersonalInfo()->getFullName(),
$appraisal->getTitle(),
$submitDate . ' (in ' . $daysRemaining . ' day/s)',
$submitted,
'<options=bold>' . $reviewDate . '</>',
$reviewed,
$appraisal->getlastReminder() == null ? '-' : $appraisal->getlastReminder()->format('d/m/Y H:i:s'),
$activeState
]);
//$io->text('<options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName().$todayMarker.' (Join: '.$joinDate.', Expiry: '.$expiryDate.', <fg=black;bg=white>Submit: '.$submitDate.', Review: '.$reviewDate.'</>)');
};
};
$io->table($headers, $rows);
$io->success($total . ' active appraisal!');
}
protected function remindAppraisal($force, $input, $output) // TODO: add force
{
$io = new SymfonyStyle($input, $output);
$appraisals = $this->entityManager->getRepository(Appraisal::class)->findActiveAppraisal();
$total = 0;
$io->title('Appraisal Reminder');
$headers = ['ID', 'Full Name', 'Title', 'Status', 'Deadline', 'Last Reminder', 'Sending User', 'Sending Manager'];
$rows = [];
foreach ($appraisals as $appraisal) {
$user = $appraisal->getUser();
$sending = 'No';
$sendingManager = false;
$deadline = false;
//$status = $appraisal->getReviewedAt() == null ? 'Need to submit before '.$appraisal->getSubmitAt()->format('Y-m-d');
//$daysRemainingUser = floor((strtotime($appraisal->getSubmitAt()->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
$daysRemainingUser = $this->date_diff_weekdays(date('Ymd'), $appraisal->getSubmitAt()->format('Ymd'));
$attributes = $appraisal->getUser()->assignedCompany()->getAttributes();
if (!isset($attributes['appraisalManagerSubmitAt'])) continue;
$managerSubmitDate = new \DateTimeImmutable($attributes['appraisalManagerSubmitAt']['date']);
//$daysRemainingManager = floor((strtotime($managerSubmitDate->format('Ymd')) - strtotime(date('Ymd'))) / 60 / 60 / 24);
$daysRemainingManager = $this->date_diff_weekdays(date('Ymd'), $managerSubmitDate->format('Ymd'));
if ($user->getIsActive() == true) { // 3 days before deadline
$reminderStatus = null;
if ($user->inProbation() == false && $appraisal->getSubmittedAt() != null && $appraisal->getReviewedAt() == null && $daysRemainingManager == 3) { // Manager Turn
$sending = false;
$sendingManager = $this->appraisalService->remindAppraisal($appraisal, 'manager');
$reminderStatus = 'Manager: submit reminder';
//$deadline = $appraisal->getUser()->getPersonalInfo()->getJobExpiryDate() ? $appraisal->getUser()->getPersonalInfo()->getJobExpiryDate()->format('d/m/Y') : false;
$deadline = $managerSubmitDate->format('d/m/Y');
} elseif ($appraisal->getSubmittedAt() == null && $daysRemainingUser == 3 || $appraisal->getSubmittedAt() == null && $daysRemainingUser == -1) { // User turn
if ($appraisal->getSubmitAt()->format('Ymd') < date('Ymd')) { // Missed deadline
$sending = $this->appraisalService->missedAppraisal($appraisal, 'user');
//$sending = true;
$reminderStatus = 'User: missed deadline';
} else { // Waiting user fill the form
$sending = $this->appraisalService->remindAppraisal($appraisal, 'user');
//$sending = true;
$reminderStatus = 'User: submit reminder';
};
$deadline = $appraisal->getSubmitAt()->format('d/m/Y');
}
if ($reminderStatus) {
//$io->text('<fg=black;bg=white>'.$reminderStatus.'</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
array_push($rows, [
$appraisal->getId(),
$user->getPersonalInfo()->getFullName(),
'[' . $appraisal->getId() . '] ' . $appraisal->getTitle(),
$reminderStatus,
$deadline ? $deadline . ' (in ' . $daysRemainingUser . ' day/s)' : '-',
$appraisal->getlastReminder() ? $appraisal->getlastReminder()->format('d/m/Y H:i:s') : '-',
$sending ? '<fg=black;bg=green>Yes</>' : 'No',
$sendingManager ? '<fg=black;bg=green>Yes</>' : 'No'
]);
if ($sending || $sendingManager) $total++;
};
// if(count($user->activeAppraisals()) == 0){
// $submitAt = $user->getPersonalInfo()->getJobExpiryDate()->modify('-14 days');
// $this->appraisalService->initiateAppraisal(false, $user->getManager(), $user, $this->translator->trans('email.appraisal.probation'), $submitAt);
// $io->text('<fg=black;bg=white>Schedule Probation</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
// $daysRemaining = floor((strtotime($user->getPersonalInfo()->getJobExpiryDate()->modify('-'.$this->initiateDay.' days')->format('Ymd')) - strtotime(date('Ymd')))/60/60/24);
// $io->text('<fg=black;bg=white>Remind Appraisal</> <options=bold>['.$user->getId().']</> '.$user->getPersonalInfo()->getFullName());
// $total++;
// };
};
};
$io->table($headers, $rows);
$io->success($total . ' user reminded!');
return $total > 0 ? true : false;
//return json_decode($response->getContent(),true);
}
protected function clearAppraisalReminder($input, $output)
{
$io = new SymfonyStyle($input, $output);
$appraisals = $this->entityManager->getRepository(Appraisal::class)->findActiveAppraisal();
$total = 0;
foreach ($appraisals as $appraisal) {
$user = $appraisal->getUser();
if ($user->getIsActive() == true and $appraisal->getLastReminder() != null and $appraisal->getLastReminder()->format('Ymd') <= date('Ymd')) {
$appraisal->setLastReminder(null);
$this->entityManager->flush();
$total++;
};
};
$io->success($total . ' user reminder cleared!');
return $total > 0 ? true : false;
}
protected function remindObjective($force, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findAllActive();
$total = 0;
$io->title('Objective Reminder');
$headers = ['Full Name', 'Last Reminder', 'Sending'];
$rows = [];
foreach ($users as $user) {
$sending = 'No';
try {
$reminderLog = $user->getReminder();
$now = new \DateTime();
$sending = $user->getIsActive();
$appraisal = $user->latestAppraisal();
// TODO: Need to refactor code below to make it more efficient
if (isset($reminderLog['objective']) && $reminderLog['objective']->format('Ymd') == $now->format('Ymd') && !$force) $sending = false;
if (!isset($appraisal) || $appraisal->getReviewAt() == null) continue;
if ($user->totalObjective() == 0 && $user->inProbation() == false && $appraisal->getReviewAt()->modify('+ 1 weeks')->format('Ymd') == date('Ymd')) {
if ($sending == true) {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.reminder.objective.user', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
[$user->getEmail()],
'email/user-notification/appraisal/reminder-objective.html.twig',
[
'recipient' => $user,
'user' => $user,
'group' => 'user',
'appraisal' => $appraisal
],
false
);
foreach ($user->getAllManager() as $manager) {
$this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.reminder.objective.manager', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
[$manager->getEmail()],
'email/user-notification/appraisal/reminder-objective.html.twig',
[
'recipient' => $manager,
'user' => $user,
'group' => 'manager',
'appraisal' => $appraisal
],
false
);
};
}
if ($sending) $total++;
array_push($rows, [
$user->getPersonalInfo()->getFullName() ? $user->getPersonalInfo()->getFullName() : '-',
isset($reminderLog['objective']) ? $reminderLog['objective']->format('d/m/Y H:i:s') : '-',
$sending ? 'Yes' : 'No'
]);
$reminderLog['objective'] = $now;
$user->setReminder($reminderLog);
};
} catch (Exception $e) {
continue;
}
};
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' user reminded!');
return $total > 0 ? true : false;
//return json_decode($response->getContent(),true);
}
protected function remindSummary($appraisals, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$total = 0;
$io->title('Summary Reminder');
$headers = ['Title', 'User', 'Manager', 'Review At'];
$rows = [];
foreach ($appraisals as $appraisal) {
try {
$user = $appraisal->getUser();
$manager = $user->getManager();
$sent = $this->mailgunService->sendEmail(
$this->translator->trans('email.appraisal.reminder.summary', ['%user%' => $user->getPersonalInfo()->getFirstName()]),
[$manager->getEmail()],
'email/user-notification/appraisal/reminder-summary.html.twig',
[
'recipient' => $manager,
'user' => $user,
'appraisal' => $appraisal,
'group' => 'user',
],
false
);
if ($sent) $total++;
array_push($rows, [
$appraisal->getTitle(),
$user->getPersonalInfo()->getFullName() ? $user->getPersonalInfo()->getFullName() : $user->getEmail(),
$manager && $manager->getPersonalInfo()->getFullName() ? $manager->getPersonalInfo()->getFullName() : '-',
$appraisal->getReviewAt() ? $appraisal->getReviewAt()->format('d/m/Y H:i:s') : '-'
]);
} catch (Exception $e) {
continue;
}
};
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' manager reminded!');
return $total > 0 ? true : false;
//return json_decode($response->getContent(),true);
}
protected function onboardingEmail($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findByOnboarding();
$total = 0;
$io->title('Onboarding email');
$headers = ['Full Name', 'Email', 'Join date', 'E.Inventory', 'E.Welcome'];
$rows = [];
$now = new \DateTime();
foreach ($users as $user) {
$emailInventory = false;
$emailWelcome = false;
try {
$reminderLog = $user->getReminder();
if (!isset($reminderLog['onboardingEmail']) || $force) {
$emailWelcome = $this->userService->welcomeEmail(false, $user);
if ($emailWelcome) $total++;
};
if (!isset($reminderLog['onboardingInventoryEmail']) || $force) {
$emailInventory = $this->userService->notifyInventoryPrior(false, $user);
if ($emailInventory) $total++;
};
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$user->getEmail(),
$user->getPersonalInfo()->getJobJoinDate()->format('d/m/Y'),
$emailInventory ? 'Yes' : 'No',
$emailWelcome ? 'Yes' : 'No'
]);
} catch (Exception $e) {
continue;
}
};
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' onboarding email sent!');
return $total > 0 ? true : false;
}
function offboardingEmail($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findByOffboarding();
$total = 0;
$io->title('Offboarding email');
$headers = ['Full Name', 'Email', 'Termination date', 'E.Prior', 'E.Day', 'E.Past'];
$rows = [];
$emailGroup = $this->params->get('systemEmailGroup');
$now = new \DateTime();
foreach ($users as $user) {
$sending = false;
$emailPrior = false;
$emailDay = false;
$emailPast = false;
try {
$reminderLog = $user->getReminder();
$terminateDate = $user->getPersonalInfo()->getJobTerminateDate();
if (!isset($reminderLog['offboardingEmailPrior']) || $force) {
$emailPrior = $this->userService->notifyTerminationPrior(false, $user);
if ($emailPrior) $total++;
}
if (!isset($reminderLog['offboardingEmailDay']) || $force) {
$emailDay = $this->userService->notifyTerminationDay(false, $user);
if ($emailDay) $total++;
}
if (!isset($reminderLog['offboardingEmailPast']) || $force) {
$emailPast = $this->userService->notifyTerminationPast(false, $user);
if ($emailPast) $total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$user->getEmail(),
$terminateDate->format('Ymd') < $now->format('Ymd') ? '<fg=white;bg=red>' . $terminateDate->format('d/m/Y') . '</>' : $terminateDate->format('d/m/Y'),
$emailPrior ? 'Yes' : 'No',
$emailDay ? 'Yes' : 'No',
$emailPast ? 'Yes' : 'No'
]);
} catch (Exception $e) {
continue;
}
};
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' offboarding email sent!');
return $total > 0 ? true : false;
}
protected function remindLeave($input, $output)
{
$io = new SymfonyStyle($input, $output);
$leaves = $this->entityManager->getRepository(LeaveRequest::class)->findUncheckLeaveRequest();
$total = 0;
$io->title('Leave request reminder');
$headers = ['Created At', 'Name', 'Start', 'End', 'Days', 'Days Left', 'Last Reminder', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave->getUser();
$sending = false;
try {
if ($user->getIsActive() == true and ($leave->getLastReminder() == null or $leave->getLastReminder()->format('Ymd') < date('Ymd'))) {
$this->leaveService->reminderRequestLeaveEmail($leave, $user);
$leave->setLastReminder(new \DateTime());
$this->entityManager->flush();
$sending = true;
$total++;
}
array_push($rows, [
$leave->getCreatedAt()->format('d/m/Y'),
$user->getPersonalInfo()->getFullName(),
$leave->getStartDate()->format('d/m/Y'),
$leave->getEndDate()->format('d/m/Y'),
$leave->getDays(),
$leave->getDaysLeft(),
$leave->getlastReminder() ? $leave->getlastReminder()->format('d/m/Y H:i:s') : '-',
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
//$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' leave request reminder email sent!');
}
protected function clearLeaveReminder($input, $output)
{
$io = new SymfonyStyle($input, $output);
$leaves = $this->entityManager->getRepository(LeaveRequest::class)->findUncheckLeaveRequest();
$total = 0;
foreach ($leaves as $leave) {
$user = $leave->getUser();
if ($user->getIsActive() == true and $leave->getLastReminder() != null and $leave->getLastReminder()->format('Ymd') <= date('Ymd')) {
$leave->setLastReminder(null);
$this->entityManager->flush();
$total++;
};
};
$io->success($total . ' leave request reminder cleared!');
return $total > 0 ? true : false;
}
protected function dailyLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$total = 0;
$now = new \DateTime();
$companies = $this->entityManager->getRepository(Company::class)->findAll();
foreach ($companies as $company) {
if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
$reminderLog = $company->getReminder();
$leaves = $this->entityManager->getRepository(LeaveRequest::class)->findTodayLeaveByCompany($company,-1);
if ($leaves) {
try {
if (isset($reminderLog['dailyLeave']) && $reminderLog['dailyLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
$io->text('<fg=black;bg=white>' . $company->getFullName() . '</>: ' . count($leaves) . ' user leave request today');
$leaveData=array();
$c=0;
foreach($leaves as $l){
$ok=false;
if($l->getLeaveType()->getLeaveName()=='sick'){
$ok=true;
}else{
if(!is_null($l->getIsApproved())){
if(($l->getIsApproved()==1) || ($l->getIsApproved()===true)){
$ok=true;
}
}
}
if($ok){
$c=count($leaveData);
$leaveData[$c]['name']=$l->getUser()->getPersonalInfo()->getFullName();
$leaveData[$c]['User']=$l->getUser();
$leaveData[$c]['leavetype']=$l->getLeaveType()->getLeaveName();
$lattr=$l->getLeaveType()->getAttributes();
if(!is_null($lattr)){
if(isset($lattr['lable'])){ $leaveData[$c]['leavetype']=$lattr['lable'];}
}
$leaveData[$c]['days']=$l->getDays();
$leaveData[$c]['periode']='';
$txt='';
$attr=$l->getAttributes();
$daterg=array();
if(!is_null($attr)){
if(isset($attr['historymc'])){
if(isset($attr['manualapproved']) || isset($attr['manualappoved'])){
$mcmanual=null;
foreach($attr['historymc'] as $m){
$mcmanual=$m;
}
if(!is_null($mcmanual)){
$m=$mcmanual;
if(isset($m['startDate'])){
$dtstart=new \DateTime($m['startDate']);
}else{
$dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
}
if(isset($m['endDate'])){
$dtend=new \DateTime($m['endDate']);
}else{
$dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
}
$intl=date_diff($dtend,$dtstart);
if(isset($m['am'])){
$am=$m['am'];
}else{
$am=$l->getIsHalfStart();
if(is_null($am)){$am=false;}
}
if(isset($m['pm'])){
$pm=$m['pm'];
}else{
$pm=$l->getIsHalfEnd();
}
if(($pm==false) && ($pm==false)){
$am='';$pm='';
}else{
$am=$am?' PM':' AM';
$pm=$pm?' AM':' PM';
}
if((abs($intl->d) + 1) > 1){
$txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
}else{
$txt.=$dtstart->format('d M Y').$pm.', ';
}
}
} else{
foreach($attr['historymc'] as $m){
if(isset($m['startDate'])){
$dtstart=new \DateTime($m['startDate']);
}else{
$dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
}
if(isset($m['endDate'])){
$dtend=new \DateTime($m['endDate']);
}else{
$dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
}
$intl=date_diff($dtend,$dtstart);
if(isset($m['am'])){
$am=$m['am'];
}else{
$am=$l->getIsHalfStart();
if(is_null($am)){$am=false;}
}
if(isset($m['pm'])){
$pm=$m['pm'];
}else{
$pm=$l->getIsHalfEnd();
}
if(($pm==false) && ($pm==false)){
$am='';$pm='';
}else{
$am=$am?' PM':' AM';
$pm=$pm?' AM':' PM';
}
if((abs($intl->d) + 1) > 1){
$txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
}else{
$txt.=$dtstart->format('d M Y').$pm.', ';
}
}
}
}else{
$dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
$dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
$intl=date_diff($dtend,$dtstart);
$am=$l->getIsHalfStart();
$pm=$l->getIsHalfEnd();
if(is_null($am)){$am=false;}
if(is_null($pm)){$pm=false;}
if(($am==false) && ($pm==false)){
$am='';$pm='';
}else{
$am=$am?' PM':' AM';
$pm=$pm?' AM':' PM';
}
if(abs($intl->d) >= 1){
$txt.=$dtstart->format('d M Y').$am.' to '.$dtend->format('d M Y').$pm.', ';
}else{
$txt.=$dtstart->format('d M Y').$pm.', ';
}
}
}else{
$dtstart=new \DateTime($l->getStartDate()->format('Y-m-d'));
$dtend=new \DateTime($l->getEndDate()->format('Y-m-d'));
$intl=date_diff($dtend,$dtstart);
$am=$l->getIsHalfStart();
$pm=$l->getIsHalfEnd();
if(is_null($am)){$am=false;}
if(is_null($pm)){$pm=false;}
if(($am==false) && ($pm==false)){
$am='';$pm='';
}else{
$am=$am?' PM':' AM';
$pm=$pm?' AM':' PM';
}
if(abs($intl->d) >= 1){
$txt.=$dtstart->format('d M Y').$am.' - '.$dtend->format('d M Y').$pm.', ';
}else{
$txt.=$dtstart->format('d M Y').$pm.', ';
}
}
$txt=trim($txt);
$txt=trim($txt,',');
$txt=explode(',',$txt);
$txt=join('<br>',$txt);
$leaveData[$c]['periode']=$txt;
}
}
$this->leaveService->dailyLeaveEmail($leaveData);
$total++;
$reminderLog['dailyLeave'] = $now;
$company->setReminder($reminderLog);
$this->entityManager->flush();
} catch (Exception $e) {
$io->caution('Email sending error!');
continue;
}
};
}
$io->success($total . ' company daily email sent!');
}
protected function weeklyLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
if (date('N') == 5 || $force == true) {
$total = 0;
$now = new \DateTime();
$companies = $this->entityManager->getRepository(Company::class)->findAll();
foreach ($companies as $company) {
if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
$reminderLog = $company->getReminder();
$leaves = $this->entityManager->getRepository(LeaveRequest::class)->findNextWeekLeaveByCompany($company);
if ($leaves) {
try {
if (isset($reminderLog['weeklyLeave']) && $reminderLog['weeklyLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
$io->text('<fg=black;bg=white>' . $company->getFullName() . '</>: ' . count($leaves) . ' user on leave next week');
$this->leaveService->weeklyLeaveEmail($leaves);
$total++;
} catch (Exception $e) {
$io->caution('Email sending error!');
continue;
}
$reminderLog['weeklyLeave'] = $now;
$company->setReminder($reminderLog);
};
$this->entityManager->flush();
}
$io->success($total . ' company weekly leave email sent!');
} else {
$io->warning('Command only can be run on friday!');
};
}
protected function weeklyHoliday($force = false, $test = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$email = $test ? 'devops@mediatropy.com' : null;
if ($test) $io->text('[Test Mode]');
if (date('N') == 5 || $force == true) {
$total = 0;
$now = new \DateTime();
$companies = $this->entityManager->getRepository(Company::class)->findAll();
foreach ($companies as $company) {
if ($_SERVER['APP_ENV'] == 'prod' && $company->getId() != 4) continue;
$reminderLog = $company->getReminder();
$holidays = $this->entityManager->getRepository(LeaveBankHoliday::class)->findNextWeekHolidayByCompany($company);
if ($holidays) {
try {
if (isset($reminderLog['weeklyHoliday']) && $reminderLog['weeklyHoliday']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
$io->text('<fg=black;bg=white>' . $company->getFullName() . '</>: ' . count($holidays) . ' public holiday on next week');
$this->leaveService->weeklyHolidayEmail($holidays, $email);
$total++;
} catch (Exception $e) {
$io->warning('Email sending error!');
continue;
}
if (!$test) $reminderLog['weeklyHoliday'] = $now;
$company->setReminder($reminderLog);
};
$this->entityManager->flush();
}
$io->success($total . ' company weekly holiday email sent!');
} else {
$io->caution('Command only can be run on friday!');
}
}
protected function remindExpireLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$leaves = $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireNextMonth();
$total = 0;
$io->title('Leave expire reminder');
$headers = ['Name', 'leaveType', 'Days Left', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave->getUser();
$sending = false;
try {
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['expireLeave']) && $reminderLog['expireLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->leaveService->reminderExpireLeaveEmail($leave);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$leave->getLeaveType()->getAttributes()['label'],
$leave->getLeaveLeft(),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['expireLeave'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' leave expire reminder email sent!');
}
protected function remindExpireAnnualLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
// $now = '0108';
$now = date('dm');
if ($now == '0108' || $now == '0111' || $force == true) {
$leaves = $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireAnnualLeave();
$total = 0;
$io->title('Leave expire reminder');
$headers = ['Name', 'leaveType', 'Days Left', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave->getUser();
$sending = false;
try {
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['expireAnnualLeave']) && $reminderLog['expireAnnualLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->leaveService->reminderExpireAnnualLeaveEmail($leave);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$leave->getLeaveType()->getAttributes()['label'],
$leave->getLeaveLeft(),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['expireAnnualLeave'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' annual leave expire reminder email sent!');
}else{
$io->caution('Command only can be run on 1st August & 1st November!');
}
}
protected function remindExpireCarryForwardLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
// $now = '0101';
$now = date('dm');
if ($now == '0101' || $now == '0102' || $force == true) {
$leaves = $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireCarryForwardLeave();
$total = 0;
$io->title('Leave expire reminder');
$headers = ['Name', 'leaveType', 'Days Left', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave['user'];
$sending = false;
try {
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['expireCarryForwardLeave']) && $reminderLog['expireCarryForwardLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->leaveService->reminderExpireCarryForwardLeaveEmail($leave);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
'Carry Over '.$leave['year'],
$leave['carryLeft'],
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['expireCarryForwardLeave'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' carry forward leave expire reminder email sent!');
}else{
$io->caution('Command only can be run on 1st January & 1st February!');
}
}
protected function remindExpireAdjustmentLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$leaves = $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireAdjustment();
$total = 0;
$io->title('Adjustment leave expire reminder');
$headers = ['Name', 'leaveType', 'Days Left', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave->getUser();
$sending = false;
try {
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['expireAdjLeave']) && $reminderLog['expireAdjLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->leaveService->reminderExpireBonusAdjLeaveEmail($leave);
$notificationData = [
'%user%' => $user->getPersonalInfo()->getFirstName(),
];
$this->notificationService->push($user, 'notification.leave.adjustment', null, 'i-holiday-svg', null, true);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$leave->getLeaveType()->getAttributes()['label'],
$leave->getLeaveLeft(),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['expireAdjLeave'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' Adjustment leave expire reminder email sent!');
}
protected function remindExpireBonusLeave($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$leaves = $this->entityManager->getRepository(LeaveEntitlement::class)->findExpireBonus();
$total = 0;
$io->title('Bonus leave expire reminder');
$headers = ['Name', 'leaveType', 'Days Left', 'Sending'];
$rows = [];
foreach ($leaves as $leave) {
$user = $leave->getUser();
$sending = false;
try {
if (!in_array($user->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod') continue;
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['expireBonusLeave']) && $reminderLog['expireBonusLeave']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->leaveService->reminderExpireBonusAdjLeaveEmail($leave);
$notificationData = [
'%user%' => $user->getPersonalInfo()->getFirstName(),
];
$this->notificationService->push($user, 'notification.leave.bonus', null, 'i-holiday-svg', null, true);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$leave->getLeaveType()->getAttributes()['label'],
$leave->getLeaveLeft(),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['expireBonusLeave'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' Bonus leave expire reminder email sent!');
}
protected function birthdayNow($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findBirthdayNow();
$total = 0;
$io->title('Today Employee Birthday');
$headers = ['Name', 'Birth Date', 'Sending'];
$rows = [];
foreach ($users as $user) {
$sending = false;
try {
$reminderLog = $user->getReminder();
$permission = $user->getPermission();
$now = new \DateTime();
if (isset($reminderLog['birthdayNow']) && $reminderLog['birthdayNow']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true && (isset($permission['birthdayAnnouncement']) && $permission['birthdayAnnouncement'] == true)) {
$this->userService->birthdayEmail($user);
$receivers = $this->entityManager->getRepository(User::class)->findAllActive();
foreach ($receivers as $receiver) {
$notificationData = [
'%user%' => $user->getPersonalInfo()->getFirstName(),
];
$this->notificationService->push($receiver, 'notification.user.birthday', $notificationData, 'i-cake', null, true);
}
$sending = true;
$total++;
$reminderLog['birthdayNow'] = $now;
$user->setReminder($reminderLog);
};
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$user->getPersonalInfo()->getBirthDate()->format('d/m/Y'),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' employee birthday email sent!');
}
protected function remindBirthday($force, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$users = $this->entityManager->getRepository(User::class)->findIncomingBirthday();
$total = 0;
$io->title('Employee\'s birthday 3 days to come');
$headers = ['Name', 'Birth Date', 'Sending'];
$rows = [];
foreach ($users as $user) {
$sending = false;
try {
$reminderLog = $user->getReminder();
$now = new \DateTime();
if (isset($reminderLog['remindBirthday']) && $reminderLog['remindBirthday']->format('Ymd') == $now->format('Ymd') && $force == false) continue;
if ($user->getIsActive() == true) {
$this->userService->birthdayReminder($user);
$sending = true;
$total++;
}
array_push($rows, [
$user->getPersonalInfo()->getFullName(),
$user->getPersonalInfo()->getBirthDate()->format('d/m/Y'),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
$reminderLog['remindBirthday'] = $now;
$user->setReminder($reminderLog);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' employee birthday reminder email sent!');
}
protected function leaveProRate($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$io->text('<fg=black;bg=white>Processing...</>');
$total = $this->leaveService->LeaveProRateCron($force);
$io->success($total . ' leave Pro Rate processed!');
}
protected function syncStatus($input, $output)
{
$io = new SymfonyStyle($input, $output);
$io->text('<fg=black;bg=white>Processing...</>');
$userLeaveIds = $this->userService->syncStatusWithLeave();
$affectedUsersId = $this->userService->syncStatusWithWFA($userLeaveIds);
$users = $this->entityManager->getRepository(User::class)->findNotWorking($affectedUsersId);
foreach ($users as $user) {
if (!in_array($user->getId(), $affectedUsersId)) {
$user->setStatus('status.working_home');
};
}
$this->entityManager->flush();
$io->success('User status synced!');
}
static function date_diff_weekdays($from, $to)
{
if ($from === null || $to === null)
return null;
$date_from = new \DateTime($from);
$date_to = new \DateTime($to);
// calculate number of weekdays from start of week - start date
$from_day = intval($date_from->format('w')); // 0 (for Sunday) through 6 (for Saturday)
if ($from_day == 0)
$from_day = 7;
$from_wdays = $from_day > 5 ? 5 : $from_day;
// calculate number of weekdays from start of week - end date
$to_day = intval($date_to->format('w'));
if ($to_day == 0)
$to_day = 7;
$to_wdays = $to_day > 5 ? 5 : $to_day;
// calculate number of days between the two dates
$interval = $date_from->diff($date_to);
$days = intval($interval->format('%R%a')); // shows negative values too
// calculate number of full weeks between the two dates
$weeks_between = floor($days / 7);
if ($to_day >= $from_day)
$weeks_between -= 1;
// complete calculation of number of working days between
$diff_wd = 5 * ($weeks_between) + (5 - $from_wdays) + $to_wdays;
return $diff_wd;
}
protected function projectEndToday($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$projectEnds = $this->entityManager->getRepository(Project::class)->findProjectEndToday();
$total = 0;
$io->title('Project End Today');
$headers = ['Project Name', 'Start Date', 'End Date', 'PIC Name', 'Last Reminder', 'Sending'];
$rows = [];
$sending = false;
foreach ($projectEnds as $project) {
try {
if(($project->getLastReminder() != null) && ($project->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
$this->projectService->projectEndEmail($project);
$sending = true;
$project->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
$total++;
array_push($rows, [
$project->getName(),
$project->getStartDate()->format('d/m/Y'),
$project->getEndDate()->format('d/m/Y'),
$project->getPersonInCharge()->getPersonalInfo()->getFullName(),
$project->getLastReminder()->format('d/m/Y'),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' project end today email sent!');
}
protected function projectVendorPlanningEmpty($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$projectVendorPlanningEmpties = $this->entityManager->getRepository(Project::class)->findProjectVendorPlanningEmpty();
$total = 0;
$io->title('Project Vendor Planning Empty');
$headers = ['Project Name', 'created At', 'PIC Name', 'Last Reminder', 'Sending'];
$rows = [];
$sending = false;
foreach ($projectVendorPlanningEmpties as $project) {
try {
if(($project->getLastReminder() != null) && ($project->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
$this->projectService->projectVendorPlanningEmail($project);
$sending = true;
$project->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
$total++;
array_push($rows, [
$project->getName(),
$project->getCreatedAt()->format('d/m/Y'),
$project->getPersonInCharge()->getPersonalInfo()->getFullName(),
$project->getLastReminder()->format('d/m/Y'),
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' project empty vendor planning email sent!');
}
protected function remindProjectHosting($force = false, $test = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$projectHostings = $this->entityManager->getRepository(Project::class)->findExpiringProjectHosting();
$total = 0;
if($test){
$io->title('[Test Mode] Project Hosting Renewal Reminder');
} else {
$io->title('Project Hosting Renewal Reminder');
}
$headers = ['Project Name', 'Type', 'Renewal Date', 'PIC Email', 'Last Reminder', 'Sending'];
$rows = [];
$sending = false;
foreach ($projectHostings as $project) {
try {
if(($project->getProjectHosting()->getLastReminder() != null) && ($project->getProjectHosting()->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false && $test == false) continue;
if($project->getProjectHosting()->getRenewalDate()->format('d/m/Y') == date('d/m/Y', strtotime('+30 days'))){
array_push($rows, [
$project->getName(),
'Domain',
$project->getProjectHosting()->getRenewalDate()->format('d/m/Y') ,
$project->getPersonInCharge()->getEmail(),
$project->getProjectHosting()->getLastReminder() ? $project->getProjectHosting()->getLastReminder()->format('d/m/Y') : '-',
$sending ? 'Yes' : 'No'
]);
if(!$test){
$sending = true;
$this->projectService->projectHostingEmail($project, 'domain');
$rows[$total][5] = 'Yes';
}
$total++;
}
if($project->getProjectHosting()->getPlatformRenewalDate()->format('d/m/Y') == date('d/m/Y', strtotime('+30 days'))){
array_push($rows, [
$project->getName(),
'Platform',
$project->getProjectHosting()->getPlatformRenewalDate()->format('d/m/Y') ,
$project->getPersonInCharge()->getEmail(),
$project->getProjectHosting()->getLastReminder() ? $project->getProjectHosting()->getLastReminder()->format('d/m/Y') : '-',
$sending ? 'Yes' : 'No'
]);
if(!$test){
$sending = true;
$this->projectService->projectHostingEmail($project, 'platform');
$rows[$total][5] = 'Yes';
}
$total++;
}
if(!$test){
$project->getProjectHosting()->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
}
} catch (Exception $e) {
$sending = false;
continue;
}
}
$io->table($headers, $rows);
if(!$test) {
$this->entityManager->flush();
$io->success($total . ' project hosting expiring email sent!');
}
}
protected function remindUploadInvoiceExpense($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
$todayDate = date('Y-m-d');
$expenseRequests = $this->entityManager->getRepository(ExpenseRequest::class)->findByPage(1, 9999, 'ASC', "", "", null, 3, true, null, $todayDate);
$total = 0;
$io->title('Expense Request Upload Invoice Reminder');
$headers = ['Expense ID', 'Requester', 'Amount','Sheduled Payment', 'Recurring', 'Sending'];
$rows = [];
$sending = false;
foreach ($expenseRequests as $expense) {
try {
if(($expense->getLastReminder() != null) && ($expense->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
if (!in_array($expense->getRequester()->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod'){
}else{
$this->expenseRequestService->reminderUploadInvoiceEmail($expense);
$sending = true;
$expense->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
}
$total++;
array_push($rows, [
$expense->getGeneratedId(),
$expense->getRequester()->getPersonalInfo()->getShortFullName(),
$expense->getAmount(),
$expense->getPaymentScheduled()->format('d/m/Y'),
$expense->getRecurring() ?: 'No',
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' expense request upload invoice email reminder sent!');;
}
protected function remindUploadInvoiceExpenseRecurring($force = false, $input, $output)
{
$io = new SymfonyStyle($input, $output);
// $todayDate = date('2025-06-28');
$todayDate = date('Y-m-d');
$expenseRequests = $this->entityManager->getRepository(ExpenseRequest::class)->findByPage(1, 9999, 'ASC', "", "", null, "3;4;5", true, null, $todayDate, true);
$total = 0;
$io->title('Expense Request Upload Invoice Reminder (Recurring)');
$headers = ['Expense ID', 'Scheduled Payment', 'Project End Date', 'Invoice(s)', 'interval', 'Recurring', 'Sending'];
$rows = [];
$sending = false;
foreach ($expenseRequests as $expense) {
$interval = date_diff($expense->getPaymentScheduled(), new \DateTime($todayDate));
$totalInvoices = count($expense->getExpenseRequestInvoices()->toArray());
try {
if(($expense->getLastReminder() != null) && ($expense->getLastReminder()->format('Ymd') == date('Ymd')) && $force == false) continue;
if (!in_array($expense->getRequester()->getEmail(), $this->testAccounts) && $_SERVER['APP_ENV'] != 'prod'){
}else{
if($expense->getPaymentScheduled()->format('Y-m-d') == $todayDate){
$this->expenseRequestService->reminderUploadInvoiceEmail($expense);
$sending = true;
$expense->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
$total++;
}else{
$sending = false;
if($expense->getProject() && $expense->getProject()->getEndDate()){
$meetCondition = false;
if($expense->getRecurring() == 'Monthly'){
if($todayDate <= $expense->getProject()->getEndDate() && $interval->m >= 1 && ($totalInvoices < $interval->m + 1 || ($totalInvoices == $interval->m +1 && $expense->checkInvoices() == false))) $meetCondition = true;
}elseif($expense->getRecurring() == 'Yearly'){
if($todayDate <= $expense->getProject()->getEndDate() && $interval->y >= 1 && ($totalInvoices < $interval->y + 1 || ($totalInvoices == $interval->y +1 && $expense->checkInvoices() == false))) $meetCondition = true;
}
if($meetCondition){
$this->expenseRequestService->reminderUploadInvoiceEmail($expense);
$sending = true;
$expense->setLastReminder(new \DateTimeImmutable());
$this->entityManager->flush();
$total++;
}
}
}
}
array_push($rows, [
$expense->getGeneratedId(),
$expense->getPaymentScheduled()->format('d/m/Y'),
$expense->getProject() && $expense->getProject()->getEndDate() ? $expense->getProject()->getEndDate()->format('d/m/Y') : '-',
count($expense->getExpenseRequestInvoices()),
$expense->getRecurring() == 'Monthly' ? $interval->m + 1 : $interval->y + 1,
$expense->getRecurring() ?: 'No',
$sending ? '<fg=black;bg=green>Yes</>' : 'No'
]);
} catch (Exception $e) {
$sending = false;
continue;
}
}
$this->entityManager->flush();
$io->table($headers, $rows);
$io->success($total . ' expense request upload invoice email reminder sent!');;
}
protected function updateProvisionalRate($force = false, $test, $input, $output){
$io = new SymfonyStyle($input, $output);
if($test){
$io->text('<fg=black;bg=white>[Test Mode] Processing...</>');
} else {
$io->text('<fg=black;bg=white>Processing...</>');
}
$results = $this->currencyService->updateProvisionalRate($test);
if(count($results['rate']) > 0){
$headers = ['ID', 'Rate Date', 'Create Date', 'Currency', 'Old Rate', 'New Rate'];
$rows = [];
foreach ($results['rate'] as $result) {
array_push($rows, [
$result['id'],
$result['rate_date'],
$result['create_date'],
$result['currency'],
$result['old_rate'],
$result['new_rate']
]);
}
$io->table($headers, $rows);
}
if($results['total'] > count($results['rate'])){
$io->success(count($results['rate']) . ' of '.$results['total'].' Provisional Rate Updated!');
} else {
$io->success(count($results['rate']) . ' Provisional Rate Updated!');
}
}
}