<?php
/*
* Created on Fri Dec 02 2022
*
* DAVID-OLIVIER DESCOMBES
*
* @licence
* You may not sell, sub-license, rent or lease any portion of the Software or Documentation to anyone.
*
* Copyright (c) 2022 dodarchitecte.com (https://dodarchitecte.com)
*
* Developed by developpeur-informatique.ma (https://www.developpeur-informatique.ma)
*/
namespace App\Entity\Project;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\Project\ProjectAllFoldersController;
use App\Controller\Project\ProjectConversationController;
use App\Controller\Project\ProjectDevisController;
use App\Controller\Project\ProjectDiscardedController;
use App\Controller\Project\ProjectDisponibleController;
use App\Controller\Project\ProjectImageController;
use App\Controller\Project\ProjectPurchasesController;
use App\Controller\Project\ProjectFilesController;
use App\Controller\Project\ProjectFoldersController;
use App\Controller\Project\ProjectFileTransmisController;
use App\Controller\Project\ProjectFinanceController;
use App\Controller\Project\ProjectFinancialMonitoringPdfController;
use App\Controller\Project\ProjectGeneratePdfController;
use App\Controller\Project\ProjectUntouchedController;
use App\Entity\Chat\Conversation;
use App\Entity\Collaborator\CollaboratorProject;
use App\Entity\Devis\Devis;
use App\Entity\Responsable\Responsable;
use App\Entity\Enterprise\Enterprise;
use App\Entity\Folder\Folder;
use App\Entity\Localisation\Address;
use App\Entity\TraitFolder\TimeStamp;
use App\Entity\User;
use App\Repository\Collaborator\CollaboratorRepository;
use App\Repository\Project\ProjectRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
// use Vich\UploaderBundle\Entity\File as EmbeddedFile;
#[ORM\Entity(repositoryClass: ProjectRepository::class)]
#[Vich\Uploadable()]
#[ApiResource(
collectionOperations: [
'get' => [
'normalization_context' => ['groups' => 'Project:collection'],
],
'post' => [
'normalization_context' => ['groups' => 'Project:collection'],
],
'discarded' => [
'method' => 'GET',
'path' => '/projects/discarded',
'controller' => ProjectDiscardedController::class,
'openapi_context' => [
'summary' => 'Get all discarded projects',
'description' => 'Get all discarded projects',
'responses' => [
'200' => [
'description' => 'A list of projects',
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Project',
],
]
]
]
],
'openapi_description' => 'Get all discarded projects',
],
'follow_finance' => [
'method' => 'GET',
'path' => '/projects/follow_finance',
'normalization_context' => ['groups' => 'Project:finance'],
'controller' => ProjectFinanceController::class,
'openapi_context' => [
'summary' => 'Get all projects to follow finance',
'description' => 'Get all projects to follow finance',
'responses' => [
'200' => [
'description' => 'A list of projects',
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Project',
],
]
]
]
],
],
'untouched' => [
'method' => 'GET',
'path' => '/projects/untouched',
'normalization_context' => ['groups' => ['Project:untouched']],
'controller' => ProjectUntouchedController::class,
'openapi_context' => [
'summary' => 'Get all untouched projects',
'description' => 'Get all untouched projects',
'responses' => [
'200' => [
'description' => 'A list of projects',
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Project',
],
]
]
]
],
'openapi_description' => 'Get all untouched projects',
],
'disponible_for_devis' => [
'method' => 'GET',
'path' => '/projects/disponible_for_devis',
'controller' => ProjectDisponibleController::class,
'openapi_context' => [
'summary' => 'Get all disponible projects',
'description' => 'Get all disponible projects',
'responses' => [
'200' => [
'description' => 'A list of projects',
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Project',
],
]
]
]
],
'openapi_description' => 'Get all discarded projects',
],
],
itemOperations: [
'get' => ["security" => "is_granted('POST_VIEW', object)"],
'put' => [
"openapiContext" => [
"deserialize" => false,
'requestBody' => [
'content' => [
'multipart/form-data' => [
'schema' => [
'type' => 'object',
'properties' => [
'file' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
]
]
]
],
'delete',
'patch',
'image' => [
'method' => 'POST',
'path' => '/projects/{id}/image',
'controller' => ProjectImageController::class,
'deserialize' => false,
'openapi_context' => [
'requestBody' => [
'content' => [
'multipart/form-data' => [
'schema' => [
'type' => 'object',
'properties' => [
'file' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
]
]
],
],
'purchases' => [
'method' => 'GET',
'path' => '/projects/{id}/purchases',
'controller' => ProjectPurchasesController::class,
'normalization_context' => ['groups' => 'Project:purchases'],
'openapi_context' => [
'summary' => 'Get all purchases of a project',
'description' => 'Get all purchases of a project',
'responses' => [
'200' => [
'description' => 'Return all purchases of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Purchase'
]
]
]
]
]
]
],
],
'files' => [
'method' => 'GET',
'path' => '/projects/{id}/files',
'controller' => ProjectFilesController::class,
'openapi_context' => [
'summary' => 'Get all files of a project',
'description' => 'Get all files of a project',
'responses' => [
'200' => [
'description' => 'Return all files of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/File'
]
]
]
]
]
]
]
],
'folders' => [
'method' => 'GET',
'path' => '/projects/{id}/folders/{type}',
'controller' => ProjectFoldersController::class,
'openapi_context' => [
'summary' => 'Get all folders of a project',
'description' => 'Get all folders of a project',
'responses' => [
'200' => [
'description' => 'Return all folders of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Folder'
]
]
]
]
]
],
'parameters' => [
[
'name' => 'type',
'in' => 'path',
'required' => true,
'schema' => [
'type' => 'string',
'enum' => [
'Facture',
'Contrat',
'Chantier',
'Projet'
]
]
]
],
],
'requirements' => [
'type' => 'Facture|Contrat|Chantier|Projet'
],
'normalization_context' =>
[
'groups' => ['Project:read:folders'],
'openapi_definition_name' => 'Get folders of a project'
]
],
'all_folders' => [
'method' => 'GET',
'path' => '/projects/{id}/all_folders',
'controller' => ProjectAllFoldersController::class,
'openapi_context' => [
'summary' => 'Get all folders of a project',
'description' => 'Get all folders of a project',
'responses' => [
'200' => [
'description' => 'Return all folders of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Folder'
]
]
]
]
]
],
'parameters' => [
[
'name' => 'type',
'in' => 'path',
'required' => true,
'schema' => [
'type' => 'string',
'enum' => [
'Facture',
'Contrat',
'Chantier',
'Projet'
]
]
]
],
],
'requirements' => [
'type' => 'Facture|Contrat|Chantier|Projet'
],
'normalization_context' =>
[
'groups' => ['Project:read:folders'],
'openapi_definition_name' => 'Get folders of a project'
]
],
'transmis' => [
'method' => 'GET',
'path' => '/projects/{id}/transmis',
'controller' => ProjectFileTransmisController::class,
'openapi_context' => [
'summary' => 'Get all files transmis of a project',
'description' => 'Get all files transmis of a project',
'responses' => [
'200' => [
'description' => 'Return all files transmis of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/File'
]
]
]
]
]
]
]
],
'generate_pdf' => [
'method' => 'POST',
'path' => '/projects/{id}/generate_pdf',
'controller' => ProjectGeneratePdfController::class,
'openapi_context' => [
'summary' => 'Generate a pdf of a project',
'description' => 'Generate a pdf of a project',
'responses' => [
'200' => [
'description' => 'Return a pdf of a project',
'content' => [
'application/pdf' => [
'schema' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
],
'requestBody' => [
'content' => [
'application/ld+json' => [
'schema' => [
'type' => 'object',
'properties' => [
'folder' => [
'type' => 'Folder',
'format' => 'Folder'
]
]
]
]
]
]
// 'serialize' => false,
],
'normalization_context' =>
[
'groups' => ['Project:SuiviFinance'],
'openapi_definition_name' => 'Get folders of a project'
],
// 'security' => 'is_granted("ROLE_CHEF") or is_granted("ROLE_ADMIN") or is_granted("ROLE_SECRETARY")',
],
'suivi_financier_pdf' => [
'method' => 'GET',
'path' => '/projects/{id}/suivi_financier_pdf',
'controller' => ProjectFinancialMonitoringPdfController::class,
'openapi_context' => [
'summary' => 'Generate a financial monitoring pdf of a project',
'description' => 'Generate a financial monitoring pdf of a project',
'responses' => [
'200' => [
'description' => 'Return a financial monitoring pdf of a project',
'content' => [
'application/pdf' => [
'schema' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
]
],
'normalization_context' =>
[
'groups' => ['Project:SuiviFinance'],
'openapi_definition_name' => 'Get folders of a project'
],
'serialize' => false,
// 'security' => 'is_granted("ROLE_CHEF") or is_granted("ROLE_ADMIN") or is_granted("ROLE_SECRETARY")',
],
'conversations' => [
'method' => 'GET',
'path' => '/projects/{id}/conversations',
'controller' => ProjectConversationController::class,
'normalization_context' => ['groups' => ['Project:conversation']],
'openapi_context' => [
'summary' => 'Get all conversations of a project',
'description' => 'Get all conversations of a project',
'responses' => [
'200' => [
'description' => 'Return all conversations of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Conversation'
]
]
]
]
]
]
],
],
'devis' => [
'method' => 'GET',
'path' => '/projects/{id}/devis',
'controller' => ProjectDevisController::class,
'openapi_context' => [
'summary' => 'Get all devis of a project',
'description' => 'Get all devis of a project',
'responses' => [
'200' => [
'description' => 'Return all devis of a project',
'content' => [
'application/json' => [
'schema' => [
'type' => 'array',
'items' => [
'$ref' => '#/components/schemas/Devis'
]
]
]
]
]
]
]
],
],
denormalizationContext: [
'groups' => ['Project:write'],
'disable_type_enforcement' => true,
],
normalizationContext: ['groups' => ['Project:collection', 'Project:read']],
// attributes: [
// "pagination_client_enabled" => true,
// "pagination_client_items_per_page" => 10,
// ],
// paginationClientEnabled: true,
// paginationItemsPerPage: 10,
// paginationMaximumItemsPerPage: 10,
order: ["status" => "Asc", "updatedAt" => "Desc"]
)]
class Project
{
use TimeStamp;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
#[Groups([
'Project:collection', 'Project:read', 'User:Projects',
'Company:collection', 'Project:finance', 'Dod:facture',
'Dod:gestionnaire', 'Dod:Factures', 'Project:discarded', "Company:Projects",
'Project:Disponible',
'Collaborator:read',"User:collaborator", "User:clients"
])]
// #[Groups([ "User:collaborator", "User:clients", "Collaborator:read"])]
private $id;
#[ORM\Column(type: 'string', length: 255)]
#[Groups([
'Project:collection', 'Project:read', 'Project:write',
'User:Projects', 'Company:collection',
'Project:finance',
'Conversation:collection',
'User:Conversation', 'File:Facture',
'Dod:facture', 'Dod:gestionnaire', 'Company:collection',
'Devis:collection', 'Dod:Factures', 'Project:discarded', "Company:Projects",
'Project:Disponible',
// 'Collaborator:read',"User:collaborator", "User:clients"
])]
private $name;
#[ORM\Column(type: 'string', length: 255)]
#[Groups([
'Project:collection', 'User:Projects', 'Project:read', 'Company:collection',
'Project:finance', 'Project:discarded', "Company:Projects"
])]
private $slug;
#[ORM\Column(type: 'string', length: 255)]
#[Groups([
'Project:collection',
'User:Projects', 'Project:read', 'Project:write', 'Company:collection',
'Company:collection', 'Project:finance', 'Project:discarded', "Company:Projects"
])]
private $status;
#[ORM\ManyToOne(targetEntity: Enterprise::class, inversedBy: 'projects')]
#[ORM\JoinColumn(nullable: false)]
#[Groups([
'Project:collection', 'User:Projects', 'Project:read', 'Project:write',
'Conversation:read', 'Project:discarded'
])]
private $enterprise;
#[ORM\OneToOne(targetEntity: Address::class, cascade: ['persist', 'remove'])]
#[Groups(['Project:collection', 'User:Projects', 'Project:read', 'Project:write'])]
private $address;
#[ORM\OneToMany(mappedBy: 'project', targetEntity: Purchase::class, cascade: ['persist', 'remove'])]
#[Groups(['Project:read', 'Project:write'])]
private $purchases;
#[ORM\OneToMany(mappedBy: 'project', targetEntity: Folder::class, cascade: ['persist', 'remove'])]
#[Groups([
'Project:read', 'Project:finance', 'Project:SuiviFinance',
])]
private $folders;
/**
*
* @var File
*/
#[Vich\UploadableField(mapping: 'project_image', fileNameProperty: 'fileName')]
#[Groups(['Project:write'])]
private ?File $file = null;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
#[Groups(['Project:collection', 'User:Projects', 'Project:read'])]
private ?string $fileName = null;
/**
* @var string|null
*
*/
#[Groups(['Project:collection', 'User:Projects', 'Project:read', 'Conversation:read', 'Conversation:collection'])]
private ?string $fileUrl = null;
#[ORM\Column(type: 'string', length: 255)]
#[Groups(['Project:write', 'Project:read', 'Project:collection', 'User:Projects', 'Project:finance'])]
private $programme;
#[ORM\Column(type: 'decimal', precision: 50, scale: 2, nullable: true)]
#[Groups(['Project:write', 'Project:read', 'Project:collection', 'User:Projects', 'Project:finance'])]
private $surface;
#[ORM\Column(type: 'datetime', nullable: true)]
#[Groups(['Project:write', 'Project:read'])]
private $startedAt;
#[ORM\Column(type: 'datetime', nullable: true)]
#[Groups(['Project:write', 'Project:read'])]
private $endingAt;
#[ORM\Column(type: 'boolean', nullable: true, options: ['default' => false])]
#[Groups([
'Project:write', 'Project:collection', 'Project:read', 'User:Projects',
'Conversation:read', 'Conversation:collection', "Company:Projects"
])]
private $discarded;
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
#[Groups(['Project:write', 'Project:collection', 'Project:read', 'Project:discarded'])]
private $discardedAt;
#[ORM\Column(type: 'string', length: 10, nullable: true)]
#[Groups(['Project:write', 'Project:collection', 'Project:read'])]
private $maitreOuvrage;
#[ORM\Column(type: 'string', length: 10, nullable: true)]
#[Groups(['Project:write', 'Project:collection', 'Project:read', 'User:Projects'])]
private $etude;
#[Groups(['Project:conversation'])]
#[ORM\OneToMany(mappedBy: 'project', targetEntity: Conversation::class, cascade: ['persist', 'remove'])]
private Collection $conversations;
#[ORM\OneToMany(mappedBy: 'project', targetEntity: Devis::class, cascade: ['persist', 'remove'])]
private Collection $devis;
#[ORM\OneToMany(mappedBy: 'project', targetEntity: Responsable::class, cascade: ['persist', 'remove'])]
#[Groups(['Project:write', 'Project:collection', 'Project:read', 'User:Projects'])]
private Collection $responsables;
#[Groups(['Project:read'])]
private bool $allowedToSigne = false;
#[ORM\OneToMany(mappedBy: 'project', targetEntity: CollaboratorProject::class)]
private Collection $collaboratorProjects;
public function __construct()
{
$this->purchases = new ArrayCollection();
$this->folders = new ArrayCollection();
$this->slug = uniqid('', false);
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->conversations = new ArrayCollection();
$this->devis = new ArrayCollection();
$this->responsables = new ArrayCollection();
$this->collaboratorProjects = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getSlug(): string|null
{
return $this->slug;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
public function getEnterprise(): ?Enterprise
{
return $this->enterprise;
}
public function setEnterprise(?Enterprise $enterprise): self
{
$this->enterprise = $enterprise;
return $this;
}
public function getAddress(): ?Address
{
return $this->address;
}
public function setAddress(?Address $address): self
{
$this->address = $address;
return $this;
}
/**
* @return Collection<int, Purchase>
*/
public function getPurchases(): Collection
{
return $this->purchases;
}
public function addPurchase(Purchase $purchase): self
{
if (!$this->purchases->contains($purchase)) {
$this->purchases[] = $purchase;
$purchase->setProject($this);
}
return $this;
}
public function removePurchase(Purchase $purchase): self
{
if ($this->purchases->removeElement($purchase)) {
// set the owning side to null (unless already changed)
if ($purchase->getProject() === $this) {
$purchase->setProject(null);
}
}
return $this;
}
/**
* @return Collection<int, Folder>
*/
public function getFolders(): Collection
{
return $this->folders;
}
public function addFolder(Folder $folder): self
{
if (!$this->folders->contains($folder)) {
$this->folders[] = $folder;
$folder->setProject($this);
}
return $this;
}
public function setFolders(?Collection $folders): self
{
$this->folders = $folders ?? new ArrayCollection();
return $this;
}
public function removeFolder(Folder $folder): self
{
if ($this->folders->removeElement($folder)) {
// set the owning side to null (unless already changed)
if ($folder->getProject() === $this) {
$folder->setProject(null);
}
}
return $this;
}
public function getFileName(): ?string
{
return $this->fileName;
}
public function setFileName(?string $fileName): self
{
$this->fileName = $fileName;
return $this;
}
public function getFile(): ?File
{
return $this->file;
}
public function setFile(?File $file): self
{
$this->file = $file;
if ($file) {
$this->updatedAt = new \DateTime('now');
}
return $this;
}
public function getFileUrl(): ?string
{
return $this->fileUrl;
}
public function setFileUrl(?string $fileUrl): self
{
$this->fileUrl = $fileUrl;
return $this;
}
// public function setUpdatedAt(): self
// {
// $this->updatedAt = new \DateTime('now');
// return $this;
// }
public function getProgramme(): ?string
{
return $this->programme;
}
public function setProgramme(string $programme): self
{
$this->programme = $programme;
return $this;
}
public function getSurface(): ?string
{
return $this->surface;
}
public function setSurface(?string $surface): self
{
$this->surface = $surface;
return $this;
}
public function getStartedAt(): ?\DateTimeInterface
{
return $this->startedAt;
}
public function setStartedAt(?\DateTimeInterface $startedAt): self
{
$this->startedAt = $startedAt;
return $this;
}
public function getEndingAt(): ?\DateTimeInterface
{
return $this->endingAt;
}
public function setEndingAt(?\DateTimeInterface $endingAt): self
{
$this->endingAt = $endingAt;
return $this;
}
public function isDiscarded(): ?bool
{
return $this->discarded;
}
public function setDiscarded(bool $discarded): self
{
$this->discarded = $discarded;
if ($discarded)
$this->discardedAt = new \DateTimeImmutable();
else
$this->discardedAt = null;
return $this;
}
public function getDiscardedAt(): ?\DateTimeImmutable
{
return $this->discardedAt;
}
public function setDiscardedAt(?\DateTimeImmutable $discardedAt): self
{
$this->discardedAt = $discardedAt;
return $this;
}
public function getMaitreOuvrage(): ?string
{
return $this->maitreOuvrage;
}
public function setMaitreOuvrage(?string $maitreOuvrage): self
{
$this->maitreOuvrage = $maitreOuvrage;
return $this;
}
public function getEtude(): ?string
{
return $this->etude;
}
public function setEtude(?string $etude): self
{
$this->etude = $etude;
return $this;
}
/**
* @return Collection<int, Conversation>
*/
public function getConversations(): Collection
{
return $this->conversations;
}
public function addConversation(Conversation $conversation): self
{
if (!$this->conversations->contains($conversation)) {
$this->conversations->add($conversation);
$conversation->setProject($this);
}
return $this;
}
public function removeConversation(Conversation $conversation): self
{
if ($this->conversations->removeElement($conversation)) {
// set the owning side to null (unless already changed)
if ($conversation->getProject() === $this) {
$conversation->setProject(null);
}
}
return $this;
}
/**
* @return Collection<int, Devis>
*/
public function getDevis(): Collection
{
return $this->devis;
}
public function addDevi(Devis $devi): self
{
if (!$this->devis->contains($devi)) {
$this->devis->add($devi);
$devi->setProject($this);
}
return $this;
}
public function removeDevi(Devis $devi): self
{
if ($this->devis->removeElement($devi)) {
// set the owning side to null (unless already changed)
if ($devi->getProject() === $this) {
$devi->setProject(null);
}
}
return $this;
}
/**
* @return Collection<int, Responsable>
*/
public function getResponsables(): Collection
{
return $this->responsables;
}
public function addResponsable(Responsable $responsable): self
{
if (!$this->responsables->contains($responsable)) {
$this->responsables->add($responsable);
$responsable->setProject($this);
}
return $this;
}
public function removeResponsable(Responsable $responsable): self
{
if ($this->responsables->removeElement($responsable)) {
// set the owning side to null (unless already changed)
if ($responsable->getProject() === $this) {
$responsable->setProject(null);
}
}
return $this;
}
/**
* @return bool
*/
public function isAllowedToSigne(): bool
{
return $this->allowedToSigne;
}
/**
* @param bool $allowedToSigne
*/
public function setAllowedToSigne(bool $allowedToSigne): void
{
$this->allowedToSigne = $allowedToSigne;
}
/**
* @return Collection<int, CollaboratorProject>
*/
public function getCollaboratorProjects(): Collection
{
return $this->collaboratorProjects;
}
public function addCollaboratorProject(CollaboratorProject $collaboratorProject): self
{
if (!$this->collaboratorProjects->contains($collaboratorProject)) {
$this->collaboratorProjects->add($collaboratorProject);
$collaboratorProject->setProject($this);
}
return $this;
}
public function removeCollaboratorProject(CollaboratorProject $collaboratorProject): self
{
if ($this->collaboratorProjects->removeElement($collaboratorProject)) {
// set the owning side to null (unless already changed)
if ($collaboratorProject->getProject() === $this) {
$collaboratorProject->setProject(null);
}
}
return $this;
}
}