Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions apps/ex05_plan_demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Plan Management Demo

A comprehensive example demonstrating subscription plan management using the MindPaystack SDK.

## Features Demonstrated

- **Create Plan**: Create new subscription plans with various billing intervals
- **List Plans**: Retrieve and display all available subscription plans
- **Fetch Plan**: Get detailed information about a specific plan
- **Update Plan**: Modify existing plan details like name and amount

## Setup

1. **Environment Variables** (Recommended):
```bash
export PAYSTACK_PUBLIC_KEY=pk_test_your_public_key
export PAYSTACK_SECRET_KEY=sk_test_your_secret_key
```

2. **Install Dependencies**:
```bash
dart pub get
```

## Usage

### Interactive Mode
Run the demo with an interactive menu:
```bash
dart run bin/ex05_plan_demo.dart
```

### Complete Demo
Run an automated demonstration of all features:
```bash
dart run bin/ex05_plan_demo.dart --complete
```

## Example Plan Operations

### Creating a Plan
```dart
final createResult = await sdk.plan.create(
CreatePlanOptions(
name: 'Premium Monthly',
amount: 500000, // ₦5,000 in kobo
interval: 'monthly',
planCode: 'premium_monthly',
description: 'Premium features with monthly billing',
currency: 'NGN',
),
);
```

### Listing Plans
```dart
final listResult = await sdk.plan.list(
ListPlansOptions(
perPage: 10,
page: 1,
status: 'active',
),
);
```

### Fetching a Specific Plan
```dart
final fetchResult = await sdk.plan.fetch('premium_monthly');
```

### Updating a Plan
```dart
final updateResult = await sdk.plan.update(
'premium_monthly',
UpdatePlanOptions(
name: 'Premium Monthly (Updated)',
amount: 600000, // ₦6,000 in kobo
),
);
```

## Plan Properties

- **name**: Human-readable plan name
- **amount**: Billing amount in kobo (smallest currency unit)
- **interval**: Billing frequency (`daily`, `weekly`, `monthly`, `biannually`, `annually`)
- **planCode**: Unique identifier for the plan
- **description**: Optional plan description
- **currency**: Plan currency (defaults to NGN)
- **invoiceLimit**: Maximum number of invoices (optional)
- **sendInvoices**: Whether to send email invoices
- **sendSms**: Whether to send SMS notifications

## Error Handling

The demo includes comprehensive error handling for common scenarios:
- Network connectivity issues
- Invalid API credentials
- Missing required parameters
- Plan not found errors
- Validation failures

## Next Steps

After running this demo, you can:
1. Create plans for your subscription tiers
2. Use these plans in subscription creation
3. Implement plan selection in your UI
4. Set up subscription management workflows
40 changes: 40 additions & 0 deletions apps/ex05_plan_demo/bin/ex05_plan_demo.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'dart:io';
import 'package:ex05_plan_demo/ex05_plan_demo.dart';

/// Plan Management Demo Application
///
/// This demo application showcases the plan management features of the
/// MindPaystack SDK including creating, listing, fetching, and updating
/// subscription plans.
///
/// Usage:
/// 1. Set environment variables (optional):
/// - PAYSTACK_PUBLIC_KEY=pk_test_your_key
/// - PAYSTACK_SECRET_KEY=sk_test_your_key
///
/// 2. Run the demo:
/// dart run bin/ex05_plan_demo.dart
///
/// 3. Choose from interactive mode or complete demo
void main(List<String> arguments) async {
print('🎯 MindPaystack Plan Management Demo');
print('=====================================');

try {
// Initialize the SDK
await PlanDemo.initializeSdk();

if (arguments.contains('--complete') || arguments.contains('-c')) {
// Run complete automated demo
await PlanDemo.runCompleteDemo();
} else {
// Run interactive menu
print('\nπŸ’‘ Tip: Use --complete flag to run automated demo');
await PlanDemo.showMenu();
}

} catch (e) {
print('❌ Demo failed: $e');
exit(1);
}
}
212 changes: 212 additions & 0 deletions apps/ex05_plan_demo/lib/ex05_plan_demo.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import 'dart:io';
import 'package:dotenv/dotenv.dart';
import 'package:mind_paystack/mind_paystack.dart';

