<?php
namespace App\Entity\Crm\Opportunity;
use App\Entity\Account\User;
use App\Entity\Channel\Channel;
use App\Entity\Channel\ChannelContact;
use App\Entity\Channel\Company;
use App\Entity\Channel\Drive;
use App\Entity\Channel\Place;
use App\Entity\Channel\Training;
use App\Entity\Common\Contact;
use App\Entity\Crm\ActivityFeed\ActivityFeed;
use App\Entity\Crm\Target\HasTargetInterface;
use App\Entity\Crm\Target\HasTargetTrait;
use App\Entity\Crm\Target\TargetableInterface;
use App\Entity\Crm\Contact\ChannelContactRelationInterface;
use App\Entity\Crm\Contact\HasChannelContactsInterface;
use App\Entity\Crm\Contact\HasChannelContactsMethodTrait;
use App\Entity\Crm\Embed\Money;
use App\Entity\Crm\Embed\TextContent;
use App\Entity\Crm\HasStatusInterface;
use App\Entity\Crm\Pipeline\Pipeline;
use App\Entity\Crm\Pipeline\PipelineStep;
use App\Entity\Crm\Quote\Document\Quote;
use App\Entity\Crm\Trait\HasStatusTrait;
use App\Entity\Crm\Trait\HasTargetValidationTrait;
use App\Entity\Crm\Trait\IgnoreUpdatedCurrentStepFieldTrait;
use App\Entity\Crm\Trait\TextContentProxyTrait;
use App\Enum\CurrencyEnum;
use App\Enum\Status\OpportunityStatusEnum;
use App\Enum\TargetTypeEnum;
use App\Enum\Serialization\OpportunitySerializationGroups;
use App\Enum\Validation\OpportunityValidationGroups;
use App\Repository\Crm\Opportunity\OpportunityRepository;
use DateTimeImmutable;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use DrosalysWeb\ObjectExtensions\Blame\Model\BlameInterface;
use DrosalysWeb\ObjectExtensions\Blame\Model\BlameTrait;
use DrosalysWeb\ObjectExtensions\Blame\Model\IgnoreUpdatedBlameInterface;
use DrosalysWeb\ObjectExtensions\Timestamp\Model\IgnoreUpdatedTimestampInterface;
use DrosalysWeb\ObjectExtensions\Timestamp\Model\TimestampInterface;
use DrosalysWeb\ObjectExtensions\Timestamp\Model\TimestampTrait;
use Nellapp\Bundle\SDKBundle\Archivable\Entity\ArchivableInterface;
use Nellapp\Bundle\SDKBundle\Archivable\Entity\ArchivableTrait;
use Nellapp\Bundle\SDKBundle\Channel\Entity\ChannelInterface;
use Nellapp\Bundle\SDKBundle\Drive\Entity\DriveInterface;
use Nellapp\Bundle\SDKBundle\Drive\Entity\HasDriveInterface;
use Nellapp\Bundle\SDKBundle\Drive\Entity\HasDriveTrait;
use Nellapp\Bundle\SDKBundle\Enum\ChannelUserData\CursusCourseEnum;
use Nellapp\Bundle\SDKBundle\Enum\ChannelUserData\CursusModalityEnum;
use Nellapp\Bundle\SDKBundle\Enum\ChannelUserData\RqthStatusEnum;
use Nellapp\Bundle\SDKBundle\Permission\Entity\ChannelResourceInterface;
use Nellapp\Bundle\SDKBundle\Planning\Entity\PlanningResourceInterface;
use Nellapp\Bundle\SDKBundle\Serializer\SerialRelation\Attribute\SerialRelation;
use Nellapp\Bundle\SDKBundle\TrackData\Attribute\TrackEntity;
use Nellapp\Bundle\SDKBundle\TrackData\Attribute\TrackField;
use Nellapp\Bundle\SDKBundle\Utils\NellappFormatService;
use Symfony\Component\Serializer\Annotation as Serial;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @see OpportunityNormalizer for some serialization logic
*/
#[ORM\Entity(repositoryClass: OpportunityRepository::class),
ORM\Table(name: 'crm_opportunity'),
TrackEntity(
fieldGroups: [
'informations' => [],
]
)]
class Opportunity implements TimestampInterface, IgnoreUpdatedTimestampInterface, BlameInterface, IgnoreUpdatedBlameInterface, ArchivableInterface, ChannelResourceInterface, HasChannelContactsInterface, HasStatusInterface, HasTargetInterface, HasDriveInterface
{
use BlameTrait;
use TimestampTrait;
use ArchivableTrait;
use TextContentProxyTrait;
use HasChannelContactsMethodTrait;
use HasStatusTrait;
use HasTargetTrait;
use HasTargetValidationTrait;
use IgnoreUpdatedCurrentStepFieldTrait;
use HasDriveTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: Channel::class)]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
private ?Channel $channel = null;
#[ORM\Embedded(class: TextContent::class, columnPrefix: false)]
#[Assert\Valid()]
#[TrackField(name: "", fieldKey: 'informations', embeddedFields: [
'content.label' => 'Nom',
'content.description' => 'Description des besoins',
])]
private ?TextContent $content = null;
#[ORM\Column(type: Types::STRING, length: 8)]
#[Assert\Choice(callback: [CurrencyEnum::class, 'getChoices'], multiple: false)]
#[Assert\NotBlank()]
#[Assert\Length(max: 8)]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
])]
private ?string $currency = null;
#[ORM\Embedded(class: Money::class)]
#[Assert\Valid()]
#[TrackField(name: "", fieldKey: 'informations', embeddedFields: [
'estimatedValue.amount' => 'Montant estimé',
], callable: 'formatPrice', callableClass: NellappFormatService::class)]
private ?Money $estimatedValue = null;
#[ORM\Column(type: Types::STRING, length: 16)]
#[Assert\Choice(callback: [OpportunityStatusEnum::class, 'getChoices'], multiple: false)]
#[Assert\NotBlank()]
#[Assert\Length(max: 16)]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
OpportunitySerializationGroups::UPDATE_INFORMATION,
])]
#[TrackField(name: "Statut de l'opportunité", fieldKey: 'informations', callable: 'getStatusKey', callableClass: OpportunityStatusEnum::class)]
private ?string $status = null;
#[ORM\Column(type: Types::STRING, length: 24, nullable: true)]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE,
OpportunitySerializationGroups::UPDATE_CURRENT_STEP,
])]
private ?string $currentStep = null;
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[TrackField(name: "Date prévisionnelle", fieldKey: 'informations', callable: 'format', callableParams: ['d/m/Y'])]
private ?DateTimeInterface $estimatedAt = null;
#[ORM\Column(type: Types::INTEGER, nullable: true)]
#[Assert\Choice(callback: [CursusModalityEnum::class, 'getChoices'], multiple: false)]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_TRAINING,
])]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[TrackField(name: "Modalité", fieldKey: 'informations', callable: 'getStatusKey', callableClass: CursusModalityEnum::class)]
private ?int $cursusModality = null;
#[ORM\Column(type: Types::INTEGER, nullable: true)]
#[Assert\Choice(callback: [CursusCourseEnum::class, 'getChoices'], multiple: false)]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_TRAINING,
])]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[TrackField(name: "Rythme", fieldKey: 'informations', callable: 'getStatusKey', callableClass: CursusCourseEnum::class)]
private ?int $cursusCourse = null;
#[ORM\Column(type: 'integer', nullable: true)]
#[Assert\Choice(callback: [RqthStatusEnum::class, 'getChoices'])]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE_TRAINING,
])]
#[TrackField(name: "Rqth", fieldKey: 'informations', callable: 'getStatusKey', callableClass: RqthStatusEnum::class)]
private ?int $rqth = null;
#[ORM\ManyToOne(targetEntity: Place::class, fetch: 'EAGER')]
#[JoinColumn(nullable: true, onDelete: 'CASCADE')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_TRAINING,
])]
#[SerialRelation(targetEntity: Place::class, groups: [
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::DETAIL,
])]
#[TrackField(name: "Lieu de rattachement", fieldKey: 'informations')]
private ?Place $place = null;
#[ORM\ManyToOne(targetEntity: Place::class, fetch: 'EAGER')]
#[JoinColumn(nullable: true, onDelete: 'CASCADE')]
#[SerialRelation(targetEntity: Place::class, groups: [
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::DETAIL,
])]
#[TrackField(name: "Centre d'examen", fieldKey: 'informations')]
private ?Place $examPlace = null;
#[ORM\ManyToOne(targetEntity: ReferralSource::class)]
#[JoinColumn(nullable: true, onDelete: 'CASCADE')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_INFORMATION,
])]
#[SerialRelation(targetEntity: ReferralSource::class, groups: [
OpportunitySerializationGroups::UPDATE_INFORMATION,
OpportunitySerializationGroups::DETAIL,
])]
#[TrackField(name: "Source de l'opportunité", fieldKey: 'informations')]
private ?ReferralSource $referralSource = null;
#[ORM\ManyToOne(targetEntity: User::class)]
#[JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_INFORMATION,
])]
#[SerialRelation(targetEntity: User::class, groups: [
OpportunitySerializationGroups::UPDATE_INFORMATION,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[Serial\Groups([
OpportunitySerializationGroups::API_COLLECTION,
])]
#[TrackField(name: "Propriétaire", fieldKey: 'informations')]
private ?User $owner = null;
#[ORM\ManyToOne(targetEntity: Company::class, inversedBy: 'opportunities')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[SerialRelation(targetEntity: Company::class, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE_TARGET,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
private ?Company $targetCompany = null;
#[ORM\ManyToOne(targetEntity: ChannelContact::class, inversedBy: 'opportunities')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[SerialRelation(targetEntity: ChannelContact::class, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::UPDATE_TARGET,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
private ?ChannelContact $targetContact = null;
#[ORM\OneToMany(mappedBy: 'opportunity', targetEntity: OpportunityChannelContact::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
private Collection $relatedContacts;
/** @var Collection<int, ChannelContact> */
#[SerialRelation(targetEntity: ChannelContact::class, multiple: true, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_TARGET,
])]
private Collection $referents;
/** @var Collection<int, ChannelContact> */
#[SerialRelation(targetEntity: ChannelContact::class, multiple: true, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_TARGET,
])]
private Collection $recipients;
#[ORM\ManyToOne(targetEntity: Training::class)]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_TRAINING,
])]
#[SerialRelation(targetEntity: Training::class, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_TRAINING,
])]
#[TrackField(name: "Formation", fieldKey: 'informations')]
private ?Training $training = null;
#[ORM\ManyToOne(targetEntity: Pipeline::class, inversedBy: 'opportunities')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_INFORMATION,
])]
#[SerialRelation(targetEntity: Pipeline::class, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_INFORMATION,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[TrackField(name: "Pipeline", fieldKey: 'informations')]
private ?Pipeline $pipeline = null;
#[ORM\ManyToOne(targetEntity: PipelineStep::class, inversedBy: 'opportunities')]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
#[Assert\NotBlank(groups: [
OpportunityValidationGroups::UPDATE_INFORMATION,
])]
#[SerialRelation(targetEntity: PipelineStep::class, groups: [
OpportunitySerializationGroups::CREATE,
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::UPDATE_INFORMATION,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
#[TrackField(name: "Étape du pipeline", fieldKey: 'informations')]
private ?PipelineStep $pipelineStep = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
private ?DateTimeInterface $pipelineStepSetAt = null;
#[ORM\OneToMany(mappedBy: 'opportunity', targetEntity: Quote::class)]
// #[TrackField(name: "Devis", fieldKey: 'quote')]
private Collection $quotes;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
private ?Drive $drive = null;
#[Orm\OneToOne(targetEntity: ActivityFeed::class, cascade: ['persist', 'remove'], fetch: 'EXTRA_LAZY', orphanRemoval: true)]
private ?ActivityFeed $activityFeed = null;
public function __construct()
{
$this->content = new TextContent();
$this->estimatedValue = new Money($this->currency);
$this->relatedContacts = new ArrayCollection();
$this->quotes = new ArrayCollection();
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getContentLabel(): ?string
{
return $this->getLineContextLabel();
}
#[Serial\Groups([
OpportunitySerializationGroups::UPDATE_INFORMATION,
OpportunitySerializationGroups::CREATE,
])]
public function setContentLabel(?string $label): static
{
$this->setLineContextLabel($label);
return $this;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
])]
public function getContentDescription(): ?string
{
return $this->getLineContextDescription();
}
#[Serial\Groups([
OpportunitySerializationGroups::UPDATE_TRAINING,
OpportunitySerializationGroups::CREATE,
])]
public function setContentDescription(?string $description): static
{
$this->setLineContextDescription($description);
return $this;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
public function getEstimatedValueAmount(): ?int
{
return $this->estimatedValue?->getAmount() ?? null;
}
#[Serial\Groups([
OpportunitySerializationGroups::UPDATE_TRAINING,
])]
public function setEstimatedValueAmount(?int $amount): static
{
$this->estimatedValue?->setAmount($amount);
return $this;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
public function getEstimatedValueCurrency(): ?string
{
return $this->estimatedValue?->getCurrency() ?? null;
}
#[Serial\Groups([
OpportunitySerializationGroups::UPDATE_TRAINING,
])]
public function setEstimatedValueCurrency(?string $currency): static
{
if (
null === $currency
&& null === $this->getEstimatedValueAmount()
) {
$this->estimatedValue?->setCurrency($currency);
return $this;
}
$this->estimatedValue?->setCurrency($currency ?? $this->currency ?? CurrencyEnum::default());
return $this;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getTrainingLabel(): ?string
{
return $this->training?->getName();
}
#[Serial\Groups([
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
public function getTargetLabel(): ?string
{
return match ($this->getTargetType()) {
TargetTypeEnum::COMPANY => $this->targetCompany?->getDisplayName(),
TargetTypeEnum::CONTACT => $this->getTargetContact()?->getDisplayName(),
default => null,
};
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getPipelineLabel(): ?string
{
return $this->pipeline?->getContentLabel();
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getPipelineStepLabel(): ?string
{
return $this->pipelineStep?->getLabel();
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getPipelineStepPercentage(): ?int
{
return $this->pipelineStep?->getPercentage();
}
public function getTargetName(): string
{
return $this->getTarget()?->getDisplayName() ?? '(inconnu)';
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
OpportunitySerializationGroups::API_COLLECTION,
])]
public function getDisplayLabel(): string
{
return $this->getContentLabel() ?? sprintf('OPPORTUNITÉ du %s pour %s',
$this->getCreatedAt()->format('d/m/Y'),
$this->getTargetName(),
);
}
public function __toString()
{
return $this->getDisplayLabel();
}
public function createRelatedContact(): ChannelContactRelationInterface
{
return (new OpportunityChannelContact())
->setOpportunity($this)
;
}
public function getStatusEnumClass(): string
{
return OpportunityStatusEnum::class;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
])]
public function isOpen(): bool
{
return $this->status === OpportunityStatusEnum::OPEN;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
])]
public function isEditable(): bool
{
return false === $this->isArchived();
// return $this->isOpen();
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
])]
public function isWon(): bool
{
return $this->status === OpportunityStatusEnum::WON;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
])]
public function isLost(): bool
{
return $this->status === OpportunityStatusEnum::LOST;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::COLLECTION,
])]
public function isClosed(): bool
{
return $this->isWon() || $this->isLost();
}
public function closeToWon(): static
{
$this->status = OpportunityStatusEnum::WON;
return $this;
}
public function closeToLost(): static
{
$this->status = OpportunityStatusEnum::LOST;
return $this;
}
public function reopen(): static
{
$this->status = OpportunityStatusEnum::OPEN;
return $this;
}
public function initializePipelineStepSetAtValue(): static
{
$this->pipelineStepSetAt = new DateTimeImmutable();
return $this;
}
public function resetPipelineStepSetAt(): static
{
$this->pipelineStepSetAt = null;
return $this;
}
public static function getPermissionResourceClass(): ?string
{
return null;
}
public function getOwnerChannel(): ?ChannelInterface
{
return $this->channel;
}
public function getId(): ?int
{
return $this->id;
}
public function getChannel(): ?Channel
{
return $this->channel;
}
public function setChannel(?Channel $channel): static
{
$this->channel = $channel;
return $this;
}
public function getContent(): ?TextContent
{
return $this->content;
}
public function setContent(?TextContent $content): static
{
$this->content = $content;
return $this;
}
public function getCurrency(): ?string
{
return $this->currency;
}
public function setCurrency(?string $currency): static
{
$this->currency = $currency;
return $this;
}
public function getEstimatedValue(): ?Money
{
return $this->estimatedValue;
}
public function setEstimatedValue(?Money $estimatedValue): static
{
$this->estimatedValue = $estimatedValue;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
public function getCurrentStep(): ?string
{
return $this->currentStep;
}
public function setCurrentStep(?string $currentStep): static
{
$this->currentStep = $currentStep;
return $this;
}
public function getEstimatedAt(): ?DateTimeInterface
{
return $this->estimatedAt;
}
public function setEstimatedAt(?DateTimeInterface $estimatedAt): static
{
if ($estimatedAt === null) {
if ($this->estimatedAt === null) {
return $this;
}
$this->estimatedAt = null;
return $this;
}
$newEstimatedAt = \DateTimeImmutable::createFromInterface($estimatedAt)
->setTime(0, 0, 0, 0);
if (
$this->estimatedAt !== null
&& $this->estimatedAt->format('Y-m-d') === $newEstimatedAt->format('Y-m-d')
) {
return $this;
}
$this->estimatedAt = $newEstimatedAt;
return $this;
}
public function getCursusModality(): ?int
{
return $this->cursusModality;
}
public function setCursusModality(?int $cursusModality): static
{
$this->cursusModality = $cursusModality;
return $this;
}
public function getCursusCourse(): ?int
{
return $this->cursusCourse;
}
public function setCursusCourse(?int $cursusCourse): static
{
$this->cursusCourse = $cursusCourse;
return $this;
}
public function getRqth(): ?int
{
return $this->rqth;
}
public function setRqth(?int $rqth): static
{
$this->rqth = $rqth;
return $this;
}
public function getPlace(): ?Place
{
return $this->place;
}
public function setPlace(?Place $place): static
{
$this->place = $place;
return $this;
}
public function getExamPlace(): ?Place
{
return $this->examPlace;
}
public function setExamPlace(?Place $examPlace): static
{
$this->examPlace = $examPlace;
return $this;
}
public function getReferralSource(): ?ReferralSource
{
return $this->referralSource;
}
public function setReferralSource(?ReferralSource $referralSource): static
{
$this->referralSource = $referralSource;
return $this;
}
public function getOwner(): ?User
{
return $this->owner;
}
public function setOwner(?User $owner): static
{
$this->owner = $owner;
return $this;
}
#[Serial\Groups([
OpportunitySerializationGroups::DETAIL,
OpportunitySerializationGroups::PIPELINE_BOARD_DETAIL,
])]
public function getTargetType(): ?string
{
$target = $this->getTarget();
return $target === null ? null
: match (true) {
$target instanceof Company => TargetTypeEnum::COMPANY,
$target instanceof ChannelContact => TargetTypeEnum::CONTACT,
default => null,
};
}
public function setTarget(?TargetableInterface $target): static
{
if ($target !== null) {
$target->addOpportunity($this);
} else {
$this->setTargetCompany(null);
$this->setTargetContact(null);
}
return $this;
}
public function setTargetCompany(?Company $targetCompany): static
{
$this->targetCompany = $targetCompany;
if ($targetCompany !== null) {
$this->setTargetContact(null);
}
return $this;
}
public function setTargetContact(?ChannelContact $targetContact): static
{
$this->targetContact = $targetContact;
if ($targetContact !== null) {
$this->setTargetCompany(null);
}
return $this;
}
public function getTraining(): ?Training
{
return $this->training;
}
public function setTraining(?Training $training): static
{
$this->training = $training;
return $this;
}
public function getPipeline(): ?Pipeline
{
return $this->pipeline;
}
public function setPipeline(?Pipeline $pipeline): static
{
$this->pipeline = $pipeline;
return $this;
}
public function getPipelineStep(): ?PipelineStep
{
return $this->pipelineStep;
}
public function setPipelineStep(?PipelineStep $pipelineStep): static
{
$this->pipelineStep = $pipelineStep;
if (null !== $pipelineStep) {
$this->initializePipelineStepSetAtValue();
} else {
$this->resetPipelineStepSetAt();
}
return $this;
}
public function getPipelineStepSetAt(): ?DateTimeInterface
{
return $this->pipelineStepSetAt;
}
public function setPipelineStepSetAt(?DateTimeInterface $pipelineStepSetAt): static
{
$this->pipelineStepSetAt = $pipelineStepSetAt;
return $this;
}
/**
* @return Collection<int, Quote>
*/
public function getQuotes(): Collection
{
return $this->quotes;
}
public function addQuote(Quote $quote): static
{
if (!$this->quotes->contains($quote)) {
$this->quotes->add($quote);
$quote->setOpportunity($this);
}
return $this;
}
public function removeQuote(Quote $quote): static
{
if ($this->quotes->removeElement($quote)) {
// set the owning side to null (unless already changed)
if ($quote->getOpportunity() === $this) {
$quote->setOpportunity(null);
}
}
return $this;
}
public function getActivityFeed(): ?ActivityFeed
{
return $this->activityFeed;
}
public function setActivityFeed(?ActivityFeed $activityFeed): Opportunity
{
$this->activityFeed = $activityFeed;
return $this;
}
}