feat: MTN Cameroon + Orange Guinea + Wave Senegal provider integration (#1795-#1798) - #1891
Merged
Merged
Conversation
Addresses four Mobile Money <-> Stellar Bridge issues: sublime247#1795 Fix token renewal scheduler in bridge authorization module - baseProvider.cacheToken() no longer poisons the cache when a token endpoint omits/garbles expires_in (was NaN -> isTokenValid() always false -> re-auth on every call). Added normalizeExpiresInSeconds() and a finite-check in isTokenValid(). - Added a real proactive renewal scheduler (scheduleTokenRenewal / cancelTokenRenewal / destroy): unref'd timer fires `leeway` before expiry, replaces any prior timer, no-ops after destroy(), retries once on failure. Uses #private fields to avoid clashing with subclasses that already declare `private destroyed`. sublime247#1796 Integrate MTN Cameroon Mobile Money API - requestPayment: currency is now MTN_CURRENCY (default XAF for Cameroon) instead of hard-coded EUR; the collection POST now sends the Authorization: Bearer header (was unauthenticated) and the required X-Reference-Id UUID, which is returned to the caller for status polling; X-Target-Environment comes from config. - sendBatchPayout: implemented status polling + (phone, amount) fallback matching that the existing test suite expected. - Wired scheduleTokenRenewal into getAccessToken; stopped ignoring MTN_BASE_URL. - Fixed the pre-existing mtn.sendBatchPayout.test.ts (undefined `env`). sublime247#1797 Integrate Orange Guinea payment gateway - appConfig: added providers.orangeGuinea.callbackSecret and callbackSignatureHeader. Their absence made the wired-up /api/orange-guinea/callback route throw "cannot find configuration param" on every callback. - Added the missing middleware + route test coverage (mirrors Orange Madagascar). sublime247#1798 Implement Wave Senegal payment routing - wave_senegal is now a first-class routable provider: enum + limits (config/providers.ts), config block (appConfig.ts), health-check entry, KnownProvider + fallback chain (networkOutageFallbackService). - New waveSenegalRouting.ts: isWaveSenegalRoute() (explicit wave_senegal key or a +221 MSISDN) plus routeWaveSenegalPayment / routeWaveSenegalPayout that validate the MSISDN and amount against the configured limits before delegating. Docs: new env vars added to .env.example. Tests: 39 new unit tests across baseProvider, MTN requestPayment/batch, Orange Guinea middleware + routes, and Wave Senegal routing; all green with the adjacent existing suites. No new tsc/eslint/prettier issues. (Pre-existing unrelated suite failures -- mtnUganda, moov, pact, kyc -- are broken on main too and untouched here.) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@devsimze Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hardens the shared provider authorization module and integrates three
country-specific payment providers into the Mobile Money ↔ Stellar Bridge.
Closes #1795
Closes #1796
Closes #1797
Closes #1798
#1795 — Fix token renewal scheduler in bridge authorization module
src/services/providers/baseProvider.ts(the base class every provider extends).cacheToken(token, expiresIn)didDate.now() + expiresIn * 1000unconditionally. When a token endpoint omits or garbles
expires_in,tokenExpiresAtbecameNaN,isTokenValid()was permanentlyfalse, andevery API call re-authenticated (token-exchange storm against the
provider). Added
normalizeExpiresInSeconds()(coerces numeric strings,falls back to
DEFAULT_TOKEN_TTL_SECONDSfor missing /NaN/≤ 0/Infinity) plus aNumber.isFiniteguard inisTokenValid().lazily. Added a real scheduler:
scheduleTokenRenewal()/cancelTokenRenewal()/destroy(). The timer firesleewaybeforeexpiry (clamped to a minimum), is
unref()ed, replaces any prior timer,no-ops after
destroy(), and retries once on failure. Implemented with#privatefields so it never collides with subclasses that already declareprivate destroyed(e.g.OrangeProvider).#1796 — Integrate MTN Cameroon Mobile Money API
src/services/mobilemoney/providers/mtn.tsrequestPayment:"EUR"→ nowMTN_CURRENCY(defaultXAF, theCameroon MoMo settlement currency);
POSTsent noAuthorizationheader (always 401) →now sends
Authorization: Bearer <token>;X-Reference-IdUUID and return it to the caller so atransaction can actually be polled afterwards;
X-Target-Environmentnow comes from config instead of the literal"sandbox".sendBatchPayout: implemented the status polling loop and(phoneNumber, amount)fallback matching that the existing test suitealready expected (
MTN_BATCH_PAYOUT_MAX_ATTEMPTS/MTN_BATCH_PAYOUT_POLL_DELAY_MS).scheduleTokenRenewalintogetAccessToken; removed a fieldinitializer that silently ignored
MTN_BASE_URL.mtn.sendBatchPayout.test.ts(referenced anundefined
env, so the whole suite failed to run).#1797 — Integrate Orange Guinea payment gateway
verifyOrangeGuineaCallbackSignaturereadsproviders.orangeGuinea.callbackSecret/providers.orangeGuinea.callbackSignatureHeader, but those keys were neverdeclared in
appConfig(Orange Madagascar has them). Result:cannot find configuration paramthrown on every request to thealready-wired
/api/orange-guinea/callbackroute. Added both keys.mirroring the Orange Madagascar suites.
#1798 — Implement Wave Senegal payment routing
wave_senegalis now a first-class routable provider:src/config/providers.ts,appConfig.ts,ProviderName+ health-check entry inhealthCheck.ts,KnownProvider+ fallback chain (["orange", "sms_portal"]) innetworkOutageFallbackService.ts.src/services/mobilemoney/waveSenegalRouting.ts:isWaveSenegalRoute()— routes when thewave_senegalkey is chosenexplicitly or, absent a forced provider, when the MSISDN is a valid
Senegalese number (
+221+ 9 digits);routeWaveSenegalPayment/routeWaveSenegalPayout— validate theMSISDN and the amount against the configured limits before delegating to
WaveSenegalProvider, with a DI seam for testing.Docs
New env vars documented in
.env.example(MTN_CURRENCY, MTN batch-polltuning,
ORANGE_GUINEA_CALLBACK_*, theWAVE_*block).Testing
baseProvider, MTNrequestPayment/ batchpayout, Orange Guinea middleware + routes, and Wave Senegal routing.
(
fallbackRouter,networkOutageFallbackService,appConfig, OrangeMadagascar callback middleware + routes,
mtnPayoutConfirmationintegration) — 13 suites / 144 tests green.
npx tsc --noEmit: no new errors.eslint/prettier: clean on all changed files.main(mtnUganda.test.tsandmoov.test.tsmissing mock modules, the PactmtnProvider.test.tsESMparse error,
kycUpload.test.ts,config/database.test.ts) are untouchedand out of scope here.
🤖 Generated with Claude Code