<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Trait\TimestampableEntity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\MaxDepth;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
#[ORM\Entity]
#[ApiResource(
iri: 'MarketRumor',
itemOperations: [
'get' => [
'security' => "
is_granted('ROLE_ADMIN') or
is_granted('ROLE_OPERATOR') or
is_granted('ROLE_OPERATIONS_COORDINATOR') or
is_granted('ROLE_RESEARCH_ANALYST') or
is_granted('ROLE_BROKER') or
is_granted('ROLE_INTERN')
",
'normalization_context' => [
'groups' => 'market_rumor:item:get',
'enable_max_depth' => true
]
],
'put' => [
'security' => "
is_granted('ROLE_ADMIN') or
is_granted('ROLE_INTERN') or
is_granted('ROLE_RESEARCH_ANALYST') or
is_granted('ROLE_BROKER')
",
'normalization_context' => [
'groups' => 'market_rumor:item:put',
'enable_max_depth' => true
],
'denormalization_context' => [
'groups' => 'market_rumor:item:put',
'enable_max_depth' => true
],
],
'delete' => [
'security' => "
is_granted('ROLE_ADMIN') or
is_granted('ROLE_INTERN') or
is_granted('ROLE_RESEARCH_ANALYST') or
is_granted('ROLE_BROKER')
",
],
],
collectionOperations: [
'get' => [
'security' => "
is_granted('ROLE_ADMIN') or
is_granted('ROLE_OPERATOR') or
is_granted('ROLE_OPERATIONS_COORDINATOR') or
is_granted('ROLE_RESEARCH_ANALYST') or
is_granted('ROLE_BROKER') or
is_granted('ROLE_INTERN')
",
'normalization_context' => [
'groups' => [
'market_rumor:collection:get',
'createdAt'
],
'enable_max_depth' => true,
],
],
'post' => [
'security' => "
is_granted('ROLE_ADMIN') or
is_granted('ROLE_INTERN') or
is_granted('ROLE_RESEARCH_ANALYST') or
is_granted('ROLE_BROKER')
",
'normalization_context' => [
'groups' => 'market_rumor:collection:post',
'enable_max_depth' => true
],
'denormalization_context' => [
'groups' => 'market_rumor:collection:post',
'enable_max_depth' => true
],
],
],
)]
#[ApiFilter(
SearchFilter::class,
properties: [
'registerDate' => 'start',
'vessel.vesselName' => 'partial',
'charterer.companyName' => 'partial',
'owner.companyName' => 'partial',
'broker' => 'partial',
'laycanStartDate' => 'start',
'laycanEndDate' => 'start',
'status' => 'exact',
'createdAt' => 'start'
],
)]
#[ApiFilter(
OrderFilter::class,
properties: [
'registerDate',
'vessel.vesselName',
'charterer.companyName',
'owner.companyName',
'broker',
'laycanStartDate',
'laycanEndDate',
'status',
'createdAt'
],
)]
class MarketRumor
{
use TimestampableEntity;
public const COST_TYPE_PMT = 'PMT';
public const COST_TYPE_LUMPSUM = 'LUMPSUM';
public const COST_TYPE_WS = 'WS';
public const COST_TYPE_TC = 'TC';
public const COST_TYPES = [
self::COST_TYPE_PMT,
self::COST_TYPE_LUMPSUM,
self::COST_TYPE_WS,
self::COST_TYPE_TC,
];
public const MARKET_RUMOR_STATUS_QUOTED = 'QUOTED';
public const MARKET_RUMOR_STATUS_IN_MARKET = 'IN_MARKET';
public const MARKET_RUMOR_STATUS_RUMORED = 'RUMORED';
public const MARKET_RUMOR_STATUS_ON_SUBS = 'ON_SUBS';
public const MARKET_RUMOR_STATUS_FIXED = 'FIXED';
public const MARKET_RUMOR_STATUSES = [
self::MARKET_RUMOR_STATUS_QUOTED,
self::MARKET_RUMOR_STATUS_IN_MARKET,
self::MARKET_RUMOR_STATUS_RUMORED,
self::MARKET_RUMOR_STATUS_ON_SUBS,
self::MARKET_RUMOR_STATUS_FIXED,
];
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'NONE')]
#[ORM\Column(type: 'uuid', unique: true)]
private ?UuidInterface $id = null;
#[ORM\Column(type: 'date', nullable: true)]
#[ApiProperty()]
// #[Assert\NotBlank]
#[Assert\Type(\DateTimeInterface::class)]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?\DateTimeInterface $registerDate = null;
#[ORM\Column(type: 'string', nullable: true)]
##[Assert\NotNull]
##[Assert\Type('string')]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $dwt = null;
#[ORM\Column(type: 'date', nullable: true)]
#[ApiProperty()]
// #[Assert\NotBlank]
#[Assert\Type(\DateTimeInterface::class)]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?\DateTimeInterface $laycanStartDate = null;
#[ORM\Column(type: 'date', nullable: true)]
#[ApiProperty()]
// #[Assert\NotBlank]
#[Assert\Type(\DateTimeInterface::class)]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?\DateTimeInterface $laycanEndDate = null;
#[ORM\ManyToOne(
targetEntity: Vessel::class,
inversedBy: 'marketRumors'
)]
#[ORM\JoinColumn(nullable: true)]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?Vessel $vessel = null;
#[ORM\ManyToOne(
targetEntity: Owner::class,
inversedBy: 'marketRumors'
)]
#[ORM\JoinColumn(nullable: true)]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
#[MaxDepth(1)]
private ?Owner $owner = null;
#[ORM\ManyToOne(
targetEntity: Charterer::class,
inversedBy: 'marketRumors'
)]
#[ORM\JoinColumn(nullable: true)]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
#[MaxDepth(1)]
private ?Charterer $charterer = null;
#[ORM\ManyToOne(
targetEntity: Charterer::class,
inversedBy: 'marketRumors2'
)]
#[ORM\JoinColumn(nullable: true)]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
#[MaxDepth(1)]
private ?Charterer $charterer2 = null;
// #[ORM\ManyToOne(
// targetEntity: User::class,
// inversedBy: 'marketRumors'
// )]
// #[ORM\JoinColumn(nullable: true)]
// #[ApiProperty()]
// #[Groups([
// 'market_rumor:item:get',
// 'market_rumor:item:put',
// 'market_rumor:collection:get',
// 'market_rumor:collection:post'
// ])]
// #[MaxDepth(1)]
// private ?User $broker = null;
#[ORM\Column(type: 'string', nullable: true)]
##[Assert\NotNull]
##[Assert\Type('string')]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
// 'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $broker = null;
#[ORM\Column(type: 'string', nullable: false)]
#[ApiProperty()]
#[Assert\NotBlank]
#[Assert\Type('string')]
#[Assert\Choice(
choices: self::MARKET_RUMOR_STATUSES,
message: 'The status is not valid.'
)]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $status = null;
#[ORM\Column(type: 'string', nullable: true)]
#[Assert\Type('string')]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $freightCost = null;
#[ORM\Column(type: 'string', nullable: true)]
#[Assert\Type('string')]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $freightCostCurrency = null;
#[ORM\Column(type: 'string', nullable: true)]
#[Assert\Type('string')]
#[Assert\Choice(
choices: self::COST_TYPES,
message: 'The type is not valid.'
)]
#[ApiProperty()]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $freightType = null;
#[ORM\OneToMany(
targetEntity: MarketRumorPort::class,
mappedBy: 'marketRumor',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
#[ORM\OrderBy(['portIndex' => 'ASC'])]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
// 'market_rumor:collection:get',
'market_rumor:collection:post'
])]
#[MaxDepth(1)]
private ?Collection $portCalls = null;
#[ORM\OneToMany(
targetEntity: MarketRumorCargo::class,
mappedBy: 'marketRumor',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
##[ORM\OrderBy(['taskIndex' => 'ASC'])]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
// 'market_rumor:collection:get',
'market_rumor:collection:post'
])]
#[MaxDepth(1)]
private ?Collection $cargoItems = null;
#[ORM\Column(type: 'text', nullable: true)]
#[ApiProperty()]
#[Assert\Type('string')]
#[Groups([
'market_rumor:item:get',
'market_rumor:item:put',
'market_rumor:collection:get',
'market_rumor:collection:post'
])]
private ?string $notes = null;
#[ApiProperty()]
#[Groups([
'market_rumor:collection:get',
'market_rumor:item:get'
])]
private ?string $loadPortsResume = null;
#[ApiProperty()]
#[Groups([
'market_rumor:collection:get',
'market_rumor:item:get'
])]
private ?string $dischargePortsResume = null;
#[ApiProperty()]
#[Groups([
'market_rumor:collection:get',
'market_rumor:item:get'
])]
private ?string $cargoResume = null;
#[ApiProperty()]
#[Groups([
'market_rumor:collection:get',
'market_rumor:item:get'
])]
private ?string $cargoVolumeM3 = null;
#[ApiProperty()]
#[Groups([
'market_rumor:collection:get',
'market_rumor:item:get'
])]
private ?string $cargoVolumeMT = null;
public function __construct()
{
$this->id = Uuid::uuid4();
$this->portCalls = new ArrayCollection();
$this->cargoItems = new ArrayCollection();
}
public function getId(): ?UuidInterface
{
return $this->id;
}
public function setRegisterDate(?\DateTimeInterface $registerDate): void
{
$this->registerDate = $registerDate;
}
public function getRegisterDate(): ?string
{
return $this->registerDate?->format('Y-m-d');
}
public function setLaycanStartDate(?\DateTimeInterface $laycanStartDate): void
{
$this->laycanStartDate = $laycanStartDate;
}
public function getLaycanStartDate(): ?string
{
return $this->laycanStartDate?->format('Y-m-d');
}
public function setLaycanEndDate(?\DateTimeInterface $laycanEndDate): void
{
$this->laycanEndDate = $laycanEndDate;
}
public function getLaycanEndDate(): ?string
{
return $this->laycanEndDate?->format('Y-m-d');
}
public function setDwt(?string $dwt): void
{
$this->dwt = $dwt;
}
public function getDwt(): ?string
{
return $this->dwt;
}
public function setVessel(?Vessel $vessel): void
{
$this->vessel = $vessel;
}
public function getVessel(): ?Vessel
{
return $this->vessel;
}
public function setOwner(?Owner $owner): void
{
$this->owner = $owner;
}
public function getOwner(): ?Owner
{
return $this->owner;
}
public function setCharterer(?Charterer $charterer): void
{
$this->charterer = $charterer;
}
public function getCharterer(): ?Charterer
{
return $this->charterer;
}
public function setCharterer2(?Charterer $charterer): void
{
$this->charterer2 = $charterer;
}
public function getCharterer2(): ?Charterer
{
return $this->charterer2;
}
public function setBroker(?string $broker): void
{
$this->broker = $broker;
}
public function getBroker(): ?string
{
return $this->broker;
}
public function addPortCall(MarketRumorPort $portCall): void
{
$portCall->setMarketRumor($this);
$this->portCalls[] = $portCall;
}
public function removePortCall(MarketRumorPort $portCall): void
{
$this->portCalls->removeElement($portCall);
}
public function getPortCalls(): Collection
{
return $this->portCalls;
}
public function addCargoItem(MarketRumorCargo $cargoItem): void
{
$cargoItem->setMarketRumor($this);
$this->cargoItems[] = $cargoItem;
}
public function removeCargoItem(MarketRumorCargo $cargoItem): void
{
$this->cargoItems->removeElement($cargoItem);
}
public function getCargoItems(): Collection
{
return $this->cargoItems;
}
public function getFreightCost(): ?string
{
return $this->freightCost;
}
public function setFreightCost(?string $freightCost): void
{
$this->freightCost = $freightCost;
}
public function getFreightCostCurrency(): ?string
{
return $this->freightCostCurrency;
}
public function setFreightCostCurrency(?string $freightCostCurrency): void
{
$this->freightCostCurrency = $freightCostCurrency;
}
public function getFreightType(): ?string
{
return $this->freightType;
}
public function setFreightType(?string $freightType): void
{
$this->freightType = $freightType;
}
public function setStatus(?string $status): void
{
$this->status = $status;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setNotes(?string $notes): void
{
$this->notes = $notes;
}
public function getNotes(): ?string
{
return $this->notes;
}
public function getLoadPortsResume(): ?string
{
$portCalls = array_filter($this->getPortCalls()->toArray(), function($pc) {
return $pc->getPortCallType() === PortCall::PORT_CALL_TYPE_LOAD;
});
$portCount = count($portCalls);
if ($portCount === 0) {
return null;
}
$portCall = reset($portCalls);
$portName = $portCall ? $portCall->getPort()->getPortName() : '';
$portSuffix = $portCount > 1 ? ' (+)' : '';
return $portName . $portSuffix;
}
public function getDischargePortsResume(): ?string
{
$portCalls = array_filter($this->getPortCalls()->toArray(), function($pc) {
return $pc->getPortCallType() === PortCall::PORT_CALL_TYPE_DISCHARGE;
});
$portCount = count($portCalls);
if ($portCount === 0) {
return null;
}
$portCall = reset($portCalls);
$portName = $portCall ? $portCall->getPort()->getPortName() : '';
$portSuffix = $portCount > 1 ? ' (+)' : '';
return $portName . $portSuffix;
}
public function getCargoResume(): ?string
{
$cargoCount = $this->getCargoItems()->count();
if ($cargoCount === 0) {
return null;
}
$cargoItems = $this->getCargoItems();
$cargoItem = $cargoItems->first();
if (!$cargoItem instanceof MarketRumorCargo) {
return null;
}
$cargoName = $cargoItem->getCargo()->getName();
$cargoSuffix = $cargoCount > 1 ? ' (+)' : '';
return $cargoName . $cargoSuffix;
}
public function getCargoVolumeM3(): ?string
{
$totalVolume = 0.0;
foreach ($this->getCargoItems() as $cargoItem) {
// $totalVolume += (float) $cargoItem->getQuantityM3();
$totalVolume += (float) str_replace(',', '.', str_replace('.', '', $cargoItem->getQuantityM3() ?? ''));
}
// return number_format($totalVolume, 3, '.', '');
return $totalVolume ? str_replace(',00', '', number_format($totalVolume, 2, ',', '.')) : null;
}
public function getCargoVolumeMT(): ?string
{
$totalVolume = 0.0;
foreach ($this->getCargoItems() as $cargoItem) {
// $totalVolume += (float) $cargoItem->getQuantityMT();
$totalVolume += (float) str_replace(',', '.', str_replace('.', '', $cargoItem->getQuantityMT() ?? ''));
}
// return number_format($totalVolume, 3, '.', '');
return $totalVolume ? str_replace(',00', '', number_format($totalVolume, 2, ',', '.')) : null;
}
}