414 lines
9.8 KiB
PHP
414 lines
9.8 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Entity;
|
||
|
|
|
||
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
||
|
|
use Doctrine\Common\Collections\Collection;
|
||
|
|
use Doctrine\ORM\Mapping as ORM;
|
||
|
|
use Symfony\Component\HttpFoundation\File\File;
|
||
|
|
use Vich\UploaderBundle\Mapping\Attribute as Vich;
|
||
|
|
|
||
|
|
#[ORM\Entity]
|
||
|
|
#[Vich\Uploadable]
|
||
|
|
class EFlex
|
||
|
|
{
|
||
|
|
public const STATE_DRAFT = 'draft';
|
||
|
|
public const STATE_ACTIVE = 'active';
|
||
|
|
public const STATE_COMPLETED = 'completed';
|
||
|
|
public const STATE_CANCELLED = 'cancelled';
|
||
|
|
public const STATE_PENDING_SETUP = 'pending_setup';
|
||
|
|
|
||
|
|
public const METHOD_SEPA = 'sepa';
|
||
|
|
public const METHOD_CB = 'cb';
|
||
|
|
public const METHOD_VIREMENT = 'virement';
|
||
|
|
|
||
|
|
#[ORM\Id]
|
||
|
|
#[ORM\GeneratedValue]
|
||
|
|
#[ORM\Column]
|
||
|
|
private ?int $id = null;
|
||
|
|
|
||
|
|
#[ORM\ManyToOne(targetEntity: Customer::class)]
|
||
|
|
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||
|
|
private Customer $customer;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 500)]
|
||
|
|
private string $description;
|
||
|
|
|
||
|
|
#[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
|
||
|
|
private string $totalAmount;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 20, options: ['default' => 'draft'])]
|
||
|
|
private string $state = self::STATE_DRAFT;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 20, options: ['default' => 'sepa'])]
|
||
|
|
private string $paymentMethod = self::METHOD_SEPA;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 255, nullable: true)]
|
||
|
|
private ?string $stripeCustomerId = null;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 255, nullable: true)]
|
||
|
|
private ?string $stripePaymentMethodId = null;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 4, nullable: true)]
|
||
|
|
private ?string $stripeSepaLast4 = null;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 100, nullable: true)]
|
||
|
|
private ?string $stripeSepaBankName = null;
|
||
|
|
|
||
|
|
#[ORM\Column(length: 2, nullable: true)]
|
||
|
|
private ?string $stripeSepaCountry = null;
|
||
|
|
|
||
|
|
#[ORM\Column(nullable: true)]
|
||
|
|
private ?string $submissionId = null;
|
||
|
|
|
||
|
|
// ── PDF Unsigned ──
|
||
|
|
#[ORM\Column(length: 255, nullable: true)]
|
||
|
|
private ?string $pdfUnsigned = null;
|
||
|
|
|
||
|
|
#[Vich\UploadableField(mapping: 'eflex_pdf', fileNameProperty: 'pdfUnsigned')]
|
||
|
|
private ?File $pdfUnsignedFile = null;
|
||
|
|
|
||
|
|
// ── PDF Signed ──
|
||
|
|
#[ORM\Column(length: 255, nullable: true)]
|
||
|
|
private ?string $pdfSigned = null;
|
||
|
|
|
||
|
|
#[Vich\UploadableField(mapping: 'eflex_signed_pdf', fileNameProperty: 'pdfSigned')]
|
||
|
|
private ?File $pdfSignedFile = null;
|
||
|
|
|
||
|
|
// ── PDF Audit ──
|
||
|
|
#[ORM\Column(length: 255, nullable: true)]
|
||
|
|
private ?string $pdfAudit = null;
|
||
|
|
|
||
|
|
#[Vich\UploadableField(mapping: 'eflex_audit_pdf', fileNameProperty: 'pdfAudit')]
|
||
|
|
private ?File $pdfAuditFile = null;
|
||
|
|
|
||
|
|
/** @var Collection<int, EFlexLine> */
|
||
|
|
#[ORM\OneToMany(targetEntity: EFlexLine::class, mappedBy: 'eflex', cascade: ['persist', 'remove'], orphanRemoval: true)]
|
||
|
|
#[ORM\OrderBy(['position' => 'ASC'])]
|
||
|
|
private Collection $lines;
|
||
|
|
|
||
|
|
#[ORM\Column]
|
||
|
|
private \DateTimeImmutable $createdAt;
|
||
|
|
|
||
|
|
#[ORM\Column(nullable: true)]
|
||
|
|
private ?\DateTimeImmutable $updatedAt = null;
|
||
|
|
|
||
|
|
public function __construct(Customer $customer, string $description, string $totalAmount)
|
||
|
|
{
|
||
|
|
$this->customer = $customer;
|
||
|
|
$this->description = $description;
|
||
|
|
$this->totalAmount = $totalAmount;
|
||
|
|
$this->lines = new ArrayCollection();
|
||
|
|
$this->createdAt = new \DateTimeImmutable();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getId(): ?int
|
||
|
|
{
|
||
|
|
return $this->id;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getCustomer(): Customer
|
||
|
|
{
|
||
|
|
return $this->customer;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getDescription(): string
|
||
|
|
{
|
||
|
|
return $this->description;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setDescription(string $description): static
|
||
|
|
{
|
||
|
|
$this->description = $description;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getTotalAmount(): string
|
||
|
|
{
|
||
|
|
return $this->totalAmount;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setTotalAmount(string $totalAmount): static
|
||
|
|
{
|
||
|
|
$this->totalAmount = $totalAmount;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getState(): string
|
||
|
|
{
|
||
|
|
return $this->state;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setState(string $state): static
|
||
|
|
{
|
||
|
|
$this->state = $state;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPaymentMethod(): string
|
||
|
|
{
|
||
|
|
return $this->paymentMethod;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPaymentMethod(string $paymentMethod): static
|
||
|
|
{
|
||
|
|
$this->paymentMethod = $paymentMethod;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getStripeCustomerId(): ?string
|
||
|
|
{
|
||
|
|
return $this->stripeCustomerId;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setStripeCustomerId(?string $stripeCustomerId): static
|
||
|
|
{
|
||
|
|
$this->stripeCustomerId = $stripeCustomerId;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getStripePaymentMethodId(): ?string
|
||
|
|
{
|
||
|
|
return $this->stripePaymentMethodId;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setStripePaymentMethodId(?string $stripePaymentMethodId): static
|
||
|
|
{
|
||
|
|
$this->stripePaymentMethodId = $stripePaymentMethodId;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getStripeSepaLast4(): ?string
|
||
|
|
{
|
||
|
|
return $this->stripeSepaLast4;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setStripeSepaLast4(?string $stripeSepaLast4): static
|
||
|
|
{
|
||
|
|
$this->stripeSepaLast4 = $stripeSepaLast4;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getStripeSepaBankName(): ?string
|
||
|
|
{
|
||
|
|
return $this->stripeSepaBankName;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setStripeSepaBankName(?string $stripeSepaBankName): static
|
||
|
|
{
|
||
|
|
$this->stripeSepaBankName = $stripeSepaBankName;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getStripeSepaCountry(): ?string
|
||
|
|
{
|
||
|
|
return $this->stripeSepaCountry;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setStripeSepaCountry(?string $stripeSepaCountry): static
|
||
|
|
{
|
||
|
|
$this->stripeSepaCountry = $stripeSepaCountry;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @return Collection<int, EFlexLine> */
|
||
|
|
public function getLines(): Collection
|
||
|
|
{
|
||
|
|
return $this->lines;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function addLine(EFlexLine $line): static
|
||
|
|
{
|
||
|
|
if (!$this->lines->contains($line)) {
|
||
|
|
$this->lines->add($line);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getCreatedAt(): \DateTimeImmutable
|
||
|
|
{
|
||
|
|
return $this->createdAt;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getUpdatedAt(): ?\DateTimeImmutable
|
||
|
|
{
|
||
|
|
return $this->updatedAt;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static
|
||
|
|
{
|
||
|
|
$this->updatedAt = $updatedAt;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getSubmissionId(): ?string
|
||
|
|
{
|
||
|
|
return $this->submissionId;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setSubmissionId(?string $submissionId): static
|
||
|
|
{
|
||
|
|
$this->submissionId = $submissionId;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPdfUnsigned(): ?string
|
||
|
|
{
|
||
|
|
return $this->pdfUnsigned;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfUnsigned(?string $pdfUnsigned): static
|
||
|
|
{
|
||
|
|
$this->pdfUnsigned = $pdfUnsigned;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPdfUnsignedFile(): ?File
|
||
|
|
{
|
||
|
|
return $this->pdfUnsignedFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfUnsignedFile(?File $pdfUnsignedFile): static
|
||
|
|
{
|
||
|
|
$this->pdfUnsignedFile = $pdfUnsignedFile;
|
||
|
|
if (null !== $pdfUnsignedFile) {
|
||
|
|
$this->updatedAt = new \DateTimeImmutable();
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPdfSigned(): ?string
|
||
|
|
{
|
||
|
|
return $this->pdfSigned;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfSigned(?string $pdfSigned): static
|
||
|
|
{
|
||
|
|
$this->pdfSigned = $pdfSigned;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfSignedFile(?File $pdfSignedFile): static
|
||
|
|
{
|
||
|
|
$this->pdfSignedFile = $pdfSignedFile;
|
||
|
|
if (null !== $pdfSignedFile) {
|
||
|
|
$this->updatedAt = new \DateTimeImmutable();
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPdfAudit(): ?string
|
||
|
|
{
|
||
|
|
return $this->pdfAudit;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfAudit(?string $pdfAudit): static
|
||
|
|
{
|
||
|
|
$this->pdfAudit = $pdfAudit;
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function setPdfAuditFile(?File $pdfAuditFile): static
|
||
|
|
{
|
||
|
|
$this->pdfAuditFile = $pdfAuditFile;
|
||
|
|
if (null !== $pdfAuditFile) {
|
||
|
|
$this->updatedAt = new \DateTimeImmutable();
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Reference unique (E_FLEX_00001).
|
||
|
|
*/
|
||
|
|
public function getReference(): string
|
||
|
|
{
|
||
|
|
return 'E_FLEX_'.str_pad((string) ($this->id ?? 0), 5, '0', \STR_PAD_LEFT);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getNbLines(): int
|
||
|
|
{
|
||
|
|
return $this->lines->count();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Montant mensuel (total / nb echeances).
|
||
|
|
*/
|
||
|
|
public function getMonthlyAmount(): float
|
||
|
|
{
|
||
|
|
$nb = $this->getNbLines();
|
||
|
|
|
||
|
|
return $nb > 0 ? round((float) $this->totalAmount / $nb, 2) : 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getNbPaid(): int
|
||
|
|
{
|
||
|
|
$count = 0;
|
||
|
|
foreach ($this->lines as $line) {
|
||
|
|
if (EFlexLine::STATE_OK === $line->getState()) {
|
||
|
|
++$count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $count;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getNbFailed(): int
|
||
|
|
{
|
||
|
|
$count = 0;
|
||
|
|
foreach ($this->lines as $line) {
|
||
|
|
if (EFlexLine::STATE_KO === $line->getState()) {
|
||
|
|
++$count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $count;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getTotalPaid(): float
|
||
|
|
{
|
||
|
|
$total = 0.0;
|
||
|
|
foreach ($this->lines as $line) {
|
||
|
|
if (EFlexLine::STATE_OK === $line->getState()) {
|
||
|
|
$total += (float) $line->getAmount();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $total;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getProgress(): int
|
||
|
|
{
|
||
|
|
$nb = $this->getNbLines();
|
||
|
|
|
||
|
|
return $nb > 0 ? (int) round($this->getNbPaid() / $nb * 100) : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getPaymentMethodLabel(): string
|
||
|
|
{
|
||
|
|
return match ($this->paymentMethod) {
|
||
|
|
self::METHOD_SEPA => 'Prelevement SEPA',
|
||
|
|
self::METHOD_CB => 'Carte bancaire',
|
||
|
|
self::METHOD_VIREMENT => 'Virement bancaire',
|
||
|
|
default => $this->paymentMethod,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|