Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
gen_rentals
Commits
e4263a00
Commit
e4263a00
authored
Nov 05, 2025
by
Sai Srinivas
Browse files
Razorpay Setup
parents
42164fa1
2af2b2b7
Changes
21
Hide whitespace changes
Inline
Side-by-side
android/app/build.gradle.kts
View file @
e4263a00
...
...
@@ -32,7 +32,7 @@ android {
applicationId
=
"in.webgrid.genrentals"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk
=
flutter
.
minSdkVersion
minSdk
=
23
targetSdk
=
36
versionCode
=
flutter
.
versionCode
versionName
=
flutter
.
versionName
...
...
assets/svg/homes_ic.svg
0 → 100644
View file @
e4263a00
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<mask
id=
"mask0_468_717"
style=
"mask-type:luminance"
maskUnits=
"userSpaceOnUse"
x=
"0"
y=
"0"
width=
"24"
height=
"24"
>
<path
d=
"M24 0H0V24H24V0Z"
fill=
"white"
/>
</mask>
<g
mask=
"url(#mask0_468_717)"
>
<path
d=
"M12 18.75C11.59 18.75 11.25 18.41 11.25 18V15C11.25 14.59 11.59 14.25 12 14.25C12.41 14.25 12.75 14.59 12.75 15V18C12.75 18.41 12.41 18.75 12 18.75Z"
fill=
"white"
/>
<path
d=
"M17.6 22.5608H6.39996C4.57996 22.5608 2.91996 21.1608 2.61996 19.3708L1.28996 11.4008C1.06996 10.1608 1.67996 8.5708 2.66996 7.7808L9.59996 2.2308C10.94 1.1508 13.05 1.1608 14.4 2.2408L21.33 7.7808C22.31 8.5708 22.91 10.1608 22.71 11.4008L21.38 19.3608C21.08 21.1308 19.38 22.5608 17.6 22.5608ZM11.99 2.9308C11.46 2.9308 10.93 3.0908 10.54 3.4008L3.60996 8.9608C3.04996 9.4108 2.64996 10.4508 2.76996 11.1608L4.09996 19.1208C4.27996 20.1708 5.32996 21.0608 6.39996 21.0608H17.6C18.67 21.0608 19.72 20.1708 19.9 19.1108L21.23 11.1508C21.34 10.4508 20.94 9.3908 20.39 8.9508L13.46 3.4108C13.06 3.0908 12.52 2.9308 11.99 2.9308Z"
fill=
"white"
/>
</g>
</svg>
lib/Models/BillsModels/billListResponse.dart
View file @
e4263a00
...
...
@@ -3,6 +3,7 @@ class BillListResponse {
List
<
Bills
>?
bills
;
LatestBill
?
latestBill
;
String
?
message
;
String
?
payAmount
;
int
?
sessionExists
;
BillListResponse
(
...
...
@@ -24,6 +25,7 @@ class BillListResponse {
?
new
LatestBill
.
fromJson
(
json
[
'latest_bill'
])
:
null
;
message
=
json
[
'message'
];
payAmount
=
json
[
'pay_amount'
];
sessionExists
=
json
[
'session_exists'
];
}
...
...
@@ -37,6 +39,7 @@ class BillListResponse {
data
[
'latest_bill'
]
=
this
.
latestBill
!.
toJson
();
}
data
[
'message'
]
=
this
.
message
;
data
[
'pay_amount'
]
=
this
.
payAmount
;
data
[
'session_exists'
]
=
this
.
sessionExists
;
return
data
;
}
...
...
lib/Models/TransactionModels/PayAmountResponse.dart
0 → 100644
View file @
e4263a00
class
PayAmountResponse
{
String
?
error
;
String
?
amount
;
String
?
message
;
String
?
orderId
;
String
?
razorKey
;
PayAmountResponse
(
{
this
.
error
,
this
.
amount
,
this
.
message
,
this
.
orderId
,
this
.
razorKey
});
PayAmountResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
amount
=
json
[
'amount'
];
message
=
json
[
'message'
];
orderId
=
json
[
'order_id'
];
razorKey
=
json
[
'razor_key'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
data
[
'amount'
]
=
this
.
amount
;
data
[
'message'
]
=
this
.
message
;
data
[
'order_id'
]
=
this
.
orderId
;
data
[
'razor_key'
]
=
this
.
razorKey
;
return
data
;
}
}
lib/Notifier/PayAmountProvider.dart
0 → 100644
View file @
e4263a00
import
'dart:convert'
;
import
'package:flutter/foundation.dart'
;
import
'package:gen_rentals/Services/api_calling.dart'
;
import
'../Models/CommonResponse.dart'
;
import
'../Models/TransactionModels/PayAmountResponse.dart'
;
class
PayAmountProvider
with
ChangeNotifier
{
bool
_isLoading
=
false
;
PayAmountResponse
?
_payResponse
;
PaymentStatusResponse
?
_statusResponse
;
String
?
_errorMessage
;
bool
get
isLoading
=>
_isLoading
;
PayAmountResponse
?
get
payResponse
=>
_payResponse
;
PaymentStatusResponse
?
get
statusResponse
=>
_statusResponse
;
String
?
get
errorMessage
=>
_errorMessage
;
/// Pay Amount API
Future
<
void
>
payAmount
({
required
String
sessionId
,
required
String
empId
,
required
String
amount
,
required
String
refType
,
required
String
refId
,
})
async
{
_isLoading
=
true
;
_errorMessage
=
null
;
notifyListeners
();
try
{
final
res
=
await
ApiCalling
.
payAmountApi
(
sessionId
,
empId
,
amount
,
refType
,
refId
,
);
if
(
res
!=
null
)
{
_payResponse
=
res
;
}
else
{
_errorMessage
=
"No response from server"
;
}
}
catch
(
e
)
{
_errorMessage
=
"Error:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
/// Get Payment Status API
Future
<
void
>
getPaymentStatus
({
required
String
sessionId
,
required
String
empId
,
required
String
razorpayOrderId
,
})
async
{
_isLoading
=
true
;
_errorMessage
=
null
;
notifyListeners
();
try
{
final
res
=
await
ApiCalling
.
getPaymentStatusApi
(
sessionId
,
empId
,
razorpayOrderId
,
);
if
(
res
!=
null
)
{
_statusResponse
=
res
;
}
else
{
_errorMessage
=
"No response from server"
;
}
}
catch
(
e
)
{
_errorMessage
=
"Error:
$e
"
;
}
finally
{
_isLoading
=
false
;
notifyListeners
();
}
}
/// Reset all states
void
reset
()
{
_payResponse
=
null
;
_statusResponse
=
null
;
_errorMessage
=
null
;
notifyListeners
();
}
}
// Payment Status Response
class
PaymentStatusResponse
{
int
?
error
;
double
?
amount
;
String
?
date
;
String
?
message
;
int
?
sessionExists
;
PaymentStatusResponse
(
{
this
.
error
,
this
.
amount
,
this
.
date
,
this
.
message
,
this
.
sessionExists
});
PaymentStatusResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
error
=
json
[
'error'
];
amount
=
json
[
'amount'
];
date
=
json
[
'date'
];
message
=
json
[
'message'
];
sessionExists
=
json
[
'session_exists'
];
}
Map
<
String
,
dynamic
>
toJson
()
{
final
Map
<
String
,
dynamic
>
data
=
new
Map
<
String
,
dynamic
>();
data
[
'error'
]
=
this
.
error
;
data
[
'amount'
]
=
this
.
amount
;
data
[
'date'
]
=
this
.
date
;
data
[
'message'
]
=
this
.
message
;
data
[
'session_exists'
]
=
this
.
sessionExists
;
return
data
;
}
}
lib/Notifier/RentalContactProvider .dart
View file @
e4263a00
...
...
@@ -50,16 +50,12 @@ class RentalProvider extends ChangeNotifier {
isOtpLoading
=
true
;
notifyListeners
();
try
{
if
(
Platform
.
isAndroid
){
initAndroidId
();
}
else
{
getDevId
();
}
final
result
=
await
ApiCalling
.
fetchMobileOtpApi
(
mob
,
otp
,
deviceDetails
);
final
result
=
await
ApiCalling
.
fetchMobileOtpApi
(
mob
,
otp
,
deviceDetails
??
""
);
otpResponse
=
result
;
}
catch
(
e
)
{
debugPrint
(
"❌ OT
Ps
API Error:
$e
"
);
debugPrint
(
"❌ OT API Error:
$e
"
);
otpResponse
=
null
;
}
finally
{
isOtpLoading
=
false
;
...
...
lib/Screens/BillScreens/BillDetailListScreen.dart
View file @
e4263a00
...
...
@@ -4,9 +4,13 @@ import 'package:gen_rentals/Models/BillsModels/BillDetailsResponse.dart';
import
'package:gen_rentals/Utility/AppColors.dart'
;
import
'package:gen_rentals/Utility/Reusablewidgets.dart'
;
import
'package:provider/provider.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
import
'../../Notifier/BillProvider.dart'
;
import
'../../Notifier/PayAmountProvider.dart'
;
import
'../../Utility/CustomSnackbar.dart'
;
import
'../DashboardScreen.dart'
;
import
'../TransactionScreens/PaymentSuccessfailScreen.dart'
;
import
'BillDetailScreen.dart'
;
...
...
@@ -27,15 +31,123 @@ class BillDetailListScreen extends StatefulWidget {
}
class
_BillDetailListScreenState
extends
State
<
BillDetailListScreen
>
{
late
Razorpay
_razorpay
;
bool
?
isSuccess
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
@override
void
initState
()
{
super
.
initState
();
_razorpay
=
Razorpay
();
Future
.
microtask
(()
{
final
provider
=
Provider
.
of
<
BillProvider
>(
context
,
listen:
false
);
provider
.
fetchBillList
(
widget
.
sessionId
,
widget
.
orderId
,
widget
.
accId
);
});
}
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
{
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed!"
,
);
// buttonLoading = false;
});
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{}
Future
<
void
>
payAmountFunction
(
String
amount
,
String
id
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Payment"
,
refId:
id
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Could not Complete Payment:
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
CustomSnackBar
.
showError
(
context:
context
,
message:
'Error occurred:
$e
'
,
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
// _buildCheckWidget();
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Rentals'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Bill"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
User_contact
,
'email'
:
''
}
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint
(
e
.
toString
());
}
}
void
verifyPayment
(
String
orderId
)
{
isSuccess
=
true
;
setState
(()
{
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
Consumer
<
BillProvider
>(
...
...
@@ -136,13 +248,27 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
"₹
${latest.totalPrice ?? '0'}
"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
cardAmountText
,
fontSize:
34
,
fontWeight:
FontWeight
.
w500
,
InkResponse
(
onTap:
()
{
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
PaymentSuccessFaillScreen
(
total:
"10218"
,
date:
"8th Oct, 2025"
,
payMode:
"UPI"
,
status:
"Fail"
,
)),
);
},
child:
Text
(
"₹
${latest.totalPrice ?? '0'}
"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
AppColors
.
cardAmountText
,
fontSize:
34
,
fontWeight:
FontWeight
.
w500
,
),
),
),
Container
(
...
...
@@ -175,26 +301,26 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
],
),
// Pending
//
if(latest.billPaid == "No")
//
InkResponse(
//
onTap: () =>
show
Payment
Bottom
Sheet(context, p
ayBill: "1299", payTotal: "4218"
),
//
child: Container(
//
padding: const EdgeInsets.symmetric(
//
horizontal: 12, vertical: 8),
//
decoration: BoxDecoration(
//
color: const Color(0xE0008CDE),
//
borderRadius: BorderRadius.circular(14),
//
),
//
child: const Text(
//
"Pay Now",
//
style: TextStyle(
//
color: Colors.white,
//
fontSize: 14,
//
fontWeight: FontWeight.w500,
//
),
//
),
//
),
//
),
if
(
latest
.
billPaid
==
"No"
)
InkResponse
(
onTap:
()
=>
_open
PaymentSheet
(
context
,
p
rovider
.
billListResponse
!.
payAmount
.
toString
(),
latest
.
totalPrice
??
'0'
,
latest
.
orderId
.
toString
()
),
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
8
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xE0008CDE
),
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
const
Text
(
"Pay Now"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
),
),
),
),
],
),
),
...
...
@@ -290,7 +416,7 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
padding:
const
EdgeInsets
.
only
(
bottom:
8
),
child:
InkResponse
(
onTap:
()
{
Navigator
.
push
(
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
BillDetailScreen
(
sessionId:
widget
.
sessionId
,
...
...
@@ -405,6 +531,234 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
);
}
/// Pay balance sheet
void
_openPaymentSheet
(
BuildContext
context
,
String
totalAmountStr
,
String
billAmount
,
String
id
)
{
TextEditingController
amountController
=
TextEditingController
();
bool
isPartPayment
=
false
;
final
double
totalAmount
=
double
.
tryParse
(
totalAmountStr
)
??
0
;
showModalBottomSheet
(
isScrollControlled:
true
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
)),
),
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
top:
16
,
left:
16
,
right:
16
,
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Handle Bar
Center
(
child:
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
[
300
],
borderRadius:
BorderRadius
.
circular
(
4
),
),
),
),
const
SizedBox
(
height:
16
),
// Title
const
Text
(
"Balance Amount Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
10
),
// Pay Total Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
false
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
false
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Pay Total"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
Text
(
"Avoid late payment fees."
,
style:
TextStyle
(
color:
Color
(
0xff5FBB54
),
fontSize:
12
,
fontFamily:
"Poppins"
,
),
),
],
),
const
Spacer
(),
Text
(
"₹
${totalAmount.toStringAsFixed(0)}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
10
),
// Part Payment Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
true
);
},
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
[
Radio
<
bool
>(
value:
true
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
Text
(
"Pay Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
const
SizedBox
(
width:
24
),
Text
(
"₹
${billAmount}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
6
),
// Continue Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
double
enteredAmount
=
isPartPayment
?
double
.
tryParse
(
amountController
.
text
)
??
0
:
totalAmount
;
if
(
enteredAmount
<=
0
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Please enter a valid amount"
),
),
);
return
;
}
if
(
isPartPayment
&&
enteredAmount
>
totalAmount
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Entered amount cannot exceed total amount"
,
),
),
);
return
;
}
Navigator
.
pop
(
context
);
// Pass selected amount to your payAmountFunction
payAmountFunction
(
enteredAmount
.
toStringAsFixed
(
2
),
id
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF008CDE
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Continue Payment"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
white
,
fontSize:
16
,
),
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
Colors
.
white
,
height:
25
,
width:
25
,
),
],
),
),
),
),
const
SizedBox
(
height:
16
),
],
),
);
},
);
},
);
}
void
showPaymentBottomSheet
(
BuildContext
context
,
{
String
?
payTotal
=
"4218"
,
...
...
lib/Screens/BillScreens/BillDetailScreen.dart
View file @
e4263a00
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:provider/provider.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
import
'../../Notifier/BillProvider.dart'
;
import
'../../Notifier/PayAmountProvider.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'../../Utility/CustomSnackbar.dart'
;
import
'../../Utility/Reusablewidgets.dart'
;
class
BillDetailScreen
extends
StatefulWidget
{
...
...
@@ -22,6 +25,12 @@ class BillDetailScreen extends StatefulWidget {
}
class
_BillDetailScreenState
extends
State
<
BillDetailScreen
>
{
late
Razorpay
_razorpay
;
bool
?
isSuccess
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
// Responsive text size function
double
getResponsiveTextSize
(
BuildContext
context
,
double
baseSize
)
{
final
double
width
=
MediaQuery
.
of
(
context
).
size
.
width
;
...
...
@@ -55,12 +64,110 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
@override
void
initState
()
{
super
.
initState
();
_razorpay
=
Razorpay
();
Future
.
microtask
(()
{
final
provider
=
Provider
.
of
<
BillProvider
>(
context
,
listen:
false
);
provider
.
fetchBillDetails
(
widget
.
sessionId
,
widget
.
accId
,
widget
.
billId
);
});
}
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
{
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed!"
,
);
// buttonLoading = false;
});
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{}
Future
<
void
>
payAmountFunction
(
String
amount
,
String
id
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Payment"
,
refId:
id
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Could not Complete Payment:
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
CustomSnackBar
.
showError
(
context:
context
,
message:
'Error occurred:
$e
'
,
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
// _buildCheckWidget();
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Rentals'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Bill"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
User_contact
,
'email'
:
''
}
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint
(
e
.
toString
());
}
}
void
verifyPayment
(
String
orderId
)
{
isSuccess
=
true
;
setState
(()
{
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
}
@override
Widget
build
(
BuildContext
context
)
{
final
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
...
...
@@ -230,7 +337,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
],
),
),
bottomNavigationBar:
_buildBottomButtons
(
provider
,
isPaid
,
screenWidth
,
screenHeight
),
bottomNavigationBar:
_buildBottomButtons
(
provider
,
isPaid
,
screenWidth
,
screenHeight
,
details
.
totalPrice
??
"0"
,
details
.
id
??
""
),
),
);
},
...
...
@@ -238,7 +345,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
}
/// Conditional Bottom Buttons based on payment status
Widget
_buildBottomButtons
(
BillProvider
provider
,
bool
isPaid
,
double
screenWidth
,
double
screenHeight
)
{
Widget
_buildBottomButtons
(
BillProvider
provider
,
bool
isPaid
,
double
screenWidth
,
double
screenHeight
,
String
totalPrice
,
String
id
)
{
return
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
getResponsivePadding
(
context
),
...
...
@@ -257,33 +364,35 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
child:
Row
(
children:
[
// Pay Now Button (only if not paid)
// if (!isPaid) ...[
// Expanded(
// child: ElevatedButton(
// onPressed: () {
// _showPayNowDialog(screenWidth, screenHeight);
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: AppColors.buttonColor,
// foregroundColor: Colors.white,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(screenWidth * 0.03),
// ),
// padding: EdgeInsets.symmetric(vertical: screenHeight * 0.018),
// elevation: 0,
// ),
// child: Text(
// "Pay Now",
// style: TextStyle(
// fontSize: getResponsiveTextSize(context, 14),
// fontFamily: "Poppins",
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ),
// SizedBox(width: screenWidth * 0.03),
// ],
if
(!
isPaid
)
...[
Expanded
(
child:
ElevatedButton
(
onPressed:
()
{
Navigator
.
pop
(
context
);
// handle payment navigation
payAmountFunction
(
totalPrice
,
id
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
screenWidth
*
0.03
),
),
padding:
EdgeInsets
.
symmetric
(
vertical:
screenHeight
*
0.018
),
elevation:
0
,
),
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
fontSize:
getResponsiveTextSize
(
context
,
14
),
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
SizedBox
(
width:
screenWidth
*
0.03
),
],
// Download Receipt Button
Expanded
(
...
...
lib/Screens/DashboardScreen.dart
View file @
e4263a00
...
...
@@ -14,7 +14,10 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import
'package:provider/provider.dart'
;
import
'../Models/DashboardResponse.dart'
;
import
'../Notifier/DashboardProvider.dart'
;
import
'../Notifier/PayAmountProvider.dart'
;
import
'TransactionScreens/PaymentSuccessfailScreen.dart'
;
import
'authScreen/LoginScreen.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
class
DashboardScreen
extends
StatefulWidget
{
final
String
accId
;
...
...
@@ -28,9 +31,16 @@ class DashboardScreen extends StatefulWidget {
class
_DashboardScreenState
extends
State
<
DashboardScreen
>
with
WidgetsBindingObserver
{
DateTime
?
currentBackPressTime
;
late
Razorpay
_razorpay
;
bool
?
isSuccess
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
@override
void
initState
()
{
super
.
initState
();
_razorpay
=
Razorpay
();
WidgetsBinding
.
instance
.
addObserver
(
this
);
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
...
...
@@ -38,6 +48,138 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
});
}
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
response
.
orderId
.
toString
()
);
final
data
=
provider
.
statusResponse
;
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
PaymentSuccessFaillScreen
(
total:
"
${data?.amount}
"
,
date:
"
${data?.date}
"
,
payMode:
"UPI"
,
status:
"Success"
,
)),
);
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
data
?.
message
??
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
""
);
final
data
=
provider
.
statusResponse
;
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
PaymentSuccessFaillScreen
(
total:
"
${data?.amount}
"
,
date:
"
${data?.date}
"
,
payMode:
"UPI"
,
status:
"Fail"
,
)),
);
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
});
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{}
Future
<
void
>
payAmountFunction
(
String
amount
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Payment"
,
refId:
"1"
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
debugPrint
(
"❌ 'Error occurred:
$e
'"
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
// _buildCheckWidget();
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Rentals'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Payment"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
User_contact
,
'email'
:
''
}
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint
(
e
.
toString
());
}
}
void
verifyPayment
(
String
orderId
)
{
isSuccess
=
true
;
setState
(()
{
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override
void
dispose
()
{
WidgetsBinding
.
instance
.
removeObserver
(
this
);
...
...
@@ -362,7 +504,6 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
Text
(
dashboardData
?.
balanceAmount
?.
toString
()
??
"0"
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
getResponsiveTextSize
(
context
,
34
),
fontWeight:
FontWeight
.
w500
,
...
...
@@ -370,6 +511,18 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
),
],
),
InkResponse
(
onTap:
()
=>
_openPaymentSheet
(
context
,
dashboardData
!.
balanceAmount
.
toString
()),
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
color:
Colors
.
blue
,
fontFamily:
"Poppins"
,
fontSize:
getResponsiveTextSize
(
context
,
14
),
fontWeight:
FontWeight
.
w500
,
),
),
),
],
),
SizedBox
(
height:
screenHeight
*
0.015
),
...
...
@@ -794,7 +947,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
],
),
//
✅
Gradient expiry badge
// Gradient expiry badge
if
(
product
.
expiringText
!=
null
&&
product
.
expiringText
!.
isNotEmpty
)
Container
(
padding:
EdgeInsets
.
symmetric
(
...
...
@@ -1112,6 +1265,251 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
);
}
}
/// Pay balance sheet
void
_openPaymentSheet
(
BuildContext
context
,
String
totalAmountStr
)
{
TextEditingController
amountController
=
TextEditingController
();
bool
isPartPayment
=
false
;
final
double
totalAmount
=
double
.
tryParse
(
totalAmountStr
)
??
0
;
showModalBottomSheet
(
isScrollControlled:
true
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
)),
),
context:
context
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
top:
16
,
left:
16
,
right:
16
,
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Handle Bar
Center
(
child:
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
[
300
],
borderRadius:
BorderRadius
.
circular
(
4
),
),
),
),
const
SizedBox
(
height:
16
),
// Title
const
Text
(
"Balance Amount Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
10
),
// Pay Total Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
false
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
false
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Pay Total"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
Text
(
"Avoid late payment fees."
,
style:
TextStyle
(
color:
Color
(
0xff5FBB54
),
fontSize:
12
,
fontFamily:
"Poppins"
,
),
),
],
),
const
Spacer
(),
Text
(
"₹
${totalAmount.toStringAsFixed(0)}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
10
),
// Part Payment Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
true
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
true
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
const
Text
(
"Part Payment"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
const
SizedBox
(
width:
24
),
Expanded
(
child:
Container
(
height:
50
,
alignment:
Alignment
.
center
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade100
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
TextFormField
(
controller:
amountController
,
enabled:
isPartPayment
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
black87
,
),
keyboardType:
TextInputType
.
number
,
decoration:
const
InputDecoration
(
hintText:
"Enter amount"
,
hintStyle:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
),
border:
InputBorder
.
none
,
),
),
),
),
],
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
6
),
// Continue Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
double
enteredAmount
=
isPartPayment
?
double
.
tryParse
(
amountController
.
text
)
??
0
:
totalAmount
;
if
(
enteredAmount
<=
0
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Please enter a valid amount"
),
),
);
return
;
}
if
(
isPartPayment
&&
enteredAmount
>
totalAmount
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Entered amount cannot exceed total amount"
,
),
),
);
return
;
}
Navigator
.
pop
(
context
);
// Pass selected amount to your payAmountFunction
payAmountFunction
(
enteredAmount
.
toStringAsFixed
(
2
));
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF008CDE
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Continue Payment"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
white
,
fontSize:
16
,
),
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
Colors
.
white
,
height:
25
,
width:
25
,
),
],
),
),
),
),
const
SizedBox
(
height:
16
),
],
),
);
},
);
},
);
}
void
showPaymentBottomSheet
(
BuildContext
context
,
{
...
...
@@ -1204,7 +1602,7 @@ class _PaymentBottomSheetContentState extends State<PaymentBottomSheetContent> {
}
void
_handleContinuePayment
()
{
//
✅
Validation
// Validation
if
(
selectedOption
==
-
1
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
...
...
lib/Screens/HelpScreens/HelpScreen.dart
View file @
e4263a00
...
...
@@ -27,7 +27,7 @@ class _HelpScreenState extends State<HelpScreen> {
void
initState
()
{
super
.
initState
();
///
✅
Fetch ticket list on screen load
/// Fetch ticket list on screen load
Future
.
microtask
(()
async
{
final
provider
=
Provider
.
of
<
HelpAndEnquiryProvider
>(
context
,
listen:
false
);
await
provider
.
fetchTicketList
(
...
...
@@ -37,7 +37,7 @@ class _HelpScreenState extends State<HelpScreen> {
});
}
//
✅
(unchanged)
// (unchanged)
final
List
<
Map
<
String
,
dynamic
>>
createNewTickets
=
[
{
'title'
:
'Payment Issues'
,
...
...
@@ -102,7 +102,7 @@ class _HelpScreenState extends State<HelpScreen> {
),
),
//
✅
Provider Consumer used here
// Provider Consumer used here
body:
Consumer
<
HelpAndEnquiryProvider
>(
builder:
(
context
,
provider
,
_
)
{
if
(
provider
.
isLoading
)
{
...
...
@@ -257,7 +257,7 @@ class _HelpScreenState extends State<HelpScreen> {
);
}
///
✅
Processing tickets from provider
/// Processing tickets from provider
Widget
_buildProcessingTicketsSection
(
List
<
dynamic
>
tickets
)
{
if
(
tickets
.
isEmpty
)
{
return
const
Center
(
child:
Text
(
"No processing tickets"
));
...
...
@@ -294,7 +294,7 @@ class _HelpScreenState extends State<HelpScreen> {
);
}
///
✅
Closed tickets from provider
/// Closed tickets from provider
Widget
_buildClosedTicketsSection
(
List
<
dynamic
>
tickets
)
{
if
(
tickets
.
isEmpty
)
{
return
const
Center
(
child:
Text
(
"No closed tickets"
));
...
...
lib/Screens/ProductsDetailScreen.dart
View file @
e4263a00
...
...
@@ -90,7 +90,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
),
SizedBox
(
width:
screenWidth
*
0.025
),
Text
(
"
Bill
Details"
,
"
Order
Details"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
isSmallScreen
?
14
:
16
,
...
...
lib/Screens/TransactionScreens/BillPendingToast.dart
View file @
e4263a00
...
...
@@ -26,7 +26,7 @@ class _BillPendingToastState extends State<BillPendingToast> {
void
initState
()
{
super
.
initState
();
///
🔹
Fetch data after one frame (safe after build)
/// Fetch data after one frame (safe after build)
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
final
provider
=
Provider
.
of
<
TransactionsProvider
>(
context
,
listen:
false
);
provider
.
fetchPaymentReceiptDetails
(
...
...
@@ -246,27 +246,27 @@ class _BillPendingToastState extends State<BillPendingToast> {
),
),
const
SizedBox
(
width:
12
),
//
Expanded(
//
child: ElevatedButton(
//
onPressed: widget.onPayNow,
//
style: ElevatedButton.styleFrom(
//
backgroundColor: AppColors.amountText,
//
shape: RoundedRectangleBorder(
//
borderRadius: BorderRadius.circular(50),
//
),
//
padding: const EdgeInsets.symmetric(vertical: 14),
//
),
//
child: const Text(
//
"Pay Now",
//
style: TextStyle(
//
fontSize: 15,
//
fontFamily: "Poppins",
//
fontWeight: FontWeight.w600,
//
color: Colors.white,
//
),
//
),
//
),
//
),
Expanded
(
child:
ElevatedButton
(
onPressed:
widget
.
onPayNow
,
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
amountText
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
50
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
14
),
),
child:
const
Text
(
"Pay Now"
,
style:
TextStyle
(
fontSize:
15
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
white
,
),
),
),
),
],
),
],
...
...
lib/Screens/TransactionScreens/BillStatusToast.dart
View file @
e4263a00
...
...
@@ -25,7 +25,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
void
initState
()
{
super
.
initState
();
//
✅
Automatically fetch data when dialog opens
// Automatically fetch data when dialog opens
Future
.
microtask
(()
{
final
provider
=
Provider
.
of
<
TransactionsProvider
>(
context
,
listen:
false
);
...
...
@@ -105,7 +105,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
),
const
SizedBox
(
height:
16
),
//
✅
Title & Amount
// Title & Amount
const
Text
(
"Payment Receipt"
,
style:
TextStyle
(
...
...
@@ -130,7 +130,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const
Divider
(
thickness:
1
,
color:
Color
(
0xFFE6E6E6
)),
const
SizedBox
(
height:
12
),
//
✅
Payment Details
// Payment Details
const
Align
(
alignment:
Alignment
.
centerLeft
,
child:
Text
(
...
...
@@ -153,7 +153,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const
Divider
(
thickness:
1
,
color:
Color
(
0xFFE6E6E6
)),
const
SizedBox
(
height:
12
),
//
✅
Products
// Products
const
Align
(
alignment:
Alignment
.
centerLeft
,
child:
Text
(
...
...
@@ -177,7 +177,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const
Divider
(
thickness:
1
,
color:
Color
(
0xFFE6E6E6
)),
const
SizedBox
(
height:
8
),
//
✅
Total
// Total
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
...
...
@@ -204,7 +204,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const
SizedBox
(
height:
22
),
//
✅
Download Button
// Download Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
.
icon
(
...
...
lib/Screens/TransactionScreens/PaymentSuccessf
u
lScreen.dart
→
lib/Screens/TransactionScreens/PaymentSuccessf
ai
lScreen.dart
View file @
e4263a00
...
...
@@ -3,14 +3,32 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import
'../../Utility/AppColors.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
class
PaymentSuccessfulScreen
extends
StatefulWidget
{
const
PaymentSuccessfulScreen
({
super
.
key
});
import
'../../Utility/SharedpreferencesService.dart'
;
import
'../DashboardScreen.dart'
;
class
PaymentSuccessFaillScreen
extends
StatefulWidget
{
final
String
total
;
final
String
date
;
final
String
payMode
;
final
String
status
;
const
PaymentSuccessFaillScreen
({
super
.
key
,
required
this
.
total
,
required
this
.
date
,
required
this
.
payMode
,
required
this
.
status
,
});
@override
State
<
PaymentSuccess
fu
lScreen
>
createState
()
=>
_PaymentSuccess
fu
lScreenState
();
State
<
PaymentSuccess
Fail
lScreen
>
createState
()
=>
_PaymentSuccess
Fail
lScreenState
();
}
class
_PaymentSuccessfulScreenState
extends
State
<
PaymentSuccessfulScreen
>
{
class
_PaymentSuccessFaillScreenState
extends
State
<
PaymentSuccessFaillScreen
>
{
final
prefs
=
SharedPreferencesService
.
instance
;
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
...
...
@@ -38,6 +56,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
const
SizedBox
(
height:
40
),
// Success Icon
if
(
widget
.
status
==
"Success"
)
Container
(
width:
double
.
infinity
,
height:
140
,
...
...
@@ -48,23 +67,45 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
width:
80
,
),
),
if
(
widget
.
status
==
"Fail"
)
Container
(
width:
double
.
infinity
,
height:
140
,
color:
Colors
.
white
,
child:
Image
.
asset
(
'assets/images/failed_pay_gif.gif'
,
height:
80
,
width:
80
,
),
),
const
SizedBox
(
height:
24
),
// Success Title
if
(
widget
.
status
==
"Success"
)
const
Text
(
"Payment Successful"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
24
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
),
if
(
widget
.
status
==
"Fail"
)
const
Text
(
"Payment Failed"
,
style:
TextStyle
(
fontSize:
24
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
),
const
SizedBox
(
height:
8
),
// Success Message
if
(
widget
.
status
==
"Success"
)
Text
(
"Now enjoy a seamless,
\n
uninterrupted rental service."
,
textAlign:
TextAlign
.
center
,
...
...
@@ -76,49 +117,85 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
height:
1.5
,
),
),
if
(
widget
.
status
==
"Fail"
)
Text
(
"There may be an issue with your,
\n
Payment, please try again."
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
16
,
fontWeight:
FontWeight
.
w400
,
color:
AppColors
.
subtitleText
,
height:
1.5
,
),
),
const
SizedBox
(
height:
22
),
Text
(
"₹
${widget.total}
"
,
style:
TextStyle
(
fontSize:
34
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
),
const
SizedBox
(
height:
9
),
Divider
(),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
SizedBox
(
height:
25
),
const
SectionHeading
(
title:
"Payment Details"
),
SectionHeading
(
title:
"Payment Details"
,
textStyle:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
),
// Payment Details Section
_buildSection
(
children:
[
_buildDetailRow
(
title:
"Date"
,
value:
"8th Oct, 2025"
),
_buildDetailRow
(
title:
"Payment Mode"
,
value:
"Credit Card **56"
),
_buildDetailRow
(
title:
"Payment Status"
,
value:
"Paid"
,
valueStyle:
const
TextStyle
(
color:
Color
(
0xFF4CAF50
),
fontWeight:
FontWeight
.
w600
,
),
),
_buildDetailRow
(
title:
"Payment Mode"
,
value:
widget
.
payMode
),
],
),
const
SizedBox
(
height:
10
),
const
SectionHeading
(
title:
"Bill Details"
),
// Bill Details Section
_buildSection
(
children:
[
_buildDetailRow
(
title:
"Total Amount"
,
value:
"₹421"
),
_buildDetailRow
(
title:
"Bill Cycle"
,
value:
"7th Sep, 2025 – 7th Oct, 2025"
),
_buildDetailRow
(
title:
"Bill Generated Date"
,
value:
"8th Oct, 2025"
),
_buildDetailRow
(
title:
"Payable Amount"
,
value:
"₹421"
),
_buildDetailRow
(
title:
"Paid Date/Due Date"
,
value:
"7th Oct, 2025"
),
],
),
const
SizedBox
(
height:
2
),
Divider
(),
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
SectionHeading
(
title:
"Total"
,
textStyle:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
),
Text
(
"₹
${widget.total}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
normalText
,
),
)
],
),
)
],
),
const
SizedBox
(
height:
25
),
// Back to Home Button
const
SizedBox
(
height:
110
),
if
(
widget
.
status
==
"Fail"
)
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
...
...
@@ -134,20 +211,16 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
const
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Text
(
"Back to Home"
,
style:
TextStyle
(
color:
Color
(
0xFFFFFFFF
),
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
),
),
],
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Color
(
0xFFFFFFFF
),
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
),
),
),
),
...
...
@@ -159,6 +232,59 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
),
),
),
bottomNavigationBar:
Padding
(
padding:
const
EdgeInsets
.
all
(
16.0
),
child:
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
async
{
final
String
?
savedAccId
=
await
prefs
.
getString
(
"accId"
);
final
String
?
savedSessionId
=
await
prefs
.
getString
(
"session_id"
);
// Add navigation logic here
Navigator
.
pop
(
context
);
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
DashboardScreen
(
sessionId:
savedSessionId
!,
accId:
savedAccId
.
toString
(),)
)
//route
);
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
widget
.
status
==
"Fail"
?
AppColors
.
backgroundRegular
:
AppColors
.
buttonColor
,
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
SvgPicture
.
asset
(
"assets/svg/homes_ic.svg"
,
color:
widget
.
status
==
"Fail"
?
Colors
.
blue
:
Color
(
0xFFFFFFFF
),
height:
22
,
width:
22
,
),
SizedBox
(
width:
12
),
Text
(
"Back to Home"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
widget
.
status
==
"Fail"
?
Colors
.
blue
:
Color
(
0xFFFFFFFF
),
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
),
),
],
),
),
),
),
),
);
}
...
...
@@ -167,9 +293,9 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
})
{
return
Container
(
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
14
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
6
),
decoration:
BoxDecoration
(
color:
const
Color
(
0x
FF
F8F9FA
),
color:
const
Color
(
0x
11
F8F9FA
),
borderRadius:
BorderRadius
.
circular
(
18
),
),
child:
Column
(
...
...
@@ -218,7 +344,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
style:
valueStyle
??
const
TextStyle
(
fontFamily:
"Poppins"
,
fontSize:
14
,
fontWeight:
FontWeight
.
w
4
00
,
fontWeight:
FontWeight
.
w
5
00
,
color:
AppColors
.
normalText
,
),
),
...
...
lib/Screens/TransactionScreens/TransactionsScreen.dart
View file @
e4263a00
...
...
@@ -2,14 +2,17 @@ import 'package:flutter/material.dart';
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:gen_rentals/Screens/TransactionScreens/BillStatusToast.dart'
;
import
'package:provider/provider.dart'
;
import
'package:razorpay_flutter/razorpay_flutter.dart'
;
import
'../../Notifier/BillProvider.dart'
;
import
'../../Notifier/PayAmountProvider.dart'
;
import
'../../Notifier/TransactionsProvider.dart'
;
import
'../../Utility/AppColors.dart'
;
import
'../../Utility/CustomSnackbar.dart'
;
import
'../BillScreens/BillDetailScreen.dart'
;
import
'../DashboardScreen.dart'
;
import
'BillPendingToast.dart'
;
import
'PaymentSuccessfailScreen.dart'
;
class
TransactionsScreen
extends
StatefulWidget
{
...
...
@@ -26,8 +29,15 @@ class TransactionsScreen extends StatefulWidget {
}
class
_TransactionsScreenState
extends
State
<
TransactionsScreen
>
{
bool
isSuccess
=
false
;
late
Razorpay
_razorpay
;
var
paymentMethod
=
""
;
var
User_contact
=
"0"
;
@override
void
initState
()
{
_razorpay
=
Razorpay
();
super
.
initState
();
Future
.
microtask
(()
{
Provider
.
of
<
TransactionsProvider
>(
context
,
listen:
false
)
...
...
@@ -35,6 +45,125 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
});
}
void
_handlePaymentSuccess
(
PaymentSuccessResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
response
.
orderId
.
toString
()
);
final
data
=
provider
.
statusResponse
;
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
PaymentSuccessFaillScreen
(
total:
"
${data?.amount}
"
,
date:
"
${data?.date}
"
,
payMode:
"UPI"
,
status:
"Success"
,
)),
);
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
data
?.
message
??
"Payment Success!"
,
);
// buttonLoading = false;
});
}
void
_handlePaymentError
(
PaymentFailureResponse
response
)
{
setState
(()
async
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
getPaymentStatus
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
razorpayOrderId:
""
);
final
data
=
provider
.
statusResponse
;
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
PaymentSuccessFaillScreen
(
total:
"
${data?.amount}
"
,
date:
"
${data?.date}
"
,
payMode:
"UPI"
,
status:
"Fail"
,
)),
);
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
});
CustomSnackBar
.
showError
(
context:
context
,
message:
"Payment failed, please try again."
,
);
}
void
_handleExternalWallet
(
ExternalWalletResponse
response
)
{}
Future
<
void
>
payAmountFunction
(
String
amount
)
async
{
try
{
final
provider
=
Provider
.
of
<
PayAmountProvider
>(
context
,
listen:
false
);
await
provider
.
payAmount
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
accId
,
amount:
amount
,
refType:
"Payment"
,
refId:
"1"
,
);
final
data
=
provider
.
payResponse
;
if
(
data
!=
null
)
{
if
(
data
.
error
==
"0"
)
{
openCheckout
(
data
.
orderId
,
data
.
razorKey
!);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"
${data.message}
"
,
);
debugPrint
(
"❌ Could not Complete Payment:
${data.message}
"
);
}
}
else
{
debugPrint
(
"❌ No response received from PayAmount API"
);
}
}
catch
(
e
)
{
debugPrint
(
"❌ 'Error occurred:
$e
'"
);
}
}
//razorpay payments__________________________________________________________
void
openCheckout
(
razorPayOrderId
,
String
razorpayKey
)
async
{
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_SUCCESS
,
_handlePaymentSuccess
);
_razorpay
.
on
(
Razorpay
.
EVENT_PAYMENT_ERROR
,
_handlePaymentError
);
_razorpay
.
on
(
Razorpay
.
EVENT_EXTERNAL_WALLET
,
_handleExternalWallet
);
//
Map
<
String
,
dynamic
>
options
=
{
'key'
:
razorpayKey
,
'amount'
:
int
.
parse
(
"
${((0) * 100).round()}
"
),
'name'
:
'Gen Rentals'
,
'order_id'
:
razorPayOrderId
,
'description'
:
"Payment"
,
'currency'
:
'INR'
,
'method'
:
'upi'
,
'prefill'
:
{
'contact'
:
User_contact
,
'email'
:
''
}
};
// print(options);
try
{
_razorpay
.
open
(
options
);
}
catch
(
e
,
s
)
{
debugPrint
(
e
.
toString
());
}
}
@override
Widget
build
(
BuildContext
context
)
{
final
provider
=
Provider
.
of
<
TransactionsProvider
>(
context
);
...
...
@@ -110,6 +239,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
SizedBox
(
height:
8
),
...
items
.
map
((
txn
)
=>
InkResponse
(
onTap:
()
async
{
final
amount
=
txn
.
amount
??
0
;
final
provider
=
Provider
.
of
<
TransactionsProvider
>(
context
,
listen:
false
);
await
provider
.
fetchPaymentReceiptDetails
(
widget
.
sessionId
,
...
...
@@ -119,6 +249,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
if
(
txn
.
type
==
"Credit"
)
{
showDialog
(
context:
context
,
builder:
(
context
)
=>
BillStatusToast
(
sessionId:
widget
.
sessionId
,
...
...
@@ -136,6 +267,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
onPayNow:
()
{
Navigator
.
pop
(
context
);
// handle payment navigation
payAmountFunction
(
amount
.
toString
());
},
),
);
...
...
@@ -346,18 +478,18 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
fontWeight:
FontWeight
.
w500
,
),
),
//
InkResponse(
//
onTap: () =>
show
Payment
Bottom
Sheet(context),
//
child: Text(
//
"Pay Now",
//
style: TextStyle(
//
fontFamily: "Poppins",
//
color: Color(0xFF008CDE),
//
fontSize: 14,
//
fontWeight: FontWeight.w500,
//
),
//
),
//
),
InkResponse
(
onTap:
()
=>
_open
PaymentSheet
(
context
,
balance
.
toString
()
),
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Color
(
0xFF008CDE
),
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
),
),
),
],
),
const
SizedBox
(
height:
12
),
...
...
@@ -451,25 +583,248 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
);
}
void
show
Payment
Bottom
Sheet
(
BuildContext
context
,
{
String
?
payTotal
=
"4218"
,
String
?
payBill
=
"2018"
,
})
{
void
_open
PaymentSheet
(
BuildContext
context
,
String
totalAmountStr
)
{
TextEditingController
amountController
=
TextEditingController
();
bool
isPartPayment
=
false
;
final
double
totalAmount
=
double
.
tryParse
(
totalAmountStr
)
??
0
;
showModalBottomSheet
(
isScrollControlled:
true
,
backgroundColor:
Colors
.
white
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
24
)),
),
context:
context
,
isScrollControlled:
true
,
// This is important
backgroundColor:
Colors
.
transparent
,
isDismissible:
true
,
enableDrag:
true
,
builder:
(
BuildContext
context
)
{
return
PaymentBottomSheetContent
(
payTotal:
payTotal
,
payBill:
payBill
,
billFlag:
false
,
partFlag:
true
,
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
top:
16
,
left:
16
,
right:
16
,
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// Handle Bar
Center
(
child:
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
[
300
],
borderRadius:
BorderRadius
.
circular
(
4
),
),
),
),
const
SizedBox
(
height:
16
),
// Title
const
Text
(
"Balance Amount Bill"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Poppins"
,
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
10
),
// Pay Total Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
false
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
false
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Text
(
"Pay Total"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
Text
(
"Avoid late payment fees."
,
style:
TextStyle
(
color:
Color
(
0xff5FBB54
),
fontSize:
12
,
fontFamily:
"Poppins"
,
),
),
],
),
const
Spacer
(),
Text
(
"₹
${totalAmount.toStringAsFixed(0)}
"
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
const
SizedBox
(
height:
10
),
// Part Payment Option
GestureDetector
(
onTap:
()
{
setState
(()
=>
isPartPayment
=
true
);
},
child:
Row
(
children:
[
Radio
<
bool
>(
value:
true
,
groupValue:
isPartPayment
,
onChanged:
(
v
)
=>
setState
(()
=>
isPartPayment
=
v
!),
activeColor:
const
Color
(
0xFF008CDE
),
),
const
Text
(
"Part Payment"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
fontWeight:
FontWeight
.
w400
,
),
),
const
SizedBox
(
width:
24
),
Expanded
(
child:
Container
(
height:
50
,
alignment:
Alignment
.
center
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade100
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
TextFormField
(
controller:
amountController
,
enabled:
isPartPayment
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
black87
,
),
keyboardType:
TextInputType
.
number
,
decoration:
const
InputDecoration
(
hintText:
"Enter amount"
,
hintStyle:
TextStyle
(
fontSize:
14
,
fontFamily:
"Poppins"
,
color:
Colors
.
grey
,
),
border:
InputBorder
.
none
,
),
),
),
),
],
),
),
const
SizedBox
(
height:
6
),
Divider
(),
const
SizedBox
(
height:
6
),
// Continue Button
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
double
enteredAmount
=
isPartPayment
?
double
.
tryParse
(
amountController
.
text
)
??
0
:
totalAmount
;
if
(
enteredAmount
<=
0
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Please enter a valid amount"
),
),
);
return
;
}
if
(
isPartPayment
&&
enteredAmount
>
totalAmount
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Entered amount cannot exceed total amount"
,
),
),
);
return
;
}
Navigator
.
pop
(
context
);
// Pass selected amount to your payAmountFunction
payAmountFunction
(
enteredAmount
.
toStringAsFixed
(
2
));
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF008CDE
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
30
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
22
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
const
Text
(
"Continue Payment"
,
style:
TextStyle
(
fontFamily:
"Poppins"
,
color:
Colors
.
white
,
fontSize:
16
,
),
),
SvgPicture
.
asset
(
"assets/svg/continue_ic.svg"
,
color:
Colors
.
white
,
height:
25
,
width:
25
,
),
],
),
),
),
),
const
SizedBox
(
height:
16
),
],
),
);
},
);
},
);
}
}
lib/Screens/authScreen/forgot_password_screen.dart
deleted
100644 → 0
View file @
42164fa1
// forgot_password_screen.dart
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
class
ForgotPasswordScreen
extends
StatelessWidget
{
const
ForgotPasswordScreen
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
final
emailController
=
TextEditingController
();
return
Scaffold
(
backgroundColor:
const
Color
(
0xFFF5F8FC
),
body:
Center
(
child:
SingleChildScrollView
(
padding:
const
EdgeInsets
.
all
(
16
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
SvgPicture
.
network
(
"https://genrentals.in/assets/img/logo-black.svg"
,
height:
70
,
),
const
SizedBox
(
height:
20
),
const
Text
(
"Forgot Password"
,
style:
TextStyle
(
fontSize:
24
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
const
SizedBox
(
height:
20
),
Container
(
padding:
const
EdgeInsets
.
all
(
20
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
8
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black12
,
blurRadius:
6
,
offset:
Offset
(
0
,
2
),
)
],
),
child:
Column
(
children:
[
TextFormField
(
controller:
emailController
,
decoration:
InputDecoration
(
labelText:
"Email Address"
,
border:
OutlineInputBorder
(
borderRadius:
BorderRadius
.
circular
(
6
),
),
),
),
const
SizedBox
(
height:
16
),
SizedBox
(
width:
double
.
infinity
,
height:
45
,
child:
ElevatedButton
(
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
const
Color
(
0xFF2563EB
),
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
6
),
),
),
onPressed:
()
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"Password reset link sent to email"
)),
);
},
child:
const
Text
(
"Confirm"
,
style:
TextStyle
(
color:
Colors
.
white
),
),
),
)
],
),
),
],
),
),
),
);
}
}
lib/Services/api_URLs.dart
View file @
e4263a00
...
...
@@ -14,6 +14,8 @@ const billListUrl = "${baseUrl}bill_list";
const
downloadBillUrl
=
"
${baseUrl}
download_bill"
;
const
paymentReceiptDetailsUrl
=
"
${baseUrl}
payment_receipt_details"
;
const
downloadReceiptUrl
=
"
${baseUrl}
download_receipt"
;
const
payAmountUrl
=
"
${baseUrl}
pay_amount"
;
const
getPaymentStatusUrl
=
"
${baseUrl}
get_payment_status"
;
/// info
const
checkInOutSubmitUrl
=
"
${baseUrl}
check_in_out_submit"
;
...
...
lib/Services/api_calling.dart
View file @
e4263a00
...
...
@@ -14,10 +14,12 @@ import 'package:gen_rentals/Models/HelpAndEnquiryModels/ticketListResponse.dart'
import
'../Models/BillsModels/BillDetailsResponse.dart'
;
import
'../Models/DashboardResponse.dart'
;
import
'../Models/RentalPaymentDetailsResponse.dart'
;
import
'../Models/TransactionModels/PayAmountResponse.dart'
;
import
'../Models/TransactionModels/TransactionsResponse.dart'
;
import
'../Models/orderDetailsBillResponse.dart'
;
import
'../Models/rentalAccountResponse.dart'
;
import
'../Models/rentalContactResponse.dart'
;
import
'../Notifier/PayAmountProvider.dart'
;
import
'../Notifier/RentalContactProvider .dart'
;
import
'api_URLs.dart'
;
import
'api_post_request.dart'
;
...
...
@@ -54,7 +56,7 @@ class ApiCalling {
String
otp
,
deviceDetails
)
async
{
debugPrint
(
"############################### Api calling "
);
debugPrint
(
"############################### Api
fetch otp
calling "
);
try
{
Map
<
String
,
String
>
data
=
{
"mob"
:
mob
,
...
...
@@ -64,7 +66,7 @@ class ApiCalling {
print
(
data
);
final
res
=
await
post
(
data
,
fetchOtpUrl
,
{});
if
(
res
!=
null
)
{
print
(
res
);
return
FetchMobileResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
...
...
@@ -101,27 +103,61 @@ class ApiCalling {
}
/// Fetch Rental Account Info
static
Future
<
RentalAccountResponse
?>
fetchRentalAccountInfoApi
(
/// pay_amount
static
Future
<
PayAmountResponse
?>
payAmountApi
(
String
sessionId
,
String
empId
,
String
ammount
,
String
refType
,
String
refId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
"session_id"
:
sessionId
,
"acc_id"
:
empId
,
"amount"
:
ammount
,
"ref_type"
:
refType
,
"ref_id"
:
refId
,
};
final
res
=
await
post
(
data
,
payAmountUrl
,
{});
debugPrint
(
"PayAmount Response
${res?.body}
"
);
if
(
res
!=
null
)
{
return
PayAmountResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
"❌ API Error (payAmountApi):
$e
"
);
return
null
;
}
}
/// Fetch or get_payment_status
static
Future
<
PaymentStatusResponse
?>
getPaymentStatusApi
(
String
sessionId
,
String
empId
,
String
razorpayOrderId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
"session_id"
:
sessionId
,
"emp_id"
:
empId
,
"razorpay_order_id"
:
razorpayOrderId
,
};
final
res
=
await
post
(
data
,
get
RentalAccInfo
Url
,
{});
final
res
=
await
post
(
data
,
get
PaymentStatus
Url
,
{});
if
(
res
!=
null
)
{
return
RentalAccount
Response
.
fromJson
(
jsonDecode
(
res
.
body
));
return
PaymentStatus
Response
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
"❌ API Error (
fetchRentalAccountInfo
):
$e
"
);
debugPrint
(
"❌ API Error (
razorpay_order_id
):
$e
"
);
return
null
;
}
}
...
...
@@ -296,32 +332,7 @@ class ApiCalling {
}
/// Fetch Order Details Product
static
Future
<
OrderDetailsProductResponse
?>
fetchOrderDetailProductApi
(
String
sessionId
,
String
empId
,
String
orderId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
"session_id"
:
sessionId
,
"emp_id"
:
empId
,
"order_id"
:
orderId
,
};
final
res
=
await
post
(
data
,
orderDetailsProductUrl
,
{});
if
(
res
!=
null
)
{
return
OrderDetailsProductResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
"❌ API Error (fetchOrderDetailProduct):
$e
"
);
return
null
;
}
}
/// Fetch Order Details Main
static
Future
<
OrderDetailsMainResponse
?>
fetchOrderDetailMainApi
(
...
...
lib/main.dart
View file @
e4263a00
...
...
@@ -5,6 +5,7 @@ import 'package:gen_rentals/Notifier/HelpAndEnquiryProvider.dart';
import
'package:gen_rentals/Notifier/TransactionsProvider.dart'
;
import
'package:gen_rentals/Screens/SplashScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'Notifier/PayAmountProvider.dart'
;
import
'Notifier/RentalContactProvider .dart'
;
import
'Notifier/SubscribeOrderDetailsProvider.dart'
;
import
'Notifier/theme_provider.dart'
;
...
...
@@ -36,6 +37,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider
(
create:
(
_
)
=>
TransactionsProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
HelpAndEnquiryProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
BillProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
PayAmountProvider
()),
],
child:
Consumer
<
ThemeProvider
>(
builder:
(
context
,
themeProvider
,
child
)
{
...
...
pubspec.lock
View file @
e4263a00
...
...
@@ -153,14 +153,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.3"
eventify:
dependency: transitive
description:
name: eventify
sha256: b829429f08586cc2001c628e7499e3e3c2493a1d895fd73b00ecb23351aa5a66
url: "https://pub.dev"
source: hosted
version: "1.0.1"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "
5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44
"
sha256: "
6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc
"
url: "https://pub.dev"
source: hosted
version: "1.3.
3
"
version: "1.3.
2
"
ffi:
dependency: transitive
description:
...
...
@@ -296,6 +304,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
fluttertoast:
dependency: transitive
description:
name: fluttertoast
sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8"
url: "https://pub.dev"
source: hosted
version: "8.2.14"
google_fonts:
dependency: "direct main"
description:
...
...
@@ -396,26 +412,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256:
"33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
sha256:
c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "1
1
.0.
2
"
version: "1
0
.0.
8
"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256:
"1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
sha256:
f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.
10
"
version: "3.0.
9
"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "
8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1
"
sha256: "
6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3
"
url: "https://pub.dev"
source: hosted
version: "3.0.
2
"
version: "3.0.
1
"
lints:
dependency: transitive
description:
...
...
@@ -672,6 +688,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
razorpay_flutter:
dependency: "direct main"
description:
name: razorpay_flutter
sha256: "7d86b2a2ba2c3a71366bbfb65664236ba4b12fd6aeaed4c13dfc5c998786b2d6"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
rxdart:
dependency: transitive
description:
...
...
@@ -841,10 +865,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256:
"522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
sha256:
fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.
6
"
version: "0.7.
4
"
typed_data:
dependency: transitive
description:
...
...
@@ -889,10 +913,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256:
d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
sha256:
"80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.
2.0
"
version: "2.
1.4
"
vm_service:
dependency: transitive
description:
...
...
@@ -942,5 +966,5 @@ packages:
source: hosted
version: "6.5.0"
sdks:
dart: ">=3.
8.0-0
<4.0.0"
dart: ">=3.
7.2
<4.0.0"
flutter: ">=3.29.0"
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment