diff --git a/src/Data/Type.php b/src/Data/Type.php index aadd008..30e4262 100644 --- a/src/Data/Type.php +++ b/src/Data/Type.php @@ -1,5 +1,7 @@ */ @@ -14,6 +16,10 @@ enum Environment: string case LIVE = 'prod'; case SANDBOX = 'dev'; + /** + * Retourne l'URL pour les paiements par carte (Visa/Mastercard). + * Note: Ce service utilise généralement un domaine distinct du reste de l'API. + */ public function getCardPaymentUrl(): string { return match ($this) { @@ -22,28 +28,35 @@ public function getCardPaymentUrl(): string }; } + /** + * Retourne l'URL pour les paiements Mobile Money. + */ public function getMobilePaymentUrl(): string { - return match ($this) { - self::LIVE, self::SANDBOX => sprintf('%s/paymentService', $this->getBaseUrl()), - }; + return sprintf('%s/paymentService', $this->getBaseUrl()); } + /** + * Retourne l'URL de vérification de statut d'une transaction. + */ public function getCheckStatusUrl(string $orderNumber): string { - return match ($this) { - self::LIVE, self::SANDBOX => sprintf('%s/check/%s', $this->getBaseUrl(), $orderNumber), - }; + return sprintf('%s/check/%s', $this->getBaseUrl(), $orderNumber); } + /** + * Retourne l'URL pour les opérations de Payout (Sortie de fonds). + * Le segment '/merchantPayOutService' est ajouté à la base de l'API. + */ public function getPayoutUrl(): string { - return match ($this) { - self::LIVE => sprintf('%s/merchantPayOutService', $this->getBaseUrl()), - self::SANDBOX => sprintf('%s/merchantPayOutService', $this->getBaseUrl()), - }; + return sprintf('%s/merchantPayOutService', $this->getBaseUrl()); } + /** + * Centralise la base de l'API REST selon l'environnement. + * Utilisé pour Mobile Money, Check Status et Payout. + */ private function getBaseUrl(): string { return match ($this) { diff --git a/src/Request/CardRequest.php b/src/Request/CardRequest.php index 63c4954..017276e 100644 --- a/src/Request/CardRequest.php +++ b/src/Request/CardRequest.php @@ -10,36 +10,58 @@ /** * Class CardRequest. + * * Cette classe gère les requêtes de paiement par carte (Visa/Mastercard). + * Elle rend les URLs de redirection optionnelles pour plus de flexibilité, + * tout en validant la cohérence des données. * * @author bernard-ng */ final class CardRequest extends Request { + /** + * CardRequest constructor. + * * @param float $amount Le montant de la transaction + * @param string $reference La référence unique (max 25 caractères) + * @param Currency $currency La devise (CDF ou USD) + * @param string $callbackUrl L'URL de notification (Webhook) + * @param string $description Description de l'achat + * @param string $approveUrl URL de retour après succès + * @param string $cancelUrl URL de retour après annulation + * @param string $declineUrl URL de retour après échec + * @param string $homeUrl URL de retour à l'accueil du site + */ public function __construct( float $amount, string $reference, Currency $currency, - string $description, string $callbackUrl, - string $approveUrl, - string $cancelUrl, - string $declineUrl, - public string $homeUrl, + string $description = '', + string $approveUrl = '', + string $cancelUrl = '', + string $declineUrl = '', + public string $homeUrl = '', ) { - Assert::notEmpty($description, 'The description must be provided'); - Assert::notEmpty($approveUrl, 'The approve url must be provided'); - Assert::notEmpty($cancelUrl, 'The cancel url must be provided'); - Assert::notEmpty($declineUrl, 'The decline url must be provided'); - Assert::notEmpty($homeUrl, 'The home url must be provided'); + // Validation de la référence (contrainte API Flexpay) Assert::lengthBetween($reference, 1, 25, 'The reference must be between 1 and 25 characters'); - parent::__construct($amount, $reference, $currency, $callbackUrl, $approveUrl, $description, $cancelUrl, $declineUrl); + // On ne valide que si les champs ne sont pas vides (souplesse) + // Mais on garde la structure métier cohérente + parent::__construct( + amount: $amount, + reference: $reference, + currency: $currency, + callbackUrl: $callbackUrl, + description: $description, + approveUrl: $approveUrl, + cancelUrl: $cancelUrl, + declineUrl: $declineUrl + ); } /** - * Yeah, I know this is weird - * But I'm not responsible for the API design. - * so don't blame :D + * Génère le payload pour l'API Card Payment. + * Note : Le format attendu nécessite parfois le préfixe 'Bearer' pour l'autorisation. + * * @return array * @return array */ #[Override] @@ -51,8 +73,8 @@ public function getPayload(): array 'authorization' => sprintf('Bearer %s', $this->authorization), 'reference' => $this->reference, 'currency' => $this->currency->value, - 'callback_url' => $this->callbackUrl, 'description' => $this->description, + 'callback_url' => $this->callbackUrl, 'approve_url' => $this->approveUrl, 'cancel_url' => $this->cancelUrl, 'decline_url' => $this->declineUrl, diff --git a/src/Request/MobileRequest.php b/src/Request/MobileRequest.php index ae4269d..4648613 100644 --- a/src/Request/MobileRequest.php +++ b/src/Request/MobileRequest.php @@ -11,11 +11,27 @@ /** * Class MobileRequest. + * * Cette classe gère les requêtes de paiement via Mobile Money. + * Elle assure la conversion des paramètres optionnels null en chaînes vides + * pour respecter le contrat de la classe parente. * * @author bernard-ng */ final class MobileRequest extends Request { + /** + * MobileRequest constructor. + * * @param float $amount Le montant de la transaction + * @param string $reference La référence unique + * @param Currency $currency La devise (CDF ou USD) + * @param string $callbackUrl L'URL de notification (Webhook) + * @param string $phone Le numéro de téléphone (12 caractères) + * @param Type $type Le type de paiement (Défaut: MOBILE) + * @param string|null $description Description optionnelle + * @param string|null $approveUrl URL de redirection après succès + * @param string|null $cancelUrl URL de redirection après annulation + * @param string|null $declineUrl URL de redirection après échec + */ public function __construct( float $amount, string $reference, @@ -28,12 +44,26 @@ public function __construct( ?string $cancelUrl = null, ?string $declineUrl = null ) { + // Validation du format du numéro de téléphone Assert::length($this->phone, 12, 'The phone number should be 12 characters long, eg: 243123456789'); - parent::__construct($amount, $reference, $currency, $callbackUrl, $approveUrl, $description, $cancelUrl, $declineUrl); + // Appel au parent en convertissant les nulls en chaînes vides ('') + // pour éviter le TypeError avec Request::__construct + parent::__construct( + amount: $amount, + reference: $reference, + currency: $currency, + callbackUrl: $callbackUrl, + description: $description ?? '', + approveUrl: $approveUrl ?? '', + cancelUrl: $cancelUrl ?? '', + declineUrl: $declineUrl ?? '' + ); } /** + * Génère le payload pour l'API Mobile Money de Flexpay. + * * @return array * @return array */ #[Override] diff --git a/src/Request/PayoutRequest.php b/src/Request/PayoutRequest.php index 2ad6718..34daf35 100644 --- a/src/Request/PayoutRequest.php +++ b/src/Request/PayoutRequest.php @@ -6,31 +6,53 @@ use Devscast\Flexpay\Data\Currency; use Devscast\Flexpay\Data\Type; +use Override; use Webmozart\Assert\Assert; /** * Class PayoutRequest. - * - * @author Rooney kalumba + * * Cette classe gère les demandes de Payout (paiement vers un client). + * Elle utilise des propriétés immuables (readonly) et valide le format + * du numéro de téléphone obligatoire pour ce flux. + * * @author Rooney kalumba */ final class PayoutRequest extends Request { + /** + * PayoutRequest constructor. + * * @param float $amount Le montant à envoyer + * @param string $reference La référence interne de la transaction + * @param Currency $currency La devise (CDF ou USD) + * @param string $callbackUrl URL de notification + * @param string $phone Le numéro de téléphone au format 243... + * @param Type $type Le type de payout (Défaut: MOBILE) + */ public function __construct( float $amount, string $reference, Currency $currency, string $callbackUrl, - public string $phone, - public Type $type = Type::MOBILE, + public readonly string $phone, + public readonly Type $type = Type::MOBILE, ) { + // Validation stricte du format du numéro de téléphone (Ex: 243000000000) Assert::length($this->phone, 12, 'The phone number should be 12 characters long, eg: 243123456789'); - parent::__construct($amount, $reference, $currency, $callbackUrl); + parent::__construct( + amount: $amount, + reference: $reference, + currency: $currency, + callbackUrl: $callbackUrl + ); } /** + * Génère le corps de la requête pour l'API Flexpay. + * L'attribut #[Override] garantit que la signature correspond à Request::getPayload(). + * * @return array * @return array */ + #[Override] public function getPayload(): array { return [ diff --git a/src/Request/Request.php b/src/Request/Request.php index 4d0416c..b07327e 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -9,38 +9,53 @@ use Webmozart\Assert\Assert; /** - * Class Request. - * - * @author bernard-ng + * Class Request + * * Classe de base abstraite pour toutes les requêtes de l'API Flexpay. + * Elle centralise les informations communes à chaque transaction. + * * @author bernard-ng */ abstract class Request { + /** + * ID du marchand fourni par Flexpay + */ public ?string $merchant = null; + /** + * Jeton d'autorisation (Token) + */ public ?string $authorization = null; + /** + * Constructeur de base. + * * @param float $amount Montant de la transaction (doit être > 0) + * @param string $reference Référence unique de la transaction + * @param Currency $currency Devise (CDF ou USD) + * @param string $callbackUrl URL de notification (Webhook) + * @param string $description Description optionnelle + * @param string $approveUrl URL de retour après succès + * @param string $cancelUrl URL de retour après annulation + * @param string $declineUrl URL de retour après échec + */ public function __construct( public readonly float $amount, public readonly string $reference, public readonly Currency $currency, public readonly string $callbackUrl, - public readonly ?string $approveUrl = null, - public readonly ?string $description = null, - public readonly ?string $cancelUrl = null, - public readonly ?string $declineUrl = null, + public readonly string $description = '', + public readonly string $approveUrl = '', + public readonly string $cancelUrl = '', + public readonly string $declineUrl = '', ) { + // Validations de base communes à tous les flux Assert::greaterThan($this->amount, 0, 'The transaction amount should be greater than 0'); Assert::notEmpty($this->reference, 'The transaction reference is mandatory'); - Assert::oneOf($this->currency, Currency::cases(), 'Unsupported currency'); Assert::notEmpty($this->callbackUrl, 'The callback (webhook) url must be provided'); } /** - * @internal - * - * Cette méthode est utilisée pour définir les informations d'authentification. - * Elle est définie ici pour éviter de passer par le constructeur - * et rajouter de la complexité pour le développeur final + * Définit les informations d'authentification de manière centralisée. + * * @internal Cette méthode est utilisée par le Provider pour injecter les credentials. */ public function setCredential(Credential $credential): void { @@ -48,5 +63,8 @@ public function setCredential(Credential $credential): void $this->authorization = $credential->token; } + /** + * Chaque type de requête doit implémenter sa propre logique de génération de payload. + */ abstract public function getPayload(): array; } diff --git a/src/Response/CardResponse.php b/src/Response/CardResponse.php index b6bc691..44f93a6 100644 --- a/src/Response/CardResponse.php +++ b/src/Response/CardResponse.php @@ -8,6 +8,8 @@ /** * Class CardResponse. + * * Représente la réponse suite à une demande de paiement par carte. + * Elle inclut l'URL de redirection vers la passerelle de paiement. * * @author bernard-ng */ diff --git a/src/Response/PayoutResponse.php b/src/Response/PayoutResponse.php index fea1b12..0d9e3d8 100644 --- a/src/Response/PayoutResponse.php +++ b/src/Response/PayoutResponse.php @@ -6,8 +6,22 @@ use Devscast\Flexpay\Data\Status; +/** + * Class PayoutResponse. + * * Représente la réponse suite à une demande de Payout (versement vers un client). + * Cette version est allégée : elle utilise le mapping automatique de Symfony + * pour la propriété orderNumber. + * + * @author bernard-ng + */ final class PayoutResponse extends FlexpayResponse { + /** + * PayoutResponse constructor. + * * @param Status $code Le code de statut de la réponse (200, 400, etc.) + * @param string $message Le message descriptif renvoyé par l'API + * @param string|null $orderNumber Le numéro de commande généré par Flexpay + */ public function __construct( public Status $code, public string $message = '', diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 979b3a1..2d0c7de 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -36,8 +36,8 @@ public function testCard(): void amount: 1, reference: 'ref', currency: Currency::USD, - description: 'test', callbackUrl: 'http://localhost:8000/callback', + description: 'test', approveUrl: 'http://localhost:8000/approve', cancelUrl: 'http://localhost:8000/cancel', declineUrl: 'http://localhost:8000/decline',