<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\ReferralRepository;
use DateTime;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Index;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\ORM\Mapping\OneToOne;
#[Entity(ReferralRepository::class)]
#[Index(fields: ['code'], name: 'idx_referral_code')]
class Referral
{
public const DEFAULT_REFERRAL_ACTIVITY_COMMISSION_PERCENT = 10;
public const DEFAULT_REFERRAL_NEW_CAMPAIGN_COMMISSION_PERCENT = 10;
public const DEFAULT_DURATION_DAYS_PER_REFERRED_USER = 90;
public const DURATION_365_DAYS_PER_REFERRED_USER = 365;
#[Id]
#[OneToOne(targetEntity: User::class)]
#[JoinColumn(name: 'id', unique: true, nullable: false, onDelete: 'CASCADE')]
private User $user;
#[Column(length: 10, nullable: true)]
private ?string $code = null;
/**
* @var User|null The User who referred this user
*/
#[ManyToOne(targetEntity: User::class)]
#[JoinColumn(name: 'referred_by_id', referencedColumnName: 'id', nullable: true)]
private ?User $referredBy = null;
/**
* @var Collection|User[] The Users referred by this user
*/
#[OneToMany(mappedBy: 'referredBy', targetEntity: User::class)]
private Collection|array $referrals = [];
#[Column(options: ['default' => 1])]
private bool $isEnabled = true;
#[Column(name: 'duration_days_per_referred_user', type: 'integer', options: ['unsigned' => true])]
private int $durationDaysPerReferredUser = self::DEFAULT_DURATION_DAYS_PER_REFERRED_USER;
#[Column('referred_by_ended_at', 'datetime', nullable: true)]
private ?DateTime $referredByEndedAt = null;
#[Column(name: 'referral_activity_commission_percent', type: 'integer', options: ['unsigned' => true])]
private int $referralActivityCommissionPercent = self::DEFAULT_REFERRAL_ACTIVITY_COMMISSION_PERCENT;
#[Column(name: 'referral_new_campaign_commission_percent', type: 'integer', options: ['unsigned' => true])]
private int $referralNewCampaignCommissionPercent = self::DEFAULT_REFERRAL_NEW_CAMPAIGN_COMMISSION_PERCENT;
/**
* The total monetary balance earned through referrals.
* This column stores the cumulative earnings from successful referral actions.
* Currently, it is used exclusively for sponsors.
*/
#[Column(type: 'float', nullable: false)]
private float $balance = 0;
public function __construct(User $user, string $code)
{
$this->user = $user;
$this->code = $code;
}
public function getUser(): User
{
return $this->user;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): static
{
$this->code = $code;
return $this;
}
public function getReferredBy(): ?User
{
return $this->referredBy;
}
public function setReferredBy(User $referredBy): static
{
$this->referredBy = $referredBy;
return $this;
}
public function hasReferredBy(): bool
{
return $this->referredBy !== null;
}
/**
* @return Collection<int, User>
*/
public function getReferrals(): Collection
{
return $this->referrals;
}
public function isEnabled(): bool
{
return $this->isEnabled;
}
public function isDisabled(): bool
{
return $this->isEnabled === false;
}
public function setIsReferralEnabled(bool $isEnabled): static
{
$this->isEnabled = $isEnabled;
return $this;
}
public function getDurationDaysPerReferredUser(): int
{
return $this->durationDaysPerReferredUser;
}
public function setDurationDaysPerReferredUser(int $durationDaysPerReferredUser): self
{
$this->durationDaysPerReferredUser = $durationDaysPerReferredUser;
return $this;
}
public function getReferredByEndedAt(): ?DateTime
{
return $this->referredByEndedAt;
}
public function setReferredByEndedAt(DateTime $referredByEndedAt): self
{
$this->referredByEndedAt = $referredByEndedAt;
return $this;
}
public function isReferredByExpired(): bool
{
if ($this->referredByEndedAt === null) {
return false;
}
return $this->referredByEndedAt < (new DateTime())->setTime(23, 59, 59);
}
public function getReferralActivityCommissionPercent(): int
{
return $this->referralActivityCommissionPercent;
}
public function setReferralActivityCommissionPercent(int $referralActivityCommissionPercent): self
{
$this->referralActivityCommissionPercent = $referralActivityCommissionPercent;
return $this;
}
public function getReferralNewCampaignCommissionPercent(): int
{
return $this->referralNewCampaignCommissionPercent;
}
public function setReferralNewCampaignCommissionPercent(int $referralNewCampaignCommissionPercent): self
{
$this->referralNewCampaignCommissionPercent = $referralNewCampaignCommissionPercent;
return $this;
}
public function getBalance(): float
{
return $this->balance;
}
public function setBalance(float $balance): self
{
$this->balance = $balance;
return $this;
}
public function __toString(): string
{
return sprintf(
'#%s %s [%s]',
$this->user->getId(),
$this->user->getEmail(),
basename(str_replace('\\', '/', get_class($this->user)))
);
}
}