<?php
namespace Bidcoz\Bundle\CoreBundle\Entity\Auction;
use Bidcoz\Bundle\CoreBundle\Entity\Campaign;
use Bidcoz\Bundle\CoreBundle\ObjectChange\ObjectChangeTrackable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serialize;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @ORM\Entity(repositoryClass="AuctionRepository")
* @ORM\Table(
* name="auctions",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="uniq_72d6e900f639f774", columns={"campaign_id", "type"})
* }
* )
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="type", type="string", length=20)
* @ORM\DiscriminatorMap({
* "auction" = "Auction",
* "shop" = "Shop",
* "fund-a-need" = "FundANeed",
* })
* @Serialize\ExclusionPolicy("all")
*/
class Auction implements ObjectChangeTrackable
{
public const OVERTIME_NONE = 'none';
public const OVERTIME_SINGLE = 'single';
public const OVERTIME_UNLIMITED = 'unlimited';
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
* @Serialize\Expose
*/
protected ?int $id = null;
/**
* @ORM\OneToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\Campaign", inversedBy="auction")
* @ORM\JoinColumn(name="campaign_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $campaign;
/**
* @ORM\Column(name="online_begin", type="datetime", nullable=true);
* @Serialize\Expose
*/
protected $onlineBegin;
/**
* @ORM\Column(name="online_end", type="datetime", nullable=true);
* @Serialize\Expose
*/
protected $onlineEnd;
/**
* @ORM\Column(name="onsite_begin", type="datetime", nullable=true);
* @Serialize\Expose
*/
protected $onsiteBegin;
/**
* @ORM\Column(name="onsite_end", type="datetime", nullable=true);
* @Serialize\Expose
*/
protected $onsiteEnd;
/**
* @ORM\Column(name="has_online", type="boolean")
*/
protected $hasOnline = true;
/**
* @ORM\Column(name="has_onsite", type="boolean")
*/
protected $hasOnsite = false;
/**
* @ORM\Column(name="online_ticket_required", type="boolean")
*/
protected $onlineTicketRequired = false;
/**
* @ORM\Column(name="onsite_ticket_required", type="boolean")
*/
protected $onsiteTicketRequired = false;
/**
* @ORM\Column(name="online_registration_required", type="boolean")
*/
protected $onlineRegistrationRequired = false;
/**
* @ORM\Column(name="onsite_registration_required", type="boolean")
*/
protected $onsiteRegistrationRequired = false;
/**
* @ORM\Column(name="location", type="text", nullable=true);
* @Serialize\Expose
*/
protected $location;
/**
* @ORM\Column(name="location_link", type="boolean")
*/
protected $locationLink = true;
/**
* @ORM\Column(name="bid_increment", type="decimal", scale=2, precision=10, nullable=true)
* @Assert\Range(min=0)
*/
protected $bidIncrement = 5;
/**
* @ORM\Column(name="pickup_instructions", type="text", nullable=true)
*/
protected $pickupInstructions;
/**
* @ORM\Column(name="bidding_rules", type="text", nullable=true);
*/
protected $biddingRules;
/**
* @ORM\Column(name="overtime_bidding", type="string", length=10)
*/
protected $overtimeBidding = self::OVERTIME_NONE;
/**
* @var ItemCategory[]|Collection|null
* @ORM\OneToMany(targetEntity="ItemCategory", mappedBy="auction", cascade={"remove", "persist"})
*/
protected ?Collection $itemCategories = null;
/**
* @var Item[]|Collection|null
* @ORM\OneToMany(targetEntity="Item", mappedBy="auction", cascade={"remove", "persist"})
*/
protected ?Collection $items = null;
/**
* @ORM\Column(name="created_at", type="datetime")
* @Serialize\Expose
*/
protected $createdAt;
/**
* @ORM\Column(name="show_auction_title", type="boolean", options={"default"= true})
*/
protected $showAuctionTitle = true;
/**
* @ORM\Column(name="show_qty_remaining", type="boolean", options={"default"= true})
*/
protected $showQtyRemaining = true;
/**
* @ORM\Column(name="are_you_sure_modal", type="boolean");
*/
protected $areYouSureModal = false;
public function __construct(Campaign $campaign)
{
$this->campaign = $campaign;
$campaign->setAuction($this);
$this->itemCategories = new ArrayCollection();
$this->items = new ArrayCollection();
$this->createdAt = new \DateTime();
}
public function setId(?int $id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function getCampaign()
{
return $this->campaign;
}
public function setCampaign(Campaign $campaign): void
{
$this->campaign = $campaign;
}
public function setOnlineBegin(\DateTime $date = null)
{
$this->onlineBegin = $date;
}
public function getOnlineBegin()
{
return $this->onlineBegin;
}
public function setOnlineEnd(\DateTime $date = null)
{
$this->onlineEnd = $date;
}
public function getOnlineEnd()
{
return $this->onlineEnd;
}
public function isOver()
{
$now = new \DateTime();
if ($this->hasOnsite && $now < $this->onsiteEnd) {
return false;
}
if ($this->hasOnline && $now < $this->onlineEnd) {
return false;
}
return true;
}
public function getStatus(): string
{
$now = new \DateTime();
$lastEndDate = $this->getLastEndDate();
$firstStartDate = $this->getFirstStartDate();
if ($now > $lastEndDate) {
return 'Past';
} elseif ($firstStartDate > $now) {
return 'Future';
} else {
return 'Current';
}
}
public function getFirstStartDate()
{
$dates = [];
if ($this->hasOnline) {
$dates[] = $this->onlineBegin;
}
if ($this->hasOnsite) {
$dates[] = $this->onsiteBegin;
}
$dates = array_filter($dates, function ($date) {
return !is_null($date);
});
if (0 === count($dates)) {
return;
}
return min($dates);
}
public function getLastEndDate()
{
$dates = [];
if ($this->hasOnline) {
$dates[] = $this->onlineEnd;
}
if ($this->hasOnsite) {
$dates[] = $this->onsiteEnd;
}
$dates = array_filter($dates, function ($date) {
return !is_null($date);
});
if (0 === count($dates)) {
return;
}
return max($dates);
}
/**
* @Assert\Callback
*/
public function ensureOnlineDatesValid(ExecutionContextInterface $context)
{
// Fields onlineBegin and onlineEnd are nullable, however they are checked when updating Auction that 'hasOnline'.
// Skip this check for Shop and Fund-a-Need entities that don't update these fields anywhere.
if ($this->hasOnline && Auction::class === get_class($this)) {
if (!$this->onlineBegin) {
$context->buildViolation('Start Date required for Online Auction')
->atPath('onlineBegin')
->addViolation();
} elseif (!$this->onlineEnd) {
$context->buildViolation('End Date required for Online Auction')
->atPath('onlineEnd')
->addViolation();
} elseif ($this->onlineBegin > $this->onlineEnd) {
$context->buildViolation('Start Date cannot be after End Date')
->atPath('onlineEnd')
->addViolation();
}
}
}
public function setOnsiteBegin(\DateTime $date = null)
{
$this->onsiteBegin = $date;
}
public function getOnsiteBegin()
{
return $this->onsiteBegin;
}
public function setOnsiteEnd(\DateTime $date = null)
{
$this->onsiteEnd = $date;
}
public function getOnsiteEnd()
{
return $this->onsiteEnd;
}
/**
* @Assert\Callback
*/
public function ensureOnsiteDatesValid(ExecutionContextInterface $context)
{
if ($this->hasOnsite) {
if (!$this->onsiteBegin) {
$context->buildViolation('Start Date required for Onsite Auction')
->atPath('onsiteBegin')
->addViolation();
} elseif (!$this->onsiteEnd) {
$context->buildViolation('End Date required for Onsite Auction')
->atPath('onsiteEnd')
->addViolation();
} elseif ($this->onsiteBegin > $this->onsiteEnd) {
$context->buildViolation('Start Date cannot be after End Date')
->atPath('onsiteBegin')
->addViolation();
}
}
}
public function setHasOnline($hasOnline)
{
$this->hasOnline = $hasOnline;
}
public function hasOnline()
{
return $this->hasOnline;
}
public function setHasOnsite($hasOnsite)
{
$this->hasOnsite = $hasOnsite;
}
public function hasOnsite()
{
return $this->hasOnsite;
}
public function isAvailable(): bool
{
return ($this->hasOnsite() || $this->hasOnline()) && !$this->isOver();
}
public function setOnlineTicketRequired($onlineTicketRequired)
{
$this->onlineTicketRequired = $onlineTicketRequired;
}
public function getOnlineTicketRequired()
{
return $this->onlineTicketRequired;
}
public function setOnsiteTicketRequired($onsiteTicketRequired)
{
$this->onsiteTicketRequired = $onsiteTicketRequired;
}
public function getOnsiteTicketRequired()
{
return $this->onsiteTicketRequired;
}
public function setOnlineRegistrationRequired($onlineRegistrationRequired)
{
$this->onlineRegistrationRequired = $onlineRegistrationRequired;
}
public function getOnlineRegistrationRequired()
{
return $this->onlineRegistrationRequired;
}
public function setOnsiteRegistrationRequired($onsiteRegistrationRequired)
{
$this->onsiteRegistrationRequired = $onsiteRegistrationRequired;
}
public function getOnsiteRegistrationRequired()
{
return $this->onsiteRegistrationRequired;
}
public function setLocation($location)
{
$this->location = $location;
}
public function getLocation()
{
return $this->location;
}
public function setLocationLink(bool $locationLink)
{
$this->locationLink = $locationLink;
}
public function getLocationLink(): bool
{
return $this->locationLink;
}
public function setBidIncrement($bidIncrement)
{
$this->bidIncrement = $bidIncrement;
}
public function getBidIncrement()
{
return $this->bidIncrement;
}
public function setPickupInstructions($pickupInstructions)
{
$this->pickupInstructions = $pickupInstructions;
}
public function getPickupInstructions()
{
return $this->pickupInstructions;
}
public function setOvertimeBidding($overtimeBidding)
{
$this->overtimeBidding = $overtimeBidding;
}
public function getOvertimeBidding()
{
return $this->overtimeBidding;
}
public static function getOvertimeBiddingChoices()
{
return [
'None' => self::OVERTIME_NONE,
'Single time extension' => self::OVERTIME_SINGLE,
'Unlimited time extensions' => self::OVERTIME_UNLIMITED,
];
}
public function isOvertimeBiddingSingleExtension()
{
return self::OVERTIME_SINGLE === $this->overtimeBidding;
}
public function isOvertimeBiddingUnlimitedExtension()
{
return self::OVERTIME_UNLIMITED === $this->overtimeBidding;
}
public function getVenueChoices()
{
$choices = [];
if ($this->hasOnline) {
$choices[AuctionVenue::ONLINE] = 'Online';
}
if ($this->hasOnsite) {
$choices[AuctionVenue::ONSITE] = 'Onsite';
}
if ($this->hasOnline && $this->hasOnsite) {
// TODO - Figure out this logic
// $choices[null] = 'Both (Online and Onsite)';
}
return $choices;
}
/**
* @return ItemCategory[]|Collection|null
*/
public function getItemCategories(): ?Collection
{
return $this->itemCategories;
}
public function addItemCategory(ItemCategory $itemCategory): void
{
if (!$this->itemCategories->contains($itemCategory)) {
$this->itemCategories->add($itemCategory);
$itemCategory->setAuction($this);
}
}
public function removeItemCategory(ItemCategory $itemCategory): void
{
if ($this->itemCategories->contains($itemCategory)) {
$this->itemCategories->removeElement($itemCategory);
$itemCategory->setAuction(null);
}
}
public function getShowAuctionTitle(): bool
{
return $this->showAuctionTitle;
}
public function getShowQtyRemaining(): bool
{
return $this->showQtyRemaining;
}
public function setShowQtyRemaining($showQtyRemaining)
{
$this->showQtyRemaining = $showQtyRemaining;
}
public function getObjectName()
{
return 'Auction';
}
public function setShopDisplayName(string $shopDisplayName)
{
$this->campaign->setShopDisplayName($shopDisplayName);
}
public function getShopDisplayName(): string
{
return $this->campaign->getShopDisplayName();
}
public function setFundANeedDisplayName(string $shopDisplayName)
{
$this->campaign->setFundANeedDisplayName($shopDisplayName);
}
public function getFundANeedDisplayName(): string
{
return $this->campaign->getFundANeedDisplayName();
}
/**
* @return Collection|Item[]|null
*/
public function getItems(): ?Collection
{
return $this->items;
}
public function setItems(?Collection $items): void
{
$this->items = $items;
}
public function addItem(Item $item): void
{
$this->items->add($item);
$item->setAuction($this);
}
public function removeItem(Item $item): void
{
$this->items->removeElement($item);
$item->setAuction(null);
}
public function setShopGoal(string $goal)
{
$this->campaign->setShopGoal($goal);
}
public function getShopGoal(): string
{
return $this->campaign->getShopGoal();
}
public function setFundANeedGoal(string $goal)
{
$this->campaign->setFundANeedGoal($goal);
}
public function getFundANeedGoal(): string
{
return $this->campaign->getFundANeedGoal();
}
public function getAreYouSureModal(): bool
{
return $this->areYouSureModal;
}
public function setAreYouSureModal(bool $areYouSureModal): void
{
$this->areYouSureModal = $areYouSureModal;
}
public function getTrackedParams()
{
return [
'overtimeBidding' => 'Overtime bidding',
'onlineBegin' => 'Online Begin',
'onlineEnd' => 'Online End',
'onsiteBegin' => 'Event Begin',
'onsiteEnd' => 'Event End',
'hasOnline' => 'Has Online',
'hasOnsite' => 'Has Event',
];
}
public function getRoutePath(): string
{
return 'auction';
}
}