✨ feat(AvisPaymentState): Ajoute champ isRecover pour suivi des relances.
✨ feat(Customer): Ajoute relation avec FaultPayment pour suivi des impayés. 🐛 fix(CheckAvisPaymentStateCommand): Crée FaultPayment et relance si nécessaire. 🎨 style(customer.twig): Affiche si le client a des factures impayées. `
This commit is contained in:
36
migrations/Version20251113132634.php
Normal file
36
migrations/Version20251113132634.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20251113132634 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE fault_payment (id SERIAL NOT NULL, customer_id INT DEFAULT NULL, id_advert_payment INT NOT NULL, entry_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_873651E99395C3F3 ON fault_payment (customer_id)');
|
||||
$this->addSql('COMMENT ON COLUMN fault_payment.entry_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE fault_payment ADD CONSTRAINT FK_873651E99395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('ALTER TABLE fault_payment DROP CONSTRAINT FK_873651E99395C3F3');
|
||||
$this->addSql('DROP TABLE fault_payment');
|
||||
}
|
||||
}
|
||||
32
migrations/Version20251113133056.php
Normal file
32
migrations/Version20251113133056.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20251113133056 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE avis_payment_state ADD is_recover BOOLEAN DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('ALTER TABLE avis_payment_state DROP is_recover');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\FaultPayment;
|
||||
use App\Repository\AvisPaymentStateRepository;
|
||||
use App\Service\Customer\Billing\CreateAvisEventSend;
|
||||
use App\Service\Customer\Billing\CreateAvisEventSend2nd;
|
||||
@@ -70,14 +71,27 @@ class CheckAvisPaymentStateCommand extends Command
|
||||
$this->entityManager->persist($avisPaymentState);
|
||||
$evDevis = new CreateAvisEventSendFinal($avisPaymentState->getAvisPayment());
|
||||
$this->eventDispatcher->dispatch($evDevis);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/* foreach ($this->avisPaymentStateRepository->findAll() as $avisPaymentState) {
|
||||
$evDevis = new CreateAvisEventSendRecover($avisPaymentState->getAvisPayment());
|
||||
$this->eventDispatcher->dispatch($evDevis);
|
||||
}*/
|
||||
foreach ($this->avisPaymentStateRepository->findBy(['isFinalSend'=>true,'isRecover'=>null]) as $avisPaymentState) {
|
||||
$paymentFault = $this->entityManager->getRepository(FaultPayment::class)->findOneBy([
|
||||
'customer' => $avisPaymentState->getAvisPayment()->getCustomer(),
|
||||
'idAdvertPayment' => $avisPaymentState->getAvisPayment()->getId()
|
||||
]);
|
||||
if(!$paymentFault instanceof FaultPayment){
|
||||
$avisPaymentState->setIsRecover(true);
|
||||
$this->entityManager->persist($avisPaymentState);
|
||||
$paymentFault = new FaultPayment();
|
||||
$paymentFault->setCustomer($avisPaymentState->getAvisPayment()->getCustomer());
|
||||
$paymentFault->setIdAdvertPayment($avisPaymentState->getAvisPayment()->getId());
|
||||
$paymentFault->setEntryAt(new \DateTimeImmutable());
|
||||
$this->entityManager->persist($paymentFault);
|
||||
$this->entityManager->flush();
|
||||
$evDevis = new CreateAvisEventSendRecover($avisPaymentState->getAvisPayment());
|
||||
$this->eventDispatcher->dispatch($evDevis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@ class AvisPaymentState
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $month = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $isRecover = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -242,4 +245,16 @@ class AvisPaymentState
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isRecover(): ?bool
|
||||
{
|
||||
return $this->isRecover;
|
||||
}
|
||||
|
||||
public function setIsRecover(?bool $isRecover): static
|
||||
{
|
||||
$this->isRecover = $isRecover;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,12 @@ class Customer
|
||||
#[ORM\OneToOne(mappedBy: 'customer', cascade: ['persist', 'remove'])]
|
||||
private ?CustomerWallet $customerWallet = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, FaultPayment>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: FaultPayment::class, mappedBy: 'customer')]
|
||||
private Collection $faultPayments;
|
||||
|
||||
|
||||
public function __clone(): void
|
||||
{
|
||||
@@ -150,6 +156,7 @@ class Customer
|
||||
$this->websites = new ArrayCollection();
|
||||
$this->customerSplits = new ArrayCollection();
|
||||
$this->customerSepas = new ArrayCollection();
|
||||
$this->faultPayments = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -658,4 +665,34 @@ class Customer
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, FaultPayment>
|
||||
*/
|
||||
public function getFaultPayments(): Collection
|
||||
{
|
||||
return $this->faultPayments;
|
||||
}
|
||||
|
||||
public function addFaultPayment(FaultPayment $faultPayment): static
|
||||
{
|
||||
if (!$this->faultPayments->contains($faultPayment)) {
|
||||
$this->faultPayments->add($faultPayment);
|
||||
$faultPayment->setCustomer($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeFaultPayment(FaultPayment $faultPayment): static
|
||||
{
|
||||
if ($this->faultPayments->removeElement($faultPayment)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($faultPayment->getCustomer() === $this) {
|
||||
$faultPayment->setCustomer(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
65
src/Entity/FaultPayment.php
Normal file
65
src/Entity/FaultPayment.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\FaultPaymentRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: FaultPaymentRepository::class)]
|
||||
class FaultPayment
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'faultPayments')]
|
||||
private ?Customer $customer = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $idAdvertPayment = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?\DateTimeImmutable $entryAt = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCustomer(): ?Customer
|
||||
{
|
||||
return $this->customer;
|
||||
}
|
||||
|
||||
public function setCustomer(?Customer $customer): static
|
||||
{
|
||||
$this->customer = $customer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIdAdvertPayment(): ?int
|
||||
{
|
||||
return $this->idAdvertPayment;
|
||||
}
|
||||
|
||||
public function setIdAdvertPayment(int $idAdvertPayment): static
|
||||
{
|
||||
$this->idAdvertPayment = $idAdvertPayment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEntryAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->entryAt;
|
||||
}
|
||||
|
||||
public function setEntryAt(\DateTimeImmutable $entryAt): static
|
||||
{
|
||||
$this->entryAt = $entryAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
src/Repository/FaultPaymentRepository.php
Normal file
43
src/Repository/FaultPaymentRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\FaultPayment;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<FaultPayment>
|
||||
*/
|
||||
class FaultPaymentRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, FaultPayment::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return FaultPayment[] Returns an array of FaultPayment objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('f')
|
||||
// ->andWhere('f.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('f.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?FaultPayment
|
||||
// {
|
||||
// return $this->createQueryBuilder('f')
|
||||
// ->andWhere('f.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -73,7 +73,11 @@
|
||||
<td class="px-6 py-4 text-center text-sm">{{ customer.customerDns.count }}</td>
|
||||
<td class="px-6 py-4 text-center text-sm">{{ customer|countEmail }}</td>
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm text-green-500 font-bold">Non</td>
|
||||
{% if customer.faultPayments.count > 0 %}
|
||||
<td class="px-6 py-4 text-center text-sm text-red-500 font-bold">OUI ({{ customer.faultPayments.count}} facture en retard)</td>
|
||||
{% else %}
|
||||
<td class="px-6 py-4 text-center text-sm text-green-500 font-bold">Non</td>
|
||||
{% endif %}
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Voir</a>
|
||||
<a data-turbo="false" is="confirm-modal" type="cp-customer" href="{{ path('artemis_intranet_customer',{idCopy:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Copier le client</a>
|
||||
|
||||
Reference in New Issue
Block a user