/// Demonstrates plan management operations using the MindPaystack SDK
class PlanDemo {
/// Initialize the SDK with environment variables or test keys
static Future<void> initializeSdk() async {
try {
// Try to initialize from environment variables first
await MindPaystack.fromEnvironment();
print('βœ… SDK initialized from environment variables');
} catch (e) {
final env = DotEnv(includePlatformEnvironment: true)..load();
final secretKey = env['PAYSTACK_SECRET_KEY'];
final publicKey = env['PAYSTACK_PUBLIC_KEY'];

// Fallback to test configuration
await MindPaystack.initialize(
PaystackConfig(
publicKey: publicKey!,
secretKey: secretKey!,
environment: Environment.test,
),
);
print('βœ… SDK initialized with test configuration');
print(
'πŸ’‘ Set PAYSTACK_PUBLIC_KEY and PAYSTACK_SECRET_KEY environment variables for automatic configuration');
}
}

/// Demonstrates creating a new subscription plan
static Future<Plan?> createPlan() async {
print('\nπŸ”„ Creating a new subscription plan...');

final sdk = MindPaystack.instance;

final createResult = await sdk.plan.create(
CreatePlanOptions(
name: 'Premium Monthly Plan',
amount: 500000, // ₦5,000 in kobo
interval: 'monthly',
// planCode: 'premium_monthly_${DateTime.now().millisecondsSinceEpoch}',
description: 'Premium features with monthly billing',
currency: 'NGN',
invoiceLimit: 12, // 12 months
sendInvoices: true,
sendSms: true,
),
);

if (createResult.isSuccess) {
final plan = createResult.data!;
print('βœ… Plan created successfully!');
print(' Plan Code: ${plan.planCode}');
print(' Plan ID: ${plan.id}');
print(' Name: ${plan.name}');
print(' Amount: ₦${(plan.amount! / 100).toStringAsFixed(2)}');
print(' Interval: ${plan.interval}');
return plan;
} else {
print('❌ Plan creation failed: ${createResult.message}');
return null;
}
}

/// Demonstrates listing subscription plans
static Future<void> listPlans() async {
print('\nπŸ”„ Fetching subscription plans...');

final sdk = MindPaystack.instance;

final listResult = await sdk.plan.list(
ListPlansOptions(
perPage: 10,
page: 1,
status: 'active',
),
);

if (listResult.isSuccess) {
final planList = listResult.data!;
print('βœ… Found ${planList.length} plans (${listResult.meta} total)');

if (listResult.data?.isEmpty ?? false) {
print(' No plans found. Create one first!');
return;
}

print(' Available Plans:');
for (int i = 0; i < planList.length; i++) {
final plan = planList[i];
print(' ${i + 1}. ${plan.name}');
print(' Code: ${plan.planCode}');
print(
' Amount: ₦${(plan.amount! / 100).toStringAsFixed(2)} per ${plan.interval}');
}
} else {
print('❌ Plan listing failed: ${listResult.message}');
}
}

/// Demonstrates fetching a specific plan
static Future<void> fetchPlan(String planIdOrCode) async {
print('\nπŸ”„ Fetching plan: $planIdOrCode');

final sdk = MindPaystack.instance;

final fetchResult = await sdk.plan.fetch(planIdOrCode);

if (fetchResult.isSuccess) {
final plan = fetchResult.data!;
print('βœ… Plan fetched successfully!');
print(' Name: ${plan.name}');
print(' Code: ${plan.planCode}');
print(' Amount: ₦${(plan.amount! / 100).toStringAsFixed(2)}');
print(' Interval: ${plan.interval}');
} else {
print('❌ Plan fetch failed: ${fetchResult.message}');
}
}

/// Demonstrates updating a subscription plan
static Future<void> updatePlan(String planIdOrCode) async {
print('\nπŸ”„ Updating plan: $planIdOrCode');

final sdk = MindPaystack.instance;

final updateResult = await sdk.plan.update(
planIdOrCode,
UpdatePlanOptions(
name: 'Premium Monthly Plan (Updated)',
amount: 600000, // ₦6,000 in kobo
description: 'Enhanced premium features with monthly billing',
),
);

if (updateResult.isSuccess) {
final updatedPlan = updateResult.data!;
print('βœ… Plan updated successfully!');
print(' New Name: ${updatedPlan.name}');
print(
' New Amount: ₦${(updatedPlan.amount! / 100).toStringAsFixed(2)}');
} else {
print('❌ Plan update failed: ${updateResult.message}');
}
}

/// Interactive menu for plan operations
static Future<void> showMenu() async {
while (true) {
print('\nπŸ“‹ Plan Management Demo');
print('1. Create a new plan');
print('2. List all plans');
print('3. Fetch a specific plan');
print('4. Update a plan');
print('5. Exit');
print('');
stdout.write('Choose an option (1-5): ');

final choice = stdin.readLineSync();

switch (choice) {
case '1':
await createPlan();
break;
case '2':
await listPlans();
break;
case '3':
stdout.write('Enter plan ID or code: ');
final planId = stdin.readLineSync();
if (planId?.isNotEmpty == true) {
await fetchPlan(planId!);
}
break;
case '4':
stdout.write('Enter plan ID or code to update: ');
final planId = stdin.readLineSync();
if (planId?.isNotEmpty == true) {
await updatePlan(planId!);
}
break;
case '5':
print('πŸ‘‹ Goodbye!');
return;
default:
print('❌ Invalid option. Please choose 1-5.');
}
}
}

/// Runs a complete demo of all plan operations
static Future<void> runCompleteDemo() async {
print('πŸš€ Running complete plan management demo...');

// Create a plan
final createdPlan = await createPlan();
if (createdPlan == null) return;

// List plans
await listPlans();

// Fetch the created plan
await fetchPlan(createdPlan.planCode!);

// Update the plan
await updatePlan(createdPlan.planCode!);

print('\nβœ… Complete demo finished!');
}
}
Loading