Code committed
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
class APIURL {
|
||||
static const BASE_URL = "http://210.89.44.183:3333/xam/";
|
||||
static const BASE_URL = "https://www.mv.frontshopemporium.in/xam/";
|
||||
static const String sendOtp = "${BASE_URL}auth/send-otp/customer";
|
||||
static const String verifyOtp = "${BASE_URL}auth/verify-otp/customer";
|
||||
static const String loginOtp = "${BASE_URL}auth/login/customer";
|
||||
static const String login = "${BASE_URL}auth/login/vendor";
|
||||
static const String customerRegister = "${BASE_URL}auth/register/customer";
|
||||
static const String getAllProduct = "${BASE_URL}products";
|
||||
static const String getAllProduct = "${BASE_URL}products?order=home";
|
||||
static const String getProductDetails = "${BASE_URL}products/";
|
||||
static const String getBanners = "${BASE_URL}banners";
|
||||
static const String customerLogOut = "${BASE_URL}auth/logout/customer";
|
||||
@@ -39,6 +39,8 @@ class APIURL {
|
||||
static const String getProduct = "${BASE_URL}products";
|
||||
static const String getCategoryByLevel = "${BASE_URL}categories/by-level/1";
|
||||
static const String getMe = "${BASE_URL}auth/me";
|
||||
static const String distanctByProduct = "${BASE_URL}distance/delivery-charges-by-distance";
|
||||
|
||||
|
||||
static const String createProduct = "${BASE_URL}products";
|
||||
|
||||
@@ -50,6 +52,7 @@ class APIURL {
|
||||
static const String updateStatus = "${BASE_URL}orders/items/";
|
||||
static const String checkAddress = "${BASE_URL}distance/by-address/";
|
||||
|
||||
|
||||
static const String productReview = "${BASE_URL}products/";
|
||||
|
||||
static const String upDateDeviceToken = "${BASE_URL}devices/register";
|
||||
|
||||
@@ -377,75 +377,66 @@ class AddtocartProvider extends ChangeNotifier {
|
||||
|
||||
////////////////////////////COD ////////////
|
||||
|
||||
Future<void> paymentCODOrder(
|
||||
BuildContext context,
|
||||
double subtotal,
|
||||
int deliverCharge,
|
||||
String couponId,
|
||||
String addressId,
|
||||
) async {
|
||||
Future<bool> paymentCODOrder(
|
||||
BuildContext context,
|
||||
double subtotal,
|
||||
int deliverCharge,
|
||||
String couponId,
|
||||
String addressId,
|
||||
) async {
|
||||
ispaymentLoader = true;
|
||||
notifyListeners();
|
||||
var data;
|
||||
if (couponId.isNotEmpty) {
|
||||
data = {
|
||||
"addressId": addressId,
|
||||
"paymentMethod": "COD",
|
||||
"paymentStatus": "PENDING",
|
||||
"orderStatus": "PENDING",
|
||||
"subtotal": subtotal,
|
||||
"deliveryCharge": deliverCharge,
|
||||
"transactionId": "phonepe_transaction_123",
|
||||
"couponId": couponId
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
"addressId": addressId,
|
||||
"paymentMethod": "COD",
|
||||
"paymentStatus": "PENDING",
|
||||
"orderStatus": "PENDING",
|
||||
"subtotal": subtotal,
|
||||
"deliveryCharge": deliverCharge,
|
||||
};
|
||||
}
|
||||
|
||||
print("kjfhxgkljfhg ${data}");
|
||||
var data = {
|
||||
"addressId": addressId,
|
||||
"paymentMethod": "COD",
|
||||
"paymentStatus": "PENDING",
|
||||
"orderStatus": "PENDING",
|
||||
"subtotal": subtotal,
|
||||
"deliveryCharge": deliverCharge,
|
||||
};
|
||||
|
||||
if (couponId.isNotEmpty) {
|
||||
data["couponId"] = couponId;
|
||||
data["transactionId"] = "phonepe_transaction_123";
|
||||
}
|
||||
|
||||
try {
|
||||
var result = await _homeRepo.paymentCODOrder(data);
|
||||
|
||||
return result.fold(
|
||||
(error) {
|
||||
(error) {
|
||||
Fluttertoast.showToast(
|
||||
msg: "${error.message}",
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: Colors.red,
|
||||
textColor: Colors.white,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
ispaymentLoader = false;
|
||||
notifyListeners();
|
||||
return false;
|
||||
},
|
||||
(response) {
|
||||
context.clearAndPush(routePath: MyRoutes.SUCCESSPAYMENT);
|
||||
|
||||
(response) {
|
||||
ispaymentLoader = false;
|
||||
notifyListeners();
|
||||
return true;
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
ispaymentLoader = false;
|
||||
notifyListeners();
|
||||
|
||||
Fluttertoast.showToast(
|
||||
msg: "${e}",
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: Colors.red,
|
||||
textColor: Colors.white,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
notifyListeners();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:grocery_app/src/common_widget/name_text_field.dart';
|
||||
import 'package:grocery_app/src/common_widget/network_image.dart';
|
||||
import 'package:grocery_app/src/logic/provider/addTocart_provider.dart';
|
||||
import 'package:grocery_app/src/ui/payment/phonepe_payment.dart';
|
||||
import 'package:grocery_app/utils/constants/assets_constant.dart';
|
||||
import 'package:grocery_app/utils/constants/color_constant.dart';
|
||||
import 'package:grocery_app/utils/extensions/uicontext.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../payment/razorpay_payment.dart';
|
||||
|
||||
class CardCheckoutScreen extends StatefulWidget {
|
||||
int deliveryCharge;
|
||||
// String currency;
|
||||
@@ -15,7 +19,7 @@ class CardCheckoutScreen extends StatefulWidget {
|
||||
// String name;
|
||||
// String phone;
|
||||
// String email;
|
||||
// String userId;
|
||||
String userId;
|
||||
String cartId;
|
||||
String addressId;
|
||||
// String remarks;
|
||||
@@ -30,7 +34,7 @@ class CardCheckoutScreen extends StatefulWidget {
|
||||
// required this.name,
|
||||
// required this.phone,
|
||||
// required this.email,
|
||||
// required this.userId,
|
||||
required this.userId,
|
||||
required this.cartId,
|
||||
required this.addressId,
|
||||
// required this.remarks,
|
||||
@@ -84,7 +88,7 @@ class _CardCheckoutScreenState extends State<CardCheckoutScreen> {
|
||||
),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
/* onTap: () {
|
||||
if (paymentProvider.selectedPaymentMethod == "Online") {
|
||||
print("dsjfkhkdfhgdkfghdfg");
|
||||
paymentProvider.orderPaymnet(
|
||||
@@ -93,7 +97,8 @@ class _CardCheckoutScreenState extends State<CardCheckoutScreen> {
|
||||
widget.cartId,
|
||||
widget.addressId,
|
||||
widget.couponId!);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
paymentProvider.paymentCODOrder(
|
||||
context,
|
||||
widget.originalAmount,
|
||||
@@ -102,6 +107,68 @@ class _CardCheckoutScreenState extends State<CardCheckoutScreen> {
|
||||
widget.addressId,
|
||||
);
|
||||
}
|
||||
},*/
|
||||
onTap: (){
|
||||
if(paymentProvider.selectedPaymentMethod!=null) {
|
||||
if (paymentProvider.selectedPaymentMethod ==
|
||||
"razorpay") {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
RazorpayPaymentScreen(
|
||||
amount: widget.originalAmount +
|
||||
widget.deliveryCharge,
|
||||
cartId: widget.cartId,
|
||||
addressId: widget.addressId,
|
||||
couponId: widget.couponId,
|
||||
userId: widget.userId,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (paymentProvider.selectedPaymentMethod ==
|
||||
"phonepe") {
|
||||
// Navigate to PhonePe screen (optional for now)
|
||||
// Replace this when you implement PhonePe
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
PhonePePaymentScreen(
|
||||
amount: widget.originalAmount +
|
||||
widget.deliveryCharge,
|
||||
cartId: widget.cartId,
|
||||
addressId: widget.addressId,
|
||||
//couponId: widget.couponId,
|
||||
userId: widget.userId,
|
||||
),
|
||||
),
|
||||
);
|
||||
/* ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("PhonePe integration coming soon")),
|
||||
);*/
|
||||
} /*
|
||||
else {
|
||||
paymentProvider.paymentCODOrder(
|
||||
context,
|
||||
widget.originalAmount,
|
||||
widget.deliveryCharge,
|
||||
widget.couponId ?? "",
|
||||
widget.addressId,
|
||||
);
|
||||
}*/
|
||||
}else
|
||||
{
|
||||
Fluttertoast.showToast(
|
||||
msg: "Select Payment method",
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
textColor: Colors.white,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
@@ -173,16 +240,34 @@ class _CardCheckoutScreenState extends State<CardCheckoutScreen> {
|
||||
),
|
||||
SizedBox(height: 0),
|
||||
|
||||
ListTile(
|
||||
/* ListTile(
|
||||
leading: Icon(Icons.payment, color: Colors.blue),
|
||||
title: Text("Online Payment"),
|
||||
trailing: paymentProvider.selectedPaymentMethod == "Online"
|
||||
? Icon(Icons.check_circle, color: Colors.green)
|
||||
: null,
|
||||
onTap: () {
|
||||
paymentProvider.selectPaymentMethod("Online");
|
||||
// paymentProvider.selectPaymentMethod("Online");
|
||||
// Navigator.pop(context);
|
||||
},
|
||||
),*/
|
||||
|
||||
RadioListTile<String>(
|
||||
value: "razorpay",
|
||||
groupValue: paymentProvider.selectedPaymentMethod,
|
||||
title: const Text("Razorpay Online Payment"),
|
||||
onChanged: (value) {
|
||||
paymentProvider.selectPaymentMethod(value!);
|
||||
},
|
||||
),
|
||||
|
||||
RadioListTile<String>(
|
||||
value: "phonepe",
|
||||
groupValue: paymentProvider.selectedPaymentMethod,
|
||||
title: const Text("PhonePe Online Payment"),
|
||||
onChanged: (value) {
|
||||
paymentProvider.selectPaymentMethod(value!);
|
||||
},
|
||||
),
|
||||
|
||||
// Cash on Delivery (COD) Option
|
||||
@@ -404,3 +489,4 @@ class _CardCheckoutScreenState extends State<CardCheckoutScreen> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
@@ -15,6 +17,7 @@ import 'package:grocery_app/src/ui/widgets/elevated_button.dart';
|
||||
import 'package:grocery_app/utils/constants/color_constant.dart';
|
||||
import 'package:grocery_app/utils/constants/shared_pref_utils.dart';
|
||||
import 'package:grocery_app/utils/extensions/uicontext.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -1006,6 +1009,8 @@ class _MycartState extends State<Mycart> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _showAddressBottomSheet(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
@@ -1140,6 +1145,67 @@ class AddressBottomSheet extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AddressBottomSheetState extends State<AddressBottomSheet> {
|
||||
Future<String?> fetchDeliveryMessage() async {
|
||||
const String url = 'https://www.mv.frontshopemporium.in/xam/distance/delivery-charges-by-distance';
|
||||
|
||||
try {
|
||||
final response = await http.get(Uri.parse(url), headers: {
|
||||
"Content-Type": "application/json",
|
||||
"authorization": "Bearer ${await SharedPrefUtils.getToken()}"
|
||||
});
|
||||
|
||||
print('continue response');
|
||||
print(response.statusCode);
|
||||
print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
|
||||
final Map<String, dynamic> data = json.decode(response.body);
|
||||
print(data);
|
||||
final List<dynamic> nonDeliverableProducts = data['nonDeliverableProducts'] ?? [];
|
||||
if (nonDeliverableProducts.isNotEmpty) {
|
||||
final String reason = nonDeliverableProducts[0]['reason'];
|
||||
print(reason);
|
||||
return reason;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
return 'Failed with status: ${response.statusCode}';
|
||||
}
|
||||
} catch (e) {
|
||||
return 'Error: $e';
|
||||
}
|
||||
}
|
||||
Future<String?> setDefaultAddress(String addressId) async {
|
||||
String url = 'https://www.mv.frontshopemporium.in/xam/user/addresses/${addressId}/set-default';
|
||||
|
||||
try {
|
||||
final response = await http.put(Uri.parse(url), headers: {
|
||||
"Content-Type": "application/json",
|
||||
"authorization": "Bearer ${await SharedPrefUtils.getToken()}"
|
||||
});
|
||||
|
||||
print('address response');
|
||||
print(response.statusCode);
|
||||
print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
|
||||
/* final Map<String, dynamic> data = json.decode(response.body);
|
||||
print(data);
|
||||
final List<dynamic> nonDeliverableProducts = data['nonDeliverableProducts'] ?? [];
|
||||
if (nonDeliverableProducts.isNotEmpty) {
|
||||
final String reason = nonDeliverableProducts[0]['reason'];
|
||||
return reason;
|
||||
} else {
|
||||
return 'No non-deliverable products found';
|
||||
}*/
|
||||
} else {
|
||||
return 'Failed with status: ${response.statusCode}';
|
||||
}
|
||||
} catch (e) {
|
||||
return 'Error: $e';
|
||||
}
|
||||
}
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
@@ -1186,8 +1252,8 @@ class _AddressBottomSheetState extends State<AddressBottomSheet> {
|
||||
Consumer<AddtocartProvider>(
|
||||
builder: (context, paymentProvider, child) {
|
||||
return ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
if (paymentProvider.selectedAddress.isNotEmpty) {
|
||||
onPressed: () async{
|
||||
/* if (paymentProvider.selectedAddress.isNotEmpty) {
|
||||
if (paymentProvider.isDeliverable) {
|
||||
Navigator.pop(context);
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
@@ -1200,7 +1266,7 @@ class _AddressBottomSheetState extends State<AddressBottomSheet> {
|
||||
// name: paymentProvider.selecteUserName,
|
||||
// phone: paymentProvider.selecteUserPhone,
|
||||
// email: paymentProvider.selecteEmail,
|
||||
// userId: paymentProvider.allitem.userId!,
|
||||
userId: paymentProvider.allitem.userId!,
|
||||
cartId: paymentProvider.allitem.id!,
|
||||
addressId: paymentProvider.selectedAddress,
|
||||
// remarks: paymentProvider.selecteUserName,
|
||||
@@ -1229,17 +1295,97 @@ class _AddressBottomSheetState extends State<AddressBottomSheet> {
|
||||
textColor: Colors.white,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
}*/
|
||||
|
||||
// Call your API and get the message
|
||||
String? message = await fetchDeliveryMessage(); // Use the function from earlier
|
||||
|
||||
if (message != null && message.isNotEmpty) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text("Alert"),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close the dialog
|
||||
},
|
||||
child: Text("OK"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Navigator.pop(context);
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CardCheckoutScreen(
|
||||
deliveryCharge: paymentProvider.getdeliverycharge,
|
||||
originalAmount: paymentProvider.grandPrice,
|
||||
userId: paymentProvider.allitem.userId!,
|
||||
cartId: paymentProvider.allitem.id!,
|
||||
addressId: paymentProvider.selectedAddress,
|
||||
couponId: paymentProvider.couponId,
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
/*
|
||||
|
||||
// Call your API and get the message
|
||||
await paymentProvider.paymentCODOrder(
|
||||
context,
|
||||
paymentProvider.grandPrice,
|
||||
paymentProvider.getdeliverycharge,
|
||||
paymentProvider.couponId ?? "",
|
||||
paymentProvider.selectedAddress,
|
||||
);
|
||||
|
||||
*/
|
||||
/* if (message != null && message.isNotEmpty) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
backgroundColor: Colors.red,
|
||||
textColor: Colors.white,
|
||||
fontSize: 14.0,
|
||||
);
|
||||
} else {*/
|
||||
/*
|
||||
Navigator.pop(context);
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CardCheckoutScreen(
|
||||
deliveryCharge: paymentProvider.getdeliverycharge,
|
||||
originalAmount: paymentProvider.grandPrice,
|
||||
userId: paymentProvider.allitem.userId!,
|
||||
cartId: paymentProvider.allitem.id!,
|
||||
addressId: paymentProvider.selectedAddress,
|
||||
couponId: paymentProvider.couponId,
|
||||
);
|
||||
},
|
||||
));
|
||||
// }
|
||||
|
||||
|
||||
},*/
|
||||
label: Text(
|
||||
"Continue",
|
||||
style: TextStyle(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: paymentProvider.isDeliverable
|
||||
backgroundColor:Colors.green,
|
||||
/*backgroundColor: paymentProvider.isDeliverable
|
||||
? Colors.green
|
||||
: Colors.grey,
|
||||
minimumSize: Size(double.infinity, 50),
|
||||
*/minimumSize: Size(double.infinity, 50),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
@@ -1278,12 +1424,13 @@ class _AddressBottomSheetState extends State<AddressBottomSheet> {
|
||||
activeColor: Colors.green,
|
||||
onChanged: (value) {
|
||||
addressProvider.checkAddress(context, value);
|
||||
|
||||
setDefaultAddress(address.id);
|
||||
addressProvider.selectAddress(
|
||||
value.toString(),
|
||||
address.phoneNumber,
|
||||
address.name,
|
||||
address.user!.email);
|
||||
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
|
||||
@@ -59,7 +59,7 @@ class _MyOrderScreenState extends State<MyOrderScreen> {
|
||||
width: 20,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.clearAndPush(routePath: MyRoutes.BOTTOMNAV);
|
||||
context.clearAndPush(routePath: MyRoutes.HOME);
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
APPASSETS.back,
|
||||
|
||||
271
lib/src/ui/payment/phonepe_payment.dart
Normal file
271
lib/src/ui/payment/phonepe_payment.dart
Normal file
@@ -0,0 +1,271 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:phonepe_payment_sdk/phonepe_payment_sdk.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import 'package:app_links/app_links.dart';
|
||||
import '../../../utils/constants/shared_pref_utils.dart';
|
||||
import '../../core/routes/routes.dart';
|
||||
import '../myOrder/my_order.dart';
|
||||
class PhonePePaymentScreen extends StatefulWidget {
|
||||
final double amount;
|
||||
final String cartId;
|
||||
final String addressId;
|
||||
final String userId;
|
||||
|
||||
const PhonePePaymentScreen({
|
||||
required this.amount,
|
||||
required this.cartId,
|
||||
required this.addressId,
|
||||
required this.userId,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PhonePePaymentScreen> createState() => _PhonePePaymentScreenState();
|
||||
}
|
||||
|
||||
class _PhonePePaymentScreenState extends State<PhonePePaymentScreen> {
|
||||
String _statusMessage = "Initiating payment...";
|
||||
bool _isLoading = true;
|
||||
|
||||
final AppLinks _appLinks = AppLinks();
|
||||
StreamSubscription<Uri>? _linkSub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_listenForRedirect();
|
||||
_initiateAndStartPayment();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_linkSub?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _listenForRedirect() {
|
||||
print("Listening for redirect...");
|
||||
_linkSub = _appLinks.uriLinkStream.listen((Uri uri) {
|
||||
print("Deep link received: $uri");
|
||||
final transactionId = uri.queryParameters['transactionId'];
|
||||
final status = uri.queryParameters['status'];
|
||||
|
||||
if (transactionId != null && status == "SUCCESS") {
|
||||
//_verifyPayment(transactionId);
|
||||
} else if (status == "CANCEL") {
|
||||
setState(() {
|
||||
_statusMessage = "Payment cancelled by user.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // 👈 Return failure
|
||||
} else {
|
||||
setState(() {
|
||||
_statusMessage = "Payment failed or unknown status.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // 👈 Return failure
|
||||
}
|
||||
}, onError: (err) {
|
||||
print("Deep link error: $err");
|
||||
setState(() {
|
||||
_statusMessage = "Error handling redirect: $err";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // 👈 Return failure
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _initiateAndStartPayment() async {
|
||||
try {
|
||||
final uri = Uri.parse("https://www.mv.frontshopemporium.in/xam/payment/phonepe/sdk/initiate");
|
||||
|
||||
print("Calling backend initiate API...");
|
||||
final response = await http.post(
|
||||
uri,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"authorization": "Bearer ${await SharedPrefUtils.getToken()}",
|
||||
},
|
||||
body: jsonEncode({
|
||||
"amount": widget.amount,
|
||||
"cartId": widget.cartId,
|
||||
"addressId": widget.addressId,
|
||||
}),
|
||||
);
|
||||
|
||||
print("Response code: ${response.statusCode}");
|
||||
print("Response body: ${response.body}");
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 201) {
|
||||
setState(() {
|
||||
_statusMessage = "Failed to initiate payment.";
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final data = jsonDecode(response.body);
|
||||
final String? orderId = data['orderId'];
|
||||
final String? merchantId = data['merchantId'];
|
||||
final String? token = data['token'];
|
||||
|
||||
const String environment = "PRODUCTION";
|
||||
const String appSchema = "frontshop";
|
||||
final String flowId = 'FLWID_${Uuid().v4()}';
|
||||
|
||||
if (orderId == null || merchantId == null || token == null) {
|
||||
print("Invalid response from backend. Missing fields.");
|
||||
setState(() {
|
||||
_statusMessage = "Invalid response from backend.";
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
print("Initializing SDK...");
|
||||
|
||||
PhonePePaymentSdk.init(environment, merchantId, flowId, true);
|
||||
|
||||
final payload = {
|
||||
"orderId": orderId,
|
||||
"merchantId": merchantId,
|
||||
"token": token,
|
||||
"paymentMode": {"type": "PAY_PAGE"},
|
||||
};
|
||||
String request = jsonEncode(payload);
|
||||
|
||||
print("Starting transaction with payload: $request");
|
||||
|
||||
final result = await PhonePePaymentSdk.startTransaction(request, appSchema);
|
||||
print("Transaction result: $result");
|
||||
|
||||
if (result != null) {
|
||||
final status = result['status']?.toString() ?? '';
|
||||
final error = result['error']?.toString() ?? '';
|
||||
|
||||
if (status == 'SUCCESS') {
|
||||
final txnId = data['merchantOrderId']?? '';
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Payment Successful!")),
|
||||
);
|
||||
_verifyPayment(txnId);
|
||||
context.push(MyRoutes.MYORDER);
|
||||
} else if (status == 'CANCELLED') {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Payment Cancelled by User")),
|
||||
);
|
||||
setState(() {
|
||||
_statusMessage = "Payment cancelled.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Payment Failed: $error")),
|
||||
);
|
||||
setState(() {
|
||||
_statusMessage = "Payment failed.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false);
|
||||
}
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("No response from PhonePe")),
|
||||
);
|
||||
setState(() {
|
||||
_statusMessage = "No response.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
print("Error during payment: $e");
|
||||
setState(() {
|
||||
_statusMessage = "Error: ${e.toString()}";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // 👈 Exit with failure
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _verifyPayment(String transactionId) async {
|
||||
try {
|
||||
|
||||
|
||||
|
||||
final verifyUri = Uri.parse(
|
||||
"https://mv.frontshopemporium.in/xam/payment/phonepe/sdk/status/$transactionId",
|
||||
);
|
||||
|
||||
final response = await http.get(
|
||||
verifyUri,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"authorization": "Bearer ${await SharedPrefUtils.getToken()}",
|
||||
},
|
||||
);
|
||||
|
||||
print("Status check response: ${response.body}");
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final statusData = jsonDecode(response.body);
|
||||
final paymentStatus = statusData['status'];
|
||||
|
||||
if (paymentStatus == "SUCCESS") {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Order Placed Successfully")),
|
||||
);
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => MyOrderScreen()),
|
||||
(route) => false,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
setState(() {
|
||||
_statusMessage = "Payment verification failed: $paymentStatus";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // ❌ Return failure
|
||||
}
|
||||
} else {
|
||||
setState(() {
|
||||
_statusMessage = "Failed to verify payment.";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false);
|
||||
}
|
||||
} catch (e) {
|
||||
print("Verification error: $e");
|
||||
setState(() {
|
||||
_statusMessage = "Verification error: ${e.toString()}";
|
||||
_isLoading = false;
|
||||
});
|
||||
Navigator.pop(context, false); // ❌ Return failure
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text("PhonePe Payment")),
|
||||
body: Center(
|
||||
child: _isLoading
|
||||
? const CircularProgressIndicator()
|
||||
: Text(
|
||||
_statusMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user