From 20b2e93e8145280542dd0ad8ec33b0ed05e5a1e8 Mon Sep 17 00:00:00 2001 From: lepresk Date: Wed, 22 Apr 2026 19:43:46 +0100 Subject: [PATCH 1/3] fix: apply base_uri via withOptions() when a custom client is injected When useClient() was called before collection(), disbursement(), or create(), the base_uri setup was skipped entirely, causing Symfony to throw "Invalid URL: scheme is missing" on relative paths. Closes #10 Co-Authored-By: Claude Sonnet 4.6 --- src/MomoApi.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MomoApi.php b/src/MomoApi.php index e80f805..de6be45 100644 --- a/src/MomoApi.php +++ b/src/MomoApi.php @@ -68,6 +68,8 @@ public static function create(string $environment): MomoApi self::$client = HttpClient::create([ 'base_uri' => self::getBaseUrl($environment), ]); + } else { + self::$client = self::$client->withOptions(['base_uri' => self::getBaseUrl($environment)]); } return new self($environment); } @@ -90,6 +92,8 @@ public static function collection(array $config): CollectionApi self::$client = HttpClient::create([ 'base_uri' => self::getBaseUrl($environment), ]); + } else { + self::$client = self::$client->withOptions(['base_uri' => self::getBaseUrl($environment)]); } $configObject = Config::collection($subscriptionKey, $apiUser, $apiKey, $callbackUrl); @@ -114,6 +118,8 @@ public static function disbursement(array $config): DisbursementApi self::$client = HttpClient::create([ 'base_uri' => self::getBaseUrl($environment), ]); + } else { + self::$client = self::$client->withOptions(['base_uri' => self::getBaseUrl($environment)]); } $configObject = Config::disbursement($subscriptionKey, $apiUser, $apiKey, $callbackUrl); From 495ca3794fed388eb309c09be838e87ba1104880 Mon Sep 17 00:00:00 2001 From: lepresk Date: Wed, 22 Apr 2026 19:52:44 +0100 Subject: [PATCH 2/3] fix: correct getPayee(), intval truncation, and silent env fallback - Transaction::getPayee() was delegating to getPayer(); model now stores payer and payee separately so each getter reads the right data (#12) - AirtelDisbursementApi was casting amounts via intval(), silently truncating fractional values like 100.50 to 100 (#14) - MomoApi::getBaseUrl() was falling through to PRODUCTION_URL for any unknown environment string; now throws InvalidArgumentException (#15) Co-Authored-By: Claude Sonnet 4.6 --- src/Models/Transaction.php | 9 ++++++--- src/MomoApi.php | 13 ++++++++++++- src/Products/AirtelDisbursementApi.php | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Models/Transaction.php b/src/Models/Transaction.php index 9471401..fa2d61f 100644 --- a/src/Models/Transaction.php +++ b/src/Models/Transaction.php @@ -14,6 +14,7 @@ class Transaction private ?string $amount; private string $currency; private array $payer = []; + private array $payee = []; private ?string $payerMessage; private ?string $payeeNote; private string $status; @@ -31,13 +32,14 @@ class Transaction * @param string $status * @param ErrorReason|null $reason */ - public function __construct(?string $financialTransactionId, ?string $externalId, ?string $amount, string $currency, array $payer, ?string $payerMessage, ?string $payeeNote, string $status, ?ErrorReason $reason) + public function __construct(?string $financialTransactionId, ?string $externalId, ?string $amount, string $currency, array $payer, array $payee, ?string $payerMessage, ?string $payeeNote, string $status, ?ErrorReason $reason) { $this->financialTransactionId = $financialTransactionId; $this->externalId = $externalId; $this->amount = $amount; $this->currency = $currency; $this->payer = $payer; + $this->payee = $payee; $this->payerMessage = $payerMessage; $this->payeeNote = $payeeNote; $this->status = $status; @@ -63,7 +65,8 @@ public static function parse(array $array): Transaction $array['externalId'], $array['amount'], $array['currency'], - $array['payer'] ?? $array['payee'] ?? [], + $array['payer'] ?? [], + $array['payee'] ?? [], $array['payerMessage'], $array['payeeNote'], $array['status'], @@ -158,7 +161,7 @@ public function getPayer(): ?string */ public function getPayee(): ?string { - return $this->getPayer(); + return $this->payee['partyId'] ?? null; } /** diff --git a/src/MomoApi.php b/src/MomoApi.php index de6be45..3797558 100644 --- a/src/MomoApi.php +++ b/src/MomoApi.php @@ -128,9 +128,20 @@ public static function disbursement(array $config): DisbursementApi public static function getBaseUrl($environment): string { - if ($environment === MomoApi::ENVIRONMENT_SANDBOX) { + if ($environment === self::ENVIRONMENT_SANDBOX) { return self::SANDBOX_URL; } + $known = [ + self::ENVIRONMENT_MTN_CONGO, self::ENVIRONMENT_MTN_UGANDA, + self::ENVIRONMENT_MTN_GHANA, self::ENVIRONMENT_IVORY_COAST, + self::ENVIRONMENT_ZAMBIA, self::ENVIRONMENT_CAMEROON, + self::ENVIRONMENT_BENIN, self::ENVIRONMENT_SWAZILAND, + self::ENVIRONMENT_GUINEACONAKRY, self::ENVIRONMENT_SOUTHAFRICA, + self::ENVIRONMENT_LIBERIA, + ]; + if (!in_array($environment, $known, true)) { + throw new \InvalidArgumentException("Unknown environment: '$environment'"); + } return self::PRODUCTION_URL; } diff --git a/src/Products/AirtelDisbursementApi.php b/src/Products/AirtelDisbursementApi.php index c4450e6..c1ae048 100644 --- a/src/Products/AirtelDisbursementApi.php +++ b/src/Products/AirtelDisbursementApi.php @@ -95,7 +95,7 @@ public function transfer(string $amount, string $phone, string $reference): stri 'reference' => $reference, 'pin' => $this->config->getEncryptedPin(), 'transaction' => [ - 'amount' => (string) intval($amount), + 'amount' => (string) $amount, 'id' => $externalId, ], ], From b96b3524e2ae0555d8d36f2ed86593a097c20eae Mon Sep 17 00:00:00 2001 From: lepresk Date: Wed, 22 Apr 2026 19:55:40 +0100 Subject: [PATCH 3/3] revert: restore intval cast on Airtel amount (intentional behavior) Co-Authored-By: Claude Sonnet 4.6 --- src/Products/AirtelDisbursementApi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Products/AirtelDisbursementApi.php b/src/Products/AirtelDisbursementApi.php index c1ae048..c4450e6 100644 --- a/src/Products/AirtelDisbursementApi.php +++ b/src/Products/AirtelDisbursementApi.php @@ -95,7 +95,7 @@ public function transfer(string $amount, string $phone, string $reference): stri 'reference' => $reference, 'pin' => $this->config->getEncryptedPin(), 'transaction' => [ - 'amount' => (string) $amount, + 'amount' => (string) intval($amount), 'id' => $externalId, ], ],