78cb5bfa23
Entites metier (Client, ClientContact, ClientAddress, ClientRib) avec #[Auditable] + Timestampable/Blamable, et 4 referentiels comptables statiques (TvaMode, PaymentDelay, PaymentType, Bank). 8 repositories interfaces + impl Doctrine. Aucun ApiResource (Provider/Processor = ERP-55). - Client : 2 FK auto-referentes distributor/broker (mutuellement exclusives, CHECK en base), M2M categories, FK referentiels comptables, groupes de serialisation par onglet. Pas de #[ORM\UniqueConstraint] : unicite du nom de societe portee par l'index partiel Postgres (decision Q4). - ClientRib : tous les champs audites, aucun #[AuditIgnore] sur iban/bic (decision 29/05, audit admin-only). - M2M Category via le contrat Shared CategoryInterface + resolve_target_entities (regle n°1, pas d'import inter-modules) ; sites via SiteInterface. - CommercialReferentialFixtures : re-seed idempotent des 4 referentiels (sinon vides apres db-reset car desormais tables mappees, purgees par les fixtures). - Referentiels whitelistes dans EntitiesAreTimestampableBlamableTest::EXCLUDED. - doctrine.yaml : mapping ORM du module Commercial + resolve CategoryInterface. - ColumnCommentsCatalog : ajout des colonnes M1 (chemin schema:update/test) ; migration retrofit Version20260528120000 filtree sur les tables existantes pour ne pas casser sur les tables des modules crees plus tard. - makefile test-db-setup : recreation de l'index partiel uq_client_company_name_active. Refs ERP-54.
135 lines
3.5 KiB
PHP
135 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Module\Commercial\Domain\Entity;
|
|
|
|
use App\Module\Commercial\Infrastructure\Doctrine\DoctrineClientRibRepository;
|
|
use App\Shared\Domain\Attribute\Auditable;
|
|
use App\Shared\Domain\Contract\BlamableInterface;
|
|
use App\Shared\Domain\Contract\TimestampableInterface;
|
|
use App\Shared\Domain\Trait\TimestampableBlamableTrait;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
use Symfony\Component\Serializer\Attribute\Groups;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
/**
|
|
* Coordonnees bancaires d'un client (1:n) — onglet Comptabilite. Au moins un
|
|
* RIB est obligatoire si le type de reglement du client est LCR (RG-1.13,
|
|
* verifie au futur Processor).
|
|
*
|
|
* Audit (#[Auditable]) : TOUS les champs sont audites, y compris `iban` et
|
|
* `bic` — AUCUN #[AuditIgnore] (decision Matthieu en revue MR 29/05/2026 :
|
|
* l'audit etant admin-only, la tracabilite RIB est necessaire pour le suivi
|
|
* comptable et la conformite, cf. spec § 2.5 / § 6.1).
|
|
*
|
|
* Validation IBAN/BIC : Assert\Iban + Assert\Bic standard Symfony au M1
|
|
* (HP-M2-14 : pas de controle externe banque reelle). Timestampable/Blamable
|
|
* standard. Aucun ApiResource au M1.1 (sous-ressource branchee ulterieurement).
|
|
*/
|
|
#[ORM\Entity(repositoryClass: DoctrineClientRibRepository::class)]
|
|
#[ORM\Table(name: 'client_rib')]
|
|
#[ORM\Index(name: 'idx_client_rib_client', columns: ['client_id'])]
|
|
#[Auditable]
|
|
class ClientRib implements TimestampableInterface, BlamableInterface
|
|
{
|
|
use TimestampableBlamableTrait;
|
|
|
|
#[ORM\Id]
|
|
#[ORM\GeneratedValue]
|
|
#[ORM\Column]
|
|
#[Groups(['client_rib:read'])]
|
|
private ?int $id = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: Client::class, inversedBy: 'ribs')]
|
|
#[ORM\JoinColumn(name: 'client_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
|
private ?Client $client = null;
|
|
|
|
#[ORM\Column(length: 120)]
|
|
#[Assert\NotBlank]
|
|
#[Assert\Length(max: 120, normalizer: 'trim')]
|
|
#[Groups(['client_rib:read', 'client_rib:write'])]
|
|
private ?string $label = null;
|
|
|
|
#[ORM\Column(length: 20)]
|
|
#[Assert\NotBlank]
|
|
#[Assert\Bic]
|
|
#[Groups(['client_rib:read', 'client_rib:write'])]
|
|
private ?string $bic = null;
|
|
|
|
#[ORM\Column(length: 34)]
|
|
#[Assert\NotBlank]
|
|
#[Assert\Iban]
|
|
#[Groups(['client_rib:read', 'client_rib:write'])]
|
|
private ?string $iban = null;
|
|
|
|
#[ORM\Column(options: ['default' => 0])]
|
|
#[Groups(['client_rib:read', 'client_rib:write'])]
|
|
private int $position = 0;
|
|
|
|
public function getId(): ?int
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getClient(): ?Client
|
|
{
|
|
return $this->client;
|
|
}
|
|
|
|
public function setClient(?Client $client): static
|
|
{
|
|
$this->client = $client;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getLabel(): ?string
|
|
{
|
|
return $this->label;
|
|
}
|
|
|
|
public function setLabel(string $label): static
|
|
{
|
|
$this->label = $label;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getBic(): ?string
|
|
{
|
|
return $this->bic;
|
|
}
|
|
|
|
public function setBic(string $bic): static
|
|
{
|
|
$this->bic = $bic;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getIban(): ?string
|
|
{
|
|
return $this->iban;
|
|
}
|
|
|
|
public function setIban(string $iban): static
|
|
{
|
|
$this->iban = $iban;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getPosition(): int
|
|
{
|
|
return $this->position;
|
|
}
|
|
|
|
public function setPosition(int $position): static
|
|
{
|
|
$this->position = $position;
|
|
|
|
return $this;
|
|
}
|
|
}
|