<?php
namespace App\Entity;
use App\Repository\WorksPlanJobRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* WorksPlanJob — task altındaki iş birimi (Order'daki ProjectOrderTaskJobs aynası).
* Planlama otoritesi burada: start_at + should_end_at cascade kaynağı.
* is_end_at Order'dan listener ile geri akar; cascade tetiklemez (informational).
*
* Dependency edge'i child sahibinde — bu job için "ben başlamadan önce şunlar bitsin":
* - $parent_dependencies: bu job'a gelen kenarlar (child=$this)
* - $child_dependencies: bu job'tan giden kenarlar (parent=$this)
*
* @ORM\Entity(repositoryClass=WorksPlanJobRepository::class)
* @ORM\Table(name="works_plan_jobs")
*/
class WorksPlanJob
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({
* "works_plan_job@base",
* "works_plan_job@core"
* })
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=WorksPlanTask::class, inversedBy="jobs")
* @ORM\JoinColumn(name="works_plan_task_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $works_plan_task;
/**
* @ORM\Column(type="integer")
* @Groups({
* "works_plan_job@base",
* "works_plan_job@core"
* })
*/
private $job_index;
/**
* @ORM\Column(type="text", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
*/
private $job_description;
/**
* Serbest açıklama/not (başlık=job_description'dan ayrı). Drawer'da düzenlenir.
*
* @ORM\Column(type="text", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
*/
private $description;
/**
* @ORM\Column(type="float")
* @Groups({
* "works_plan_job@core"
* })
*/
private $job_weight;
/**
* Ağırlık pin: kullanıcı bu job'un yüzdesini bilerek sabitlediyse true.
* Rebalance pinli job'lara dokunmaz; pinsiz kardeşler kalanı orantılı paylaşır.
*
* @ORM\Column(type="boolean", options={"default": false})
* @Groups({
* "works_plan_job@core"
* })
*/
private $weight_locked = false;
/**
* Tamamlama kilidi (weight_locked'tan FARKLI). Order job tamamlanınca true olur
* (back-sync). Kilitliyken order job'u değiştiremez; sadece plan yöneticisi unlock eder.
* Plan = lock otoritesi; materialize ile order'a (project_order_task_jobs.locked) yansır.
*
* @ORM\Column(type="boolean", options={"default": false})
* @Groups({
* "works_plan_job@core"
* })
*/
private $locked = false;
/**
* @ORM\Column(type="date_immutable", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
* @Context({"datetime_format"="Y-m-d"})
*/
private $start_at;
/**
* @ORM\Column(type="date_immutable", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
* @Context({"datetime_format"="Y-m-d"})
*/
private $should_end_at;
/**
* @ORM\Column(type="date_immutable", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
* @Context({"datetime_format"="Y-m-d"})
*/
private $is_end_at;
/**
* Bitiş geri bildirimi / sebep (elle is_end_at girilince). Yalnızca Plan tarafında;
* Order'a yansımaz (orada gerekmez).
*
* @ORM\Column(type="text", nullable=true)
* @Groups({
* "works_plan_job@core"
* })
*/
private $is_end_note;
/**
* @ORM\Column(type="float")
* @Groups({
* "works_plan_job@core"
* })
*/
private $duration_days;
/**
* Bu job'a gelen kenarlar (child=$this). UI'da "Bekle: [parent chip] +Ng" listesi.
*
* @ORM\OneToMany(targetEntity=WorksPlanJobDependency::class, mappedBy="child_job", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"dependency_index" = "ASC"})
* @Groups({
* "works_plan_job@dependencies"
* })
*/
private $parent_dependencies;
/**
* Bu job'tan giden kenarlar (parent=$this). Yalnızca cascade hesabı / cycle detection için.
* Serialization gerekmez (back-reference).
*
* @ORM\OneToMany(targetEntity=WorksPlanJobDependency::class, mappedBy="parent_job", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $child_dependencies;
/**
* @ORM\OneToMany(targetEntity=WorksPlanJobHistory::class, mappedBy="job", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"changed_at" = "DESC"})
* @Groups({
* "works_plan_job@history"
* })
*/
private $history;
public function __construct()
{
$this->parent_dependencies = new ArrayCollection();
$this->child_dependencies = new ArrayCollection();
$this->history = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getWorksPlanTask(): ?WorksPlanTask
{
return $this->works_plan_task;
}
public function setWorksPlanTask(?WorksPlanTask $works_plan_task): self
{
$this->works_plan_task = $works_plan_task;
return $this;
}
public function getJobIndex(): ?int
{
return $this->job_index;
}
public function setJobIndex(int $job_index): self
{
$this->job_index = $job_index;
return $this;
}
public function getJobDescription(): ?string
{
return $this->job_description;
}
public function setJobDescription(?string $job_description): self
{
$this->job_description = $job_description;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getJobWeight(): ?float
{
return $this->job_weight;
}
public function setJobWeight(float $job_weight): self
{
$this->job_weight = $job_weight;
return $this;
}
public function getWeightLocked(): bool
{
return (bool) $this->weight_locked;
}
public function getLocked(): bool
{
return (bool) $this->locked;
}
public function setLocked(bool $locked): self
{
$this->locked = $locked;
return $this;
}
public function setWeightLocked(bool $weight_locked): self
{
$this->weight_locked = $weight_locked;
return $this;
}
public function getStartAt(): ?\DateTimeImmutable
{
return $this->start_at;
}
public function setStartAt(?\DateTimeImmutable $start_at): self
{
$this->start_at = $start_at;
return $this;
}
public function getShouldEndAt(): ?\DateTimeImmutable
{
return $this->should_end_at;
}
public function setShouldEndAt(?\DateTimeImmutable $should_end_at): self
{
$this->should_end_at = $should_end_at;
return $this;
}
public function getIsEndAt(): ?\DateTimeImmutable
{
return $this->is_end_at;
}
public function setIsEndAt(?\DateTimeImmutable $is_end_at): self
{
$this->is_end_at = $is_end_at;
return $this;
}
public function getIsEndNote(): ?string
{
return $this->is_end_note;
}
public function setIsEndNote(?string $is_end_note): self
{
$this->is_end_note = $is_end_note;
return $this;
}
public function getDurationDays(): ?float
{
return $this->duration_days;
}
public function setDurationDays(float $duration_days): self
{
$this->duration_days = $duration_days;
return $this;
}
/**
* @return Collection<int, WorksPlanJobDependency>
*/
public function getParentDependencies(): Collection
{
return new ArrayCollection(array_values($this->parent_dependencies->toArray()));
}
public function addParentDependency(WorksPlanJobDependency $dependency): self
{
if (!$this->parent_dependencies->contains($dependency)) {
$this->parent_dependencies[] = $dependency;
$dependency->setChildJob($this);
}
return $this;
}
public function removeParentDependency(WorksPlanJobDependency $dependency): self
{
if ($this->parent_dependencies->removeElement($dependency)) {
if ($dependency->getChildJob() === $this) {
$dependency->setChildJob(null);
}
}
return $this;
}
/**
* @return Collection<int, WorksPlanJobDependency>
*/
public function getChildDependencies(): Collection
{
return new ArrayCollection(array_values($this->child_dependencies->toArray()));
}
/**
* @return Collection<int, WorksPlanJobHistory>
*/
public function getHistory(): Collection
{
return new ArrayCollection(array_values($this->history->toArray()));
}
public function addHistory(WorksPlanJobHistory $entry): self
{
if (!$this->history->contains($entry)) {
$this->history[] = $entry;
$entry->setJob($this);
}
return $this;
}
}