<?php
namespace App\Entity\Membership;
use App\Entity\User;
use App\Utility\DateTimeUtility;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Please keep direct usage of this class as low as possible. Instead,
* use BillwerkSynchronizationService and MembershipService as facades.
*
* @ORM\Entity(repositoryClass="App\Repository\BillwerkContractRepository")
*
* @ORM\Table(
* name="billwerk_contracts",
* indexes={
*
* @ORM\Index(name="users_id_updated_at_idx", columns={"customer_id", "updated_at"})
* }
* )
*
* @ORM\HasLifecycleCallbacks()
*/
class BillwerkContract
{
public const ACTIVE_LIFECYCLE_STATUS = [
self::STATUS_ACTIVE,
self::STATUS_TRIAL,
self::STATUS_IN_ORDER_PROCESS,
];
public const STATUS_ACTIVE = 'Active';
public const STATUS_TRIAL = 'InTrial';
public const STATUS_IN_ORDER_PROCESS = 'InOrderProcess';
public const STATUS_CANCELLED = 'Cancelled';
public const STATUS_PAUSED = 'Paused';
/**
* @var string
*
* @ORM\Column(name="id", type="string")
*
* @ORM\Id
*/
private $id;
public function setId(string $id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
/**
* @var string
*
* @ORM\Column(name="customer_id", type="string", length=255, nullable=false)
*
* @Assert\NotBlank()
*
* @Assert\Length(
* min = 24,
* max = 255,
* )
*/
private $customerId;
public function setCustomerId(string $customerId)
{
$this->customerId = $customerId;
}
public function getCustomerId()
{
return $this->customerId;
}
/**
* @var string
*
* @ORM\Column(name="lifecycle_status", type="string", length=255, nullable=false)
*
* @Assert\NotBlank()
*/
private $lifecycleStatus;
public function setLifecycleStatus(string $lifecycleStatus): BillwerkContract
{
$this->lifecycleStatus = $lifecycleStatus;
return $this;
}
public function getLifecycleStatus()
{
return $this->lifecycleStatus;
}
/**
* @ORM\Column(name="plan_variant_id", type="string", length=255, nullable=true)
*/
private ?string $planVariantId;
public function setPlanVariantId(?string $planVariantId = null): void
{
$this->planVariantId = $planVariantId;
}
public function getPlanVariantId(): ?string
{
return $this->planVariantId;
}
/**
* @var string
*
* @ORM\Column(name="recurring_fee", type="float", nullable=true)
*/
private $recurringFee;
public function setRecurringFee(?float $recurringFee = null)
{
$this->recurringFee = $recurringFee;
}
public function getRecurringFee()
{
return $this->recurringFee;
}
/**
* @var string
*
* @ORM\Column(name="currency", type="string", nullable=false)
*/
private $currency;
public function setCurrency(string $currency)
{
$this->currency = $currency;
}
public function getCurrency()
{
return $this->currency;
}
/**
* @var string
*
* @ORM\Column(name="payload", type="text", nullable=false)
*
* @Assert\NotBlank()
*/
private $payload;
public function setPayload(string $payload)
{
$this->payload = $payload;
}
public function getPayload()
{
return $this->payload;
}
/**
* @ORM\Column(name="next_billing_at", type="datetime_microsecond", nullable=true)
*/
private ?DateTime $nextBillingAt = null;
public function getNextBillingAt(): ?DateTime
{
return $this->nextBillingAt;
}
public function setNextBillingAt(?DateTime $nextBillingAt = null): void
{
$this->nextBillingAt = $nextBillingAt;
}
/**
* @ORM\Column(name="is_payment_escalated", type="boolean", nullable=false)
*/
private $isPaymentEscalated = false;
public function isPaymentEscalated(): bool
{
return $this->isPaymentEscalated;
}
public function setIsPaymentEscalated(bool $isPaymentEscalated)
{
$this->isPaymentEscalated = $isPaymentEscalated;
}
/**
* @var DateTime
*
* @ORM\Column(name="created_at", type="datetime")
*/
private $createdAt;
/**
* @ORM\PrePersist()
*/
public function onCreate()
{
$this->setCreatedAt(DateTimeUtility::createDateTimeUtc());
$this->setUpdatedAt(DateTimeUtility::createDateTimeUtc());
}
public function getCreatedAt(): DateTime
{
return $this->createdAt;
}
public function setCreatedAt(DateTime $createdAt): void
{
$this->createdAt = $createdAt;
}
/**
* @var DateTime
*
* @ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
private $updatedAt;
/**
* @return DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
public function setUpdatedAt(DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
}
/**
* @ORM\PreUpdate()
*/
public function onUpdate()
{
$this->setUpdatedAt(DateTimeUtility::createDateTimeUtc());
}
/**
* @ORM\Column(name="last_synchronized_at", type="datetime", nullable=true)
*/
private ?DateTime $lastSynchronizedAt;
public function getLastSynchronizedAt(): ?DateTime
{
return $this->lastSynchronizedAt;
}
public function setLastSynchronizedAt(DateTime $lastSynchronizedAt): void
{
$this->lastSynchronizedAt = $lastSynchronizedAt;
}
/**
* @ORM\Column(name="ongoing_proactive_sync_initiated_at", type="datetime", nullable=true)
*/
private ?DateTime $ongoingProactiveSyncInitiatedAt;
public function getOngoingProactiveSyncInitiatedAt(): ?DateTime
{
return $this->ongoingProactiveSyncInitiatedAt;
}
public function setOngoingProactiveSyncInitiatedAt(?DateTime $at): void
{
$this->ongoingProactiveSyncInitiatedAt = $at;
}
/**
* @ORM\Column(name="number_of_consecutive_proactive_syncs_with_timeout", type="integer", nullable=false)
*/
private int $numberOfProactiveSyncsWithTimeout = 0;
public function getNumberOfConsecutiveProactiveSyncsWithTimeout(): int
{
return $this->numberOfProactiveSyncsWithTimeout;
}
public function incrementNumberOfConsecutiveProactiveSyncsWithTimeout(): void
{
++$this->numberOfProactiveSyncsWithTimeout;
}
public function resetNumberOfConsecutiveProactiveSyncsWithTimeout(): void
{
$this->numberOfProactiveSyncsWithTimeout = 0;
}
/**
* @var User
*
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="billwerkContracts")
*
* @ORM\JoinColumn(name="users_id", onDelete="CASCADE")
*/
private $user;
public function getUser(): User
{
return $this->user;
}
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @var bool
*
* @ORM\Column(type="boolean")
*/
private $cancelled = false;
public function isCancelled(): bool
{
return $this->cancelled;
}
public function setCancelled(bool $cancelled)
{
$this->cancelled = $cancelled;
}
public function isActive(): bool
{
return in_array($this->lifecycleStatus, self::ACTIVE_LIFECYCLE_STATUS);
}
public function isPaused(): bool
{
return $this->lifecycleStatus === self::STATUS_PAUSED;
}
public function __toString()
{
return (string)$this->getId();
}
/**
* The follow up billwerk contract is the specific billwerk contract which is booked when the user enters into another
* contract while having another currently active billwerk contract.
* For example if the user upgrades its basic membership to a premium membership the premium membership billwerk contract
* is considered to be the follow up billwerk contract for the previous active basic membership billwerk contract.
* On the other hand, if a user ends its current billwerk contract with a membership cancellation and then, a few weeks or
* even a minute later signs up for a new membership, the new billwerk contract is not considered a follow up billwerk contract.
*
* @ORM\ManyToOne(targetEntity="App\Entity\Membership\BillwerkContract", cascade={"persist"})
*
* @ORM\JoinColumn(name="follow_up_billwerk_contracts_id", referencedColumnName="id", onDelete="SET NULL")
*/
private ?BillwerkContract $followUpBillwerkContract = null;
public function getFollowUpBillwerkContract(): ?BillwerkContract
{
return $this->followUpBillwerkContract;
}
public function setFollowUpBillwerkContract(?BillwerkContract $followUpBillwerkContract)
{
if (!is_null($followUpBillwerkContract)) {
if ($followUpBillwerkContract->getId() === $this->id) {
throw new InvalidArgumentException("Cannot set follow up billwerk contract for billwerk contract {$this->id}, because the follow up billwerk contract and this billwerk contract are identical.");
}
}
$this->followUpBillwerkContract = $followUpBillwerkContract;
}
}