This commit is contained in:
Hamza Aleghwairyeen
2024-04-21 01:26:42 +03:00
parent 731769edc0
commit a2d1479513
18 changed files with 1087 additions and 117 deletions

2
.env
View File

@@ -12,7 +12,7 @@ chatGPTkeySeferNew=zg-Z4AJcAROgNXjgrEIU8fKC9XrxgUE4Qtrrlq1yiux0jL3dITSXrXlBl
secretKey=zg_ropj_57Iiv6MFCBFq3C2n6IXlmjykpxDmW93SW3vvXh68UA9T5FORTWgWsT37StKsOPdwDdsy8qR9srMUluahs3nPHvgBa33tGk90vV5XrXlBl
stripe_publishableKe=vg_ropj_57Iiv6MFCBFq3C2n6kNJnZByV6nuDtXe9IjEPOfhmpDtWmt3MLR0gQpiHcQmAFMUPrZc3QiCDjxBZLbxDC3efxWxz33bWH1ZgrsXrXlBl
llamaKey=RR-EuyoFDUvfRDBj46fZKAtKJ3voM8Mt768cPeJV7GNdAkPTKdY8Odm9n4ggGqI5GyoXrXlBl
serverPHP=https://ride.mobile-app.store
serverPHP=https://api.sefer.live/sefer/
cohere=Aulwd8y5SPWos0hJhG0toUf8gOhUUrpf5Q2TPmVGXrXlBl
claudeAiAPI=zg-qbc-qvo39-xWOxIGwWTOzCFBnIYSKKhfyz_KVAvrH-6_4ZEJL68G_QBH26oeTOMMoQug9KuOjjKSP_A4S3SUDlbxR9duVzoQ-MkX_UQQQXrXlBl
payPalClientId=QALymfNI5Tzt4s-ysoz6vD4_nqX0SUtkC_qYV-Ugk5gaM_8Z-kg4L53k8Uux_4jEWXDkNpXGSWPpIzDFXrXlBl

View File

