<?php
namespace Services\UsersBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Services\UsersBundle\Entity\UserSync;
use Services\PaymentBundle\Entity\Payment;
use Services\ConfigurationBundle\Entity\Roles;
use JMS\Serializer\Annotation as Serializer;
use Services\PaymentBundle\Entity\UserTokens;
use Services\LocationBundle\Entity\UserAddress;
use Services\PaymentBundle\Entity\PaymentTypes;
use Services\PaymentBundle\Entity\PaymentStatus;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\ORM\Mapping\UniqueConstraint;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
/**
* Users
*
* @Serializer\ExclusionPolicy("ALL")
*
* @ORM\Table(name="users",uniqueConstraints={@UniqueConstraint(name="user_site_unique_idx", columns={"mail", "site_id"})})
* @ORM\Entity(repositoryClass="Services\UsersBundle\Repository\UsersRepository")
* @UniqueEntity(fields={"mail"},
* message = "Le mail est déjà utilisé")
*/
class Users implements UserInterface, \Serializable, EquatableInterface, PasswordAuthenticatedUserInterface
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @ORM\Column(name="username", type="string", length=255, nullable=false)
*/
private $username;
/**
* User Score 0-100
* @var int
* @ORM\Column(name="score", type="integer", nullable=true)
*/
private $score;
/**
* // FIXME: not many to one
* @ORM\ManyToOne(targetEntity="Services\ConfigurationBundle\Entity\Roles", inversedBy="user")
* @Serializer\Expose
* @ORM\JoinColumn(nullable=false)
*/
private $roles; // singular
/**
* @var string
* @ORM\Column(name="password", type="string", length=255)
*/
private $password;
/**
* @var string
*
* @ORM\Column(name="salt", type="string", length=255)
*/
private $salt;
//@NaturalId
/**
* @var string
*
* @Serializer\Expose
* @ORM\Column(name="mail", type="string", length=255)
*/
private $mail;
/**
* @ORM\OneToOne(targetEntity="Services\UsersBundle\Entity\UserInfos", inversedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=false)
* @Serializer\Expose
* @Serializer\Groups({"user_sync"})
*/
private $userInfos;
/**
* @ORM\OneToOne(targetEntity="Services\UsersBundle\Entity\UserErrorAcquisition")
* @ORM\JoinColumn(name="user_error_acquisition_id", referencedColumnName="id", nullable=true)
*/
private $userErrorAcquisition;
/**
* @ORM\OneToMany(targetEntity="Services\PaymentBundle\Entity\Payment", mappedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
*/
private $payment;
/**
* contract modifictions, last one first
* @ORM\OneToMany(targetEntity="Services\UsersBundle\Entity\ContractModification", mappedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
* @ORM\OrderBy({"id" = "DESC"})
*/
private $contractModifications;
/**
* @ORM\OneToMany(targetEntity="Services\UsersBundle\Entity\UserSync", mappedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
* @ORM\OrderBy({"id" = "DESC"})
*/
private $userSyncs;
/**
* @ORM\ManyToOne(targetEntity="Services\ConfigurationBundle\Entity\Site", inversedBy="user")
* @ORM\JoinColumn(nullable=true)
*/
private $site;
/**
* @ORM\OneToMany(targetEntity="Services\UsersBundle\Entity\Unsubscribe", mappedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=false)
*/
private $unsubscribe;
/**
* @Serializer\Expose
* @ORM\OneToOne(targetEntity="Services\LocationBundle\Entity\UserAddress", inversedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
*/
private $userAddress;
/**
* @ORM\OneToMany(targetEntity="Services\PaymentBundle\Entity\UserTokens", mappedBy="user", cascade={"persist", "remove"})
* added an order to get the latest active first
* @ORM\OrderBy({"isActive" = "DESC", "id" = "DESC"})
*/
private $userTokens;
/**
* Flag to determine if a User is created manually by us (retry manual ghost)
*
* @var bool
*
* @ORM\Column(name="is_manual", type="boolean")
*/
private $isManual = false;
/**
* Flag to determine if the user failed to pay the remaining amount in the INITIAL_ONE_EURO campaign type
* on their first payment
*
* @var bool
* @Serializer\Expose
* @ORM\Column(name="is_preaboes", type="boolean", nullable=true, options={"default": 0})
*/
private $isPreaboEs = false;
/**
* @Serializer\Exclude
* @ORM\OneToMany(targetEntity="Services\ManualRetryBundle\Entity\RetryUser", mappedBy="user", cascade={"persist", "remove"})
*/
private $userRetries;
/**
* @var boolean
*
* @Serializer\Expose
* @ORM\Column(name="is_deleted", type="boolean", options={"default": 0})
*/
private $isDeleted;
/**
* @var bool
* @Serializer\Expose
* @ORM\Column(name="is_external_billing", type="boolean", nullable=true, options={"default": 0})
*/
private $isExternalBilling;
/**
* @var bool
* @Serializer\Expose
* @ORM\Column(name="is_external_billing_stopped", type="boolean", nullable=true, options={"default": 0})
*/
private $isExternalBillingStopped;
/**
* @var bool
* @Serializer\Expose
* @ORM\Column(name="is_inactive", type="boolean", nullable=true, options={"default": 0})
*/
private $isInactive;
/**
* @var \DateTime
*
* @ORM\Column(name="last_conversion_to_inactive", type="datetime", nullable=true)
*/
private $lastConversionToInactive;
/**
* @var \DateTime
*
* @ORM\Column(name="last_conversion_to_active", type="datetime", nullable=true)
*/
private $lastConversionToActive;
/**
* @var int|null
* @ORM\Column(name="prev_roles_id", type="smallint")
*/
private ?int $prevRoleId;
public function __construct()
{
$this->salt = md5(time());
$this->payment = new \Doctrine\Common\Collections\ArrayCollection();
$this->isManual = false;
$this->password = 'XXXXX';
$this->score = 100;
$this->isDeleted = false;
$this->isInactive = false;
$this->prevRoleId = null;
}
/**
* @inheritDoc
*/
public function eraseCredentials()
{
}
/**
* @see \Serializable::serialize()
*/
public function serialize()
{
return serialize([
$this->id,
$this->mail,
]);
}
/**
* @see \Serializable::unserialize()
*/
public function unserialize($serialized)
{
list(
$this->id,
) = unserialize($serialized);
}
public function isEqualTo(UserInterface $user)
{
return $user->id === $this->id;
}
/**
* Set roles (role singular)
*
* @param \Services\ConfigurationBundle\Entity\Roles $roles
* @return Users
*/
public function setRoles(\Services\ConfigurationBundle\Entity\Roles $roles)
{
$this->roles = $roles;
return $this;
}
/**
* Set role (role singular)
*
* @param \Services\ConfigurationBundle\Entity\Roles $roles
* @return Users
*/
public function setRole(\Services\ConfigurationBundle\Entity\Roles $roles)
{
$this->roles = $roles;
return $this;
}
/**
* Get roles returns an array of roles!
* so get the first role's name
*
* @return String
*/
public function getRoleName()
{
$roleNames = $this->roles->getName();
return is_array($roleNames) ? $roleNames[0] : $roleNames;
}
/**
* Get roles returns an array of roles!
*
* @return String
*/
public function getRoles()
{
return $this->roles->getName();
}
/**
* Get roles
*
* @return \Services\ConfigurationBundle\Entity\Roles
*/
public function getRolesString()
{
return $this->roles;
}
/**
* Get roles
*
* @return \Services\ConfigurationBundle\Entity\Roles
*/
public function getRolesObject()
{
return $this->roles;
}
/**
* @return Bool on whether this user is active (premium, error sub, split, preabo)
*/
public function isActiveRole(): bool
{
$currentRoleId = $this->getRolesObject()->getId();
return in_array($currentRoleId, Roles::ACTIVE_USER_ROLES);
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* @param string $username
* @return Users
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Get user identifier
*
* @return string
*/
public function getUserIdentifier(): string
{
return $this->getUsername();
}
/**
* Set password
*
* @param string $password
* @return Users
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* @return string
*/
public function getPassword(): ?string
{
return $this->password;
}
/**
* Set salt
*
* @param string $salt
* @return Users
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Get salt
*
* @return string
*/
public function getSalt()
{
return $this->salt;
}
/**
* Set mail
*
* @param string $mail
* @return Users
*/
public function setMail($mail)
{
$this->mail = $mail;
return $this;
}
/**
* Get mail
*
* @return string
*/
public function getMail()
{
return $this->mail;
}
/**
* Set userInfos
*
* @param \Services\UsersBundle\Entity\UserInfos $userInfos
* @return Users
*/
public function setUserInfos(\Services\UsersBundle\Entity\UserInfos $userInfos)
{
$this->userInfos = $userInfos;
return $this;
}
/**
* Get userInfos
*
* @return \Services\UsersBundle\Entity\UserInfos
*/
public function getUserInfos()
{
return $this->userInfos;
}
/**
* Add payment
*
* @param Payment $payment
* @param bool $checkIfAlreadyExists check if payment has been already added for this user
* @return Users
*/
public function addPayment(Payment $payment, bool $checkIfAlreadyExists = false)
{
$exists = false;
if ($checkIfAlreadyExists) {
foreach ($this->payment as $p) {
if ($p->getId() == $payment->getId()) {
$exists = true;
break;
}
}
}
if (!$exists) {
$this->payment[] = $payment;
}
return $this;
}
/**
* Remove payment
*
* @param \Services\PaymentBundle\Entity\Payment $payment
*/
public function removePayment(\Services\PaymentBundle\Entity\Payment $payment)
{
$this->payment->removeElement($payment);
}
/**
* Get payment (s)
* TODO: payments
* @return \Doctrine\Common\Collections\Collection
*/
public function getPayment()
{
return $this->payment;
}
/**
* Get payment (s)
* correct name for get all payments
* @return \Doctrine\Common\Collections\Collection
*/
public function getPayments()
{
return $this->payment;
}
/**
* Get contract modification (s)
* @return \Doctrine\Common\Collections\Collection
*/
public function getContractModifications()
{
return $this->contractModifications;
}
/**
* Get userSyncs
* @return \Doctrine\Common\Collections\Collection
*/
public function getUserSyncs()
{
return $this->userSyncs;
}
/**
* Get payment
*
* @return ContractModification|null if none
*/
public function getLastContractModification()
{
return
$this->contractModifications[0] ?? null;
}
/**
* Get payment
*
* @return Payment
*/
public function getLastPayment()
{
return $this->payment->last() ?: null;
//[count($this->payment) - 1];
}
/**
* Get payment
*
* @return Payment
*/
public function getFirstPayment()
{
return $this->payment[0];
}
/**
* return first `Active` payment (3, 11, 2)
* @return Payment|null if user has no active payment
*/
public function getActivePayment($includeSplit = false)
{
$activePaymentTypes = [
PaymentStatus::STATUS_PAIEMENT_SIMPLE,
PaymentStatus::STATUS_RETRY_7_DAY,
PaymentStatus::STATUS_PREMIER_PRELEVEMENT,
];
if ($includeSplit) {
$activePaymentTypes[] = PaymentStatus::STATUS_PAIEMENT_SPLIT;
}
foreach ($this->payment as $paymentCheck) {
/** @var Payment $paymentCheck */
if (in_array($paymentCheck->getPaymentStatus()->getId(), $activePaymentTypes)) {
return $paymentCheck;
}
}
return null;
}
/**
* Get the payment previous (taking into account the value of nextPaymentDate) to the provided payment
*
* @param \Services\PaymentBundle\Entity\Payment $payment
* @return Payment|null
*/
public function getPreviousPayment(Payment $payment): ?Payment
{
$paymentsList = $this->payment->toArray();
$paymentsList = array_reverse($paymentsList);
foreach ($paymentsList as $p) {
if ($p->getNextPaymentDate() < $payment->getNextPaymentDate()) {
return $p;
}
}
return null;
}
/**
* Get the start date of the first period for this user.
*
* @return \DateTime
*/
public function getInitialPeriodStartDate()
{
// PM: Period starts when 1st payment is captured (even if it has been just 1 euro)
$paymentsList = $this->getPayment(); // Get payments ordered by nextPaymentDate ASC
// 1) We get the last created payment nextPaymentDate by default
// Example: If we have an Auth today (Nov 30th) (1 euro + rest immediately - Payment D+3),
// his period start in December when we have the capture.
if ($paymentsList->isEmpty()) {
$initialDate = clone $this->getUserInfos()->getDateInscription();
} else {
$initialDate = clone $paymentsList->last()->getNextPaymentDate();
$paymentsList->first();
// 2) If we have a captured payment, get its subscription date as initial date
foreach ($paymentsList as $p) {
if ($p->getPaymentStatus()->getId() == PaymentStatus::STATUS_PAYE) {
$initialDate = clone $p->getNextPaymentDate();
break;
}
}
}
return $initialDate;
}
/**
* Get payment
*
* @return \Doctrine\Common\Collections\Collection
*/
public function countPayment()
{
return count($this->payment);
}
/**
* Set site.
*
* @param \Services\ConfigurationBundle\Entity\Site $site
*
* @return Users
*/
public function setSite(\Services\ConfigurationBundle\Entity\Site $site)
{
$this->site = $site;
return $this;
}
/**
* Get site.
*
* @return \Services\ConfigurationBundle\Entity\Site
*/
public function getSite()
{
return $this->site;
}
/**
* Add unsubscribe.
*
* @param \Services\UsersBundle\Entity\Unsubscribe $unsubscribe
*
* @return Users
*/
public function addUnsubscribe(\Services\UsersBundle\Entity\Unsubscribe $unsubscribe)
{
$this->unsubscribe[] = $unsubscribe;
return $this;
}
/**
* Remove unsubscribe.
*
* @param \Services\UsersBundle\Entity\Unsubscribe $unsubscribe
*
* @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
*/
public function removeUnsubscribe(\Services\UsersBundle\Entity\Unsubscribe $unsubscribe)
{
return $this->unsubscribe->removeElement($unsubscribe);
}
/**
* Get unsubscribe.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUnsubscribe()
{
return $this->unsubscribe;
}
/**
* Set userAddress.
*
* @param \Services\LocationBundle\Entity\UserAddress|null $userAddress
*
* @return Users
*/
public function setUserAddress(\Services\LocationBundle\Entity\UserAddress $userAddress = null)
{
$this->userAddress = $userAddress;
return $this;
}
/**
* Get userAddress.
*
* @return UserAddress
*/
public function getUserAddress()
{
return $this->userAddress;
}
/**
* Add userToken.
*
* @param \Services\PaymentBundle\Entity\UserTokens $userToken
*
* @return Users
*/
public function addUserToken(\Services\PaymentBundle\Entity\UserTokens $userToken)
{
$this->userTokens[] = $userToken;
return $this;
}
/**
* Remove userToken.
*
* @param \Services\PaymentBundle\Entity\UserTokens $userToken
*
* @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
*/
public function removeUserToken(\Services\PaymentBundle\Entity\UserTokens $userToken)
{
return $this->userTokens->removeElement($userToken);
}
/**
* Get userTokens. (latest first)
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUserTokens()
{
return $this->userTokens;
}
/**
* return last active UserToken
* if mid is not given, just return the last generated token (freshest CC)
* @param PaymentTypes $mid used
* @return UserTokens|null
*/
public function getLatestActiveUserToken($mid = null)
{
if ($this->userTokens) {
// user tokens are sorted from last to first
foreach ($this->userTokens as $userToken) {
/** @var UserTokens $userToken */
if (null == $mid
|| ($userToken->getPaymentTypes()->getId() == $mid->getId()
&& $userToken->getIsActive()
)) {
return $userToken;
}
}
}
return null;
}
/**
* WIP:
* has a valid credit card
* goes through the tokens to check if there's a least one card still valid
* @return bool
*/
public function hasValidCreditCard()
{
foreach ($this->userTokens as $userToken) {
/** @var UserTokens $userToken */
if (!$userToken->getIsExpired()) {
return true;
}
}
return false;
}
/**
* is Active
* helper
* @return bool true if active
*/
public function isActive()
{
return (null != $this->roles)
&& in_array($this->roles->getId(), [
Roles::ROLE_PREMIUM,
Roles::ROLE_ERROR_SUBSCRIPTION,
Roles::ROLE_SPLIT,
Roles::ROLE_PREABO
]);
}
/**
* Set isManual.
*
* @param bool $isManual
*
* @return Users
*/
public function setIsManual($isManual)
{
$this->isManual = $isManual;
return $this;
}
/**
* Get isManual.
*
* @return bool
*/
public function getIsManual()
{
return $this->isManual;
}
/**
* Set score.
*
* @param int|null $score
*
* @return Users
*/
public function setScore($score = null)
{
$this->score = $score;
return $this;
}
/**
* Get score.
*
* @return int|null
*/
public function getScore()
{
return $this->score;
}
/**
* Set userErrorAcquisition.
*
* @param \Services\UsersBundle\Entity\UserErrorAcquisition|null $userErrorAcquisition
*
* @return Users
*/
public function setUserErrorAcquisition(\Services\UsersBundle\Entity\UserErrorAcquisition $userErrorAcquisition = null)
{
$this->userErrorAcquisition = $userErrorAcquisition;
return $this;
}
/**
* Get userErrorAcquisition.
*
* @return \Services\UsersBundle\Entity\UserErrorAcquisition|null
*/
public function getUserErrorAcquisition()
{
return $this->userErrorAcquisition;
}
/**
* @return string|null fullname FIRST + LAST or null if not defined
*/
public function getFullname()
{
if (null == $this->userAddress) {
return null;
}
$firstName = $this->userAddress->getFirstname();
$lastName = $this->userAddress->getLastname();
if ((null == $firstName) && (null == $lastName)) {
return null;
}
return "{$firstName} {$lastName}";
}
/**
* is the user a UEA.
* this one is a bit tricky as a user with a first error made upon subscription is directly put in UEA
* i.e. even if there was a typo in the card number
* so the only way is to see if the UEA date is > than the sub date.
* @return bool
*/
public function isUEA()
{
if (null == $this->userErrorAcquisition) {
// it's obviously not an UserErrorAcquisition
return false;
}
$dateInscriptionUser = $this->userInfos->getDateInscription();
$dateInscriptionUEA = $this->userErrorAcquisition->getDateInscription();
if (is_null($dateInscriptionUser) || is_null($dateInscriptionUEA)) {
return false; // security
}
$acceptedInterval = new \DateInterval('P1D');
return $dateInscriptionUser->add($acceptedInterval) >= $dateInscriptionUEA;
// return $dateInscriptionUser->diff($dateInscriptionUEA) >= $acceptedInterval;
}
/**
* Add userRetry.
*
* @param \Services\ManualRetryBundle\Entity\RetryUser $userRetry
*
* @return Users
*/
public function addUserRetry(\Services\ManualRetryBundle\Entity\RetryUser $userRetry)
{
$this->userRetries[] = $userRetry;
return $this;
}
/**
* Remove userRetry.
*
* @param \Services\ManualRetryBundle\Entity\RetryUser $userRetry
*
* @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
*/
public function removeUserRetry(\Services\ManualRetryBundle\Entity\RetryUser $userRetry)
{
return $this->userRetries->removeElement($userRetry);
}
/**
* Get userRetries.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUserRetries()
{
return $this->userRetries;
}
/**
* Get isPreaboEs
*
* @return bool
*/
public function getIsPreaboEs()
{
return $this->isPreaboEs;
}
/**
* Set isPreaboEs
*
* @param bool $isPreaboEs
*
* @return self
*/
public function setIsPreaboEs(bool $isPreaboEs)
{
$this->isPreaboEs = $isPreaboEs;
return $this;
}
/**
* Get the value of isExternalBilling
*
* @return boolean
*/
public function getIsExternalBilling(): bool
{
return (bool) $this->isExternalBilling;
}
/**
* Set the value of isExternalBilling
*
* @param boolean $isExternalBilling
*
* @return self
*/
public function setIsExternalBilling(bool $isExternalBilling): self
{
$this->isExternalBilling = $isExternalBilling;
return $this;
}
/**
* Get isDeleted.
*
* @return bool
*/
public function getIsDeleted()
{
return $this->isDeleted;
}
/**
* Set isDeleted.
*
* @param bool $isDeleted
*
* @return Users
*/
public function setIsDeleted($isDeleted): Users
{
$this->isDeleted = $isDeleted;
return $this;
}
/**
* Retrieve if its processed from unsubscribed external billing
* @return bool
*/
public function getIsExternalBillingStopped(): bool
{
return $this->isExternalBillingStopped;
}
/**
* Mark if it's processed from unsubscribed external billing
* @param bool $isExternalBillingStopped
* @return void
*/
public function setIsExternalBillingStopped(bool $isExternalBillingStopped): self
{
$this->isExternalBillingStopped = $isExternalBillingStopped;
return $this;
}
/**
* Get the value of isInactive
*
* @return boolean
*/
public function getIsInactive(): bool
{
return (bool) $this->isInactive;
}
/**
* Set the value of isInactive
*
* @param boolean $isInactive
*
* @return self
*/
public function setIsInactive(bool $isInactive): self
{
$this->isInactive = $isInactive;
return $this;
}
/**
* Get the value of lastConversionToInactive
*
* @return \DateTime|null
*/
public function getLastConversionToInactive()
{
return $this->lastConversionToInactive ? clone $this->lastConversionToInactive : null;
}
/**
* Set the value of lastConversionToInactive
*
* @param \DateTime|null $lastConversionToInactive
*
* @return self
*/
public function setLastConversionToInactive(?\DateTime $lastConversionToInactive)
{
$this->lastConversionToInactive = $lastConversionToInactive;
return $this;
}
/**
* Get the value of lastConversionToActive
*
* @return \DateTime|null
*/
public function getLastConversionToActive()
{
return $this->lastConversionToActive ? clone $this->lastConversionToActive : null;
}
/**
* Set the value of lastConversionToActive
*
* @param \DateTime|null $lastConversionToActive
*
* @return self
*/
public function setLastConversionToActive(?\DateTime $lastConversionToActive)
{
$this->lastConversionToActive = $lastConversionToActive;
return $this;
}
/**
* Get the value of prevRoleId
*
* @return boolean
*/
public function getPrevRoleId(): bool
{
return $this->prevRoleId;
}
/**
* Set the value of prevRoleId
*
* @param int $prevRoleId
*
* @return self
*/
public function setPrevRoleId($prevRoleId): self
{
$this->prevRoleId = $prevRoleId;
return $this;
}
}