<?php
namespace App\Entity;
use App\Entity\Enum\DonationStatus;
use App\Entity\Enum\TransactionStatus;
use App\Entity\Traits\Identifiable;
use App\Entity\Traits\Timestampable;
use App\Repository\DonationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: DonationRepository::class)]
class Donation
{
use Identifiable;
use Timestampable;
#[ORM\ManyToOne(inversedBy: 'donations')]
private ?Person $person = null;
#[ORM\ManyToOne(inversedBy: 'donations')]
private ?LegalPerson $legalPerson = null;
#[ORM\Column]
private ?float $amount = 0;
#[ORM\Column]
private ?float $amountPayed = 0;
#[ORM\ManyToOne(inversedBy: 'donations')]
private ?Section $section = null;
#[ORM\ManyToOne(inversedBy: 'donations')]
private ?Project $project = null;
#[ORM\OneToMany(mappedBy: 'donation', targetEntity: BenefactorTransaction::class, cascade: ['persist', 'remove'])]
private Collection $transactions;
#[ORM\Column(type: 'string', length: 20, enumType: DonationStatus::class)]
private ?DonationStatus $status = DonationStatus::Prospect;
public function __construct()
{
$this->transactions = new ArrayCollection();
}
public function getPerson(): ?Person
{
return $this->person;
}
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
public function getLegalPerson(): ?LegalPerson
{
return $this->legalPerson;
}
public function setLegalPerson(?LegalPerson $legalPerson): self
{
$this->legalPerson = $legalPerson;
return $this;
}
public function getAmount(): ?float
{
return $this->amount;
}
public function setAmount(float $amount): self
{
$this->amount = $amount;
return $this;
}
public function getAmountPayed(): ?float
{
return $this->amountPayed;
}
public function setAmountPayed(float $amountPayed): self
{
$this->amountPayed = $amountPayed;
return $this;
}
public function getRemainingAmount(): float
{
$amount = $this->getAmount();
$statuses = [TransactionStatus::Waiting, TransactionStatus::Successful];
foreach ($this->getTransactions(statuses: $statuses) as $transaction) {
if ($transaction->getStatus() === TransactionStatus::Successful) {
$amount -= $transaction->getAmountPayed();
}
}
return $amount;
}
public function getSection(): ?Section
{
return $this->section;
}
public function setSection(?Section $section): self
{
$this->section = $section;
return $this;
}
public function getProject(): ?Project
{
return $this->project;
}
public function setProject(?Project $project): self
{
$this->project = $project;
return $this;
}
/**
* @return Collection<int, BenefactorTransaction>
*/
public function getTransactions(?string $type = null, array|TransactionStatus $statuses = null): Collection
{
$transactions = $this->transactions;
if ($type) {
$transactions = $transactions->filter(fn(BenefactorTransaction $t) => ($t instanceof $type));
}
if ($statuses) {
if (!is_array($statuses)) {
$statuses = [$statuses];
}
$transactions = $transactions->filter(
fn(BenefactorTransaction $t) => (in_array($t->getStatus(), $statuses, true))
);
}
return $transactions;
}
public function addTransaction(BenefactorTransaction $transaction): self
{
if (!$this->transactions->contains($transaction)) {
$this->transactions->add($transaction);
$transaction->setDonation($this);
}
return $this;
}
public function removeTransaction(BenefactorTransaction $transaction): self
{
if ($this->transactions->removeElement($transaction)) {
// set the owning side to null (unless already changed)
if ($transaction->getDonation() === $this) {
$transaction->setDonation(null);
}
}
return $this;
}
public function hasSuccessfulTransaction(?array $types = []): bool
{
$transactions = $this->getTransactions()
->filter(fn(BenefactorTransaction $t) => $t->getStatus() === TransactionStatus::Successful);
if (count($types) > 0) {
$transactions = $transactions->filter(fn(BenefactorTransaction $t) => in_array(get_class($t), $types, true)
);
}
return $transactions->count() > 0;
}
public function getStatus(): ?DonationStatus
{
return $this->status;
}
public function setStatus(DonationStatus $status): self
{
$this->status = $status;
return $this;
}
public function guessPaymentType(): ?string
{
$foundTransaction = null;
foreach ($this->getTransactions() as $transaction) {
if (null === $foundTransaction || $transaction->getStatus() === TransactionStatus::Successful) {
$foundTransaction = $transaction;
}
}
if ($foundTransaction) {
$type = array_flip(BenefactorTransaction::TYPE_CLASSES)[$foundTransaction::class];
return BenefactorTransaction::TYPE_NAMES[$type];
}
return null;
}
}