Flutter Mobile money payment system

115 views Asked by At

Does anyone know how to implement MOBILE MONEY PAYMENT SYSTEM (a payment system used only in some parts of Africa) in the mobile app in Flutter? Any Payment getway is welcomed. I've searched for a long time but got only one but doens't even work for me.

This is what I have so far and it's giving me error. This is using PayStack Getway

class ApiKey {
  // Paystack Test API Key
  static String secretKey = "xxxxxxxx"; //My secrete key from Paystack 
  static const String payStackPublicKey =
      "xxxxxxxx";  //My public key from Paystack 
}

class Transaction {
  final String amount;
  final String reference;
  final String currency;
  final String email;

  Transaction(
      {required this.amount,
      required this.reference,
      required this.currency,
      required this.email});

  factory Transaction.fromJson(Map<String, dynamic> json) {
    return Transaction(
        amount: json['amount'],
        reference: json['reference'],
        currency: json['currency'],
        email: json['email']);
  }

  Map<String, dynamic> toJson() {
    return {
      'amount': amount,
      'reference': reference,
      'currency': currency,
      'email': email,
    };
  }
}

class PayStackAuthResponse {
  final String authorization_url;
  final String access_code;
  final String reference;

  PayStackAuthResponse({
    required this.authorization_url,
    required this.access_code,
    required this.reference,
  });

  factory PayStackAuthResponse.fromJson(Map<String, dynamic> json) {
    return PayStackAuthResponse(
      authorization_url: json['authorization_url'],
      access_code: json['access_code'],
      reference: json['reference'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'authorization_url': authorization_url,
      'access_code': access_code,
      'reference': reference,
    };
  }
}

//on PaymentPage

class _GhanaMomoPaymentState extends State<GhanaMomoPayment> {
  // final _webViewKey = UniqueKey();
  // late WebViewController _webViewController;

  Future<PayStackAuthResponse> createTransaction(
      Transaction transaction) async {
    const String url = 'https://api.paystack.co/transaction/initialize';
    final data = transaction.toJson();
    try {
      final response = await http.post(
        Uri.parse(url),
        headers: {
          'Authorization': 'Bearer ${ApiKey.secretKey}',
          'Content-Type': 'application/json',
        },
        body: jsonEncode(data),
      );
      if (response.statusCode == 200) {
        // Payment initialization successful
        final responseData = jsonDecode(response.body);
        return PayStackAuthResponse.fromJson(responseData['data']);
      } else {
        throw 'Payment unsuceesful';
      }
    } on Exception {
      throw 'Payment Unsuceesful';
    }
  }

  final adId = DateTime.now().microsecondsSinceEpoch;
  // Future<bool> verifyTransaction(String reference) async {
  //   final String url = 'https://api.paystack.co/transaction/verify/$reference';
  //   try {
  //     final response = await http.get(Uri.parse(url), headers: {
  //       'Authorization': 'Bearer ${ApiKey.secretKey}',
  //       'Content-Type': 'application/json'
  //     });
  //     if (response.statusCode == 200) {
  //       final responseData = jsonDecode(response.body);
  //       if (responseData['data']['gateway_response'] == 'Approved') {
  //         return true;
  //       } else {
  //         return false;
  //       }
  //     } else {
  //       return false;
  //     }
  //   } on Exception {
  //     return false;
  //   }
  // }

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    final screenWidth = MediaQuery.of(context).size.width;

    //These data are from the firestore databse
    final serviceFee = widget.selectedRide["ServiceFee"];
    int amount = int.parse(serviceFee);
    final adsID = widget.selectedRide["Ads-ID"];
    final email = widget.selectedRide["PassEmail"];
    final String reference = adsID;

    Future<String> initializeTransaction() async {
      try {
        final price = double.parse(serviceFee);
        final transaction = Transaction(
          amount: (amount * 100).toString(),
          reference: reference,
          currency: 'GHS',
          email: email,
        );

        final authResponse = await createTransaction(transaction);
        return authResponse.authorization_url;
      } catch (e) {
        Utils().awesomeDialogFailNavigate(
            context,
            "Error initializing transaction: $e",
            "Failed",
            const GhanaHomeScreen());
        print('Error initializing transaction: $e');
        return e.toString();
      }
    }

    return Scaffold(
      appBar: Utils().appBar(context),
      body: Container(
          child: FutureBuilder(
              future: initializeTransaction(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  final url = snapshot.data;
                  return WebViewWidget(
                    controller: WebViewController()
                      ..setJavaScriptMode(JavaScriptMode.unrestricted)
                      ..setBackgroundColor(const Color(0x00000000))
                      ..setNavigationDelegate(
                        NavigationDelegate(
                          onProgress: (int progress) {
                            // Update loading bar.
                          },
                          onPageStarted: (String url) {},
                          onPageFinished: (String url) {},
                          onWebResourceError: (WebResourceError error) {},
                          onNavigationRequest: (NavigationRequest request) {
                            if (request.url
                                .startsWith('https://www.youtube.com/')) {
                              return NavigationDecision.prevent;
                            }
                            return NavigationDecision.navigate;
                          },
                        ),
                      )
                      ..loadRequest(Uri.parse(url!)), //The error occurs here. It says : //I/flutter ( 4807): Another exception was thrown: Invalid argument(s): Missing scheme in uri: Payment%20unsuceesful
                  );
                } else {
                  return const Center(child: CircularProgressIndicator());
                }
              })),
    );

  }
}

From the dependency webview_flutter with the controller where we have ..loadRequest(Uri.parse(url!)), the url is ..loadRequest(Uri.parse('https://flutter.dev')). But from the tutorials it was replaced with url!. I tried both cases but it's still giving me the transaction error. The error is from the future builder but can't figure out how to solve it.

Can anyone help. I really need to implement the Mobile Money Payment system on my app. It does not necessarily have to be from Paystack. Any getway that supports this will do. Thanks.

1

There are 1 answers

1
AudioBubble On
class _GhanaMomoPaymentState extends State<GhanaMomoPayment> {
  // ... (your existing code)

  Future<String> initializeTransaction() async {
    try {
      final price = double.parse(serviceFee);
      final transaction = Transaction(
        amount: (amount * 100).toString(),
        reference: reference,
        currency: 'GHS',
        email: email,
      );

      final authResponse = await createTransaction(transaction);
      print('Auth Response: $authResponse'); // Print the response

      if (authResponse.authorization_url != null) {
        return authResponse.authorization_url;
      } else {
        throw 'Invalid authorization URL';
      }
    } catch (e) {
      Utils().awesomeDialogFailNavigate(
          context,
          "Error initializing transaction: $e",
          "Failed",
          const GhanaHomeScreen());
      print('Error initializing transaction: $e');
      return e.toString();
    }
  }

  // ... (rest of your code)
}

Additionally, consider checking the Paystack API documentation to ensure that you are using the correct endpoints and parameters. If the issue persists, you might want to explore other payment gateways that support mobile money payments in the specific regions you are targeting.