How to do a Razorpay integration in Flutter - flutter

I am able to deploy payment transaction but the server part is very hard. How can I create a orderid and how can we find the payment is done by a specific user?

Hope you set up all the necessary things.
Step 1: creating Order using Razorpay official Order Api:
void createOrder() async {
String username = 'xxxxxxxxxx';// razorpay pay key
String password = "xxxxxxxxxxxxxxxx";// razoepay secret key
String basicAuth =
'Basic ${base64Encode(utf8.encode('$username:$password'))}';
Map<String, dynamic> body = {
"amount": 1 * 100,
"currency": "INR",
"receipt": "rcptid_11"
};
var res = await http.post(
Uri.https(
"api.razorpay.com", "v1/orders"), //https://api.razorpay.com/v1/orders // Api provided by Razorpay Official 💙
headers: <String, String>{
"Content-Type": "application/json",
'authorization': basicAuth,
},
body: jsonEncode(body),
);
if (res.statusCode == 200) {
openCheckout(jsonDecode(res.body)['id']); // 😎🔥
}
print(res.body);
}
//*#################################################################
Step 2: Open Razorpay checkout interface.
After getting orderId from Razorpay official Api, pass the id when calling openCheckout(jsonDecode(res.body)['id']); function
void openCheckout(String orderId) async {
var options = {
'key': 'xxxxxxxxxxxxxxxx',
"amount": 1 * 100,
'order_id': orderId,
'name': 'main.co.in',
// 'prefill': {'contact': '', 'email': 'test#razorpay.com'},
'external': {
'wallets': ['paytm']
}
};
try {
razorpay.open(options);
} catch (e) {
debugPrint('Error: e');
}
}
3rd Step: Signature verification.
This is important if you automatically wanna transfer your amount to your bank account.
for Hmac SHA key , install this package: crypto:
handlerPaymentSuccess(PaymentSuccessResponse response) {
final key = utf8.encode('NgDLPyiDRPuQpcXy1E3GKTDv');
final bytes = utf8.encode('${response.orderId}|${response.paymentId}');
final hmacSha256 = Hmac(sha256, key);
final generatedSignature = hmacSha256.convert(bytes);
if (generatedSignature.toString() == response.signature) {
log("Payment was successful!");
//Handle what to do after a successful payment.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Success : payment successful"),
// content: const Text("Are you sure you wish to delete this item?"),
actions: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(true);
// PlaceOrderPrepaid();
},
child: Text("OK"))
// ),
],
);
},
);
} else {
log("The payment was unauthentic!");
}
}

Related

how to create redirect to login if not authorized in flutter

how to make if the user's token is expired or not authorized it will be redirected to the login page.
I have a problem when I login, if the user token is expired, it should be redirected to the login page, but in this case it doesn't return to the login page, instead it gives an 'exception' error message, is there a code I missed.
Thank you.
Future<User?> login(String nim, String password) async {
String url = Constant.baseURL;
try {
var body = {
'username': nim,
'password': password,
};
var response = await http.post(
Uri.parse(
'$url/login_mhs',
),
body: body,
);
if (response.statusCode == 200) {
final token = jsonDecode(response.body)['data']['access_token'];
await UtilSharedPreferences.setToken(token);
print(token);
print(await UtilSharedPreferences.getToken());
return User.fromJson(jsonDecode(response.body));
} else {
return null;
}
} catch (e) {
print(e);
throw Exception();
}
}
and this when doing get data
Future<UserBiodata> getDataMahasiswa() async {
String url = Constant.baseURL;
String token = await UtilSharedPreferences.getToken();
final response = await http.get(
Uri.parse(
'$url/auth/mhs_siakad/biodata',
),
headers: {
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
return UserBiodata.fromJson(jsonDecode(response.body));
} else {
throw Exception();
}
}
this when calling it in the widget
TextButton(
onPressed: () async {
final prefs =
await SharedPreferences.getInstance();
prefs.setString(Constant.token, '');
if (nimController.text.isEmpty ||
passwordController.text.isEmpty) {
showError('NIM tidak sesuai');
} else {
setState(() {
isLoading = true;
});
User? user = await Provider.of<Services>(
context,
listen: false)
.login(nimController.text,
passwordController.text);
setState(() {
isLoading = false;
});
if (user == null) {
showError('NIM/Password tidak sesuai');
} else {
userProvider.user = user;
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);
}
}
},
style: TextButton.styleFrom(
backgroundColor: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(66),
),
),
child: Text(
"Login",
style: boldButton,
),
),
this is the result when I have a user whose token is expired or not authorized the result is like this
Use another if else condition (nested into your else of the event) like below:
if (user == null) {
showError('NIM/Password tidak sesuai');
} else {
if (token_is_not_found_equals_true){
Navigator.pushNamedAndRemoveUntil(
context,
'/login',
(route) => false,
);
}
else {
userProvider.user = user;
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);
}
}
The way I handle is using the package flutter_modular, there you have a feature call Route Guard. You check details in it's documentation. It's very easy to understand and implement.
I think it's the cleanest way to handle users unauthorized users.

