<?php
declare(strict_types=1);
namespace App\Domain\Payment\Model;
use App\Domain\Payment\Event\PaymentCancelledEvent;
use App\Domain\Payment\Event\PaymentCompletedEvent;
use App\Domain\Payment\Event\PaymentCreatedEvent;
use App\Domain\Payment\Event\PaymentPendingEvent;
use App\Domain\Payment\Event\PaymentRejectedEvent;
use App\Domain\PaymentNotification\Model\PaymentNotification;
use App\Domain\Shared\Exception\BusinessLogicViolationException;
use App\Domain\Shared\Model\Aggregate;
use App\Domain\Shared\Model\TimestampTrait;
use App\Domain\Site\Model\Site;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Payum\Core\Model\CreditCardInterface;
use Payum\Core\Model\PaymentInterface;
use Symfony\Component\Uid\Uuid;
class Payment extends Aggregate implements PaymentInterface
{
use TimestampTrait;
private PaymentStatus $status;
private bool $resolvedBySite;
/**
* @var Collection<array-key, PaymentNotification>
*/
private Collection $notifications;
public function __construct(
private Uuid $id,
private readonly string $externalId,
private readonly Site $site,
private readonly string $description,
private readonly int $amount,
private readonly string $currency,
private readonly string $successUrl,
private readonly string $failureUrl,
private string $pendingUrl,
private string $mappingId,
private readonly string $notificationUrl,
private readonly string $customerId,
private string $pispStatus,
private string $bankStatus,
private array $details = [],
) {
$this->pendingUrl = $pendingUrl;
$this->updatedAt = null;
$this->createdAt = new \DateTimeImmutable();
$this->notifications = new ArrayCollection();
$this->status = PaymentStatus::initiated();
$this->pispStatus = 'intiated';
$this->bankStatus = 'intiated';
$this->resolvedBySite = false;
$this->raise(new PaymentCreatedEvent($this));
}
public function getNumber(): string
{
return (string) $this->id;
}
public function getDescription(): string
{
return $this->description;
}
public function getClientEmail()
{
// TODO: Implement getClientEmail() method.
}
public function getClientId(): string
{
return $this->customerId;
}
public function getTotalAmount(): int
{
return $this->amount;
}
public function getCurrencyCode(): string
{
return $this->currency;
}
public function getCreditCard(): ?CreditCardInterface
{
return null;
}
public function setDetails($details)
{
if ($details instanceof \Traversable) {
$details = iterator_to_array($details);
}
$this->details = $details;
}
public function getDetails(): array
{
return $this->details;
}
public function getId(): Uuid
{
return $this->id;
}
public function getSite(): Site
{
return $this->site;
}
public function getAmount(): int
{
return $this->amount;
}
public function getFloatAmount(): float
{
return $this->getAmount() / 100;
}
public function getCurrency(): string
{
return $this->currency;
}
public function getSuccessUrl(): string
{
return $this->successUrl;
}
public function getFailureUrl(): string
{
return $this->failureUrl;
}
public function setPendingUrl($pendingUrl)
{
if ($pendingUrl instanceof \Traversable) {
$pendingUrl = $pendingUrl;
}
$this->pendingUrl = $pendingUrl;
}
public function getPendingUrl(): string
{
return $this->pendingUrl;
}
public function setMappingId($mappingId)
{
$this->mappingId = $mappingId;
}
public function getMappingId(): string
{
return $this->mappingId;
}
public function getNotificationUrl(): string
{
return $this->notificationUrl;
}
public function getStatus(): PaymentStatus
{
return $this->status;
}
public function setStatus(PaymentStatus $status): void
{
$this->status = $status;
}
public function cancel(): void
{
$this->status = PaymentStatus::cancelled();
$this->setUpdatedAt(new \DateTimeImmutable());
$this->raise(new PaymentCancelledEvent($this));
}
/**
* @throws BusinessLogicViolationException
*/
public function complete(): void
{
if ($this->status->isCompleted()) {
return;
}
if ($this->status->isFailed()) {
throw new BusinessLogicViolationException('Failed payment can\'t be completed');
}
$this->status = PaymentStatus::completed();
$this->setUpdatedAt(new \DateTimeImmutable());
$this->raise(new PaymentCompletedEvent($this));
}
/**
* @throws BusinessLogicViolationException
*/
public function reject(): void
{
if ($this->status->isRejected()) {
return;
}
if ($this->status->isCompleted()) {
throw new BusinessLogicViolationException('Completed payment can\'t be rejected');
}
$this->status = PaymentStatus::rejected();
$this->setUpdatedAt(new \DateTimeImmutable());
$this->raise(new PaymentRejectedEvent($this));
}
/**
* @throws BusinessLogicViolationException
*/
public function pending(): void
{
if ($this->status->isPending()) {
return;
}
// if ($this->status->isCompleted() || $this->status->isFailed() || $this->status->isRejected()) {
// throw new BusinessLogicViolationException('Completed, failed or rejected payment can\'t be pending');
// }
$this->status = PaymentStatus::pending();
$this->setUpdatedAt(new \DateTimeImmutable());
$this->raise(new PaymentPendingEvent($this));
}
public function setResolvedBySite(bool $resolvedBySite): void
{
$this->resolvedBySite = $resolvedBySite;
}
public function getExternalId(): string
{
return $this->externalId;
}
public function getPispStatus(): string
{
return $this->pispStatus;
}
public function setPispStatus($status): void
{
$this->pispStatus = $status;
}
public function getBankStatus(): string
{
return $this->bankStatus;
}
public function setBankStatus($status): void
{
$this->bankStatus = $status;
}
}