Fix: Corriger le type PDO dans StripeService et retirer getConnection()
This commit is contained in:
493
api/src/Controllers/StripeController.php
Normal file
493
api/src/Controllers/StripeController.php
Normal file
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Services\StripeService;
|
||||
use Session;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Controller principal pour les opérations Stripe
|
||||
* Gère les comptes Connect, les paiements et Terminal
|
||||
*/
|
||||
class StripeController extends Controller {
|
||||
private StripeService $stripeService;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->stripeService = StripeService::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/accounts
|
||||
* Créer un compte Stripe Connect pour une amicale
|
||||
*/
|
||||
public function createAccount(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
$this->requireRole(2); // Admin amicale minimum
|
||||
|
||||
$data = $this->getJsonInput();
|
||||
$entiteId = $data['fk_entite'] ?? Session::getEntityId();
|
||||
|
||||
if (!$entiteId) {
|
||||
$this->sendError('ID entité requis', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier les droits sur cette entité
|
||||
if (Session::getEntityId() != $entiteId && Session::getRole() < 3) {
|
||||
$this->sendError('Non autorisé pour cette entité', 403);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->stripeService->createConnectAccount($entiteId);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess($result);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur lors de la création du compte: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/accounts/{accountId}/onboarding-link
|
||||
* Générer un lien d'onboarding pour finaliser la configuration
|
||||
*/
|
||||
public function createOnboardingLink(string $accountId): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
$this->requireRole(2);
|
||||
|
||||
$data = $this->getJsonInput();
|
||||
$returnUrl = $data['return_url'] ?? '';
|
||||
$refreshUrl = $data['refresh_url'] ?? '';
|
||||
|
||||
if (!$returnUrl || !$refreshUrl) {
|
||||
$this->sendError('URLs de retour requises', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->stripeService->createOnboardingLink($accountId, $returnUrl, $refreshUrl);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess(['url' => $result['url']]);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/locations
|
||||
* Créer une Location pour Terminal/Tap to Pay
|
||||
*/
|
||||
public function createLocation(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
$this->requireRole(2);
|
||||
|
||||
$data = $this->getJsonInput();
|
||||
$entiteId = $data['fk_entite'] ?? Session::getEntityId();
|
||||
|
||||
$result = $this->stripeService->createLocation($entiteId);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess($result);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/terminal/connection-token
|
||||
* Créer un token de connexion pour Terminal/Tap to Pay
|
||||
*/
|
||||
public function createConnectionToken(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
$entiteId = Session::getEntityId();
|
||||
if (!$entiteId) {
|
||||
$this->sendError('Entité non définie', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->stripeService->createConnectionToken($entiteId);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess(['secret' => $result['secret']]);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/payments/create-intent
|
||||
* Créer une intention de paiement
|
||||
*/
|
||||
public function createPaymentIntent(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
$data = $this->getJsonInput();
|
||||
|
||||
// Validation
|
||||
$amount = $data['amount'] ?? 0;
|
||||
if ($amount < 100) {
|
||||
$this->sendError('Le montant minimum est de 1€ (100 centimes)', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($amount > 50000) {
|
||||
$this->sendError('Le montant maximum est de 500€', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
$params = [
|
||||
'amount' => $amount,
|
||||
'fk_entite' => $data['fk_entite'] ?? Session::getEntityId(),
|
||||
'fk_user' => Session::getUserId(),
|
||||
'metadata' => $data['metadata'] ?? []
|
||||
];
|
||||
|
||||
$result = $this->stripeService->createPaymentIntent($params);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess([
|
||||
'client_secret' => $result['client_secret'],
|
||||
'payment_intent_id' => $result['payment_intent_id'],
|
||||
'amount' => $result['amount'],
|
||||
'application_fee' => $result['application_fee']
|
||||
]);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/stripe/payments/{paymentIntentId}
|
||||
* Récupérer le statut d'un paiement
|
||||
*/
|
||||
public function getPaymentStatus(string $paymentIntentId): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
$stmt = $this->db->prepare(
|
||||
"SELECT spi.*, e.nom as entite_nom, u.nom as user_nom, u.prenom as user_prenom
|
||||
FROM stripe_payment_intents spi
|
||||
LEFT JOIN entites e ON spi.fk_entite = e.id
|
||||
LEFT JOIN users u ON spi.fk_user = u.id
|
||||
WHERE spi.stripe_payment_intent_id = :pi_id"
|
||||
);
|
||||
$stmt->execute(['pi_id' => $paymentIntentId]);
|
||||
$payment = $stmt->fetch();
|
||||
|
||||
if (!$payment) {
|
||||
$this->sendError('Paiement non trouvé', 404);
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier les droits
|
||||
$userEntityId = Session::getEntityId();
|
||||
$userRole = Session::getRole();
|
||||
$userId = Session::getUserId();
|
||||
|
||||
if ($payment['fk_entite'] != $userEntityId &&
|
||||
$payment['fk_user'] != $userId &&
|
||||
$userRole < 3) {
|
||||
$this->sendError('Non autorisé', 403);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendSuccess([
|
||||
'payment_intent_id' => $payment['stripe_payment_intent_id'],
|
||||
'status' => $payment['status'],
|
||||
'amount' => $payment['amount'],
|
||||
'currency' => $payment['currency'],
|
||||
'application_fee' => $payment['application_fee'],
|
||||
'entite' => [
|
||||
'id' => $payment['fk_entite'],
|
||||
'nom' => $payment['entite_nom']
|
||||
],
|
||||
'user' => [
|
||||
'id' => $payment['fk_user'],
|
||||
'nom' => $payment['user_nom'],
|
||||
'prenom' => $payment['user_prenom']
|
||||
],
|
||||
'created_at' => $payment['created_at']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/stripe/accounts/{entityId}/status
|
||||
* Vérifier le statut du compte Stripe d'une entité
|
||||
*/
|
||||
public function getAccountStatus(int $entityId): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
// Vérifier les droits : admin de l'amicale ou super admin
|
||||
$userEntityId = Session::getEntityId();
|
||||
$userRole = Session::getRole();
|
||||
|
||||
if ($entityId != $userEntityId && $userRole < 3) {
|
||||
$this->sendError('Non autorisé', 403);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
// Récupérer le compte Stripe
|
||||
$stmt = $db->prepare(
|
||||
"SELECT sa.*, e.encrypted_name as entite_nom
|
||||
FROM stripe_accounts sa
|
||||
LEFT JOIN entites e ON sa.fk_entite = e.id
|
||||
WHERE sa.fk_entite = :entity_id"
|
||||
);
|
||||
$stmt->execute(['entity_id' => $entityId]);
|
||||
$account = $stmt->fetch();
|
||||
|
||||
if (!$account || !$account['stripe_account_id']) {
|
||||
$this->sendSuccess([
|
||||
'has_account' => false,
|
||||
'account_id' => null,
|
||||
'charges_enabled' => false,
|
||||
'payouts_enabled' => false,
|
||||
'onboarding_completed' => false
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupérer le statut depuis Stripe
|
||||
$stripeService = StripeService::getInstance();
|
||||
$stripeAccount = $stripeService->retrieveAccount($account['stripe_account_id']);
|
||||
|
||||
if (!$stripeAccount) {
|
||||
$this->sendSuccess([
|
||||
'has_account' => true,
|
||||
'account_id' => $account['stripe_account_id'],
|
||||
'charges_enabled' => false,
|
||||
'payouts_enabled' => false,
|
||||
'onboarding_completed' => false,
|
||||
'error' => 'Compte non trouvé sur Stripe'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mettre à jour la base de données avec le statut actuel
|
||||
$stmt = $db->prepare(
|
||||
"UPDATE stripe_accounts
|
||||
SET charges_enabled = :charges,
|
||||
payouts_enabled = :payouts,
|
||||
details_submitted = :details,
|
||||
updated_at = NOW()
|
||||
WHERE id = :id"
|
||||
);
|
||||
$stmt->execute([
|
||||
'charges' => $stripeAccount->charges_enabled ? 1 : 0,
|
||||
'payouts' => $stripeAccount->payouts_enabled ? 1 : 0,
|
||||
'details' => $stripeAccount->details_submitted ? 1 : 0,
|
||||
'id' => $account['id']
|
||||
]);
|
||||
|
||||
$this->sendSuccess([
|
||||
'has_account' => true,
|
||||
'account_id' => $account['stripe_account_id'],
|
||||
'charges_enabled' => $stripeAccount->charges_enabled,
|
||||
'payouts_enabled' => $stripeAccount->payouts_enabled,
|
||||
'onboarding_completed' => $stripeAccount->details_submitted,
|
||||
'entite' => [
|
||||
'id' => $entityId,
|
||||
'nom' => $account['entite_nom']
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
Logger::getInstance()->error('Erreur statut compte Stripe', [
|
||||
'entity_id' => $entityId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/stripe/devices/check-tap-to-pay
|
||||
* Vérifier la compatibilité Tap to Pay d'un appareil
|
||||
*/
|
||||
public function checkTapToPayCapability(): void {
|
||||
try {
|
||||
$data = $this->getJsonInput();
|
||||
|
||||
$platform = $data['platform'] ?? '';
|
||||
|
||||
if ($platform === 'ios') {
|
||||
// Pour iOS, on vérifie côté client (iPhone XS+ avec iOS 15.4+)
|
||||
$this->sendSuccess([
|
||||
'message' => 'Vérification iOS à faire côté client',
|
||||
'requirements' => 'iPhone XS ou plus récent avec iOS 15.4+'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($platform === 'android') {
|
||||
$manufacturer = $data['manufacturer'] ?? '';
|
||||
$model = $data['model'] ?? '';
|
||||
|
||||
if (!$manufacturer || !$model) {
|
||||
$this->sendError('Manufacturer et model requis pour Android', 400);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->stripeService->checkAndroidTapToPayCompatibility($manufacturer, $model);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess($result);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
} else {
|
||||
$this->sendError('Platform doit être ios ou android', 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/stripe/devices/certified-android
|
||||
* Récupérer la liste des appareils Android certifiés
|
||||
*/
|
||||
public function getCertifiedAndroidDevices(): void {
|
||||
try {
|
||||
$result = $this->stripeService->getCertifiedAndroidDevices();
|
||||
|
||||
if ($result['success']) {
|
||||
$this->sendSuccess(['devices' => $result['devices']]);
|
||||
} else {
|
||||
$this->sendError($result['message'], 400);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/stripe/config
|
||||
* Récupérer la configuration publique Stripe
|
||||
*/
|
||||
public function getPublicConfig(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
$this->sendSuccess([
|
||||
'public_key' => $this->stripeService->getPublicKey(),
|
||||
'test_mode' => $this->stripeService->isTestMode()
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/stripe/stats
|
||||
* Récupérer les statistiques de paiement
|
||||
*/
|
||||
public function getPaymentStats(): void {
|
||||
try {
|
||||
$this->requireAuth();
|
||||
|
||||
$entiteId = $_GET['fk_entite'] ?? Session::getEntityId();
|
||||
$userId = $_GET['fk_user'] ?? null;
|
||||
$dateFrom = $_GET['date_from'] ?? date('Y-m-01');
|
||||
$dateTo = $_GET['date_to'] ?? date('Y-m-d');
|
||||
|
||||
// Vérifier les droits
|
||||
if ($entiteId != Session::getEntityId() && Session::getRole() < 3) {
|
||||
$this->sendError('Non autorisé', 403);
|
||||
return;
|
||||
}
|
||||
|
||||
$query = "SELECT
|
||||
COUNT(CASE WHEN status = 'succeeded' THEN 1 END) as total_ventes,
|
||||
SUM(CASE WHEN status = 'succeeded' THEN amount ELSE 0 END) as total_montant,
|
||||
SUM(CASE WHEN status = 'succeeded' THEN application_fee ELSE 0 END) as total_commissions,
|
||||
DATE(created_at) as date_vente
|
||||
FROM stripe_payment_intents
|
||||
WHERE fk_entite = :entite_id
|
||||
AND DATE(created_at) BETWEEN :date_from AND :date_to";
|
||||
|
||||
$params = [
|
||||
'entite_id' => $entiteId,
|
||||
'date_from' => $dateFrom,
|
||||
'date_to' => $dateTo
|
||||
];
|
||||
|
||||
if ($userId) {
|
||||
$query .= " AND fk_user = :user_id";
|
||||
$params['user_id'] = $userId;
|
||||
}
|
||||
|
||||
$query .= " GROUP BY DATE(created_at) ORDER BY date_vente DESC";
|
||||
|
||||
$stmt = $this->db->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$stats = $stmt->fetchAll();
|
||||
|
||||
// Calculer les totaux
|
||||
$totals = [
|
||||
'total_ventes' => 0,
|
||||
'total_montant' => 0,
|
||||
'total_commissions' => 0
|
||||
];
|
||||
|
||||
foreach ($stats as $stat) {
|
||||
$totals['total_ventes'] += $stat['total_ventes'];
|
||||
$totals['total_montant'] += $stat['total_montant'];
|
||||
$totals['total_commissions'] += $stat['total_commissions'];
|
||||
}
|
||||
|
||||
$this->sendSuccess([
|
||||
'stats' => $stats,
|
||||
'totals' => $totals,
|
||||
'period' => [
|
||||
'from' => $dateFrom,
|
||||
'to' => $dateTo
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->sendError('Erreur: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user