moneyhash_payment 4.0.9
moneyhash_payment: ^4.0.9 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_state.dart';
import 'package:moneyhash_payment/data/intent_type.dart';
import 'package:moneyhash_payment/data/methods/get_methods_params.dart';
import 'package:moneyhash_payment/data/native_pay_data.dart';
import 'package:moneyhash_payment/data/bank_account_tokenization_status.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> {
// Configuration constants
static const String INTENT_ID = 'ZOMmYvv';
static const String PUBLIC_KEY = 'public.zOr9kfOu.x2wFA9d9IDM4KVb5QEMXNvNf4Qify1s5348Xi9RB';
static const double TEST_AMOUNT = 10;
static const String TEST_CURRENCY = 'egp';
static const String CUSTOMER_ID = 'd609763b-4fd9-44b6-9833-23c12acc0b96';
static const String BANK_INTENT_ID = 'YLP8vL3';
static const String CARD_TOKEN_INTENT_ID = '97j5dmZ';
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,
cardHolderValidations: {
"Card holder name must contain only letters and spaces": "^[a-zA-Z\\s]+\$",
"Card holder name must be between 2 and 50 characters": "^.{2,50}\$"
},
// 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 Tokenize Receipt (iOS Only)",
() => _testTokenizeReceipt(),
),
_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(),
),
_buildScenarioButton(
"🏦 Test Bank Account Tokenization",
() => _testBankAccountTokenization(),
),
_buildScenarioButton(
"🏦 Test Saved Bank Account Flow",
() => _testSavedBankAccountFlow(),
),
_buildScenarioButton(
"📷 Test Camera Access URL",
() => _testCameraAccessURL(),
),
],
),
),
],
),
),
);
}
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> _testTokenizeReceipt() async {
try {
print('🪙 Testing tokenize receipt flow');
_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),
);
// Test tokenizeReceipt with example IDs (replace with actual IDs for real use)
var cardTokenId = await moneyHashSDK.tokenizeReceipt(
receipt!.receipt,
applePayData.methodID!,
CARD_TOKEN_INTENT_ID,
);
print('✅ Receipt tokenized successfully, card token ID: $cardTokenId');
} catch (error) {
print('❌ Tokenize receipt 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');
}
}
Future<void> _testBankAccountTokenization() async {
try {
print('🏦 Starting bank account tokenization test...');
_initializeSDK(); // Ensure SDK is initialized
print('🚀 Starting bank account tokenization for intent: $BANK_INTENT_ID');
BankAccountTokenizationStatus bankAccountResult = await moneyHashSDK.renderCreateBankAccountTokenEmbed(
BANK_INTENT_ID,
);
print('✅ Bank account tokenization completed: $bankAccountResult');
// Show result to user based on status
String statusMessage;
switch (bankAccountResult) {
case BankAccountTokenizationStatus.successful:
statusMessage = 'Bank account tokenization was successful! ✅';
break;
case BankAccountTokenizationStatus.pendingApproval:
statusMessage = 'Bank account tokenization is pending approval ⏳';
break;
case BankAccountTokenizationStatus.failed:
statusMessage = 'Bank account tokenization failed ❌';
break;
}
print('📢 Status: $statusMessage');
} catch (error) {
print('❌ Bank account tokenization error: $error');
}
}
Future<void> _testSavedBankAccountFlow() async {
try {
print('🏦 Starting saved bank account flow test...');
_initializeSDK(); // Ensure SDK is initialized
// Step 1: Get methods to find saved bank accounts
print('📋 Getting payment methods...');
var methods = await moneyHashSDK.getMethods(
GetMethodsParams.withCurrency(
amount: TEST_AMOUNT,
currency: TEST_CURRENCY,
customer: CUSTOMER_ID,
),
);
print('📋 Methods retrieved: $methods');
// Step 2: Find saved bank accounts
final savedBankAccounts = methods.savedBankAccounts;
print('🏦 Saved bank accounts found: $savedBankAccounts');
if (savedBankAccounts == null || savedBankAccounts.isEmpty) {
print('❌ No saved bank accounts found for this customer. Please save a bank account first.');
return;
}
// Step 3: Use the first saved bank account
final firstSavedBankAccount = savedBankAccounts[0];
print('🏦 Using saved bank account: $firstSavedBankAccount');
// Step 4: Proceed with the saved bank account
print('🚀 Proceeding with saved bank account method...');
var proceedResult = await moneyHashSDK.proceedWithMethod(
INTENT_ID,
IntentType.payment,
firstSavedBankAccount.id ?? '',
MethodType.savedBankAccount,
null, // methodMetaData
null, // useWalletBalance
);
print('✅ Proceed with saved bank account result: $proceedResult');
// Step 5: Check the state and handle URL rendering
final state = proceedResult.details?.intentState;
print('🔍 Current state: $state');
// Check if we need to render a URL
if (state != null && state is UrlToRender) {
final urlToShow = state.url;
print('🌐 URL to render: $urlToShow');
try {
print('🌐 Rendering URL: $urlToShow');
var urlResult = await moneyHashSDK.renderURL(
urlToShow!,
INTENT_ID,
IntentType.payment,
null,
);
print('✅ URL render result: $urlResult');
print('📢 URL rendering completed successfully!');
} catch (urlError) {
print('❌ URL rendering error: $urlError');
}
} else {
print('📢 Current state type: ${state?.runtimeType}');
print('📢 This scenario expects UrlToRender state.');
}
} catch (error) {
print('❌ Saved bank account flow error: $error');
}
}
Future<void> _testCameraAccessURL() async {
try {
print('📷 Starting camera access test...');
_initializeSDK();
const testUrl = 'https://camera-access-app.vercel.app/';
print('🌐 Testing URL: $testUrl');
var urlResult = await moneyHashSDK.renderURL(
testUrl,
INTENT_ID,
IntentType.payment,
null,
);
print('✅ Camera access URL test result: $urlResult');
print('📢 Camera access URL rendering completed successfully!');
} catch (error) {
print('❌ Camera access URL error: $error');
}
}
}