fundlypay 0.0.6 copy "fundlypay: ^0.0.6" to clipboard
fundlypay: ^0.0.6 copied to clipboard

A Flutter library by Fundly Pay for seamless and standardized payment integration across multiple payment methods — simplifying invoice collection, reconciliation, and settlement.

🏦 FundlyPay #

A Flutter library by Fundly Pay for seamless and standardized payment integration.
It enables effortless management of invoice-based and direct payment lifecycles while maintaining a clear separation between system transaction statuses and manual distributor settlements.

This ensures transparent payment tracking, reconciliation, and settlement across multiple payment methods such as Cash, Cheque, Static QR, Dynamic QR, Payment Link, and Fundly Pay.


🚀 Features #

✅ Seamless integration for Fundly Pay transactions
✅ Supports both Invoice Collect and Direct Collect payment flows
✅ Easy environment configuration (Sandbox / Production)
✅ Event-driven architecture for handling HOME and CLOSE actions
✅ Secure authentication via credential object (API Key or Username/Password)
✅ Standardized and extensible payment object structure


⚙️ Getting Started #

1️⃣ Installation #

Add the dependency to your pubspec.yaml:

dependencies:
  fundlypay: ^0.0.5

Then run:

flutter pub get

2️⃣ Import #

import 'package:fundlypay/fundlypay.dart';

3️⃣ iOS Configuration (Required) #

For UPI payment app integration and media uploads (camera/gallery) on iOS, add the following to your ios/Runner/Info.plist:

<!-- UPI payment app schemes -->
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>phonepe</string>
    <string>paytmmp</string>
    <string>gpay</string>
    <string>upi</string>
    <string>tez</string>
    <string>bhim</string>
    <string>cred</string>
    <string>credpay</string>
    <string>mobikwik</string>
    <string>amazonpay</string>
    <string>whatsapp-consumer</string>
    <string>navipay</string>
    <string>myairtel</string>
    <string>popclubapp</string>
    <string>super</string>
    <string>kiwi</string>
    <string>simplypayupi</string>
</array>

<!-- Permissions descriptions for document uploads -->
<key>NSCameraUsageDescription</key>
<string>We need access to the camera to capture invoice and document photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to the photo library to upload invoice and document files.</string>

This allows your app to detect/launch payment apps for UPI transactions and handle camera/photo uploads.

4️⃣ Android Configuration (Required) #

For Android 11 (API Level 30) and above, package visibility queries must be declared in your android/app/src/main/AndroidManifest.xml. Add the <queries> element inside the <manifest> tag to allow the plugin to detect and launch external UPI payment apps:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    ...
    <queries>
        <!-- For launching external UPI payment apps -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="upi" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="phonepe" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="paytmmp" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="gpay" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="tez" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="bhim" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="cred" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="credpay" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="mobikwik" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="navipay" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="myairtel" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="popclubapp" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="super" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="kiwi" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="simplypayupi" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="whatsapp-consumer" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="postpe" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="tnupi" />
        </intent>
    </queries>
</manifest>

To allow direct opening of selected payment apps (such as Google Pay, CRED, Paytm, and PhonePe) without triggering the Android system resolver chooser dialog, add the following MethodChannel handler to your Android app's MainActivity.kt:

package com.yourcompany.yourapp

