I am trying to assign a delivery agent to the order of products with a dropdown containing a list of delivery agents. I am trying to get documentId
and merging new field value to the documentId which already exists. But as a result, I a getting a duplicate document with the same documentId
containing filed values which I want to merge. kindly help me to understand what I am doing wrong.
full code order_view.dart
import 'package:flutter/material.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import '../../services/firebase_database.dart';
import '../widgets/snack_bar.dart';
import 'client_address.dart';
import 'dashboard.dart';
import 'package:url_launcher/url_launcher.dart';
class OrderView extends StatefulWidget {
final Map<String, dynamic> orderData;
final List<String> deliveryAgent;
const OrderView(
{Key? key, required this.orderData, required this.deliveryAgent})
: super(key: key);
@override
State<OrderView> createState() => _OrderViewState();
}
class _OrderViewState extends State<OrderView> {
final FirebaseDatabase _database = FirebaseDatabase();
int index = 0;
num totalAmount = 0;
Map<String, dynamic> clientData = {};
getcountTotalAmount() async {
for (var item in widget.orderData["orders"]) {
totalAmount = totalAmount (item["productPrice"] * item["amount"]);
}
clientData = (await _database.getClientData(widget.orderData["userId"]))!;
setState(() {});
}
@override
void initState() {
getcountTotalAmount();
super.initState();
}
@override
Widget build(BuildContext context) {
bool _isloading = true;
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
elevation: 4,
title: const Text("Open Order"),
actions: [
TextButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: const Text(
"Are you sure you want to cancel this order?",
textAlign: TextAlign.center,
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
"No",
style:
TextStyle(color: Colors.green, fontSize: 16),
)),
TextButton(
onPressed: () async {
// Navigator.pop(context);
showDialog(
context: context,
builder: (context) {
return LoadingAnimationWidget.inkDrop(
color: Colors.orange,
size: 50,
);
});
await _database.removeOrder(
createTime: widget.orderData["createAt"],
);
Navigator.of(context).pop();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
const AdminDashboard()),
ModalRoute.withName(''),
);
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Your order is removed",
color: Colors.deepOrange),
);
},
child: const Text(
"Yes",
style: TextStyle(color: Colors.red, fontSize: 16),
)),
],
);
});
},
child: const Text(
"Cancel Order",
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
],
),
body: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView(
physics: const BouncingScrollPhysics(),
children: [
Container(
color: Colors.white,
child: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 8),
shrinkWrap: true,
itemCount: widget.orderData["orders"].length,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
leading: Image.network(
widget.orderData["orders"][index]["productImage"],
),
title: Text(
widget.orderData["orders"][index]["productTitle"],
),
subtitle: SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Text(
"₹ ${widget.orderData["orders"][index]["productPrice"]}",
style: const TextStyle(
color: Colors.green, fontSize: 12),
),
const Text(" - "),
Text(
widget.orderData["orders"][index]["productUnit"],
style: const TextStyle(fontSize: 12),
),
const Text(" x "),
Text(widget.orderData["orders"][index]["amount"]
.toString()),
const SizedBox(width: 5),
Text(
"Total ₹ ${widget.orderData["orders"][index]["productPrice"] * widget.orderData["orders"][index]["amount"]}",
style: const TextStyle(
color: Colors.green,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider();
},
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Delivery Slot'),
Text(
'${widget.orderData["deliverySlot"]}',
style: const TextStyle(
fontWeight: FontWeight.w500, fontSize: 16),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"Delivery charge: ₹${widget.orderData["taxes"]}",
),
Text(
"Total Price: ₹${totalAmount widget.orderData["taxes"]}",
style: const TextStyle(
fontWeight: FontWeight.w500, fontSize: 16),
),
],
)
],
),
),
const SizedBox(height: 16),
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
decoration: const BoxDecoration(
color: Colors.white,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Ordered on: ${widget.orderData["createAt"]}',
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
Text(
'Delivery at ${widget.orderData["addressType"]}',
),
const SizedBox(
height: 16,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: Text(
'Address: ${widget.orderData["address"]}',
),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ClientAddress(
lat: widget.orderData["latitude"],
lag: widget.orderData["longitude"],
)));
},
child: const Text('Open location'))
],
),
],
),
),
const SizedBox(
height: 16,
),
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Client Details",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Text(
clientData["username"] ?? "",
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
SizedBox(
child: Text(
clientData["contact"] ?? "",
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
ElevatedButton.icon(
onPressed: () async {
String telephoneNumber = clientData["contact"];
Uri telephoneUrl = Uri.parse("tel:$telephoneNumber");
if (await canLaunchUrl(telephoneUrl)) {
await launchUrl(telephoneUrl);
}
},
icon: const Icon(
Icons.call,
),
label: const Text('Call'),
)
],
),
],
),
),
const SizedBox(
height: 16,
),
Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: const EdgeInsets.only(bottom: 8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Text(
"Delivery Agent",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
DropdownButton(
items: widget.deliveryAgent
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e),
),
)
.toList(),
onChanged: (val) {
setState(() {
index =
widget.deliveryAgent.indexOf(val.toString());
});
},
isExpanded: false,
hint: Text(
widget.deliveryAgent[index],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
),
],
),
ElevatedButton(
onPressed: () async {
bool results;
results = await _database.updateDeliveryAgent(
orderId: widget.orderData["orderId"],
deliveryAgent: widget.deliveryAgent[index].toString(),
);
if (results) {
setState(() {
_isloading = true;
});
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Delivery agent assigned",
color: Colors.green,
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Error",
color: Colors.red,
),
);
}
setState(() {
_isloading = true;
});
},
child: const Text('Assign Agent')),
],
)),
],
),
),
);
}
}
firebase_database.dart
CollectionReference<Map<String, dynamic>> testorders =
FirebaseFirestore.instance.collection('testorders');
Future<bool> updateDeliveryAgent(
{required String orderId, required String deliveryAgent}) async {
try {
testorders.doc(orderId).set({
"deliveryAgent": {
"agentName": deliveryAgent,
"agentContact": '',
},
}, SetOptions(merge: true));
return true;
} catch (e) {
if (kDebugMode) {
print("error while assigning delivery agent: $e");
}
}
return false;
}
order.dart
Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: const EdgeInsets.only(bottom: 8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Text(
"Delivery Agent",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
DropdownButton(
items: widget.deliveryAgent
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e),
),
)
.toList(),
onChanged: (val) {
setState(() {
index =
widget.deliveryAgent.indexOf(val.toString());
});
},
isExpanded: false,
hint: Text(
widget.deliveryAgent[index],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
),
],
),
ElevatedButton(
onPressed: () async {
bool results;
results = await _database.updateDeliveryAgent(
orderId: widget.orderData["orderId"],
deliveryAgent: widget.deliveryAgent[index].toString(),
);
if (results) {
setState(() {
_isloading = true;
});
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Delivery agent assigned",
color: Colors.green,
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Error",
color: Colors.red,
),
);
}
setState(() {
_isloading = true;
});
},
child: const Text('Assign Agent')),
],
)),
CodePudding user response:
You cannot update a document ID once it's been defined.
See the following answer on alternative steps you can take: https://stackoverflow.com/a/52117929/9063088
CodePudding user response:
There is no way you can have duplicate document IDs inside the same collection. The screenshot shows two documents sharing the same ID but for sure one of them contains one or more white spaces at the end. So there are two situations, the orderId
is correct and when you call set()
it adds the document with a document ID that doesn't contains white spaces, while in the database there is already one present that contains white spaces, or vice versa. When it comes to document IDs, always call .trim() so it can remove the white spaces from the beginning and from the end.