Paypal Order API capture payment in Angular and NestJS

My stack is NestJS and Angular12, I am using the OrderAPI v2.
I succesfully implemented the order flow using an SDK button, but, since I have several payment systems that are activated by a single button "Pay now", I need to avoid SDK in my front end. Follows the methods I use to create and capture payments, and they works with the SDK button.
async createOrder(value: number): Promise<any> {
const accessToken = await this.generateAccessToken();
const url = this.baseUrl+`/v2/checkout/orders`;
const body = {
intent: "CAPTURE",
return_url: process.env.CLIENT+"/success",
purchase_units: [
{
amount: {
currency_code: "EUR",
value: value.toFixed(2)
}
}
]
}
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`
}
const obs = this.httpService.post(url, JSON.stringify(body),{headers: headers});
const response = await firstValueFrom(obs);
return response.data;
}
async capturePayment(order: CreateOrderDto, orderId: string): Promise<any> {
const accessToken = await this.generateAccessToken();
const url = this.baseUrl+`/v2/checkout/orders/${orderId}/capture`;
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`
}
const obs = this.httpService.post(
url,
{},
{
headers: headers
}
)
const response = await firstValueFrom(obs);
if (response.data.success) await this.orderService.createOrder(order)
return response.data;
}
When calling the createOrder() function I return the url of the approvation, and in my Front-end I do the redirect to the approve page of Paypal. The problem is that when approving the transaction on the approve url the user is shown a infinite loading page.
Is there something I am missing?

Flutter Stripe paymentsheet is opening webpage (hooks.stripe.com) while processing payments

I am developing a flutter application which uses stripe for payments. I am using https://pub.dev/packages/flutter_stripe for this.
Everything is working fine but whenever I initiate payments I always get a webpage middleware (Screenshots attached). What am I doing wrong?
Here is my implementation in Flutter
Future<void> makePayment(String planName, String type) async {
Fluttertoast.showToast(msg: "initiating Payments, Please wait.");
ApiProvider provider = ApiProvider();
final tokenResponse = await provider
.getPaymentToken(PlanPayment(planName: planName, type: type));
if (tokenResponse != null) {`
var _service = locator<NavigationService>();
String secret = tokenResponse.clientSecret;
// make a get call from this url
Map<String, dynamic> paymentIntentData = Map();
await payment.Stripe.instance.initPaymentSheet(
paymentSheetParameters: payment.SetupPaymentSheetParameters(
merchantCountryCode: 'IN',
testEnv: true,
paymentIntentClientSecret: secret,
googlePay: true,
));
try {
// await Stripe.instance.handleCardAction(secret);
await payment.Stripe.instance.presentPaymentSheet().then((value) {});
await payment.Stripe.instance
.confirmPaymentSheetPayment()
.then((value) async {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': true});
});
} catch (e) {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': false});
print("Stripe error" + e.toString());
}
await provider
.confirmPayment(tokenResponse.transactionId)
.then((value) async {
await _service
.pushReplacementNamed(paymentStatus, args: {"isSuccess": value});
});
}
}
`
Maybe you have a webhook put in your account?
1)Provide valid Secret key
2)Provide valid Publisable key
3)Update flutterstripe pacakge
4)provide valid currency code to create stripe account country
ex :- stripe account create india to inr etc..
5)Right Way to implemet
- Main.dart to main method run app to implemet
ex :--
Stripe.publishableKey = "your publishable key ";
- create controller / method
code:-
Map<String, dynamic>? paymentIntentData;
Future<void> makePayment({amount}) async {
try {
paymentIntentData =
await createPaymentIntent(amount: amount, currency: 'INR');
if (paymentIntentData != null) {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// applePay: true,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'INR'),
merchantDisplayName: "PGA",
customerId: paymentIntentData!['customer'],
paymentIntentClientSecret: paymentIntentData!['client_secret'],
customerEphemeralKeySecret: paymentIntentData!['ephemeralkey'],
));
}
displayPaymentSheet();
} catch (err) {
logger.e(err);
}
}
void displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
Get.snackbar("PaymentInfo", "Payment Successfully");
} on Exception catch (e) {
if (e is StripeException) {
logger.e(e, "Error From Stripe");
} else {
logger.e(e, "Unforeseen error");
}
} catch (e) {
logger.e("exeption === $e");
}
}
var id = "";
createPaymentIntent({amount, currency}) async {
try {
Map<String, dynamic> body = {
'amount': calculateAmount(amount: amount),
'currency': currency,
'payment_method_types[]': 'card'
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer YourSecretKey',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
logger.e(decode);
id = decode['id'];
return decode;
}
} catch (e) {
logger.e(e, "error charging user");
}
}
calculateAmount({amount}) {
logger.e(amount.round());
final a = (int.parse(amount.toString())) * 100;
logger.e(a.toString());
update();
return a.toString();
}
6) How to Access Stripe payment :-
ex :- any button click
ontap : (){
makePayment(
amount: "200")
}