@@ -1,7 +1,7 @@
import 'package:SEFER/env/env.dart';
class AppLink {
static final String server = Env.serverPHP;
static final String server = 'https://api.sefer.live/sefer'; // Env.serverPHP;
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
static String llama = 'https://api.llama-api.com/chat/completions';
static String gemini =
@@ -172,7 +172,7 @@ class AppLink {
//===================Auth============
static String auth = 'https://ride.mobile-app.store/auth';
static String auth = '$server/auth';
static String login = "$auth/login.php";
static String signUp = "$auth/signup.php";
static String sendVerifyEmail = "$auth/sendVerifyEmail.php";
@@ -180,7 +180,7 @@ class AppLink {
"$auth/passengerRemovedAccountEmail.php";
static String verifyEmail = "$auth/verifyEmail.php";
//===================Auth Captin============
static String authCaptin = 'https://ride.mobile-app.store/auth/captin';
static String authCaptin = '$server/auth/captin';
static String loginCaptin = "$authCaptin/login.php";
static String signUpCaptin = "$authCaptin/register.php";
static String sendVerifyEmailCaptin = "$authCaptin/sendVerifyEmail.php";

View File

@@ -84,17 +84,18 @@ class LoginController extends GetxController {
'phone': phoneController.text,
'password': passwordController.text
});
isloading = false;
update();
if (res == 'Failure') {
isloading = false;
update();
Get.snackbar('Failure', '', backgroundColor: Colors.red);
} else {
// print(res);
var jsonDecoeded = jsonDecode(res);
// print(jsonDecoeded);
if (jsonDecoeded.isNotEmpty) {
if (jsonDecoeded['status'] == 'success') {
print(jsonDecoeded['data'][0]['verified']);
if (jsonDecoeded['data'][0]['verified'] == 1) {
if (jsonDecoeded['data'][0]['verified'] == '1') {
box.write(BoxName.passengerID, jsonDecoeded['data'][0]['id']);
box.write(BoxName.email, jsonDecoeded['data'][0]['email']);
box.write(

View File

@@ -12,8 +12,6 @@ class CRUD {
required String link,
Map<String, dynamic>? payload,
}) async {
// String? basicAuthCredentials =
// await storage.read(key: BoxName.basicAuthCredentials);
var url = Uri.parse(
link,
);
@@ -23,26 +21,24 @@ class CRUD {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization':
// 'Basic ${base64Encode(utf8.encode('hamzaayedphp:malDEV@2101'))}',
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
// 'Basic ${base64Encode(utf8.encode(basicAuthCredentials.toString()))}',
},
);
print("-----request----" + response.request.toString());
// print("-----request----" + response.request.toString());
// print("-----headers-----" + response.headers.toString());
print("-----payload-----" + payload.toString());
if (response.statusCode == 200) {
// print(response.body);
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
print(jsonData);
// print("-----payload-----" + payload.toString());
// if (response.statusCode == 200) {
// print(response.body);
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
// print(jsonData);
return response.body;
}
return jsonData['status'];
return response.body;
}
return jsonData['status'];
}
// }
Future<dynamic> getAgoraToken({
required String channelName,
@@ -174,8 +170,8 @@ class CRUD {
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
},
);
print(response.request);
print(payload);
// print(response.request);
// print(payload);
var jsonData = jsonDecode(response.body);
// print(jsonData);

View File

@@ -164,18 +164,18 @@ class LocationController extends GetxController {
print('distance $distance');
totalDistance += distance;
}
print('totalDistance: $totalDistance');
// print('totalDistance: $totalDistance');
previousTime = _locationData.time!;
}
// Print location details
print('myLocation: ${myLocation}');
print('Accuracy: ${_locationData.accuracy}');
print('Latitude: ${_locationData.latitude}');
print('Longitude: ${_locationData.longitude}');
print('Time: ${_locationData.time}');
print('speed: ${_locationData.speed}');
print('Heading: ${_locationData.heading}');
// print('myLocation: ${myLocation}');
// print('Accuracy: ${_locationData.accuracy}');
// print('Latitude: ${_locationData.latitude}');
// print('Longitude: ${_locationData.longitude}');
// print('Time: ${_locationData.time}');
// print('speed: ${_locationData.speed}');
// print('Heading: ${_locationData.heading}');
// isLoading = false;
update();
}

View File

@@ -107,6 +107,7 @@ class LogOutController extends GetxController {
box.remove(BoxName.apiKeyRun);
box.remove(BoxName.countryCode);
box.remove(BoxName.accountIdStripeConnect);
box.remove(BoxName.passengerWalletTotal);
Get.offAll(OnBoardingPage());
},
child: Text(

View File

@@ -6,6 +6,9 @@ class MyTranslation extends Translations {
"ar": {
"Choose Language": "اختر اللغة",
"Login": "تسجيل الدخول",
'Pay with Wallet': 'ادفع باستخدام المحفظة',
'Invalid MPIN': 'رمز PIN غير صحيح',
'Invalid OTP': 'كود التحقق خاطئ',
"Enter your email address": "أدخل عنوان بريدك الإلكتروني",
"Please enter Your Email.": "يرجى إدخال بريدك الإلكتروني.",
"Enter your phone number": "أدخل رقم هاتفك",

View File

@@ -1,6 +1,8 @@
import 'dart:convert';
import 'package:SEFER/constant/api_key.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/functions/tts.dart';
import 'package:SEFER/controller/payment/paymob/paymob_response.dart';
import 'package:SEFER/views/widgets/elevated_btn.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
@@ -9,7 +11,6 @@ import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:local_auth/local_auth.dart';
import 'package:SEFER/controller/home/map_passenger_controller.dart';
import 'package:paymob_payment/paymob_payment.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
@@ -18,6 +19,7 @@ import '../../constant/links.dart';
import '../../main.dart';
import '../functions/crud.dart';
import '../functions/toast.dart';
import 'paymob/paymob_wallet.dart';
class PaymentController extends GetxController {
bool isLoading = false;
@@ -55,7 +57,6 @@ class PaymentController extends GetxController {
box.write(BoxName.passengerWalletTotal,
jsonDecode(value)['message'][0]['total'].toString());
});
isLoading = false;
update();
}
@@ -479,11 +480,17 @@ class PaymentController extends GetxController {
context: context,
currency: currency, //"EGP",
amountInCents: newAmount, // 19.00 EGP
billingData: PaymobBillingData(),
onPayment: (PaymobResponse response) {
print('Success: ${response.success}');
print('Transaction ID: ${response.transactionID}');
print('Response Code: ${response.responseCode}');
// print('Message: ${response.message}');
print(box.read(BoxName.passengerWalletTotal));
print(box.read(BoxName.name));
print(box.read(BoxName.phone));
// print();
},
);
@@ -533,6 +540,178 @@ class PaymentController extends GetxController {
context: context,
currency: currency, //"EGP",
amountInCents: newAmount, // 19.00 EGP
billingData: PaymobBillingData(),
onPayment: (PaymobResponse response) {
// print('Success: ${response.success}');
// print('Transaction ID: ${response.transactionID}');
// print('Response Code: ${response.responseCode}');
// print('Message: ${response.message}');
},
);
if (response!.responseCode == 'APPROVED') {
Get.defaultDialog(
barrierDismissible: false,
title: 'Payment Successful'.tr,
titleStyle: AppStyle.title,
// backgroundColor: AppColor.greenColor,
content: Text(
'The payment was approved.'.tr,
style: AppStyle.title,
),
confirm: MyElevatedButton(
kolor: AppColor.greenColor,
title: 'OK'.tr,
onPressed: () async {
Get.back();
method();
},
),
);
} else {
Get.defaultDialog(
barrierDismissible: false,
// backgroundColor: AppColor.redColor,
title: 'Payment Failed'.tr,
content: Column(
children: [
IconButton(
onPressed: () {
Get.find<TextToSpeechController>().speakText(
'The payment was not approved. Please try again.'.tr,
);
},
icon: const Icon(Icons.headphones),
),
Text(
'The payment was not approved. Please try again.'.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
Text(
'${'The reason is'.tr} ${response.message!.tr}',
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(color: AppColor.redColor),
),
],
),
confirm: MyElevatedButton(
title: 'OK'.tr,
kolor: AppColor.redColor,
onPressed: () async {
Get.back();
},
),
);
}
}
} catch (e) {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(
'An error occurred during the payment process.'.tr,
style: AppStyle.title,
),
);
rethrow;
}
}
Future<void> payWithPayMobWallet(
BuildContext context, String amount, currency, Function method) async {
String newAmount = (double.parse(amount) * 100).toStringAsFixed(2);
try {
bool isAvailable = await LocalAuthentication().isDeviceSupported();
if (isAvailable) {
// Authenticate the user
bool didAuthenticate = await LocalAuthentication().authenticate(
localizedReason: 'Use Touch ID or Face ID to confirm payment',
);
if (didAuthenticate) {
final PaymobResponseWallet? response =
await PaymobPaymentWallet.instance.pay(
context: context,
currency: currency, //"EGP",
amountInCents: newAmount, // 19.00 EGP
billingData: PaymobBillingDataWallet(),
onPayment: (PaymobResponseWallet response) {
print('Success: ${response.success}');
print('Transaction ID: ${response.transactionID}');
print('Response Code: ${response.responseCode}');
print('Message: ${response.message}');
// print(box.read(BoxName.passengerWalletTotal));//
// print(box.read(BoxName.name));
// print(box.read(BoxName.phone));
// print();
},
);
if (response!.success == true && response.responseCode == '200') {
Get.defaultDialog(
barrierDismissible: false,
title: 'Payment Successful'.tr,
titleStyle: AppStyle.title,
content: Text(
'The payment was approved.'.tr,
style: AppStyle.title,
),
confirm: MyElevatedButton(
title: 'OK'.tr,
kolor: AppColor.greenColor,
onPressed: () async {
Get.back();
method();
},
),
);
} else {
Get.defaultDialog(
barrierDismissible: false,
// backgroundColor: AppColor.redColor,
title: 'Payment Failed'.tr,
content: Column(
children: [
IconButton(
onPressed: () {
Get.find<TextToSpeechController>().speakText(
'The payment was not approved. Please try again.'.tr,
);
},
icon: const Icon(Icons.headphones),
),
Text(
'The payment was not approved. Please try again.'.tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
Text(
'${'The reason is'.tr} ${response.message!.tr}',
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(color: AppColor.redColor),
),
],
),
confirm: MyElevatedButton(
title: 'OK'.tr,
kolor: AppColor.redColor,
onPressed: () async {
Get.back();
},
),
);
}
} else {
// Authentication failed, handle accordingly
print('Authentication failed');
}
} else {
final PaymobResponse? response = await PaymobPayment.instance.pay(
context: context,
currency: currency, //"EGP",
amountInCents: newAmount, // 19.00 EGP
billingData: PaymobBillingData(),
onPayment: (PaymobResponse response) {
// print('Success: ${response.success}');
// print('Transaction ID: ${response.transactionID}');

View File

@@ -1,6 +1,7 @@
import 'package:SEFER/constant/box_name.dart';
import 'package:dio/dio.dart' as dio;
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -62,16 +63,18 @@ class PaymobManager extends GetxController {
final dio = Dio();
try {
final response = await dio.post(
'https://accept.paymob.com/api/acceptance/payments/pay',
'https://accept.paymobsolutions.com/api/acceptance/payments/pay',
data: data,
);
// 4. Handle Payment Response
if (response.statusCode == 200) {
// Payment successful: Process response data (e.g., transaction ID)
final paymentData = response.data; // Assuming JSON response
print("Payment successful: $paymentData");
print("redirection_url: ${paymentData['iframe_redirection_url']}");
// Navigate to success screen or display success message
launchUrl(Uri.parse(paymentData['iframe_redirection_url']));
} else {
// Payment failed: Handle errors (e.g., display error message)
print("Payment failed: ${response.statusCode} - ${response.data}");
@@ -82,24 +85,6 @@ class PaymobManager extends GetxController {
}
}
// Future<void> payWithPayMob(int amount, String currency) async {
// String key = await PaymobManager().getPaymentKey(amount, currency);
// await launchUrl(Uri.parse(
// // 'https://accept.paymob.com/api/acceptance/iframes/837992?payment_token=$key'),
// 'https://accept.paymob.com/api/acceptance/payments/pay'));
// print(key);
// final dio.Response response = await Dio()
// .post('https://accept.paymob.com/api/acceptance/payments/pay', data: {
// "source": {
// "identifier": "01010101010",
// "subtype": "WALLET",
// },
// "payment_token": key, // token obtained in step 3
// });
//
// // String paymentStatus = await _getStatusAfterPaid();
// }
Future<String> _getStatusAfterPaid() async {
print(authanticationToken1);
print(orderId1);
@@ -154,7 +139,8 @@ class PaymobManager extends GetxController {
"expiration": 200,
"auth_token": authanticationToken.toString(),
"order_id": orderId.toString(),
"integration_id": int.parse(AK.integrationIdPayMob),
"integration_id":
4556056, ////todo wallet or online card int.parse(AK.integrationIdPayMob),
"lock_order_when_paid": "false",
"amount_cents": amount,
"currency": currency,

View File

@@ -0,0 +1,328 @@
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/main.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class PaymobResponse {
bool success;
String? transactionID;
String? responseCode;
String? message;
PaymobResponse({
this.transactionID,
required this.success,
this.responseCode,
this.message,
});
factory PaymobResponse.fromJson(Map<String, dynamic> json) {
return PaymobResponse(
success: json['success'] == 'true',
transactionID: json['id'],
message: json['message'],
responseCode: json['txn_response_code'],
);
}
}
class PaymobPayment {
static PaymobPayment instance = PaymobPayment();
bool _isInitialized = false;
final Dio _dio = Dio();
final _baseURL = 'https://accept.paymob.com/api/';
late String _apiKey;
late int _integrationID;
late int _iFrameID;
late String _iFrameURL;
late int _userTokenExpiration;
/// Initializing PaymobPayment instance.
Future<bool> initialize({
/// It is a unique identifier for the merchant which used to authenticate your requests calling any of Accept's API.
/// from dashboard Select Settings -> Account Info -> API Key
required String apiKey,
/// from dashboard Select Developers -> Payment Integrations -> Online Card ID
required int integrationID,
/// from paymob Select Developers -> iframes
required int iFrameID,
/// The expiration time of this payment token in seconds. (The maximum is 3600 seconds which is an hour)
int userTokenExpiration = 300,
}) async {
if (_isInitialized) {
return true;
}
_dio.options.baseUrl = _baseURL;
_dio.options.validateStatus = (status) => true;
_apiKey = apiKey;
_integrationID = integrationID;
_iFrameID = iFrameID;
_iFrameURL =
'https://accept.paymobsolutions.com/api/acceptance/iframes/$_iFrameID?payment_token=';
_isInitialized = true;
_userTokenExpiration = userTokenExpiration;
return _isInitialized;
}
/// Get authentication token, which is valid for one hour from the creation time.
Future<String> _getAuthToken() async {
try {
final response = await _dio.post(
'auth/tokens',
data: {
'api_key': _apiKey,
},
);
print(response.data['token']);
return response.data['token'];
} catch (e) {
rethrow;
}
}
/// At this step, you will register an order to Accept's database, so that you can pay for it later using a transaction
Future<int> _addOrder({
required String authToken,
required String currency,
required String amount,
required List items,
}) async {
try {
final response = await _dio.post(
'ecommerce/orders',
data: {
"auth_token": authToken,
"delivery_needed": "false",
"amount_cents": amount,
"currency": currency,
"items": items,
},
);
print(response.data['id']);
return response.data['id'];
} catch (e) {
rethrow;
}
}
/// At this step, you will obtain a payment_key token. This key will be used to authenticate your payment request. It will be also used for verifying your transaction request metadata.
Future<String> _getPurchaseToken({
required String authToken,
required String currency,
required int orderID,
required String amount,
required PaymobBillingData billingData,
}) async {
final response = await _dio.post(
'acceptance/payment_keys',
data: {
"auth_token": authToken,
"amount_cents": amount,
"expiration": _userTokenExpiration,
"order_id": orderID,
"billing_data": billingData,
"currency": currency,
"integration_id": _integrationID,
"lock_order_when_paid": "false"
},
);
final message = response.data['message'];
if (message != null) {
throw Exception(message);
}
print(response.data['token']);
return response.data['token'];
}
/// Proceed to pay with only calling this function.
/// Opens a WebView at Paymob redirectedURL to accept user payment info.
Future<PaymobResponse?> pay(
{
/// BuildContext for navigation to WebView
required BuildContext context,
/// Which Currency you would pay in.
required String currency,
/// Payment amount in cents EX: 20000 is an 200 EGP
required String amountInCents,
/// Optional Callback if you can use return result of pay function or use this callback
void Function(PaymobResponse response)? onPayment,
/// list of json objects contains the contents of the purchase.
List? items,
/// The billing data related to the customer related to this payment.
PaymobBillingData? billingData}) async {
if (!_isInitialized) {
throw Exception(
'PaymobPayment is not initialized call:`PaymobPayment.instance.initialize`');
}
final authToken = await _getAuthToken();
final orderID = await _addOrder(
authToken: authToken,
currency: currency,
amount: amountInCents,
items: items ?? [],
);
final purchaseToken = await _getPurchaseToken(
authToken: authToken,
currency: currency,
orderID: orderID,
amount: amountInCents,
billingData: billingData ?? PaymobBillingData(),
);
if (context.mounted) {
final response = await PaymobIFrame.show(
context: context,
redirectURL: _iFrameURL + purchaseToken,
onPayment: onPayment,
);
return response;
}
return null;
}
}
class PaymobBillingData {
String? email;
String? firstName;
String? lastName;
String? phoneNumber;
String? apartment;
String? floor;
String? street;
String? building;
String? postalCode;
String? city;
String? state;
String? country;
String? shippingMethod;
PaymobBillingData({
this.email,
this.firstName,
this.lastName,
this.phoneNumber,
this.apartment,
this.floor,
this.street,
this.building,
this.postalCode,
this.city,
this.state,
this.country,
this.shippingMethod,
});
Map<String, dynamic> toJson() {
return {
"email": box.read(BoxName.email) ?? box.read(BoxName.emailDriver),
"first_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
"last_name": box.read(BoxName.lastNameDriver) ?? box.read(BoxName.name),
"phone_number": box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver),
"apartment": apartment ?? "NA",
"floor": floor ?? "NA",
"building": building ?? "NA",
"street": street ?? "NA",
"postal_code": postalCode ?? "NA",
"city": city ?? "NA",
"state": state ?? "NA",
"country": country ?? "NA",
"shipping_method": shippingMethod ?? "NA",
};
}
}
class PaymobIFrame extends StatefulWidget {
const PaymobIFrame({
Key? key,
required this.redirectURL,
this.onPayment,
}) : super(key: key);
final String redirectURL;
final void Function(PaymobResponse)? onPayment;
static Future<PaymobResponse?> show({
required BuildContext context,
required String redirectURL,
void Function(PaymobResponse)? onPayment,
}) =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return PaymobIFrame(
onPayment: onPayment,
redirectURL: redirectURL,
);
},
),
);
@override
State<PaymobIFrame> createState() => _PaymobIFrameState();
}
class _PaymobIFrameState extends State<PaymobIFrame> {
WebViewController? controller;
@override
void initState() {
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onNavigationRequest: (NavigationRequest request) {
if (request.url.contains('txn_response_code') &&
request.url.contains('success') &&
request.url.contains('id')) {
final params = _getParamFromURL(request.url);
final response = PaymobResponse.fromJson(params);
if (widget.onPayment != null) {
widget.onPayment!(response);
}
Navigator.pop(context, response);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse(widget.redirectURL));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller == null
? const Center(
child: CircularProgressIndicator.adaptive(),
)
: SafeArea(
child: WebViewWidget(
controller: controller!,
),
),
);
}
Map<String, dynamic> _getParamFromURL(String url) {
final uri = Uri.parse(url);
Map<String, dynamic> data = {};
uri.queryParameters.forEach((key, value) {
data[key] = value;
});
return data;
}
}

View File

@@ -0,0 +1,381 @@
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/main.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class PaymobResponseWallet {
final bool success;
final String? transactionID;
final String? responseCode;
final String? message;
PaymobResponseWallet({
required this.success,
this.transactionID,
this.responseCode,
this.message,
});
factory PaymobResponseWallet.fromJson(Map<String, dynamic> json) {
return PaymobResponseWallet(
success: json['success'] == 'true',
transactionID: json['id'],
responseCode: json['txn_response_code'],
message: json['data']['message'],
);
}
}
class PaymobPaymentWallet {
static PaymobPaymentWallet instance = PaymobPaymentWallet();
bool _isInitialized = false;
final Dio _dio = Dio();
final _baseURL = 'https://accept.paymob.com/api/';
late String _apiKey;
late int _integrationID;
late int _iFrameID;
late String _iFrameURL;
late int _userTokenExpiration;
/// Initializing PaymobPayment instance.
Future<bool> initialize({
/// It is a unique identifier for the merchant which used to authenticate your requests calling any of Accept's API.
/// from dashboard Select Settings -> Account Info -> API Key
required String apiKey,
/// from dashboard Select Developers -> Payment Integrations -> Online Card ID
required int integrationID,
/// from paymob Select Developers -> iframes
required int iFrameID,
/// The expiration time of this payment token in seconds. (The maximum is 3600 seconds which is an hour)
int userTokenExpiration = 300,
}) async {
if (_isInitialized) {
return true;
}
_dio.options.baseUrl = _baseURL;
_dio.options.validateStatus = (status) => true;
_apiKey = apiKey;
_integrationID = integrationID;
_iFrameID = iFrameID;
_iFrameURL =
'https://accept.paymobsolutions.com/api/acceptance/iframes/$_iFrameID?payment_token=';
_isInitialized = true;
_userTokenExpiration = userTokenExpiration;
return _isInitialized;
}
/// Get authentication token, which is valid for one hour from the creation time.
Future<String> _getAuthToken() async {
try {
final response = await _dio.post(
'auth/tokens',
data: {
'api_key': _apiKey,
},
);
print(response.data['token']);
return response.data['token'];
} catch (e) {
rethrow;
}
}
/// At this step, you will register an order to Accept's database, so that you can pay for it later using a transaction
Future<int> _addOrder({
required String authToken,
required String currency,
required String amount,
required List items,
}) async {
try {
final response = await _dio.post(
'ecommerce/orders',
data: {
"auth_token": authToken,
"delivery_needed": "false",
"amount_cents": amount,
"currency": currency,
"items": items,
},
);
print(response.data['id']);
return response.data['id'];
} catch (e) {
rethrow;
}
}
/// At this step, you will obtain a payment_key token. This key will be used to authenticate your payment request. It will be also used for verifying your transaction request metadata.
Future<String> _getPurchaseToken({
required String authToken,
required String currency,
required int orderID,
required String amount,
required PaymobBillingDataWallet billingData,
}) async {
final response = await _dio.post(
'acceptance/payment_keys',
data: {
"auth_token": authToken,
"amount_cents": amount,
"expiration": _userTokenExpiration,
"order_id": orderID,
"billing_data": billingData,
"currency": currency,
"integration_id": _integrationID,
"lock_order_when_paid": "false"
},
);
final message = response.data['message'];
if (message != null) {
throw Exception(message);
}
print(response.data['token']);
return response.data['token'];
}
Future<String> _getWalletUrl({
required String paymentToken,
}) async {
final Map<String, dynamic> data = {
"source": {
"identifier": "01010101010", // Replace with actual source identifier
"subtype": "WALLET",
},
"payment_token": paymentToken,
};
final dio = Dio();
try {
final response = await dio.post(
'https://accept.paymobsolutions.com/api/acceptance/payments/pay',
data: data,
);
// 4. Handle Payment Response
if (response.statusCode == 200) {
final paymentData = response.data; // Assuming JSON response
print("redirection_url: ${paymentData['iframe_redirection_url']}");
return paymentData['iframe_redirection_url'];
// Navigate to success screen or display success message
} else {
// Payment failed: Handle errors (e.g., display error message)
print("Payment failed: ${response.statusCode} - ${response.data}");
}
} on DioError catch (e) {
// Handle network or Dio-related errors
print("Error making payment request: $e");
}
return '';
}
/// Proceed to pay with only calling this function.
/// Opens a WebView at Paymob redirectedURL to accept user payment info.
Future<PaymobResponseWallet?> pay(
{
/// BuildContext for navigation to WebView
required BuildContext context,
/// Which Currency you would pay in.
required String currency,
/// Payment amount in cents EX: 20000 is an 200 EGP
required String amountInCents,
/// Optional Callback if you can use return result of pay function or use this callback
void Function(PaymobResponseWallet response)? onPayment,
/// list of json objects contains the contents of the purchase.
List? items,
/// The billing data related to the customer related to this payment.
PaymobBillingDataWallet? billingData}) async {
if (!_isInitialized) {
throw Exception(
'PaymobPayment is not initialized call:`PaymobPayment.instance.initialize`');
}
final authToken = await _getAuthToken();
final orderID = await _addOrder(
authToken: authToken,
currency: currency,
amount: amountInCents,
items: items ?? [],
);
final purchaseToken = await _getPurchaseToken(
authToken: authToken,
currency: currency,
orderID: orderID,
amount: amountInCents,
billingData: billingData ??
PaymobBillingDataWallet(
// email: box.read(BoxName.email) ?? box.read(BoxName.emailDriver),
// firstName: box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
// lastName:
// box.read(BoxName.lastNameDriver) ?? box.read(BoxName.name),
// phoneNumber:
// box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver),
),
);
final urlWallet = await _getWalletUrl(paymentToken: purchaseToken);
if (context.mounted) {
final response = await PaymobIFrameWallet.show(
context: context,
redirectURL: urlWallet,
onPayment: onPayment,
);
return response;
}
return null;
}
}
class PaymobBillingDataWallet {
String? email;
String? firstName;
String? lastName;
String? phoneNumber;
String? apartment;
String? floor;
String? street;
String? building;
String? postalCode;
String? city;
String? state;
String? country;
String? shippingMethod;
PaymobBillingDataWallet({
this.email,
this.firstName,
this.lastName,
this.phoneNumber,
this.apartment,
this.floor,
this.street,
this.building,
this.postalCode,
this.city,
this.state,
this.country,
this.shippingMethod,
});
Map<String, dynamic> toJson() {
return {
"email": box.read(BoxName.email) ?? box.read(BoxName.emailDriver),
"first_name": box.read(BoxName.name) ?? box.read(BoxName.nameDriver),
"last_name": box.read(BoxName.name) ?? box.read(BoxName.lastNameDriver),
"phone_number": box.read(BoxName.phone) ?? box.read(BoxName.phoneDriver),
"apartment": apartment ?? "NA",
"floor": floor ?? "NA",
"building": building ?? "NA",
"street": street ?? "NA",
"postal_code": postalCode ?? "NA",
"city": city ?? "NA",
"state": state ?? "NA",
"country": country ?? "NA",
"shipping_method": shippingMethod ?? "NA",
};
}
}
class PaymobIFrameWallet extends StatefulWidget {
const PaymobIFrameWallet({
Key? key,
required this.redirectURL,
this.onPayment,
}) : super(key: key);
final String redirectURL;
final void Function(PaymobResponseWallet)? onPayment;
static Future<PaymobResponseWallet?> show({
required BuildContext context,
required String redirectURL,
void Function(PaymobResponseWallet)? onPayment,
}) =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return PaymobIFrameWallet(
onPayment: onPayment,
redirectURL: redirectURL,
);
},
),
);
@override
State<PaymobIFrameWallet> createState() => _PaymobIFrameState();
}
class _PaymobIFrameState extends State<PaymobIFrameWallet> {
WebViewController? controller;
@override
void initState() {
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onNavigationRequest: (NavigationRequest request) {
if (request.url.contains('txn_response_code') &&
// request.url.contains('successfully') &&
request.url.contains('success') &&
request.url.contains('id')) {
final params = _getParamFromURL(request.url);
final response = PaymobResponseWallet.fromJson(params);
if (widget.onPayment != null) {
widget.onPayment!(response);
}
Navigator.pop(context, response);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse(widget.redirectURL));
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller == null
? const Center(
child: CircularProgressIndicator.adaptive(),
)
: SafeArea(
child: WebViewWidget(
controller: controller!,
),
),
);
}
Map<String, dynamic> _getParamFromURL(String url) {
final uri = Uri.parse(url);
final queryParams = uri.queryParameters;
final data = <String, dynamic>{};
queryParams.forEach((key, value) {
if (key.contains('.')) {
final parts = key.split('.');
data.putIfAbsent(parts.first, () => <String, dynamic>{});
(data[parts.first] as Map<String, dynamic>)[parts.last] = value;
} else {
data[key] = value;
}
});
return data;
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:SEFER/controller/payment/paymob/paymob_response.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
@@ -8,7 +9,6 @@ import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:flutter/services.dart';
import 'package:paymob_payment/paymob_payment.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'constant/api_key.dart';
import 'constant/box_name.dart';
@@ -19,13 +19,16 @@ import 'controller/firebase/local_notification.dart';
import 'controller/functions/location_background_controller.dart';
import 'controller/local/local_controller.dart';
import 'controller/local/translations.dart';
import 'controller/payment/paymob/paymob_wallet.dart';
import 'firebase_options.dart';
import 'models/db_sql.dart';
import 'splash_screen_page.dart';
final box = GetStorage();
const storage = FlutterSecureStorage();
// final PaymobPayment paymobPayment = PaymobPayment();
final PaymobPayment paymobPayment = PaymobPayment();
final PaymobPaymentWallet paymobPaymentWallet = PaymobPaymentWallet();
DbSql sql = DbSql.instance;
@pragma('vm:entry-point')
@@ -83,6 +86,13 @@ void main() async {
DeviceOrientation.portraitDown,
]);
}
// PaymobPayment.instance.initialize(
// apiKey: AK
// .payMobApikey, // from dashboard Select Settings -> Account Info -> API Key
// integrationID: int.parse(AK.integrationIdPayMob),
// userTokenExpiration: 200,
// iFrameID: 837992,
// );
PaymobPayment.instance.initialize(
apiKey: AK
.payMobApikey, // from dashboard Select Settings -> Account Info -> API Key
@@ -90,6 +100,13 @@ void main() async {
userTokenExpiration: 200,
iFrameID: 837992,
);
PaymobPaymentWallet.instance.initialize(
apiKey: AK
.payMobApikey, // from dashboard Select Settings -> Account Info -> API Key
integrationID: 4556056, //int.parse(AK.integrationIdPayMob),
userTokenExpiration: 200,
iFrameID: 837992,
);
runApp(const MyApp());
}

View File

@@ -5,7 +5,6 @@ import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/main.dart';
import 'package:paymob_payment/paymob_payment.dart';
import '../../../constant/colors.dart';
import '../../../controller/functions/tts.dart';
@@ -113,7 +112,12 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
borderRadius: BorderRadius.circular(15)),
child: IconButton(
onPressed: () async {
// await PaymobManager().payWithPayMob(100, 'EGP');
await PaymentController()
.payWithPayMobWallet(context, '100', 'EGP', () {});
// print(box.read(BoxName.passengerWalletTotal));
// print(box.read(BoxName.name));
// print(box.read(BoxName.phone));
// print(box.read(BoxName.email));
// await Get.find<PaymentController>()
// .payWithPayMob(context, '1100', 'EGP');
// Initiates a payment with a card using the FlutterPaymob instance

View File

@@ -18,10 +18,10 @@ class PassengerWalletDialoge extends StatelessWidget {
Widget build(BuildContext context) {
return GetBuilder<PaymentController>(
builder: (controller) => Positioned(
top: Get.height * .2,
top: Get.height * .1,
right: Get.width * .15,
left: Get.width * .15,
bottom: Get.height * .2,
bottom: Get.height * .1,
child: controller.isPromoSheetDialogue
? Container(
decoration: const BoxDecoration(
@@ -161,28 +161,72 @@ class PassengerWalletDialoge extends StatelessWidget {
},
),
box.read(BoxName.countryCode) == 'Egypt'
? MyElevatedButton(
title: 'Pay with Credit Card'.tr,
onPressed: () {
if (controller.selectedAmount != 0) {
controller.payWithPayMob(
context,
controller.selectedAmount
.toString(), // Convert int to double
box.read(BoxName.countryCode) == 'Egypt'
? 'EGP'
: 'JOD', () async {
await controller.addPassengerWallet();
controller.changePromoSheetDialogue();
await controller.getPassengerWallet();
});
} else {
Toast.show(
context,
'You will choose one of above !'.tr,
AppColor.redColor);
}
})
? Column(
children: [
MyElevatedButton(
title: '💳 Pay with Credit Card'.tr,
onPressed: () {
if (controller.selectedAmount != 0) {
controller.payWithPayMob(
context,
controller.selectedAmount
.toString(), // Convert int to double
box.read(BoxName.countryCode) ==
'Egypt'
? 'EGP'
: 'JOD',
() async {
await controller
.addPassengerWallet();
controller
.changePromoSheetDialogue();
await controller
.getPassengerWallet();
},
);
} else {
Toast.show(
context,
'⚠️ You need to choose an amount!'.tr,
AppColor.redColor,
);
}
},
),
// Add some spacing between buttons
MyElevatedButton(
kolor: AppColor.yellowColor,
title: '💰 Pay with Wallet'.tr,
onPressed: () {
if (controller.selectedAmount != 0) {
controller.payWithPayMobWallet(
context,
controller.selectedAmount
.toString(), // Convert int to double
box.read(BoxName.countryCode) ==
'Egypt'
? 'EGP'
: 'JOD',
() async {
await controller
.addPassengerWallet();
controller
.changePromoSheetDialogue();
await controller
.getPassengerWallet();
},
);
} else {
Toast.show(
context,
'⚠️ You need to choose an amount!'.tr,
AppColor.redColor,
);
}
},
),
],
)
: MyElevatedButton(
title: 'Pay with Credit Card'.tr,
onPressed: () {
@@ -191,8 +235,8 @@ class PassengerWalletDialoge extends StatelessWidget {
controller.selectedAmount!
.toDouble(), // Convert int to double
box.read(BoxName.countryCode) != 'Egypt'
? 'EGP'
: 'USD', () {
? 'usd'
: 'jod', () {
controller.addPassengerWallet();
controller.changePromoSheetDialogue();
controller.getPassengerWallet();

View File

@@ -7,6 +7,7 @@ import 'package:SEFER/controller/payment/payment_controller.dart';
import '../../../constant/box_name.dart';
import '../../../main.dart';
import '../../widgets/elevated_btn.dart';
class PointsCaptain extends StatelessWidget {
PaymentController paymentController = Get.put(PaymentController());
@@ -28,17 +29,53 @@ class PointsCaptain extends StatelessWidget {
return InkWell(
onTap: () async {
box.read(BoxName.countryCode) == 'Egypt'
? await paymentController.payWithPayMob(
context,
pricePoint.toStringAsFixed(2),
box.read(BoxName.countryCode) == 'Egypt' ? 'EGP' : 'JOD',
() async {
await captainWalletController.addDriverPayment(
'visa', pricePoint);
await captainWalletController.addDriverWallet(
'visa', countPoint);
await captainWalletController.getCaptainWalletFromBuyPoints();
})
? Get.defaultDialog(
title: 'Which method you will pay'.tr,
titleStyle: AppStyle.title,
content: Column(
children: [
MyElevatedButton(
title: '💳 Pay with Credit Card'.tr,
onPressed: () async {
Get.back();
await paymentController.payWithPayMob(
context,
pricePoint.toStringAsFixed(2),
box.read(BoxName.countryCode) == 'Egypt'
? 'EGP'
: 'JOD', () async {
await captainWalletController.addDriverPayment(
'visa', pricePoint);
await captainWalletController.addDriverWallet(
'visa', countPoint);
await captainWalletController
.getCaptainWalletFromBuyPoints();
});
}, //51524
),
// Add some spacing between buttons
MyElevatedButton(
kolor: AppColor.yellowColor,
title: '💰 Pay with Wallet'.tr,
onPressed: () async {
Get.back();
await paymentController.payWithPayMobWallet(
context,
pricePoint.toStringAsFixed(2),
box.read(BoxName.countryCode) == 'Egypt'
? 'EGP'
: 'JOD', () async {
await captainWalletController.addDriverPayment(
'visa', pricePoint);
await captainWalletController.addDriverWallet(
'visa', countPoint);
await captainWalletController
.getCaptainWalletFromBuyPoints();
});
},
),
],
))
: await paymentController.makePaymentStripe(pricePoint,
box.read(BoxName.countryCode) == 'Jordan' ? 'jod' : 'egp',
() async {

View File

@@ -318,7 +318,7 @@ class WalletCaptain extends StatelessWidget {
box.read(BoxName.countryCode) ==
'Jordan'
? '2300'
: '440',
: '450',
),
PointsCaptain(
kolor: AppColor.yellowColor,

View File

@@ -1472,14 +1472,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.1"
paymob_payment:
dependency: "direct main"
description:
name: paymob_payment
sha256: "5a7f6ef9c1d538b5bdff52e757f09a97755b0c0cabe9f5098a13cc005477584c"
url: "https://pub.dev"
source: hosted
version: "0.0.1+1"
permission_handler:
dependency: "direct main"
description:
@@ -2022,37 +2014,37 @@ packages:
source: hosted
version: "2.4.0"
webview_flutter:
dependency: transitive
dependency: "direct main"
description:
name: webview_flutter
sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf"
sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932"
url: "https://pub.dev"
source: hosted
version: "4.4.2"
version: "4.7.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: b54c89fe14a6d26a2a46e24880da0441cdd2bf1f6d01a5b3e1d39558feb1de0b
sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934
url: "https://pub.dev"
source: hosted
version: "3.13.1"
version: "3.16.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: dbe745ee459a16b6fec296f7565a8ef430d0d681001d8ae521898b9361854943
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
url: "https://pub.dev"
source: hosted
version: "2.9.0"
version: "2.10.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: eebfabfa8a115b535b52031b8b26f7a4b58ceceab378bc9db8762b0fb46f7b5d
sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7
url: "https://pub.dev"
source: hosted
version: "3.10.0"
version: "3.13.0"
win32:
dependency: transitive
description:
@@ -2094,5 +2086,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"
dart: ">=3.2.3 <4.0.0"
flutter: ">=3.16.6"

View File

@@ -60,7 +60,8 @@ dependencies:
flutter_sound: ^9.2.13
record: ^5.0.5
dio: ^5.4.3+1
paymob_payment: ^0.0.1+1
# paymob_payment: ^0.0.1+1
webview_flutter: ^4.7.0