В приложении Flutter генерируются два заказа вместо одного
Я пытаюсь создать приложение для электронной коммерции, которое позволяет пользователю размещать заказ, совершив онлайн-платеж с помощью Razorpay или выбрав оплату наложенным платежом (CoD).
В части CoD все работает нормально, именно в порядке razorpay создаются дубликаты заказов.
Мой подход: на экране оформления заказа у меня есть две кнопки, по одной для CoD и онлайн-оплаты с использованием Razorpay. у меня есть
Теперь, когда пользователь переходит к платежам Razorpay, после успешного завершения платежа в облачной базе данных Firestore создаются два заказа (на самом деле они создаются с одной и той же отметкой времени).
Мой код:
class CheckoutScreen extends StatefulWidget {
const CheckoutScreen({super.key, required this.product});
final Map<String, dynamic> product;
@override
State<CheckoutScreen> createState() => _CheckoutScreenState();
}
class _CheckoutScreenState extends State<CheckoutScreen> {
bool isCod = true;
final String? currUserId = FirebaseAuth.instance.currentUser?.uid;
var _razorpay = Razorpay();
int? amount;
final _random = Random();
@override
void initState() {
super.initState();
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
generateDropDownValues();
}
void _handlePaymentSuccess(PaymentSuccessResponse response) {
// Do something when payment succeeds
print(response);
//Add current product to Current Orders array
currentOrders.add({
'orderId': Random().nextInt(1000),
'order': [{
'product': widget.product,
'qty': dropDownValue,
}],
'date': DateTime.now(),
'amount': buyNowValue
});
FirebaseFirestore.instance.collection('customers').doc(currUserId).update({
'currentOrders': currentOrders,
});
buyNowValue = 0;
Navigator.pushNamed(context, orderSuccess);
_razorpay.clear();
}
void _handlePaymentError(PaymentFailureResponse response) {
// Do something when payment fails
print("Payment Failed");
}
void _handleExternalWallet(ExternalWalletResponse response) {
// Do something when an external wallet is selected
}
Future<String?> generateRzpOrderId() async {
try {
String basicAuth = 'Basic ${base64Encode(utf8.encode('${razorpayId}:${razorpaySecret}'))}';
Map<String, dynamic> orderData = {
"amount": (buyNowValue*100).toInt(),
"currency": "INR",
'receipt': 'CG_${1000 + _random.nextInt(9999 - 1000)}'
};
var res = await http.post(
Uri.https("api.razorpay.com", "v1/orders"),
headers: <String, String>{
'Authorization': basicAuth,
'Content-Type': 'application/json'
},
body: json.encode(orderData),
);
print(res.body);
if ((json.decode(res.body)).containsKey('error')) {
return null;
} else {
return (json.decode(res.body))['id'];
}
} catch (e) {
print(e);
throw e;
}
}
Future openGateWay() async {
generateRzpOrderId().then((value){
var options = {
'key': 'rzp_live_hUk8LTeESrQ6lL',
'amount': (buyNowValue*100).toInt(), //in the smallest currency sub-unit.
'currency': "INR",
'name': 'Cattle GURU',
'description': 'Online purchase of cattle food',
'order_id': value, // Generate order_id using Orders API
'timeout': 300, // in seconds
'prefill': {
'contact': phoneNumber
}
};
try {
_razorpay.open(options);
} catch (e) {
print(e);
}
});
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
}
@override
void dispose() {
_razorpay.clear();
super.dispose(); // Removes all listeners
}
int dropDownValue = 1;
List dropDownValues = [];
generateDropDownValues(){
for(int i = 0; i < buyNowProduct['units']; i++){
dropDownValues.add(i+1);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 0.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 2.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: ProductListTile(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
ProductScreen(
product: widget.product,
isCarted: false,
id: widget.product['prodId'],
prodQty: dropDownValue,
)));
},
imgUrl: widget.product['imgUrls'][0],
productDeliveryDays: widget.product['deliveryDays'],
date: DateTime.now(),
productName: widget.product['name'],
productWeight: widget.product['weight'].toDouble(),
price: widget.product['price'].toDouble(),
mrp: widget.product['mrp'].toDouble(),
protein: widget.product['protein'].toDouble(),
fibre: widget.product['fibre'].toDouble(),
fat: widget.product['fat'].toDouble(),
isCarted: false,
onSubtract: (){},
onAdd: (){},
qty: qty,
width: 0,
height: 0,
onAddToCart: (){},
onBuyNow: (){},
),
),
// SizedBox(height: 1.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: Row(
children: [
Text(isEnglish ? "Select quantity" : "संख्या चुनें", style: globalTextStyle.copyWith(color: black, fontSize: 4.w, fontWeight: FontWeight.bold),),
SizedBox(width: 2.5.w,),
DropdownButton(
value: dropDownValue,
style: globalTextStyle.copyWith(color: grey, fontWeight: FontWeight.bold),
iconEnabledColor: grey,
items: dropDownValues.map((items) => DropdownMenuItem(value: items, child: Text(items.toString()))).toList(),
onChanged: (newValue){
setState(() {
dropDownValue = newValue as int;
buyNowValue = dropDownValue*auxBuyNowValue;
});
},
)
// CustomDropDown(items: dropDownValues, dropdownvalue: dropDownValue)
],
),
),
SizedBox(height: 1.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: Text(isEnglish ? "Deliver to" : "इस पते पर पहुंचाएं", style: globalTextStyle.copyWith(color: black, fontSize: 4.w, fontWeight: FontWeight.bold),),
),
SizedBox(height: 1.h,),
AddressCard(
onTap: (){},
isDefault: false,
name: firestoreCurrentAddress['name'],
address: "${firestoreCurrentAddress['houseNum']}, ${firestoreCurrentAddress['village']}, ${firestoreCurrentAddress['district']}, ${firestoreCurrentAddress['state']}, ${firestoreCurrentAddress['pinCode']}",
onEditTap: (){
// Navigator.push(context, MaterialPageRoute(builder: (context) => EditAddressScreen(address: addressTiles[1], addressIndex: 1, isDefault: false,)));
Navigator.pushNamed(context, myAddresses);
},
onDefaultTap: (){
},
onRemoveTap: (){},
),
SizedBox(height: 1.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: Row(
children: [
InkWell(
onTap: (){
setState(() {
isCod= true;
});
},
child: Container(
width: 44.w,
height: 15.w,
decoration: BoxDecoration(
border: Border.all(color: primary),
borderRadius: BorderRadius.all(Radius.circular(2.w)),
color: isCod ? primary : primaryLight,
),
child: Center(
child: Text(isEnglish ? "Cash on Delivery (COD)" : "डिलवरी पर नकदी", style: globalTextStyle.copyWith(color: isCod ? white : black, fontSize: 3.5.w, fontWeight: FontWeight.bold),),
),
),
),
SizedBox(width: 2.w,),
InkWell(
onTap: (){
setState(() {
isCod = false;
});
},
child: Container(
width: 44.w,
height: 15.w,
decoration: BoxDecoration(
border: Border.all(color: primary),
borderRadius: BorderRadius.all(Radius.circular(2.w)),
color: isCod ? primaryLight : primary,
),
child: Center(
child: Text(isEnglish ? "Online Payment" : "ऑनलाइन भुगतान", style: globalTextStyle.copyWith(color: isCod ? black : white, fontSize: 3.5.w, fontWeight: FontWeight.bold),),
),
),
),
],
),
),
SizedBox(height: 1.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: CustomButton(width: 90.w, height: 15.w, color: primary,
onTap: () async {
if(isCod == false) {
await openGateWay();
} else {
//Add current product to Current Orders array
currentOrders.add({
'orderId': Random().nextInt(1000),
'order': [{
'product': widget.product,
'qty': dropDownValue,
}],
'date': DateTime.now(),
'amount': buyNowValue
});
FirebaseFirestore.instance.collection('customers').doc(currUserId).update({
'currentOrders': currentOrders,
});
buyNowValue = 0;
Navigator.pushNamed(context, orderSuccess);
}
},
text: isEnglish ? "Pay ${buyNowValue.toCurrencyString(leadingSymbol: "₹", useSymbolPadding: true)}" : "${buyNowValue.toCurrencyString(leadingSymbol: "₹", useSymbolPadding: true)} भुगतान करें ", fontColor: white, borderColor: primary),
)
],
),
),
),
);
}
}
Я хотел бы знать, что не так в моем коде, что приводит к созданию дублирующегося заказа, и как эту проблему можно решить.