marco.pms.mobileapp/lib/controller/payment/payment_controller.dart

164 lines
4.4 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:marco/helpers/services/payment_service.dart';
import 'package:marco/helpers/services/app_logger.dart';
class PaymentController with ChangeNotifier {
final Razorpay _razorpay = Razorpay();
final PaymentService _paymentService = PaymentService();
bool isProcessing = false;
BuildContext? _context; // For showing dialogs/snackbars
PaymentController() {
// Razorpay event listeners
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
}
void disposeController() {
_razorpay.clear();
}
/// ==============================
/// START PAYMENT
/// ==============================
Future<void> startPayment({
required double amount,
required String description,
required BuildContext context,
}) async {
_context = context;
isProcessing = true;
notifyListeners();
logSafe("🟢 Starting payment for ₹$amount - $description");
// Call backend to create Razorpay order
final result = await _paymentService.createOrder(amount);
if (result == null) {
_showError(context, "Failed to connect to server.");
isProcessing = false;
notifyListeners();
return;
}
final orderId = result['orderId'];
final key = result['key'];
if (orderId == null || key == null) {
_showError(context, "Invalid response from server.");
isProcessing = false;
notifyListeners();
return;
}
var options = {
'key': key,
'amount': (amount * 100).toInt(), // Razorpay takes amount in paise
'name': 'Your Company Name',
'description': description,
'order_id': orderId,
'theme': {'color': '#0D47A1'},
'timeout': 120, // 2 minutes timeout
};
try {
logSafe("🟠 Opening Razorpay with options: $options");
_razorpay.open(options);
} catch (e) {
logSafe("❌ Error opening Razorpay: $e", level: LogLevel.error);
_showError(context, "Error opening payment gateway.");
isProcessing = false;
notifyListeners();
}
}
/// ==============================
/// EVENT HANDLERS
/// ==============================
void _handlePaymentSuccess(PaymentSuccessResponse response) async {
logSafe("✅ Payment Success: ${response.paymentId}");
isProcessing = true;
notifyListeners();
final result = await _paymentService.verifyPayment(
paymentId: response.paymentId!,
orderId: response.orderId!,
signature: response.signature!,
);
isProcessing = false;
notifyListeners();
if (result != null && result['verified'] == true) {
_showDialog(
title: "Payment Successful 🎉",
message: "Your payment was verified successfully.",
success: true,
);
} else {
_showDialog(
title: "Verification Failed ❌",
message: "Payment completed but could not be verified.",
success: false,
);
}
}
void _handlePaymentError(PaymentFailureResponse response) {
logSafe("❌ Payment Failed: ${response.message}");
isProcessing = false;
notifyListeners();
_showDialog(
title: "Payment Failed ❌",
message: "Reason: ${response.message ?? 'Unknown error'}",
success: false,
);
}
void _handleExternalWallet(ExternalWalletResponse response) {
logSafe(" External Wallet Used: ${response.walletName}");
}
/// ==============================
/// HELPER DIALOGS / SNACKBARS
/// ==============================
void _showDialog({
required String title,
required String message,
required bool success,
}) {
if (_context == null) return;
showDialog(
context: _context!,
builder: (ctx) => AlertDialog(
title: Text(title),
content: Text(message),
actions: [
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(ctx).pop();
if (success) {
Navigator.of(_context!).pop(true); // Return success
}
},
),
],
),
);
}
void _showError(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message), backgroundColor: Colors.red),
);
}
}