moneyhash_payment 4.0.5 copy "moneyhash_payment: ^4.0.5" to clipboard
moneyhash_payment: ^4.0.5 copied to clipboard

MoneyHash is a Super-API infrastructure for payment orchestration and revenue operations in emerging markets.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:moneyhash_payment/data/apple_pay/apple_pay_receipt_params.dart';
import 'package:moneyhash_payment/data/apple_pay_configuration.dart';
import 'package:moneyhash_payment/data/card/card_field_type.dart';
import 'package:moneyhash_payment/data/card_form_configuration.dart';
import 'package:moneyhash_payment/data/collectible_billing_data.dart';
import 'package:moneyhash_payment/data/google_pay/native_google_pay_config.dart';
import 'package:moneyhash_payment/data/intent_methods.dart';
import 'package:moneyhash_payment/data/intent_operation.dart';
import 'package:moneyhash_payment/data/intent_state.dart';
import 'package:moneyhash_payment/data/intent_type.dart';
import 'package:moneyhash_payment/data/method_metadata.dart';
import 'package:moneyhash_payment/data/methods/get_methods_params.dart';
import 'package:moneyhash_payment/data/native_pay_data.dart';
import 'package:moneyhash_payment/log/log_level.dart';
import 'package:moneyhash_payment/vault/card_collector.dart';
import 'package:moneyhash_payment/vault/widget/secure_text_field.dart';
import 'package:moneyhash_payment/vault/card_form_builder.dart';
import 'package:moneyhash_payment/moneyhash_payment.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  CardForm? _cardForm;

  MoneyHashSDK moneyHashSDK = MoneyHashSDKBuilder()
      .setNativeGooglePayConfig(NativeGooglePayConfig(
        environment: GooglePayEnvironment.test,
        collectibleBillingData: [],
      ))
      .setNativeApplePayConfig(ApplePayConfiguration(
        collectibleBillingData: [
          CollectibleBillingData.email,
        ],
        merchantDisplayName: "Kero Store",
      ))
      .build();

  @override
  void initState() {
    _cardForm = CardFormBuilder()
        .setCardHolderNameField((state) {
          // print("CardHolderName: ${state?.isValid}");
          // print("CardHolderName: ${state?.errorMessage}");
        })
        .setCardNumberField((state) {
          // print("CardNumber: ${state?.isValid}");
          // print("CardNumber: ${state?.errorMessage}");
          // print("CardNumber: ${state?.length}");
        })
        .setCVVField((state) {
          // print("CVV: ${state?.isValid}");
          // print("CVV: ${state?.errorMessage}");
        })
        .setExpiryMonthField((state) {
          // print("ExpireMonth: ${state?.isValid}");
          // print("ExpireMonth: ${state?.errorMessage}");
        })
        .setExpiryYearField((state) {
          // print("ExpireYear: ${state?.isValid}");
          // print("ExpireYear: ${state?.errorMessage}");
        })
        .setCardBrandChangeListener((cardBrand) {
          // print("CardBrand: ${cardBrand?.brand}");
          // print("CardBrand: ${cardBrand?.brandIconUrl}");
          // print("CardBrand: ${cardBrand?.first6Digits}");
        })
        .setConfiguration(CardFormConfiguration(
          isCardHolderNameRequired: true,
          // enableCardNumberValidation: false
        ))
        .build();

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Testing card"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: <Widget>[
            SecureTextField(
              label: "cardNumber",
              placeholder: "cardNumber",
              cardForm: _cardForm!,
              type: CardFieldType.cardNumber,
            ),
            const SizedBox(height: 8),
            Row(
              children: [
                Expanded(
                  child: SecureTextField(
                    label: "expireMonth",
                    placeholder: "MM",
                    cardForm: _cardForm!,
                    type: CardFieldType.expiryMonth,
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: SecureTextField(
                    label: "expireYear",
                    placeholder: "YY",
                    cardForm: _cardForm!,
                    type: CardFieldType.expiryYear,
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  flex: 2,
                  child: SecureTextField(
                    label: "cvv",
                    placeholder: "***",
                    cardForm: _cardForm!,
                    type: CardFieldType.cvv,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 8),
            SecureTextField(
              label: "cardHolderName",
              placeholder: "John Doe",
              cardForm: _cardForm!,
              type: CardFieldType.cardHolderName,
            ),
            const SizedBox(height: 16),
            Expanded(
              child: ListView(
                children: [
                  _buildScenarioButton(
                    "Submit Card Form",
                    () => _submitCardForm(),
                  ),
                  _buildScenarioButton(
                    "🔍 Test Card Bin Lookup",
                    () => _testCardBinLookup(),
                  ),
                  _buildScenarioButton(
                    "🍎 Test Apple Pay Flow",
                    () => _testApplePayFlow(),
                  ),
                  _buildScenarioButton(
                    "📱 Check Apple Pay Compatibility",
                    () => _checkApplePayCompatibility(),
                  ),
                  _buildScenarioButton(
                    "🔍 Test Apple Pay Bin Lookup",
                    () => _testApplePayBinLookup(),
                  ),
                  _buildScenarioButton(
                    "💳 Test Google Pay Flow",
                    () => _testGooglePayFlow(),
                  ),
                  _buildScenarioButton(
                    "📱 Check Google Pay Compatibility",
                    () => _checkGooglePayCompatibility(),
                  ),
                  _buildScenarioButton(
                    "🚀 Test Google Pay with proceedWithMethod",
                    () => _testGooglePayWithProceedWithMethod(),
                  ),
                  _buildScenarioButton(
                    "📋 Get Payment Methods",
                    () => _getPaymentMethods(),
                  ),
                  _buildScenarioButton(
                    "🔧 Get Intent Details",
                    () => _getIntentDetails(),
                  ),
                  _buildScenarioButton(
                    "🖼️ Test Render Form (Custom Style)",
                    () => _testRenderFormCustomStyle(),
                  ),
                  _buildScenarioButton(
                    "🖼️ Test Render Form (Default Style)",
                    () => _testRenderFormDefaultStyle(),
                  ),
                  _buildScenarioButton(
                    "📋 Test Subscription Flow",
                    () => _testSubscriptionFlow(),
                  ),
                  _buildScenarioButton(
                    "🔍 Debug Subscription Embed Flow",
                    () => _debugSubscriptionEmbedFlow(),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  // Configuration constants
  static const String INTENT_ID = 'gEbGy4R';
  static const String PUBLIC_KEY = 'public.DxJyVTDp.MAIvOrqToMG0eJxPYbimAjRu9Pn5Oolg6bKgIyuv';
  static const double TEST_AMOUNT = 10;
  static const String TEST_CURRENCY = 'AED';

  Widget _buildScenarioButton(String title, VoidCallback onPressed) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: ElevatedButton(
        onPressed: onPressed,
        child: Text(title),
      ),
    );
  }

  void _initializeSDK() {
    moneyHashSDK.setPublicKey(PUBLIC_KEY);
    moneyHashSDK.setLogLevel(LogLevel.verbose);
    print('✅ SDK initialized with public key');
  }

  Future<void> _submitCardForm() async {
    try {
      bool isFormValid = await _cardForm?.isValid() ?? false;
      print('Card form validity: $isFormValid');
      print('Using intent ID: $INTENT_ID');

      _initializeSDK();

      // Step 1: Collect card data from secure form
      var vaultData = await _cardForm?.collect();
      print('💳 Card vault data collected: $vaultData');

      // Step 2: Proceed with CARD method
      print('🚀 Proceeding with CARD method for intent: $INTENT_ID');
      var proceedResult = await moneyHashSDK.proceedWithMethod(
        INTENT_ID,
        IntentType.payment,
        'CARD',
        MethodType.paymentMethod,
        null,
        null,
      );
      print('✅ Proceed with CARD result: $proceedResult');

      // Step 3: Pay with collected card data
      var payResult = await _cardForm?.pay(
        INTENT_ID,
        vaultData!,
        true,
        null,
        null,
      );
      print('✅ Card payment result: $payResult');
    } catch (e) {
      print('❌ Card payment error: $e');
    }
  }

  Future<void> _testCardBinLookup() async {
    try {
      print('🔍 Starting card bin lookup test...');
      bool isFormValid = await _cardForm?.isValid() ?? false;
      print('Card form validity: $isFormValid');

      if (!isFormValid) {
        print('⚠️ Card form is not valid, please fill in valid card details');
        return;
      }

      _initializeSDK();

      // Collect card data from the form
      var vaultData = await _cardForm?.collect();
      print('💳 Card vault data for bin lookup: $vaultData');

      // Perform bin lookup using the collected card data
      var lookupResult = await _cardForm?.binLookup(vaultData);
      print('✅ Card bin lookup completed successfully: $lookupResult');
    } catch (error) {
      print('❌ Card bin lookup error: $error');
    }
  }

  Future<void> _testApplePayFlow() async {
    try {
      print('🍎 Starting complete Apple Pay flow with intent: $INTENT_ID');

      _initializeSDK();

      // Check compatibility
      bool isCompatible = await moneyHashSDK.isDeviceCompatibleWithApplePay();
      print('📱 Device Apple Pay compatibility: $isCompatible');
      if (!isCompatible) {
        throw Exception('Device not compatible with Apple Pay');
      }

      // Get methods and find Apple Pay
      var methods = await moneyHashSDK.getMethods(
        GetMethodsParams.withCurrency(
          amount: TEST_AMOUNT,
          currency: TEST_CURRENCY,
        ),
      );
      print('📋 Payment methods retrieved: $methods');

      final applePayMethod = methods.expressMethods?.firstWhere(
        (em) => em.nativePayData != null && em.nativePayData is ApplePayData,
        orElse: () => throw Exception('Apple Pay method not available'),
      );

      final applePayData = applePayMethod?.nativePayData as ApplePayData;
      print('✅ Apple Pay method found: ${applePayData.toString()}');

      // Generate receipt using ApplePayReceiptParams with the actual Apple Pay data
      var receipt = await moneyHashSDK.generateApplePayReceipt(
        ApplePayReceiptParams.withApplePayData(TEST_AMOUNT, applePayData),
      );
      print('✅ Apple Pay receipt generated successfully');

      // Proceed with payment
      var proceedResult = await moneyHashSDK.proceedWithMethod(
        INTENT_ID,
        IntentType.payment,
        'APPLE_PAY',
        MethodType.paymentMethod,
        null,
        null,
      );
      print('✅ Proceed with Apple Pay result: $proceedResult');

      // Submit receipt
      var submitResult = await moneyHashSDK.submitPaymentReceipt(INTENT_ID, receipt!);
      print('✅ Apple Pay receipt submitted successfully: $submitResult');

      print('🎉 Apple Pay flow completed successfully for intent: $INTENT_ID');
    } catch (error) {
      print('❌ Apple Pay flow error: $error');
    }
  }

  Future<void> _checkApplePayCompatibility() async {
    try {
      bool isCompatible = await moneyHashSDK.isDeviceCompatibleWithApplePay();
      print('📱 Device Apple Pay compatible: $isCompatible');
    } catch (error) {
      print('❌ Compatibility check error: $error');
    }
  }

  Future<void> _testApplePayBinLookup() async {
    try {
      _initializeSDK();
      
      var methods = await moneyHashSDK.getMethods(
        GetMethodsParams.withCurrency(
          amount: TEST_AMOUNT,
          currency: TEST_CURRENCY,
        ),
      );

      final applePayMethod = methods.expressMethods?.firstWhere(
        (em) => em.nativePayData != null && em.nativePayData is ApplePayData,
        orElse: () => throw Exception('Apple Pay method not available'),
      );

      final applePayData = applePayMethod?.nativePayData as ApplePayData;
      
      var receipt = await moneyHashSDK.generateApplePayReceipt(
        ApplePayReceiptParams.withApplePayData(TEST_AMOUNT, applePayData),
      );

      // Use the actual method ID from applePayData
      var lookupData = await moneyHashSDK.getApplePayBinLookup(
        receipt!,
        applePayData.methodID!, // Use the actual method ID from the apple pay data
      );
      print('✅ Apple Pay bin lookup completed: $lookupData');
    } catch (error) {
      print('❌ Apple Pay bin lookup error: $error');
    }
  }

  Future<void> _testGooglePayFlow() async {
    try {
      print('💳 Starting complete Google Pay flow with intent: $INTENT_ID');

      _initializeSDK();

      // Check compatibility
      bool isCompatible = await moneyHashSDK.isReadyForGooglePay();
      print('📱 Device Google Pay compatibility: $isCompatible');
      if (!isCompatible) {
        throw Exception('Device not compatible with Google Pay');
      }

      // Get methods and find Google Pay
      var methods = await moneyHashSDK.getMethods(
        GetMethodsParams.withCurrency(
          amount: TEST_AMOUNT,
          currency: TEST_CURRENCY,
        ),
      );

      final googlePayMethod = methods.expressMethods?.firstWhere(
        (em) => em.nativePayData != null && em.nativePayData is GooglePayData,
        orElse: () => throw Exception('Google Pay method not available'),
      );

      final googlePayData = googlePayMethod?.nativePayData as GooglePayData;
      print('✅ Google Pay method found: ${googlePayData.toString()}');

      // Generate receipt using actual Google Pay data with fallbacks
      var receipt = await moneyHashSDK.generateGooglePayReceipt(
        googlePayData.currencyCode ?? TEST_CURRENCY,
        googlePayData.amount ?? TEST_AMOUNT,
        googlePayData.countryCode ?? "AE",
        googlePayData.gateway ?? "example",
        googlePayData.gatewayMerchantId ?? "exampleGatewayMerchantId",
        googlePayData.merchantId ?? "BCR2DN6T2MM7YIJK",
        googlePayData.merchantName ?? "Example Merchant",
        googlePayData.allowedCardNetworks ?? ["VISA", "MASTERCARD"],
        googlePayData.allowedCardAuthMethods ?? ["CRYPTOGRAM_3DS"],
      );
      print('✅ Google Pay receipt generated successfully');

      // Proceed with payment
      var proceedResult = await moneyHashSDK.proceedWithMethod(
        INTENT_ID,
        IntentType.payment,
        'GOOGLE_PAY',
        MethodType.paymentMethod,
        null,
        null,
      );
      print('✅ Proceed with Google Pay result: $proceedResult');

      // Submit receipt
      var submitResult = await moneyHashSDK.submitPaymentReceipt(INTENT_ID, receipt!);
      print('✅ Google Pay receipt submitted successfully: $submitResult');

      print('🎉 Google Pay flow completed successfully for intent: $INTENT_ID');
    } catch (error) {
      print('❌ Google Pay flow error: $error');
    }
  }

  Future<void> _checkGooglePayCompatibility() async {
    try {
      bool isCompatible = await moneyHashSDK.isReadyForGooglePay();
      print('📱 Device Google Pay compatible: $isCompatible');
    } catch (error) {
      print('❌ Compatibility check error: $error');
    }
  }

  Future<void> _testGooglePayWithProceedWithMethod() async {
    try {
      print('🚀 Starting Google Pay flow with proceedWithMethod...');

      _initializeSDK();

      // Check compatibility
      bool isCompatible = await moneyHashSDK.isReadyForGooglePay();
      if (!isCompatible) {
        throw Exception('Device not compatible with Google Pay');
      }

      // Proceed with GOOGLE_PAY method
      print('🚀 Proceeding with GOOGLE_PAY method for intent: $INTENT_ID');
      var proceedResult = await moneyHashSDK.proceedWithMethod(
        INTENT_ID,
        IntentType.payment,
        'GOOGLE_PAY',
        MethodType.paymentMethod,
        null,
        null,
      );
      print('✅ Proceed with GOOGLE_PAY result: $proceedResult');

      // Get intent details from the result
      print('📋 Getting intent details to check state...');
      var intentDetails = await moneyHashSDK.getIntentDetails(INTENT_ID, IntentType.payment);
      print('✅ Intent details: $intentDetails');

      // Check if state is native pay and get Google Pay data
      if (intentDetails.intentState?.runtimeType.toString().contains('NativePay') ?? false) {
        print('✅ Intent state is native_pay');
        
        // Cast to NativePay to get the Google Pay data
        final nativePayState = intentDetails.intentState as NativePay;
        final googlePayData = nativePayState.nativePayData as GooglePayData;
        print('✅ Google Pay data from intent: ${googlePayData.toString()}');
        
        // Use proceedWithGooglePay with the data from intent state
        var finalResult = await moneyHashSDK.proceedWithGooglePay(
          INTENT_ID,
          googlePayData.currencyCode ?? TEST_CURRENCY,
          googlePayData.amount ?? TEST_AMOUNT,
          googlePayData.countryCode ?? "AE",
          googlePayData.gateway ?? "example",
          googlePayData.gatewayMerchantId ?? "exampleGatewayMerchantId",
          googlePayData.merchantId ?? "BCR2DN6T2MM7YIJK",
          googlePayData.merchantName ?? "Example Merchant",
          googlePayData.allowedCardNetworks,
          googlePayData.allowedCardAuthMethods,
        );
        print('✅ Google Pay with proceedWithGooglePay completed: $finalResult');
      } else {
        print('❌ Intent state is not native_pay. State type: ${intentDetails.intentState?.runtimeType}');
      }
    } catch (error) {
      print('❌ Google Pay with proceedWithMethod error: $error');
    }
  }

  Future<void> _getPaymentMethods() async {
    try {
      _initializeSDK();
      var methods = await moneyHashSDK.getMethods(
        GetMethodsParams.withCurrency(
          amount: TEST_AMOUNT,
          currency: TEST_CURRENCY,
        ),
      );
      print('📋 Available payment methods: $methods');
    } catch (error) {
      print('❌ Get methods error: $error');
    }
  }

  Future<void> _getIntentDetails() async {
    try {
      _initializeSDK();
      print('Getting intent details for: $INTENT_ID');
      var details = await moneyHashSDK.getIntentDetails(INTENT_ID, IntentType.payment);
      print('🔧 Intent details: $details');
    } catch (error) {
      print('❌ Get intent details error: $error');
    }
  }

  Future<void> _testRenderFormCustomStyle() async {
    try {
      print('📱 Starting render form test with intent: $INTENT_ID');

      _initializeSDK();

      // Render the payment form with custom style (pass null for now, can be enhanced)
      var result = await moneyHashSDK.renderForm(
        INTENT_ID,
        IntentType.payment,
        null, // Custom embed style would go here
      );

      print('✅ Render form completed successfully: $result');
    } catch (error) {
      print('❌ Render form error: $error');
    }
  }

  Future<void> _testRenderFormDefaultStyle() async {
    try {
      print('📱 Starting render form test (default style) with intent: $INTENT_ID');

      _initializeSDK();

      // Render the payment form without custom styling
      var result = await moneyHashSDK.renderForm(
        INTENT_ID,
        IntentType.payment,
        null,
      );

      print('✅ Render form (default style) completed successfully: $result');
    } catch (error) {
      print('❌ Render form (default style) error: $error');
    }
  }

  Future<void> _testSubscriptionFlow() async {
    try {
      print('📋 Starting subscription flow test...');

      _initializeSDK();

      // Configuration for subscription test
      const customerID = '33dee031-d237-482f-ae6c-3f4091c0c8fb';
      const embedID = '4lgb5LB';

      print('📊 Getting subscription plan groups...');
      var subscriptionGroups = await moneyHashSDK.getSubscriptionPlanGroups(2, 1, "aed");
      print('✅ Subscription groups retrieved: $subscriptionGroups');

      print('📋 Getting subscription plans for group: $embedID');
      var subscriptionPlans = await moneyHashSDK.getSubscriptionPlans(embedID, customerID);
      print('✅ Subscription plans retrieved: $subscriptionPlans');

      const planIdx = 0;

      if (subscriptionPlans.isNotEmpty && subscriptionPlans[planIdx].id != null) {
        print('🎯 Selecting subscription plan: ${subscriptionPlans[planIdx].id}');
        var intentDetails = await moneyHashSDK.selectSubscriptionPlan(
          embedID,
          customerID,
          subscriptionPlans[planIdx].id!,
        );
        print('✅ Subscription plan selected, intent details: $intentDetails');

        // Test renderSubscriptionEmbed with the intent ID from selected plan
        if (intentDetails?.intent?.id != null) {
          var subscriptionResult = await moneyHashSDK.renderSubscriptionEmbed(
            intentDetails!.intent!.id!,
            null,
          );
          print('✅ Render subscription embed completed successfully: $subscriptionResult');
        }

        print('📋 Subscription flow completed successfully');
      } else {
        print('❌ No subscription plans available or plan ID missing');
        throw Exception('No subscription plans available');
      }
    } catch (error) {
      print('❌ Subscription flow error: $error');
    }
  }

  Future<void> _debugSubscriptionEmbedFlow() async {
    try {
      print('🔍 Starting DEBUG subscription embed flow...');

      _initializeSDK();

      // Configuration for subscription test
      const customerID = 'fe3e99eb-97b2-481f-a0cb-9b9898dbd989';
      const embedID = '4lgb5LB';

      // Step 1: Get subscription plans
      print('📋 Step 1: Getting subscription plans...');
      var subscriptionPlans = await moneyHashSDK.getSubscriptionPlans(embedID, customerID);
      print('✅ Subscription plans retrieved: $subscriptionPlans');

      if (subscriptionPlans.isEmpty) {
        throw Exception('No subscription plans available');
      }

      // Step 2: Select subscription plan
      print('🎯 Step 2: Selecting subscription plan...');
      const planIdx = 2;
      final selectedPlan = subscriptionPlans[planIdx];
      print('Selected plan: $selectedPlan');

      if (selectedPlan.id == null) {
        throw Exception('Selected subscription plan has no ID');
      }

      var intentDetails = await moneyHashSDK.selectSubscriptionPlan(
        embedID,
        customerID,
        selectedPlan.id!,
      );
      print('✅ Subscription plan selected, intent details: $intentDetails');

      // Step 3: Render subscription embed with error handling
      if (intentDetails?.intent?.id != null) {
        print('📱 Step 3: Testing renderSubscriptionEmbed...');
        print('Intent ID: ${intentDetails!.intent!.id}');

        try {
          var subscriptionResult = await moneyHashSDK.renderSubscriptionEmbed(
            intentDetails.intent!.id!,
            null,
          ).timeout(const Duration(seconds: 30));

          print('✅ Render subscription embed completed successfully: $subscriptionResult');
        } catch (embedError) {
          print('❌ renderSubscriptionEmbed error: $embedError');
          rethrow;
        }
      } else {
        throw Exception('No intent ID found in subscription plan details');
      }
    } catch (error) {
      print('❌ DEBUG Subscription embed flow error: $error');
    }
  }
}
4
likes
130
points
1.14k
downloads

Publisher

verified publishermoneyhash.io

Weekly Downloads

MoneyHash is a Super-API infrastructure for payment orchestration and revenue operations in emerging markets.

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on moneyhash_payment

Packages that implement moneyhash_payment