<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: 'App\Repository\AppraisalRepository')]
class Appraisal
{
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $title;
#[Groups(['LogService'])]
#[ORM\Column(type: 'datetime')]
private $createdAt;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Column(type: 'datetime', nullable: true)]
private $reviewedAt;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\ManyToOne(targetEntity: 'App\Entity\User')]
private $reviewedBy;
#[Groups(['LogService'])]
#[ORM\ManyToOne(targetEntity: 'App\Entity\User', inversedBy: 'appraisals')]
#[ORM\JoinColumn(nullable: true)]
private $user;
#[Groups(['LogService'])]
#[ORM\OneToMany(targetEntity: 'App\Entity\AppraisalComment', mappedBy: 'appraisal', orphanRemoval: true)]
private $appraisalComments;
#[Groups(['LogService'])]
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(nullable: true)]
private $createdBy;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Column(type: 'datetime', nullable: true)]
private $submitAt = null;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Column(type: 'datetime', nullable: true)]
private $reviewAt = null;
#[Groups(['LogService', 'EmailSchedule'])]
#[ORM\Column(type: 'datetime', nullable: true)]
private $submittedAt;
#[ORM\Column(type: 'string', length: 32, nullable: true)]
private $icsToken;
#[ORM\OneToMany(targetEntity: AppraisalNote::class, mappedBy: 'appraisal', cascade: ['persist', 'remove'])]
private $appraisalNotes;
#[Groups(['LogService'])]
#[ORM\Column(type: 'smallint')]
private $reschedule = 0;
#[ORM\ManyToMany(targetEntity: User::class)]
private $reviewers;
#[ORM\OneToMany(targetEntity: AppraisalForm::class, mappedBy: 'appraisal', cascade: ['persist', 'remove'])]
private $appraisalForms;
#[ORM\Column(type: 'datetime', nullable: true)]
private $lastReminder;
#[ORM\Column(type: 'datetime', nullable: true)]
private $concludedAt;
#[ORM\Column(type: 'boolean')]
private $adHoc = false;
#[ORM\Column(type: 'boolean')]
private $probation = false;
public function __construct()
{
$this->appraisalComments = new ArrayCollection();
$this->appraisalNotes = new ArrayCollection();
$this->reviewers = new ArrayCollection();
$this->appraisalForms = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getReviewedAt(): ?\DateTimeInterface
{
return $this->reviewedAt;
}
public function setReviewedAt(\DateTimeInterface $reviewedAt): self
{
$this->reviewedAt = $reviewedAt;
return $this;
}
public function getReviewedBy(): ?User
{
return $this->reviewedBy;
}
public function setReviewedBy(?User $reviewedBy): self
{
$this->reviewedBy = $reviewedBy;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
/**
* @return Collection|AppraisalComment[]
*/
public function getAppraisalComments(): Collection
{
return $this->appraisalComments;
}
public function addAppraisalComment(AppraisalComment $appraisalComment): self
{
if (!$this->appraisalComments->contains($appraisalComment)) {
$this->appraisalComments[] = $appraisalComment;
$appraisalComment->setAppraisal($this);
}
return $this;
}
public function removeAppraisalComment(AppraisalComment $appraisalComment): self
{
if ($this->appraisalComments->contains($appraisalComment)) {
$this->appraisalComments->removeElement($appraisalComment);
// set the owning side to null (unless already changed)
if ($appraisalComment->getAppraisal() === $this) {
$appraisalComment->setAppraisal(null);
}
}
return $this;
}
public function hasComment($user)
{
foreach ($this->appraisalComments as $comment) {
if ($comment->getUser() == $user) {
return true;
}
};
return false;
}
public function hasDraftComment($user)
{
foreach ($this->appraisalComments as $comment) {
if ($comment->getUser() == $user && $comment->getDraft() == true) {
return true;
}
};
return false;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getSubmitAt(): ?\DateTimeInterface
{
return $this->submitAt;
}
public function setSubmitAt(\DateTimeInterface $submitAt): self
{
$this->submitAt = $submitAt;
return $this;
}
public function getReviewAt(): ?\DateTimeInterface
{
return $this->reviewAt;
}
public function setReviewAt(\DateTimeInterface $reviewAt): self
{
$this->reviewAt = $reviewAt;
return $this;
}
public function getSubmittedAt(): ?\DateTimeInterface
{
return $this->submittedAt;
}
public function setSubmittedAt(?\DateTimeInterface $submittedAt): self
{
$this->submittedAt = $submittedAt;
return $this;
}
public function appraisalCommentsByUser($uid)
{
$comments = [];
foreach ($this->appraisalComments as $comment) {
if ($comment->getUser()->getId() == $uid) {
array_push($comments, $comment);
}
};
return $comments;
}
public function totalAppraisalForm(){ // used for counting form if form deleted
$total = 0;
if($this->appraisalForms->toArray()){
$total = count($this->appraisalForms);
} else {
foreach($this->appraisalComments as $commentForm){
if($commentForm->getUser() == $this->user){
$total++;
}
}
}
return $total;
}
public function appraisalCommentsByForm($form, $index = null)
{
$comments = [];
if(is_int($form) || $form->getForm()){
$fid = is_int($form) ? $form : $form->getForm()->getId();
foreach ($this->appraisalComments as $comment) {
if ($comment->getForm()->getId() == $fid) {
array_push($comments, $comment);
}
};
} else { // if form deleted, this will be used
$totalForm = $this->totalAppraisalForm();
$form = json_decode($form->getFormContent());
$formIndex = 1;
foreach ($this->appraisalComments as $comment) {
// $formContent = json_decode($comment->getFormContent());
if ($formIndex == $index){
array_push($comments, $comment);
}
$formIndex = $formIndex == $totalForm ? 1 : $formIndex + 1;
};
}
return $comments;
}
public function appraisalScore(){
$totalForm = $this->totalAppraisalForm();
$formIndex = 1;
$score = 0;
$totalValidScore = 0;
foreach($this->appraisalComments as $commentForm){
if($commentForm->getUser() != $this->user || $commentForm->getDraft() == true) continue;
$questionScore = $this->appraisalQuestionScore($commentForm, $formIndex);
if($questionScore > 0){
$score += $questionScore;
$totalValidScore++;
}
$formIndex = $formIndex == $totalForm ? 1 : $formIndex + 1;
};
if($totalValidScore > 0){
return number_format($score / $totalValidScore, 1, '.', '');
} else {
return null;
}
}
public function appraisalQuestionScore($form, $index = null){
$score = 0;
// $totalValidScore = 0;
$baseScore = 0;
$reviewerScore = 0;
$managerScore = 0;
$otherScore = 0;
$totalOtherScore = 0;
if(is_int($form) || $form->getForm()){
$fid = is_int($form) ? $form : $form->getForm()->getId();
foreach ($this->appraisalComments as $comment) {
if ($comment->getForm() && $comment->getForm()->getId() == $fid && $comment->getDraft() == false) {
if($comment->getUser() == $this->user){
$baseScore = $comment->getScore();
} else if($comment->getUser() == $this->user->getManager() || $comment->getUser() == $this->reviewedBy){
$managerScore = $comment->getScore();
} else {
$otherScore += $comment->getScore();
$totalOtherScore++;
}
}
};
} else { // if form deleted, this will be used
$formIndex = 1;
$totalForm = $this->totalAppraisalForm();
// $form = json_decode($form->getFormContent());
foreach ($this->appraisalComments as $comment) {
// $formContent = json_decode($comment->getFormContent());
if ($formIndex == $index){
if($comment->getUser() == $this->user){
$baseScore = $comment->getScore();
} else if($comment->getUser() == $this->user->getManager() || $comment->getUser() == $this->reviewedBy){
$managerScore = $comment->getScore();
} else {
$otherScore += $comment->getScore();
$totalOtherScore++;
}
}
$formIndex = $formIndex == $totalForm ? 1 : $formIndex + 1;
};
}
if($totalOtherScore > 0){ // avarage other reviewer score
$otherScore = $otherScore / $totalOtherScore;
}
if($otherScore != 0 && $managerScore != 0){ // if manager already review and other reviewer already review too
$reviewerScore = $otherScore < $managerScore ? $managerScore : ($managerScore + $otherScore) / 2; // if other score lower than manager score, use manager score
} else if($managerScore == 0){ // if manager not yet review, use other score
$reviewerScore = $otherScore;
} else { // if other reviewer not review, use manager score
$reviewerScore = $managerScore;
}
$score = $baseScore > $reviewerScore ? $reviewerScore : ($baseScore + $reviewerScore) / 2; // if base score higher than reviewer score, use reviewer score
return number_format($score, 1, '.', ''); // final score
// return number_format($score / $totalValidScore, 1, '.', '');
}
public function getIcsToken(): ?string
{
return $this->icsToken;
}
public function setIcsToken(?string $icsToken): self
{
$this->icsToken = $icsToken;
return $this;
}
/**
* @return Collection|AppraisalNote[]
*/
public function getAppraisalNotes(): Collection
{
return $this->appraisalNotes;
}
public function addAppraisalNote(AppraisalNote $appraisalNote): self
{
if (!$this->appraisalNotes->contains($appraisalNote)) {
$this->appraisalNotes[] = $appraisalNote;
$appraisalNote->setAppraisal($this);
}
return $this;
}
public function removeAppraisalNote(AppraisalNote $appraisalNote): self
{
if ($this->appraisalNotes->removeElement($appraisalNote)) {
// set the owning side to null (unless already changed)
if ($appraisalNote->getAppraisal() === $this) {
$appraisalNote->setAppraisal(null);
}
}
return $this;
}
public function hasEmptyNote()
{
$totalEmptyNote = 0;
foreach ($this->appraisalNotes as $note) {
if ($note->getNote() == null && $note->getDraft() == false){
$totalEmptyNote++;
}
}
if($totalEmptyNote == 0){
return false;
} else {
return $totalEmptyNote < count($this->appraisalNotes) ? false : true;
}
}
public function getReschedule(): ?int
{
return $this->reschedule;
}
public function setReschedule(?int $reschedule): self
{
$this->reschedule = $reschedule;
return $this;
}
/**
* @return Collection|User[]
*/
public function getReviewers(): Collection
{
return $this->reviewers;
}
public function addReviewer(User $reviewer): self
{
if (!$this->reviewers->contains($reviewer)) {
$this->reviewers[] = $reviewer;
}
return $this;
}
public function removeReviewer(User $reviewer): self
{
$this->reviewers->removeElement($reviewer);
return $this;
}
public function hasReviewed($user = null)
{
if ($this->reviewers != null && count($this->reviewers) > 0) {
if($user == null){
return true;
} else {
foreach ($this->reviewers as $reviewer) {
if ($user == $reviewer) {
return true;
}
}
}
// } elseif ($user != null && $this->reviewedBy == $user) {
// return true;
}
return false;
}
public function reviewedByManager(){
$managers = $this->user->getAllManager();
foreach ($managers as $manager) {
if($this->hasReviewed($manager)){
return true;
}
}
return false;
}
/**
* @return Collection|AppraisalForm[]
*/
public function getAppraisalForms(): Collection
{
return $this->appraisalForms;
}
public function addAppraisalForm(AppraisalForm $appraisalForm): self
{
if (!$this->appraisalForms->contains($appraisalForm)) {
$this->appraisalForms[] = $appraisalForm;
$appraisalForm->setAppraisal($this);
}
return $this;
}
public function removeAppraisalForm(AppraisalForm $appraisalForm): self
{
if ($this->appraisalForms->removeElement($appraisalForm)) {
// set the owning side to null (unless already changed)
if ($appraisalForm->getAppraisal() === $this) {
$appraisalForm->setAppraisal(null);
}
}
return $this;
}
public function getLastReminder(): ?\DateTimeInterface
{
return $this->lastReminder;
}
public function setLastReminder(?\DateTimeInterface $lastReminder): self
{
$this->lastReminder = $lastReminder;
return $this;
}
public function getConcludedAt(): ?\DateTimeInterface
{
return $this->concludedAt;
}
public function setconcludedAt(?\DateTimeInterface $concludedAt): self
{
$this->concludedAt = $concludedAt;
return $this;
}
public function currentStep($reviewer = null)
{
/*
-1 = legacy
0 = disabled
1 = waiting user to fill
2 = waiting manager to fill
3 = waiting review time
4 = review time
5 = review done but still need main manager conclusion
6 = review done
7 = past review/summary/adhoc
*/
if($this->user == null) return false;
$lastRevamp = '20220328'; // the date is from when the last appraisal revamp done
$lastRevamp2 = '20220920'; // the date is from when the last appraisal revamp done 2
if ($this->getAdHoc()) {
if ($this->getReviewAt()->format('Ymd') > date('Ymd') && ($this->hasReviewed($reviewer) == true || $this->getReviewedBy() != null)) {
return 3;
} else if ($this->getReviewAt()->format('Ymd') == date('Ymd')) {
return 4;
} else {
return 7;
}
} else if ($this->getCreatedAt() !== null && $this->getCreatedAt()->format('Ymd') >= $lastRevamp2) { // new appraisal system 2022-09-20;
if($this->getConcludedAt() == null){
if ($this->getSubmitAt() != null && $this->getSubmittedAt() == null && $this->getReviewAt() == null) {
return 1;
//} else if ($this->getSubmittedAt() != null && $this->getReviewedAt() == null && $this->getSubmitAt()->format('Ymd') > $lastRevamp2 && $this->hasReviewed() == false && $this->getReviewedBy() == null) {
} else if ($this->getSubmittedAt() != null && $this->getReviewedAt() == null && $this->getSubmitAt()->format('Ymd') > $lastRevamp2 && $this->reviewedByManager() == false) {
return 2;
} else if ($this->getSubmittedAt() != null && ($this->getReviewAt() == null || ($this->getReviewAt()->format('Ymd') > date('Ymd') && $this->reviewedByManager() == true))) {
return 3;
} else if ($this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') == date('Ymd') && $this->getSubmittedAt() != null && $this->getReviewedAt() != null && $this->getConcludedAt() == null) {
return 4;
} else if ($this->getSubmitAt() != null && $this->getReviewAt() != null && $this->getSubmittedAt() != null && $this->getReviewedAt() != null && $this->getConcludedAt() == null) {
return 5;
} else if ($this->getSubmitAt() == null && $this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') < date('Ymd') && $this->getSubmittedAt() == null) {
return 7;
} else {
return 0;
};
// } else if ($this->getSubmitAt() != null && $this->getSubmittedAt() != null &&$this->getReviewAt() == null) {
// return 8;
// } else if ($this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') < date('Ymd') && $this->getSubmittedAt() != null && $this->getReviewedAt() != null) {
} else {
return 6;
}
} else if ($this->probation) { //old rule for probation (previously for all)
if($this->getConcludedAt() == null){
if ($this->getSubmitAt() != null && $this->getSubmittedAt() == null && $this->getReviewAt() == null) {
return 1;
} else if ($this->getSubmittedAt() != null && $this->getReviewedAt() == null && $this->getSubmitAt()->format('Ymd') > $lastRevamp && $this->reviewedByManager() == false) {
return 2;
} else if ($this->getSubmittedAt() != null && ($this->getReviewAt() == null || $this->getReviewAt()->format('Ymd') > date('Ymd')) && ($this->reviewedByManager() == true)) {
//} else if ($this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') > date('Ymd') && $this->getSubmittedAt() != null && ($this->hasReviewed($reviewer) == true || $this->getReviewedBy() != null)) {
return 3;
} else if ($this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') == date('Ymd') && $this->getSubmittedAt() != null && $this->getReviewedAt() != null && $this->getConcludedAt() == null) {
return 4;
} else if ($this->getSubmitAt() != null && $this->getReviewAt() != null && $this->getSubmittedAt() != null && $this->getReviewedAt() != null && $this->getConcludedAt() == null) {
if ($this->getCreatedAt()->format('Ymd') < $lastRevamp && $this->getSubmitAt()->format('Ymd') < $lastRevamp) {
return 6;
} else {
return 5;
}
} else if ($this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') < date('Ymd') && $this->getSubmittedAt() != null && $this->getReviewedAt() != null) {
return 6;
} else if ($this->getSubmitAt() == null && $this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') < date('Ymd') && $this->getSubmittedAt() == null) {
return 7;
} else if ($this->getSubmittedAt() != null && $this->getReviewedBy() != null) {
return -1;
} else {
return 0;
};
} else {
return 6;
};
} else { // old rule for the rest
if ($this->getSubmitAt() == null && $this->getReviewAt() != null && $this->getReviewAt()->format('Ymd') < date('Ymd') && $this->getSubmittedAt() == null) {
return 7;
} else {
return -1;
};
};
}
public function getAdHoc(): ?bool
{
return $this->adHoc;
}
public function setAdHoc(bool $adHoc): self
{
$this->adHoc = $adHoc;
return $this;
}
public function getProbation(): ?bool
{
return $this->probation;
}
public function setProbation(bool $probation): self
{
$this->probation = $probation;
return $this;
}
public function getInUserDraft()
{
if($this->appraisalComments == null || count($this->appraisalComments) == 0){
return false;
}
foreach ($this->appraisalComments as $comment) {
if ($comment->getUser() == $this->user && $comment->getDraft() == true) {
return true;
}
};
return false;
}
public function getInManagerDraft()
{
if($this->appraisalComments == null || count($this->appraisalComments) == 0){
return false;
}
foreach ($this->appraisalComments as $comment) {
if ($comment->getUser() == $this->user->getManager() && $comment->getDraft() == true) {
return true;
}
};
return false;
}
}