'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 */ #[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 */ 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, }; } }