<?php
namespace App\Entity;
use App\Repository\WalletRepository;
use DateTime;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Blameable\Traits\BlameableEntity;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: WalletRepository::class)]
class Wallet
{
use BlameableEntity; //Hook blameable behaviour. Updates createdBy, updatedBy fields
use TimestampableEntity; //Hook timestampable behaviour. Updates createdAt, updatedAt fields
const TYPE_SHARE_REWARD = 'TYPE_SHARE_REWARD'; // Coins earned by the user because of sharing.
const TYPE_INFLUENCER_SHARE_REWARD = 'TYPE_INFLUENCER_SHARE_REWARD'; // Coins earned by the user because of sharing.
const TYPE_WALLET_SPENT = 'TYPE_WALLET_SPENT'; // Coins spent by the user.
const TYPE_ACHIEVEMENT_ACHIEVED = 'TYPE_ACHIEVEMENT_ACHIEVED';
const TYPE_ADMIN_REWARD = 'TYPE_ADMIN_REWARD'; // Coins earned/spent by the user. Set by the admin
#[ORM\Id]
#[ORM\GeneratedValue(strategy: "IDENTITY")]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'wallets')]
#[ORM\JoinColumn(nullable: false)]
#[Assert\NotNull()]
private ?User $owner = null;
#[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 2)]
#[Assert\NotNull()]
private ?string $amount = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
private ?OrderDetail $orderDetail = null;
#[ORM\Column(length: 50)]
#[Assert\NotNull()]
#[Assert\Length(max: 50)]
private ?string $type = null;
#[ORM\OneToOne(inversedBy: 'walletSpent', cascade: ['persist', 'remove'])]
private ?Order $spentOrder = null;
#[ORM\Column(length: 511, nullable: true)]
#[Assert\Length(max: 511)]
private ?string $description = null;
#[ORM\Column]
private ?bool $orderPaid = true;
#[ORM\OneToOne(inversedBy: 'walletSpentRefund', cascade: ['persist', 'remove'])]
private ?Order $spentOrderRefund = null;
public function __construct()
{
}
public static function createShareRewardFromUser(UserShared $userShared, OrderDetail $newOrderDetail)
{
$instance = (new Wallet())->setType(Wallet::TYPE_SHARE_REWARD);
$amount =
($userShared->getReferredPoints() ?? 0) +
($userShared->getExtraReferredPoints() ?? 0);
$instance->setAmount($amount);
$instance->setOwner($userShared->getOriginOrderDetail()->getHeader()->getBuyer());
$instance->setOrderDetail($newOrderDetail);
$instance->setOrderPaid(true);
return $instance;
}
public static function createShareRewardFromInfluencer(UserShared $userShared, OrderDetail $newOrderDetail)
{
$instance = (new Wallet())->setType(Wallet::TYPE_INFLUENCER_SHARE_REWARD);
$instance->setAmount($userShared->getReferredPoints() ?? 0);
$instance->setOwner($userShared->getInfluencer());
$instance->setOrderDetail($newOrderDetail);
$instance->setOrderPaid(true);
return $instance;
}
public static function createWalletSpent(float $amount, Order $newOrder)
{
$instance = (new Wallet())->setType(Wallet::TYPE_WALLET_SPENT);
$instance->setAmount($amount);
$instance->setOwner($newOrder->getBuyer());
$instance->setSpentOrder($newOrder);
$instance->setOrderPaid(false);
return $instance;
}
public static function createWalletSpentRefund(Order $spentOrderRefund): ?Wallet
{
$walletSpent = $spentOrderRefund->getWalletSpent();
if (!$walletSpent) {
return null;
}
$instance = (new Wallet())->setType(Wallet::TYPE_WALLET_SPENT);
$instance->setAmount(-$walletSpent->getAmount());
$instance->setOwner($spentOrderRefund->getBuyer());
$instance->setSpentOrderRefund($spentOrderRefund);
$instance->setOrderPaid(true);
return $instance;
}
public static function createAchievementAchieved()
{
return (new Wallet())->setType(Wallet::TYPE_ACHIEVEMENT_ACHIEVED);
}
public static function createAdminReward()
{
return (new Wallet())->setType(Wallet::TYPE_ADMIN_REWARD);
}
public function getId(): ?int
{
return $this->id;
}
public function getOwner(): ?User
{
return $this->owner;
}
public function setOwner(?User $owner): self
{
$this->owner = $owner;
return $this;
}
public function getAmount(): ?string
{
return $this->amount;
}
public function setAmount(string $amount): self
{
$this->amount = $amount;
return $this;
}
public function getOrderDetail(): ?OrderDetail
{
return $this->orderDetail;
}
public function setOrderDetail(?OrderDetail $orderDetail): self
{
$this->orderDetail = $orderDetail;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
public function isPending(): bool
{
if (
$this->getType() == Wallet::TYPE_SHARE_REWARD ||
$this->getType() == Wallet::TYPE_INFLUENCER_SHARE_REWARD
) {
if (
$this->getOrderDetail()->getHeader()->getStatus()->getKey() == OrderStatus::PAID
) {
if ($this->getOrderDetail()->getProduct()->getAllowReturn()) {
$endOffer = $this->getOrderDetail()->getProduct()->getEndOfferDate();
$days = $this->getOrderDetail()->getProduct()->getNDaysAllowedForReturn() ?? 0;
$dateToCompare = new DateTime('-' . $days . 'day');
return ($endOffer > $dateToCompare);
} else {
return false;
}
}
return true;
}
return false;
}
public function isCancelled(): bool
{
if (
$this->getType() == Wallet::TYPE_SHARE_REWARD ||
$this->getType() == Wallet::TYPE_INFLUENCER_SHARE_REWARD
) {
if (
$this->getOrderDetail()->getHeader()->getStatus()->getKey() == OrderStatus::NOT_SOLD ||
$this->getOrderDetail()->getHeader()->getStatus()->getKey() == OrderStatus::CANCELED
) {
return true;
}
}
return false;
}
public function getSpentOrder(): ?Order
{
return $this->spentOrder;
}
public function setSpentOrder(?Order $spentOrder): self
{
$this->spentOrder = $spentOrder;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getOrderPaid(): ?bool
{
return $this->orderPaid;
}
public function setOrderPaid(bool $orderPaid): self
{
$this->orderPaid = $orderPaid;
return $this;
}
public function getSpentOrderRefund(): ?Order
{
return $this->spentOrderRefund;
}
public function setSpentOrderRefund(?Order $spentOrderRefund): self
{
$this->spentOrderRefund = $spentOrderRefund;
return $this;
}
}