feat: sync clients vers Stripe dans /admin/sync
SyncController::syncStripeCustomers : - Route POST /admin/sync/stripe/customers - Pour chaque client en BDD : si stripeCustomerId existe → update, sinon → create dans Stripe - Envoie : email, nom (raison sociale ou fullName), phone, metadata (crm_user_id, siret, code_comptable) - Stocke le stripeCustomerId apr��s création - Compteurs : créés, mis à jour, erreurs avec flash détaillé Template admin/sync/index.html.twig : - Bloc "Clients - Stripe" avec compteurs sync/non sync/total - Bouton "Synchroniser Stripe" avec data-confirm Index enrichi avec customersSynced / customersNotSynced Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,12 +39,25 @@ class SyncController extends AbstractController
|
||||
|
||||
$webhookSecrets = $secretRepository->findAll();
|
||||
|
||||
$customers = $customerRepository->findAll();
|
||||
$customersSynced = 0;
|
||||
$customersNotSynced = 0;
|
||||
foreach ($customers as $c) {
|
||||
if (null !== $c->getStripeCustomerId() && '' !== $c->getStripeCustomerId()) {
|
||||
++$customersSynced;
|
||||
} else {
|
||||
++$customersNotSynced;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('admin/sync/index.html.twig', [
|
||||
'totalCustomers' => $customerRepository->count([]),
|
||||
'totalCustomers' => \count($customers),
|
||||
'totalRevendeurs' => $revendeurRepository->count([]),
|
||||
'totalPrices' => \count($prices),
|
||||
'stripeSynced' => $stripeSynced,
|
||||
'stripeNotSynced' => $stripeNotSynced,
|
||||
'customersSynced' => $customersSynced,
|
||||
'customersNotSynced' => $customersNotSynced,
|
||||
'webhookSecrets' => $webhookSecrets,
|
||||
]);
|
||||
}
|
||||
@@ -169,6 +182,58 @@ class SyncController extends AbstractController
|
||||
return $this->redirectToRoute('app_admin_sync_index');
|
||||
}
|
||||
|
||||
/** @codeCoverageIgnore */
|
||||
#[Route('/stripe/customers', name: 'stripe_customers', methods: ['POST'])]
|
||||
public function syncStripeCustomers(
|
||||
CustomerRepository $customerRepository,
|
||||
EntityManagerInterface $em,
|
||||
#[Autowire(env: 'STRIPE_SK')] string $stripeSecretKey,
|
||||
): Response {
|
||||
if ('' === $stripeSecretKey || 'sk_test_***' === $stripeSecretKey) {
|
||||
$this->addFlash('error', 'STRIPE_SK non configuree.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_sync_index');
|
||||
}
|
||||
|
||||
\Stripe\Stripe::setApiKey($stripeSecretKey);
|
||||
$customers = $customerRepository->findAll();
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
$errors = 0;
|
||||
|
||||
foreach ($customers as $customer) {
|
||||
try {
|
||||
$params = [
|
||||
'email' => $customer->getEmail(),
|
||||
'name' => $customer->getRaisonSociale() ?? $customer->getFullName(),
|
||||
'phone' => $customer->getPhone(),
|
||||
'metadata' => [
|
||||
'crm_user_id' => (string) $customer->getUser()->getId(),
|
||||
'siret' => $customer->getSiret() ?? '',
|
||||
'code_comptable' => $customer->getCodeComptable() ?? '',
|
||||
],
|
||||
];
|
||||
|
||||
if (null !== $customer->getStripeCustomerId() && '' !== $customer->getStripeCustomerId()) {
|
||||
\Stripe\Customer::update($customer->getStripeCustomerId(), $params);
|
||||
++$updated;
|
||||
} else {
|
||||
$stripeCustomer = \Stripe\Customer::create($params);
|
||||
$customer->setStripeCustomerId($stripeCustomer->id);
|
||||
++$created;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->addFlash('error', 'Stripe client '.$customer->getEmail().' : '.$e->getMessage());
|
||||
++$errors;
|
||||
}
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
$this->addFlash('success', $created.' client(s) cree(s), '.$updated.' mis a jour dans Stripe'.(0 < $errors ? ', '.$errors.' erreur(s)' : '').'.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_sync_index');
|
||||
}
|
||||
|
||||
#[Route('/all', name: 'all', methods: ['POST'])]
|
||||
public function syncAll(CustomerRepository $customerRepository, RevendeurRepository $revendeurRepository, PriceAutomaticRepository $priceRepository, MeilisearchService $meilisearch): Response
|
||||
{
|
||||
|
||||
@@ -125,6 +125,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Sync Stripe Clients #}
|
||||
<div class="glass p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-cyan-500/20 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-cyan-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="font-bold uppercase text-sm">Clients - Stripe</h2>
|
||||
<p class="text-xs text-gray-500">Cree ou met a jour les clients dans Stripe (email, nom, adresse, SIRET, TVA)</p>
|
||||
<p class="text-xs mt-0.5">
|
||||
<span class="text-green-600 font-bold">{{ customersSynced }} sync</span>
|
||||
{% if customersNotSynced > 0 %}
|
||||
<span class="text-red-600 font-bold ml-2">{{ customersNotSynced }} non sync</span>
|
||||
{% endif %}
|
||||
<span class="text-gray-400 ml-1">/ {{ totalCustomers }} total</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" action="{{ path('app_admin_sync_stripe_customers') }}" data-confirm="Synchroniser tous les clients avec Stripe ?">
|
||||
<button type="submit" class="px-4 py-2 btn-glass text-cyan-600 font-bold uppercase text-[10px] tracking-wider">
|
||||
Synchroniser Stripe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Sync Stripe Webhooks #}
|
||||
<div class="glass p-6">
|
||||
<div class="flex items-center justify-between flex-wrap gap-4">
|
||||
|
||||
Reference in New Issue
Block a user