How to pass data to cloud function file in flutter

I am new to flutter and I have just created app that accepts payments from user using flutter_stripe: ^2.1.0 plugin. The amount in cloud function file index.js is fixed but I want to pass the amount that is calculated dynamically. Here is my code.
Future<void> makePayment() async {
final url = Uri.parse(
'https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment');
final response =
await http.get(url, headers: {"Content-Type": "application/json"});
paymentIntentData = json.decode(response.body);
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['paymentIntent'],
applePay: true,
googlePay: true,
style: ThemeMode.light,
merchantCountryCode: 'US',
merchantDisplayName: 'Kleen My Car',
),
);
setState(() {});
displayPaymentSheet();
}
Future<void> displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet(
parameters: PresentPaymentSheetParameters(
clientSecret: paymentIntentData['paymentIntent'],
confirmPayment: true));
setState(() {
paymentIntentData = null;
});
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Payment succeeded')));
} catch (e) {
print('error error error');
}
}
and here is my index.js file's code
const functions = require("firebase-functions");
const stripe = require("stripe")(functions.config().stripe.testkey);
exports.stripePayment = functions.https.onRequest(async (req, res) => {
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
function (err, paymentIntent) {
if (err != null) {
console.log(err);
} else {
res.json({
paymentIntent: paymentIntent.client_secret,
});
}
}
);
});
Any kind of help is much appreciated. Thank you so much!
You need to adapt this line:
final response = await http.get(url, headers: {"Content-Type": "application/json"});
(Firstly, it makes no sense to give a content type on a GET, as GETs don't have any content. Remove that header.)
You could change to a POST and add the amount as a parameter, or leave it as a GET and add the amount to the URL.
With a POST, add (for example) body: {'amount': amount.toString()}
With a GET, add it to the URL, as follows:
final uri = Uri.https('us-central1-carwashapp-376b6.cloudfunctions.net', '/stripepayment', {'amount': amount.toString()});
In your cloud function access amount from the req. (For example, in the GET example, it would be req.query.amount as string.)
We also pass up other parameters like email, unique order id (to be used as the idempotency key), etc.
in index.js file change
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
to
const paymentIntent = await stripe.paymentIntents.create(
{
amount: req.query.amount,
currency: req.query.currency,
},
and deploy your function.
after that, in makepayment function, change your URL to
https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment?amount=$amount&currency=$currency.
In this way, you can pass different amounts every time by changing the value of $amount variable in the URL.

Add two in Function to a button Flutter

how can I add two function to a single button?
I have a button that sends a request to a server and I would like to add a Dialog after sending the request... I tried this:
onPressed: () {
_makePostRequest();
showAlertDialog(context);
},
But still not working...
The post code:
_makePostRequest() async {
final url = Uri.parse('http://127.0.0.1/API');
final headers = {"Content-type": "application/json"};
final json = '{"id": "1", "status": "1"}';
final response = await post(url, headers: headers, body: json);
final statusCode = response.statusCode;
final body = response.body;
}
The Show Dialog code:
void showAlertDialog(BuildContext context) {
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {},
);
AlertDialog alert = AlertDialog(
title: Text("PMZ Label Print"),
content: Text("Label is printing..."),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Try to below code
Your Button
onPressed:(){
_makePostRequest();
}
Your API Call
_makePostRequest() async {
final url = Uri.parse('http://127.0.0.1/API');
final headers = {"Content-type": "application/json"};
final json = '{"id": "1", "status": "1"}';
final response = await post(url, headers: headers, body: json);
final statusCode = response.statusCode;
final body = response.body;
//your alert function call
if (response.statusCode == 200) {
showAlertDialog(context);
} else {
print(
"Error",
);
}
}
I have try above code and my code is working
you just need to add async on onPressed.
onPressed: ()async {
await _makePostRequest();
showAlertDialog(context);
},
_makePostRequest is of type Future so you can use 2 ways :
First one:
onPress:(){
_makePostRequest().then((v){
showAlertDialog(context);
});
}
Second one:
onPress:()await {
await YourFunction();
showAlertDialog(context);
}