import android.content.Intent
import android.content.pm.ResolveInfo
import android.net.Uri
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.fundly.fundly/settings"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "isAppInstalled" -> {
                        val packageName = call.argument<String>("packageName")
                        if (packageName != null) {
                            result.success(isPackageInstalled(packageName))
                        } else {
                            result.error("BAD_ARGS", "packageName is null", null)
                        }
                    }
                    "launchUpiIntent" -> {
                        val packageName = call.argument<String>("packageName")
                        val upiUrl = call.argument<String>("upiUrl")
                        if (packageName != null && upiUrl != null) {
                            result.success(launchUpiIntent(packageName, upiUrl))
                        } else {
                            result.error("BAD_ARGS", "packageName or upiUrl is null", null)
                        }
                    }
                    else -> result.notImplemented()
                }
            }
    }

    private fun isPackageInstalled(packageName: String): Boolean {
        val pm = packageManager
        return try {
            pm.getPackageInfo(packageName, 0)
            true
        } catch (e: Exception) {
            val intent = Intent(Intent.ACTION_VIEW, Uri.parse("upi://pay"))
            val resInfo = pm.queryIntentActivities(intent, 0)
            for (info in resInfo) {
                if (info.activityInfo.packageName == packageName) {
                    return true
                }
            }
            false
        }
    }

    private fun launchUpiIntent(packageName: String, upiUrl: String): Boolean {
        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(upiUrl))
        val pm = packageManager
        val resInfo = pm.queryIntentActivities(intent, 0)
        var foundPackageFlag = false
        var upiClientResolveInfo: ResolveInfo? = null
        for (info in resInfo) {
            if (info.activityInfo.packageName == packageName) {
                foundPackageFlag = true
                upiClientResolveInfo = info
                break
            }
        }
        return try {
            if (foundPackageFlag && upiClientResolveInfo != null) {
                intent.setClassName(
                    upiClientResolveInfo.activityInfo.packageName,
                    upiClientResolveInfo.activityInfo.name
                )
                startActivity(intent)
                true
            } else {
                val launchIntent = pm.getLaunchIntentForPackage(packageName)
                if (launchIntent != null) {
                    startActivity(launchIntent)
                    true
                } else {
                    false
                }
            }
        } catch (e: Exception) {
            false
        }
    }
}

🧠 Inputs to Library #

1. Credentials #

Option 1 — Username/Password

"credential": {
  "username": "demo_user",
  "password": "dummy_password_123",
  "source": "SOURCE_APP"
}

Option 2 — API Key

"credential": {
  "apiKey": "dummy_api_key_123",
  "source": "SOURCE_APP"
}

2. Payment Details #

💰 Invoice Collect

"paymentDetails": {
  "distributorId": "DISTRIBUTOR1234",
  "chemistId": "CHEMIST1234",
  "paymentType": "INVOICE_COLLECT",
  "payableAmount": 200.0,
  "invoice": [
    {
      "invoiceNumber": "INV1001",
      "paidAmount": 500.0,
      "invoiceYear": "2025"  // Optional: Invoice year in YYYY format
    },
    {
      "invoiceNumber": "INV1002",
      "paidAmount": 500.0,
      "invoiceYear": "2025"  // Optional
    }
  ]
}

Invoice Object Parameters:

  • invoiceNumber (required): Invoice identifier
  • paidAmount (required): Amount paid for this invoice
  • invoiceYear (optional): Invoice year in YYYY format

💳 Direct Collect

"paymentDetails": {
  "distributorId": "DISTRIBUTOR1234",
  "chemistId": "CHEMIST1234",
  "paymentType": "DIRECT_COLLECT",
  "payableAmount": 200.0,
  "invoices": [
    {
      "invoiceId": "INV101",
      "invoice": [
        {
          "page": "1",
          "url": "https://example.com/invoice_page1.jpg"
        },
        {
          "page": "2",
          "url": "https://example.com/invoice_page2.jpg"
        }
      ]
    },
    {
      "invoiceId": "INV102",
      "invoice": [
        {
          "page": "1",
          "url": "https://example.com/invoice_page1.jpg"
        }
      ]
    }
  ]
}

3. Event Data (Optional) #

You can optionally pass custom event tracking or device identification data under the eventData key.

"eventData": {
  "os": "android",            // Optional: Will be auto-detected at runtime if not provided (android/ios)
  "device_type": "mobile",    // Optional: 'mobile' or 'tablet', auto-detected at runtime if not provided
  "custom_tracker_id": "xyz"  // Optional: Any other custom key-value pairs for analytics
}

