src/Entity/ProjectOrderTaskFulfillment.php line 15

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Repository\ProjectOrderTaskFulfillmentRepository;
  4. use Doctrine\Common\Collections\ArrayCollection;
  5. use Doctrine\Common\Collections\Collection;
  6. use Doctrine\ORM\Mapping as ORM;
  7. use Symfony\Component\Serializer\Annotation\Groups;
  8. use Symfony\Component\Serializer\Annotation\SerializedName;
  9. /**
  10.  * @ORM\Entity(repositoryClass=ProjectOrderTaskFulfillmentRepository::class)
  11.  */
  12. class ProjectOrderTaskFulfillment
  13. {
  14.     /**
  15.      * @ORM\Id
  16.      * @ORM\GeneratedValue
  17.      * @ORM\Column(type="integer")
  18.      * @Groups({
  19.      *     "project_order_task_fulfillment@ref",
  20.      *     "project_order_task_fulfillment@base",
  21.      *     "project_order_task_fulfillment@core"
  22.      * })
  23.      */
  24.     private $id;
  25.     /**
  26.      * @ORM\ManyToOne(targetEntity=Vendor::class, inversedBy="project_order_task_fulfillments")
  27.      * @ORM\JoinColumn(nullable=true, options={"comment": "Use this data if scope:External & work-natue: support&production"})
  28.      * @Groups({
  29.      *      "project_order_task_fulfillment@vendor"
  30.      *  })
  31.      */
  32.     private $vendor;
  33.     /**
  34.      * @ORM\ManyToOne(targetEntity=VendorContactPersons::class, inversedBy="project_order_task_fulfillments")
  35.      * @ORM\JoinColumn(nullable=true, options={"comment": "Use this data if scope:External & work-natue: support&production"})
  36.      * @Groups({
  37.      *     "project_order_task_fulfillment@contact_person"
  38.      * })
  39.      */
  40.     private $vendor_contact_person;
  41.     /**
  42.      * @ORM\Column(type="text", nullable=true)
  43.      * @Groups({
  44.      *      "project_order_task_fulfillment@core"
  45.      *  })
  46.      */
  47.     private $work_content;
  48.     /**
  49.      * 2026-08-10 karar: yeni TaskExecution akisi reason sormuyor (wizard'da yok) ->
  50.      * nullable=true yapildi. Eski Fulfillment dialog'unun `reason` zorunlu tuttugu
  51.      * senaryo hala calisir (alan opsiyonel oldu, zorunlulugu FE tarafinda kaldi).
  52.      * @ORM\ManyToOne(targetEntity=TaskFulfillmentReasons::class, inversedBy="project_order_task_fulfillments")
  53.      * @ORM\JoinColumn(nullable=true)
  54.      * @Groups({
  55.      *     "project_order_task_fulfillment@reason"
  56.      * })
  57.      */
  58.     private $reason;
  59.     // "project_order_task_fulfillment@task"
  60.     /**
  61.      * @ORM\OneToOne(targetEntity=ProjectOrderTasks::class, inversedBy="task_fulfillment")
  62.      * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
  63.      * @Groups({
  64.      *      "project_order_task_fulfillment@task"
  65.      *  })
  66.      */
  67.     private $task;
  68.     /**
  69.      * @ORM\Column(type="boolean", nullable=true)
  70.      * @Groups({
  71.      *     "project_order_task_fulfillment@core"
  72.      * })
  73.      */
  74.     private $is_linked;
  75.     /**
  76.      * @ORM\Column(type="date_immutable", nullable=true)
  77.      * @Groups({
  78.      *       "project_order_task_fulfillment@core"
  79.      *   })
  80.      */
  81.     private $planned_start_at;
  82.     /**
  83.      * @ORM\Column(type="date_immutable", nullable=true)
  84.      * @Groups({
  85.      *       "project_order_task_fulfillment@core"
  86.      *   })
  87.      */
  88.     private $planned_end_at;
  89.     /**
  90.      * @ORM\Column(type="date_immutable", nullable=true)
  91.      * @Groups({
  92.      *       "project_order_task_fulfillment@core"
  93.      *   })
  94.      */
  95.     private $actual_end_at;
  96.     /**
  97.      * @ORM\Column(type="date_immutable", nullable=true)
  98.      * @Groups({
  99.      *       "project_order_task_fulfillment@core"
  100.      *   })
  101.      */
  102.     private $delivery_at;
  103.     /**
  104.      * @ORM\Column(type="text", nullable=true)
  105.      * @Groups({
  106.      *       "project_order_task_fulfillment@core"
  107.      *   })
  108.      */
  109.     private $delivery_note;
  110.     /**
  111.      * @ORM\Column(type="float", nullable=true)
  112.      * @Groups({
  113.      *       "project_order_task_fulfillment@core"
  114.      *   })
  115.      */
  116.     private $rating;
  117.     /**
  118.      * @ORM\Column(type="float", nullable=true)
  119.      * @Groups({
  120.      *        "project_order_task_fulfillment@core"
  121.      *    })
  122.      */
  123.     private $cost;
  124.     /**
  125.      * @ORM\Column(type="string", length=64, nullable=true)
  126.      * @Groups({
  127.      *         "project_order_task_fulfillment@core"
  128.      *     })
  129.      */
  130.     private $contract_reference_nr;
  131.     /**
  132.      * @ORM\ManyToOne(targetEntity=ContractTypes::class, inversedBy="project_order_task_fulfillments")
  133.      * @Groups({
  134.      *          "project_order_task_fulfillment@contract_type"
  135.      *      })
  136.      */
  137.     private $contract_type;
  138.     /**
  139.      * @ORM\OneToMany(targetEntity=ProjectOrderTaskFulfillmentWorkDocs::class, mappedBy="project_order_task_fulfillment", cascade={"persist"}, orphanRemoval=true)
  140.      * @Groups({
  141.      *      "project_order_task_fulfillment@work_documents"
  142.      *  })
  143.      */
  144.     private $work_documents;
  145.     /**
  146.      * Gerekçeli tarih revizyon zinciri (kullanıcı kararı 2026-08-11). GÜNCEL tarih = EN SON revizyon;
  147.      * committed_* buradan türetilir. İlk satır = kabul (reason null), sonrakiler gerekçeli revizyon.
  148.      *
  149.      * @ORM\OneToMany(targetEntity=ProjectOrderTaskFulfillmentDateRevision::class, mappedBy="project_order_task_fulfillment", cascade={"persist"}, orphanRemoval=true)
  150.      * @ORM\OrderBy({"created_at" = "ASC", "id" = "ASC"})
  151.      * @Groups({
  152.      *      "project_order_task_fulfillment@core"
  153.      *  })
  154.      */
  155.     private $date_revisions;
  156.     /**
  157.      * @ORM\Column(type="task_execution_scope", nullable=true)
  158.      * @Groups({
  159.      *       "project_order_task_fulfillment@core",
  160.      *       "project_order_task_fulfillment@progress"
  161.      * })
  162.      */
  163.     private $execution_scope;
  164.     /**
  165.      * @ORM\Column(type="task_execution_work_nature", nullable=true)
  166.      * @Groups({
  167.      *       "project_order_task_fulfillment@core"
  168.      * })
  169.      */
  170.     private $execution_work_nature;
  171.     /**
  172.      * @ORM\ManyToOne(targetEntity=Branches::class, inversedBy="project_order_task_fulfillments")
  173.      * @ORM\JoinColumn(options={"comment": "Use this data if fulfillment is internal&production"})
  174.      * @Groups({
  175.      *        "project_order_task_fulfillment@branch"
  176.      *  })
  177.      */
  178.     private $branch;
  179.     /**
  180.      * @ORM\ManyToOne(targetEntity=WorkerActivities::class, inversedBy="project_order_task_fulfillments")
  181.      * @ORM\JoinColumn(options={"comment": "Use this data if fulfillment is internal&production"})
  182.      * @Groups({
  183.      *         "project_order_task_fulfillment@branch_contact_person"
  184.      *   })
  185.      */
  186.     private $branch_contact_person;
  187.     /**
  188.      * TaskExecution akisi durumu: draft (K4 — task icin acilan taslak, henuz servise
  189.      * verilmedi) | published (K5 — servise devredildi, bundan sonra tek yazar servistir).
  190.      * Default'un TEK kaynagi burasi (property default) — Doctrine Type sadece gecerli
  191.      * degerleri dogrular, varsayilan atamaz.
  192.      * @ORM\Column(type="task_execution_status", nullable=false, options={"default": "draft"})
  193.      * @Groups({
  194.      *     "project_order_task_fulfillment@core",
  195.      *     "project_order_task_fulfillment@progress"
  196.      * })
  197.      */
  198.     private $status 'draft';
  199.     /**
  200.      * Servise ne zaman devredildi (publish anindaki timestamp).
  201.      * @ORM\Column(type="datetime_immutable", nullable=true)
  202.      * @Groups({
  203.      *     "project_order_task_fulfillment@core"
  204.      * })
  205.      */
  206.     private $published_at;
  207.     /**
  208.      * K8 — icra eden kisi (vendor_contact_person / branch_contact_person) isi KABUL ettiginde
  209.      * (servis tarafindaki "Is kabul edildi" butonu) doldurulan timestamp. Kabul = published +
  210.      * accepted_at dolu. Yeni status ENUM degeri EKLENMEDI (karar 11: zengin status reddedildi);
  211.      * accepted_at aynasi published_at gibi tutulur. Yalniz servis (ag-ici accept ucu) yazar
  212.      * (K5 — yayin sonrasi tek yazar servis). Silme kilidi bu alana bagli: dolu ise task silinemez.
  213.      * @ORM\Column(type="datetime_immutable", nullable=true)
  214.      * @Groups({
  215.      *     "project_order_task_fulfillment@core",
  216.      *     "project_order_task_fulfillment@progress"
  217.      * })
  218.      */
  219.     private $accepted_at;
  220.     /**
  221.      * K8-accept — icra eden kisi isi REDDETTIGINDE (servis "Reddet" butonu) dolan timestamp.
  222.      * Alt-durum: published + accepted_at NULL + declined_at NULL = Pending; accepted_at dolu =
  223.      * Accepted; declined_at dolu = Declined. Yalniz servis yazar (K5). Reddedilen is geri
  224.      * sahibine doner → SILINEBILIR (yalniz accepted silme kilidi tetikler, declined DEGIL).
  225.      * @ORM\Column(type="datetime_immutable", nullable=true)
  226.      * @Groups({
  227.      *     "project_order_task_fulfillment@core",
  228.      *     "project_order_task_fulfillment@progress"
  229.      * })
  230.      */
  231.     private $declined_at;
  232.     /**
  233.      * PEER BATCH (2026-08-16) — RED gerekçe KATEGORİSİ. `reason_category` ile aynı deseni
  234.      * kullanır (App\Enum\TaskExecutionReasonCategoryEnum — supply/personnel/weather/
  235.      * scope_change/other, tarih revizyonuyla AYNI enum, yeni bir tane açılmadı). Opsiyonel —
  236.      * decline BE'de zorunlu tutulmuyor (K8-decline zaten idempotent bir aksiyon). `@core`'da
  237.      * → ERP owner reddin sebebini görebilsin.
  238.      * @ORM\Column(type="task_execution_reason_category", nullable=true)
  239.      * @Groups({
  240.      *     "project_order_task_fulfillment@core"
  241.      * })
  242.      */
  243.     private $decline_reason_category;
  244.     /**
  245.      * PEER BATCH (2026-08-16) — RED gerekçesi serbest metin. `decline_reason_category`'nin
  246.      * YANINDA (kategori + serbest metin ikilisi, tarih revizyonuyla aynı desen). Yalnız
  247.      * icra eden (servis, internal decline ucu) yazar.
  248.      * @ORM\Column(type="string", length=1000, nullable=true)
  249.      * @Groups({
  250.      *     "project_order_task_fulfillment@core"
  251.      * })
  252.      */
  253.     private $decline_reason;
  254.     /**
  255.      * Task-bazlı owner⟷executor mesajlaşma zinciri (karar 59, Chat-K1/Chat-K2). created_at ile
  256.      * sıralı. ⚠️ Bilerek Groups anotasyonu YOK — mesaj İÇERİĞİ bu payload'a (serializeFull/
  257.      * serializeFullWithJobs/serializeFullPreview) ASLA karışmaz; ayrı uçlardan (message/list,
  258.      * internal/message/list, internal/messages/recent) gelir (Chat-K1).
  259.      * @ORM\OneToMany(targetEntity=ProjectOrderTaskFulfillmentMessage::class, mappedBy="execution", cascade={"persist"}, orphanRemoval=true)
  260.      * @ORM\OrderBy({"created_at" = "ASC", "id" = "ASC"})
  261.      */
  262.     private $messages;
  263.     /**
  264.      * Chat-K2 (karar 59b) — owner tarafı mesajları EN SON ne zaman okudu. Geriye dönük
  265.      * üretilemez, bu yüzden BAŞTAN eklendi. 🪤 Bilerek `@core`'a KONMADI — executor bu alanı
  266.      * (owner'ın okuma izini) GÖRMEMELİ. Ayrı grup (`@read_state`); yalnız message/list +
  267.      * internal/message/list + internal/messages/recent servis-katmanı hesaplarında okunur.
  268.      * @ORM\Column(type="datetime_immutable", nullable=true)
  269.      * @Groups({
  270.      *     "project_order_task_fulfillment@read_state"
  271.      * })
  272.      */
  273.     private $owner_last_read_at;
  274.     /**
  275.      * Chat-K2 (karar 59b) — executor tarafı mesajları EN SON ne zaman okudu. Simetrik neden:
  276.      * owner bu alanı (executor'ın okuma izini) GÖRMEMELİ. Bkz. $owner_last_read_at.
  277.      * @ORM\Column(type="datetime_immutable", nullable=true)
  278.      * @Groups({
  279.      *     "project_order_task_fulfillment@read_state"
  280.      * })
  281.      */
  282.     private $executor_last_read_at;
  283.     public function __construct()
  284.     {
  285.         $this->work_documents = new ArrayCollection();
  286.         $this->date_revisions = new ArrayCollection();
  287.         $this->messages = new ArrayCollection();
  288.     }
  289.     public function getId(): ?int
  290.     {
  291.         return $this->id;
  292.     }
  293.     public function getVendor(): ?Vendor
  294.     {
  295.         return $this->vendor;
  296.     }
  297.     public function setVendor(?Vendor $vendor): self
  298.     {
  299.         $this->vendor $vendor;
  300.         return $this;
  301.     }
  302.     public function getVendorContactPerson(): ?VendorContactPersons
  303.     {
  304.         return $this->vendor_contact_person;
  305.     }
  306.     public function setVendorContactPerson(?VendorContactPersons $vendor_contact_person): self
  307.     {
  308.         $this->vendor_contact_person $vendor_contact_person;
  309.         return $this;
  310.     }
  311.     public function getWorkContent(): ?string
  312.     {
  313.         return $this->work_content;
  314.     }
  315.     public function setWorkContent(?string $work_content): self
  316.     {
  317.         $this->work_content $work_content;
  318.         return $this;
  319.     }
  320.     public function getReason(): ?TaskFulfillmentReasons
  321.     {
  322.         return $this->reason;
  323.     }
  324.     public function setReason(?TaskFulfillmentReasons $reason): self
  325.     {
  326.         $this->reason $reason;
  327.         return $this;
  328.     }
  329.     public function getTask(): ?ProjectOrderTasks
  330.     {
  331.         return $this->task;
  332.     }
  333.     public function setTask(ProjectOrderTasks $task): self
  334.     {
  335.         $this->task $task;
  336.         return $this;
  337.     }
  338.     /**
  339.      * Order listesi çipi için execution ilerlemesi (% 0-100). Task'ın job'larından türer:
  340.      * Σ(biten job_weight) / Σ(job_weight) × 100 — biten = start_at VE end_at dolu (OrderCalculator
  341.      * ile aynı "done" tanımı). SANAL: DB kolonu DEĞİL, serialize anında hesaplanır. Yalnız
  342.      * `@progress` grubu (order listesi) ile döner → `@core` payload'ı şişmez, per-execution çip verisi.
  343.      *
  344.      * @Groups({
  345.      *     "project_order_task_fulfillment@progress"
  346.      * })
  347.      * @SerializedName("execution_progress")
  348.      */
  349.     public function getExecutionProgress(): ?float
  350.     {
  351.         $task $this->task;
  352.         if ($task === null) {
  353.             return null;
  354.         }
  355.         $totalWeight 0.0;
  356.         $doneWeight 0.0;
  357.         foreach ($task->getTaskJobs() as $job) {
  358.             $weight = (float) $job->getJobWeight();
  359.             $totalWeight += $weight;
  360.             if ($job->getStartAt() !== null && $job->getEndAt() !== null) {
  361.                 $doneWeight += $weight;
  362.             }
  363.         }
  364.         if ($totalWeight <= 0.0) {
  365.             return 0.0;
  366.         }
  367.         return round(($doneWeight $totalWeight) * 1002);
  368.     }
  369.     public function isIsLinked(): ?bool
  370.     {
  371.         return $this->is_linked;
  372.     }
  373.     public function setIsLinked(?bool $is_linked): self
  374.     {
  375.         $this->is_linked $is_linked;
  376.         return $this;
  377.     }
  378.     public function getPlannedStartAt(): ?\DateTimeImmutable
  379.     {
  380.         return $this->planned_start_at;
  381.     }
  382.     public function setPlannedStartAt(?\DateTimeImmutable $planned_start_at): self
  383.     {
  384.         $this->planned_start_at $planned_start_at;
  385.         return $this;
  386.     }
  387.     public function getPlannedEndAt(): ?\DateTimeImmutable
  388.     {
  389.         return $this->planned_end_at;
  390.     }
  391.     public function setPlannedEndAt(?\DateTimeImmutable $planned_end_at): self
  392.     {
  393.         $this->planned_end_at $planned_end_at;
  394.         return $this;
  395.     }
  396.     public function getActualEndAt(): ?\DateTimeImmutable
  397.     {
  398.         return $this->actual_end_at;
  399.     }
  400.     public function setActualEndAt(?\DateTimeImmutable $actual_end_at): self
  401.     {
  402.         $this->actual_end_at $actual_end_at;
  403.         return $this;
  404.     }
  405.     public function getDeliveryAt(): ?\DateTimeImmutable
  406.     {
  407.         return $this->delivery_at;
  408.     }
  409.     public function setDeliveryAt(?\DateTimeImmutable $delivery_at): self
  410.     {
  411.         $this->delivery_at $delivery_at;
  412.         return $this;
  413.     }
  414.     public function getDeliveryNote(): ?string
  415.     {
  416.         return $this->delivery_note;
  417.     }
  418.     public function setDeliveryNote(?string $delivery_note): self
  419.     {
  420.         $this->delivery_note $delivery_note;
  421.         return $this;
  422.     }
  423.     public function getRating(): ?float
  424.     {
  425.         return $this->rating;
  426.     }
  427.     public function setRating(?float $rating): self
  428.     {
  429.         $this->rating $rating;
  430.         return $this;
  431.     }
  432.     public function getCost(): ?float
  433.     {
  434.         return $this->cost;
  435.     }
  436.     public function setCost(?float $cost): self
  437.     {
  438.         $this->cost $cost;
  439.         return $this;
  440.     }
  441.     public function getContractReferenceNr(): ?string
  442.     {
  443.         return $this->contract_reference_nr;
  444.     }
  445.     public function setContractReferenceNr(?string $contract_reference_nr): self
  446.     {
  447.         $this->contract_reference_nr $contract_reference_nr;
  448.         return $this;
  449.     }
  450.     public function getContractType(): ?ContractTypes
  451.     {
  452.         return $this->contract_type;
  453.     }
  454.     public function setContractType(?ContractTypes $contract_type): self
  455.     {
  456.         $this->contract_type $contract_type;
  457.         return $this;
  458.     }
  459.     /**
  460.      * @return Collection<int, ProjectOrderTaskFulfillmentWorkDocs>
  461.      */
  462.     public function getWorkDocuments(): Collection
  463.     {
  464.         return $this->work_documents;
  465.     }
  466.     public function addProjectOrderTaskFulfillmentWorkDoc(ProjectOrderTaskFulfillmentWorkDocs $projectOrderTaskFulfillmentWorkDocs): self
  467.     {
  468.         if (!$this->work_documents->contains($projectOrderTaskFulfillmentWorkDocs)) {
  469.             $this->work_documents[] = $projectOrderTaskFulfillmentWorkDocs;
  470.             $projectOrderTaskFulfillmentWorkDocs->setProjectOrderTaskFulfillment($this);
  471.         }
  472.         return $this;
  473.     }
  474.     public function removeProjectOrderTaskFulfillmentWorkDoc(ProjectOrderTaskFulfillmentWorkDocs $projectOrderTaskFulfillmentWorkDocs): self
  475.     {
  476.         if ($this->work_documents->removeElement($projectOrderTaskFulfillmentWorkDocs)) {
  477.             // set the owning side to null (unless already changed)
  478.             if ($projectOrderTaskFulfillmentWorkDocs->getProjectOrderTaskFulfillment() === $this) {
  479.                 $projectOrderTaskFulfillmentWorkDocs->setProjectOrderTaskFulfillment(null);
  480.             }
  481.         }
  482.         return $this;
  483.     }
  484.     /**
  485.      * @return Collection<int, ProjectOrderTaskFulfillmentDateRevision>
  486.      */
  487.     public function getDateRevisions(): Collection
  488.     {
  489.         return $this->date_revisions;
  490.     }
  491.     public function addDateRevision(ProjectOrderTaskFulfillmentDateRevision $revision): self
  492.     {
  493.         if (!$this->date_revisions->contains($revision)) {
  494.             $this->date_revisions[] = $revision;
  495.             $revision->setProjectOrderTaskFulfillment($this);
  496.         }
  497.         return $this;
  498.     }
  499.     /** EN SON (created_at max) revizyon = güncel taahhüt. Zincir boşsa null. */
  500.     private function getLatestDateRevision(): ?ProjectOrderTaskFulfillmentDateRevision
  501.     {
  502.         $latest null;
  503.         foreach ($this->date_revisions as $revision) {
  504.             if ($latest === null || $revision->getCreatedAt() >= $latest->getCreatedAt()) {
  505.                 $latest $revision;
  506.             }
  507.         }
  508.         return $latest;
  509.     }
  510.     /**
  511.      * Taahhüt edilen başlangıç = son revizyonun start_at'i (yoksa null). SANAL — zincirden türer.
  512.      *
  513.      * @Groups({
  514.      *     "project_order_task_fulfillment@core"
  515.      * })
  516.      * @SerializedName("committed_start_at")
  517.      */
  518.     public function getCommittedStartAt(): ?\DateTimeImmutable
  519.     {
  520.         $latest $this->getLatestDateRevision();
  521.         return $latest !== null $latest->getStartAt() : null;
  522.     }
  523.     /**
  524.      * Taahhüt edilen bitiş = son revizyonun end_at'i (yoksa null). SANAL — zincirden türer.
  525.      *
  526.      * @Groups({
  527.      *     "project_order_task_fulfillment@core"
  528.      * })
  529.      * @SerializedName("committed_end_at")
  530.      */
  531.     public function getCommittedEndAt(): ?\DateTimeImmutable
  532.     {
  533.         $latest $this->getLatestDateRevision();
  534.         return $latest !== null $latest->getEndAt() : null;
  535.     }
  536.     public function getExecutionScope(): ?string
  537.     {
  538.         return $this->execution_scope;
  539.     }
  540.     public function setExecutionScope(?string $execution_scope): self
  541.     {
  542.         $this->execution_scope $execution_scope;
  543.         return $this;
  544.     }
  545.     public function getExecutionWorkNature()
  546.     {
  547.         return $this->execution_work_nature;
  548.     }
  549.     public function setExecutionWorkNature($execution_work_nature): void
  550.     {
  551.         $this->execution_work_nature $execution_work_nature;
  552.     }
  553.     public function getBranch(): ?Branches
  554.     {
  555.         return $this->branch;
  556.     }
  557.     public function setBranch(?Branches $branch): self
  558.     {
  559.         $this->branch $branch;
  560.         return $this;
  561.     }
  562.     public function getBranchContactPerson(): ?WorkerActivities
  563.     {
  564.         return $this->branch_contact_person;
  565.     }
  566.     public function setBranchContactPerson(?WorkerActivities $branch_contact_person): self
  567.     {
  568.         $this->branch_contact_person $branch_contact_person;
  569.         return $this;
  570.     }
  571.     public function getStatus(): ?string
  572.     {
  573.         return $this->status;
  574.     }
  575.     public function setStatus(string $status): self
  576.     {
  577.         $this->status $status;
  578.         return $this;
  579.     }
  580.     public function getPublishedAt(): ?\DateTimeImmutable
  581.     {
  582.         return $this->published_at;
  583.     }
  584.     public function setPublishedAt(?\DateTimeImmutable $published_at): self
  585.     {
  586.         $this->published_at $published_at;
  587.         return $this;
  588.     }
  589.     public function getAcceptedAt(): ?\DateTimeImmutable
  590.     {
  591.         return $this->accepted_at;
  592.     }
  593.     public function setAcceptedAt(?\DateTimeImmutable $accepted_at): self
  594.     {
  595.         $this->accepted_at $accepted_at;
  596.         return $this;
  597.     }
  598.     /** K8 — kabul edildi mi (published + accepted_at dolu). Silme kilidi ve FE rozeti bunu okur. */
  599.     public function isAccepted(): bool
  600.     {
  601.         return $this->accepted_at !== null;
  602.     }
  603.     public function getDeclinedAt(): ?\DateTimeImmutable
  604.     {
  605.         return $this->declined_at;
  606.     }
  607.     public function setDeclinedAt(?\DateTimeImmutable $declined_at): self
  608.     {
  609.         $this->declined_at $declined_at;
  610.         return $this;
  611.     }
  612.     /** K8-accept — reddedildi mi (declined_at dolu). Reddedilen is silinebilir (accepted degil). */
  613.     public function isDeclined(): bool
  614.     {
  615.         return $this->declined_at !== null;
  616.     }
  617.     public function getDeclineReasonCategory(): ?string
  618.     {
  619.         return $this->decline_reason_category;
  620.     }
  621.     public function setDeclineReasonCategory(?string $decline_reason_category): self
  622.     {
  623.         $this->decline_reason_category $decline_reason_category;
  624.         return $this;
  625.     }
  626.     public function getDeclineReason(): ?string
  627.     {
  628.         return $this->decline_reason;
  629.     }
  630.     public function setDeclineReason(?string $decline_reason): self
  631.     {
  632.         $this->decline_reason $decline_reason;
  633.         return $this;
  634.     }
  635.     /**
  636.      * @return Collection<int, ProjectOrderTaskFulfillmentMessage>
  637.      */
  638.     public function getMessages(): Collection
  639.     {
  640.         return $this->messages;
  641.     }
  642.     public function addMessage(ProjectOrderTaskFulfillmentMessage $message): self
  643.     {
  644.         if (!$this->messages->contains($message)) {
  645.             $this->messages[] = $message;
  646.             $message->setExecution($this);
  647.         }
  648.         return $this;
  649.     }
  650.     public function getOwnerLastReadAt(): ?\DateTimeImmutable
  651.     {
  652.         return $this->owner_last_read_at;
  653.     }
  654.     public function setOwnerLastReadAt(?\DateTimeImmutable $owner_last_read_at): self
  655.     {
  656.         $this->owner_last_read_at $owner_last_read_at;
  657.         return $this;
  658.     }
  659.     public function getExecutorLastReadAt(): ?\DateTimeImmutable
  660.     {
  661.         return $this->executor_last_read_at;
  662.     }
  663.     public function setExecutorLastReadAt(?\DateTimeImmutable $executor_last_read_at): self
  664.     {
  665.         $this->executor_last_read_at $executor_last_read_at;
  666.         return $this;
  667.     }
  668. }