feat: auto-remplissage RCS, APE, TVA depuis recherche entreprise

Customer entity :
- Ajout champ ape (VARCHAR 10, nullable) avec getter/setter
- Migration : ALTER TABLE customer ADD ape

Recherche entreprise (entreprise-search.js) :
- RCS construit depuis SIREN + ville du siège (ex: RCS Saint-Quentin 418664058)
- TVA intracommunautaire calculée depuis SIREN (clé modulo 97)
- Code APE/NAF récupéré depuis activite_principale de l'API
- APE affiché dans les résultats de recherche à côté du SIREN/SIRET
- Auto-remplissage des champs : raisonSociale, siret, rcs, numTva, ape,
  address, zipCode, city, firstName, lastName

Template create.html.twig :
- Ajout champ "Code APE / NAF" dans la section Entreprise

ClientsController :
- populateCustomerData : ajout setApe depuis le formulaire

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-04 10:59:24 +02:00
parent a9a10e5584
commit db7f4eda7c
5 changed files with 61 additions and 0 deletions

View File

@@ -22,11 +22,17 @@ const fillFieldIfEmpty = (id, value) => {
if (el && !el.value && value) el.value = value
}
const buildRcs = (siren, city) => {
if (!siren || !city) return ''
return 'RCS ' + capitalize(city) + ' ' + siren
}
const renderResult = (e, onSelect) => {
const s = e.siege || {}
const d = (e.dirigeants && e.dirigeants[0]) || {}
const actif = e.etat_administratif === 'A'
const addr = [s.numero_voie, s.type_voie, s.libelle_voie].filter(Boolean).join(' ')
const ape = e.activite_principale || ''
const div = document.createElement('div')
div.className = 'glass p-4 cursor-pointer hover:bg-white/80 transition-all'
@@ -37,6 +43,7 @@ const renderResult = (e, onSelect) => {
<div class="text-xs text-gray-500 mt-1">
SIREN <span class="font-mono font-bold">${e.siren || '?'}</span>
${s.siret ? ' &mdash; SIRET <span class="font-mono font-bold">' + s.siret + '</span>' : ''}
${ape ? ' &mdash; APE <span class="font-mono font-bold">' + ape + '</span>' : ''}
</div>
<div class="text-xs text-gray-400 mt-1">${s.geo_adresse || s.adresse || ''}</div>
${d.nom ? '<div class="text-xs text-gray-400 mt-1">Dirigeant : ' + (d.prenoms || '') + ' ' + d.nom + '</div>' : ''}
@@ -49,7 +56,9 @@ const renderResult = (e, onSelect) => {
div.addEventListener('click', () => {
fillField('raisonSociale', e.nom_raison_sociale || e.nom_complet || '')
fillField('siret', s.siret || '')
fillField('rcs', buildRcs(e.siren, s.libelle_commune))
fillField('numTva', computeTva(e.siren))
fillField('ape', ape)
fillField('address', addr)
fillField('zipCode', s.code_postal || '')
fillField('city', s.libelle_commune || '')

View File

@@ -0,0 +1,31 @@
<?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 Version20260404085856 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 customer ADD ape VARCHAR(10) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE customer DROP ape');
}
}

View File

@@ -91,6 +91,7 @@ class ClientsController extends AbstractController
$customer->setSiret(trim($request->request->getString('siret')) ?: null);
$customer->setRcs(trim($request->request->getString('rcs')) ?: null);
$customer->setNumTva(trim($request->request->getString('numTva')) ?: null);
$customer->setApe(trim($request->request->getString('ape')) ?: null);
$customer->setAddress(trim($request->request->getString('address')) ?: null);
$customer->setAddress2(trim($request->request->getString('address2')) ?: null);
$customer->setZipCode(trim($request->request->getString('zipCode')) ?: null);

View File

@@ -83,6 +83,9 @@ class Customer
#[ORM\Column(length: 20, nullable: true)]
private ?string $numTva = null;
#[ORM\Column(length: 10, nullable: true)]
private ?string $ape = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $stripeCustomerId = null;
@@ -301,6 +304,18 @@ class Customer
return $this;
}
public function getApe(): ?string
{
return $this->ape;
}
public function setApe(?string $ape): static
{
$this->ape = $ape;
return $this;
}
public function getStripeCustomerId(): ?string
{
return $this->stripeCustomerId;

View File

@@ -98,6 +98,11 @@
<input type="text" id="numTva" name="numTva" placeholder="FR12345678901"
class="w-full px-4 py-3 input-glass text-sm font-medium">
</div>
<div>
<label for="ape" class="block text-xs font-bold uppercase tracking-wider mb-2">Code APE / NAF</label>
<input type="text" id="ape" name="ape" maxlength="10" placeholder="62.01Z"
class="w-full px-4 py-3 input-glass text-sm font-medium">
</div>
</div>
</section>