At runtime, the library automatically enriches this object with the running SDK version (e.g. sdk_version: "0.0.5").


🧩 Enums #

enum FundlyPayEvent {
  HOME,
  CLOSE,
}

enum PaymentType {
  DIRECT_COLLECT,
  INVOICE_COLLECT,
}

enum FundlyPayEnvironment {
  PRODUCTION,
  SANDBOX,
}

🧱 Initialization Example #

final fundlyPayObject = {
  "credential": credential,
  "paymentDetails": paymentDetails,
};

FundlyPayService(
  fundlyPayObject: fundlyPayObject,
  environment: FundlyPayEnvironment.PRODUCTION,
  onEvent: (event, data) {
    debugPrint("FundlyPayService Event: $event -> $data");

    if (event == FundlyPayEvent.HOME) {
      // Example: Navigator.of(context).popUntil((route) => route.isFirst);
    } else if (event == FundlyPayEvent.CLOSE) {
      // Example: if (Navigator.of(context).canPop()) Navigator.of(context).pop();
    }
  },
);

🧾 Example: Combined Object #

final fundlyPayObject = {
  "credential": {
    "username": "demo_user",
    "password": "dummy_password_123",
    "source": "SOURCE_APP",
  },
  "paymentDetails": {
    "distributorId": "D00000000XX",
    "chemistId": "R00000000YY",
    "paymentType": "INVOICE_COLLECT",
    "payableAmount": 1000.0,
    "invoice": [
      {
        "invoiceNumber": "INV1001",
        "paidAmount": 600.0,
        "invoiceYear": "2025"  // Optional parameter
      },
      {
        "invoiceNumber": "INV1002",
        "paidAmount": 400.0,
        "invoiceYear": "2025"  // Optional parameter
      }
    ]
  },
  "eventData": {
    "os": "ios",
    "device_type": "mobile",
    "custom_tracker_id": "analytics_tracker_xyz"
  }
};

🧭 Objective #

The Fundly Pay Flutter Library standardizes the payment lifecycle for invoice and direct collections, ensuring consistent handling of:

  • Transaction creation and tracking
  • System vs. manual settlement status separation
  • Unified reconciliation across multiple payment methods

🧩 Supporting Libraries #

The FundlyPay Flutter Library is built using the following supporting packages:

Library Purpose
flutter_inappwebview Embeds and manages Fundly Pay's web-based payment flows securely inside Flutter apps.
file_picker Enables users to select and upload invoice or proof-of-payment files.
image_picker Captures or selects images for document uploads or invoice attachments.
flutter_image_compress Optimizes and compresses images before upload to reduce file size and improve performance.
path_provider Manages local directories for caching and file storage.
permission_handler Handles runtime permissions for file, storage, and media access.
share_plus Allows sharing of receipts, payment links, and transaction data.
http Facilitates secure REST API communication with Fundly Pay backend services.
url_launcher Enables launching external payment apps (PhonePe, Paytm, GPay, etc.) for UPI transactions.

🪪 License #

Copyright © 2025 Ardour Analytics Private Limited.
All rights reserved.

This software and its source code are the property of Ardour Analytics Private Limited.
Unauthorized copying, distribution, modification, or use of this software, in whole or in part,
is strictly prohibited without prior written permission from Ardour Analytics Private Limited.

This project is proprietary and maintained by Ardour Analytics Private Limited.


💬 Support #

For integration or technical assistance:
📧 connect@fundly.ai
🌐 www.fundly.ai

0
likes
140
points
135
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter library by Fundly Pay for seamless and standardized payment integration across multiple payment methods — simplifying invoice collection, reconciliation, and settlement.

Homepage

License

unknown (license)

Dependencies

file_picker, flutter, flutter_image_compress, flutter_inappwebview, http, image_picker, path_provider, permission_handler, share_plus, url_launcher

More

Packages that depend on fundlypay