1) opening inventory api integration done

2) Billto shipto address api integration done
This commit is contained in:
saritabirare 2024-10-30 16:34:18 +05:30
parent a545efca3b
commit d101e82096
14 changed files with 1133 additions and 186 deletions

View File

@ -0,0 +1,49 @@
import 'package:cheminova/controller/product_mannual_service.dart';
import 'package:cheminova/controller/product_stock_service.dart';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/product_mannual_model.dart'; // Your model import
// Your service import
class ProductStockController extends GetxController {
var productStockList = <ProductStockModel>[].obs;
// Service to fetch data
final ProductStockService productStockService = ProductStockService();
// Loading state
var isLoading = false.obs;
// Method to fetch product manuals from the service
Future<void>fetchProductStock() async {
try {
// Set loading to true
isLoading.value = true;
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
var manuals = await productStockService.getProductStock(token!);
// If data is returned, update the list
if (manuals != null) {
productStockList.value = manuals;
} else {
productStockList.value = []; // If no data, set an empty list
}
} catch (e) {
// Handle error here, for example logging or showing an error message
print("Error fetching product stock: $e");
} finally {
// Set loading to false
isLoading.value = false;
}
}
@override
void onInit() {
// Fetch product manuals when the controller is initialized
fetchProductStock();
super.onInit();
}
}

View File

@ -0,0 +1,40 @@
import 'package:cheminova/utils/api_urls.dart';
import '../models/product_mannual_model.dart';
import '../models/product_stock_model.dart';
import '../utils/common_api_service.dart'; // Replace with your actual common API service import
class ProductStockService {
// Method to fetch product manuals using an authorization token
Future<List<ProductStockModel>?> getProductStock(String token) async {
try {
String url = ApiUrls.ProductStockUrl; // Base URL to fetch product manuals
final response = await commonApiService<List<ProductStockModel>>(
method: "GET",
url: url,
additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token',
},
fromJson: (json) {
if (json['stocks'] != null) {
// If the productManuals key is present, map the response to a list of ProductManualModel objects
final List<ProductStockModel> productstock = (json['stocks'] as List)
.map((manualJson) => ProductStockModel.fromJson(manualJson as Map<String, dynamic>))
.toList();
return productstock; // Return the list of product manuals
} else {
return [];
}
},
);
return response;
} catch (e) {
print(e.toString());
return null;
}
}
}

View File

@ -48,7 +48,8 @@ class RDOrderPlacedController extends GetxController {
// Call the service to place the order // Call the service to place the order
await _rdOrderPlacedService.placRDeOrder(orderDetails, token!); await _rdOrderPlacedService.placRDeOrder(orderDetails, token!);
} catch (e) { } catch (e) {
print("Error placing order: $e"); // print("Error placing order: $e");
showSnackbar("stock not available");
} finally { } finally {
isLoading.value = false; isLoading.value = false;
} }

View File

@ -0,0 +1,32 @@
import 'package:cheminova/controller/product_stock_service.dart';
import 'package:cheminova/controller/update_stock_service.dart';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UpdateStockController extends GetxController{
Future<void> updateProductStock(List<ProductStockModel> reason) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token'); // Get the token
if (token == null || token.isEmpty) {
throw Exception("Token is missing. Please login again.");
}
// Show loading indicator
// Call the service function and pass the token, orderId, and reason
await UpdateStockService().UpdateStockProduct(token, reason);
// Optionally refresh the data or show success message
print("UpdateStockService process complete.");
} catch (e) {
print("Error: $e");
} finally {
}
}
}

View File

@ -0,0 +1,46 @@
import 'dart:convert';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:dio/dio.dart';
import '../utils/api_urls.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class UpdateStockService{
// Function to handle password change functionality
Future<void> UpdateStockProduct(String token, List<ProductStockModel> stock) async {
try {
// Correct API URL with orderId passed in the URL
final String url = ApiUrls.ProductUpdateStockUrl;
// Make the PUT request
final response = await Dio().put(
url, // Use the correct URL here
data: {
"products": stock, // Send the cancellation reason as JSON
},
options: Options(
headers: {
'Authorization': 'Bearer $token', // Pass the token in the Authorization header
'Content-Type': 'application/json', // Set content-type to application/json
},
),
);
// Check the response status
if (response.statusCode == 200) {
print(response.data);
print("Stock Update successfully");
} else {
throw Exception('Failed to Stock Update');
}
} catch (e) {
// Handle error
print('Error Stock Update: $e');
}
}
}

View File

@ -0,0 +1,41 @@
class ProductStockModel {
final String productid;
final String name;
final String sku;
final int stock;
final int openingInventory;
ProductStockModel({
required this.productid,
required this.name,
required this.sku,
required this.stock,
required this.openingInventory,
});
factory ProductStockModel.fromJson(Map<String, dynamic> json) {
return ProductStockModel(
productid: json['productid']??"2323",
name: json['name']??"rert",
sku: json['SKU']??"",
stock: json['Stock']??"",
openingInventory: json['openingInventory']??""
);
}
// Convert a ProductStock instance to a JSON map
Map<String, dynamic> toJson() {
return {
'productid': productid,
'name': name,
'SKU': sku,
'Stock': stock,
'openingInventory':openingInventory
};
}
@override
String toString() {
return 'ProductStock(productid: $productid, name: $name, sku: $sku, stock: $stock,openingInventory:$openingInventory)';
}
}

View File

@ -19,6 +19,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'kyc/kyc_retailer_info_screen.dart'; import 'kyc/kyc_retailer_info_screen.dart';
import 'opening Inventory/inventory_management_screen.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key});
@ -206,7 +207,7 @@ class _HomeScreenState extends State<HomeScreen> {
HomeCard( HomeCard(
title: 'Opening Inventory', title: 'Opening Inventory',
onTap: () => Get.to( onTap: () => Get.to(
() => InventoryManagementScreen(), () => OpeningInventoryManagementScreen(),
), ),
), ),
// HomeCard( // HomeCard(

View File

@ -0,0 +1,290 @@
import 'dart:async';
import 'package:cheminova/controller/product_stock_controller.dart';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:cheminova/screens/opening%20Inventory/update_stock_screen.dart';
import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
import 'package:cheminova/widgets/input_field.dart';
import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../../controller/cart_controller.dart';
import '../../controller/get_order_placed_controller.dart';
import '../../models/product_model1.dart';
class OpeningInventoryManagementScreen extends StatefulWidget {
final ProductStockModel? productModel;
// PlacedOrderList? placeOrder;
OpeningInventoryManagementScreen({super.key, this.productModel,});
@override
State<OpeningInventoryManagementScreen> createState() => _OpeningInventoryManagementScreenState();
}
class _OpeningInventoryManagementScreenState extends State<OpeningInventoryManagementScreen> {
final _searchController = TextEditingController();
//final List<String> _filterList = ["Order Status", "Date Range"];
final ProductStockController _getProductStockController = Get.put(ProductStockController());
final CartController _cartController = Get.put(CartController());
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
@override
void initState() {
super.initState();
getOrder1(); // Fetch orders when the screen initializes
}
Future<void> _onRefresh() async {
await getOrder1();
await Future.delayed(Duration(seconds: 1));
}
// Fetches orders from the API
Future<void> getOrder1() async {
await _getProductStockController.fetchProductStock();
print("Opening order Inventory fetched successfully");
}
// Capitalizes the first letter of the string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
// Formats the date received from the API
String formatDate(String apiDate) {
DateTime parsedDate = DateTime.parse(apiDate);
String formattedDate = DateFormat('dd-MMM-yyyy').format(parsedDate);
return formattedDate;
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
leading: Builder(
builder: (context) {
return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset('assets/svg/menu.svg'),
),
);
},
),
actions: [
GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset('assets/svg/back_arrow.svg'),
),
),
],
title: const Text("Opening Inventory "),
),
drawer: MyDrawer(),
body: Stack(
fit: StackFit.expand,
children: [
Image.asset('assets/images/image_1.png', fit: BoxFit.cover),
SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _onRefresh,
color: Colors.black,
backgroundColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
InputField(
hintText: "Search Order",
labelText: "Search Order",
controller: _searchController,
onChanged: (value) {
//searchOrder(value);// Call search function with input value
},
),
SizedBox(height: Get.height * 0.035),
Card(
margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19),
side: const BorderSide(color: Color(0xFFFDFDFD)),
),
color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// SizedBox(
// height: Get.height * 0.05,
// child: ListView.builder(
// shrinkWrap: true,
// scrollDirection: Axis.horizontal,
// itemCount: _filterList.length,
// itemBuilder: (context, index) => Padding(
// padding: const EdgeInsets.symmetric(horizontal: 4),
// child: Chip(
// label: Text(
// _filterList[index],
// style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// ),
SizedBox(
height: Get.height * 0.6,
child: Obx(() {
// Use a set to keep track of unique order IDs
final Set<String> uniqueOrderIds = {};
final List<ProductStockModel> uniqueOrders = [];
// Loop through the fetched orders to filter unique orders
for (var order in _getProductStockController.productStockList) {
if (uniqueOrderIds.add(order.productid)) {
uniqueOrders.add(order);
}
}
// Displaying unique orders in a ListView
return ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: uniqueOrders.length,
itemBuilder: (context, index) {
final order = uniqueOrders[index];
// Combine product names into a single string
// final productNames = order.name
// .map((item) => capitalizeFirstLetter(item.name))
// .join(', ');
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Product ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text("${order.productid}")
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start, // Aligns the Column to the top of the Text
children: [
Text(
"Product Names: ",
style: GoogleFonts.roboto(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // Aligns text to the right within the Column
children: [
Text(
'${order.name}', // Adds index and trims whitespace
textAlign: TextAlign.left, // Aligns text to the right
style: GoogleFonts.roboto(
fontSize: 14,
),
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("SKU: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text("${order.sku}")
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Opening Inventory: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text("${order.openingInventory}")
],
),
),
SizedBox(
width: Get.width * 0.5,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: (){
Get.to(InventoryUpdateStockScreen(products: _getProductStockController.productStockList,selectedProductId: _getProductStockController.productStockList[index].productid,));
},
// Navigate to detail screen
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF004791),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
child: Text("Update Inventory", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
),
),
)
],
),
),
);
},
);
}),
)
],
),
),
),
],
),
),
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,350 @@
import 'package:cheminova/controller/product_stock_service.dart';
import 'package:cheminova/controller/update_stock_controller.dart';
import 'package:cheminova/controller/update_stock_service.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:cheminova/screens/opening%20Inventory/inventory_management_screen.dart';
import 'package:cheminova/widgets/input_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../utils/show_snackbar.dart';
// class InventoryUpdateStockScreen extends StatefulWidget {
// final ProductStockModel product;
//
// const InventoryUpdateStockScreen({
// super.key,
// required this.product,
// });
//
// @override
// State<InventoryUpdateStockScreen> createState() => _InventoryUpdateStockScreenState();
// }
//
// class _InventoryUpdateStockScreenState extends State<InventoryUpdateStockScreen> {
// final _textController = TextEditingController();
//
// final UpdateStockController _updateStockController = Get.put(UpdateStockController());
//
// void _onUpdateStock() async {
// try {
// // Parse the new stock quantity from the text controller
// int? newStockQuantity = int.tryParse(_textController.text.trim());
//
// // Check if the parsed quantity is valid
// if (newStockQuantity == null || newStockQuantity < 0) {
// showSnackbar("Please enter a valid stock quantity.");
// return;
// }
//
// // Create a list of ProductStockModel instances with updated stock
// List<ProductStockModel> productStockList = [
// ProductStockModel(
// productid: widget.product.productid,
// name: widget.product.name,
// sku: widget.product.sku,
// stock: newStockQuantity, // Update stock with new quantity
// ),
// ];
//
// // Call the updateStock function
// final update = await _updateStockController.updateProductStock(productStockList);
//
// // Optionally, show a confirmation message or navigate to another screen
// showSnackbar("Stock updated successfully");
// } catch (e) {
// print("Error updating stock: $e");
// showSnackbar("Error updating stock. Please try again.");
// }
// }
//
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// extendBodyBehindAppBar: true,
// appBar: AppBar(
// centerTitle: true,
// backgroundColor: Colors.transparent,
// elevation: 0,
// leading: GestureDetector(
// onTap: () {},
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SvgPicture.asset(
// 'assets/svg/menu.svg',
// ),
// ),
// ),
// actions: [
// GestureDetector(
// onTap: () => Get.back(),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: SvgPicture.asset(
// 'assets/svg/back_arrow.svg',
// ),
// ),
// ),
// ],
// title: const Text(
// "Update Inventory",
// ),
// ),
// body: Stack(
// fit: StackFit.expand,
// children: [
// Image.asset(
// 'assets/images/image_1.png',
// fit: BoxFit.cover,
// ),
// SafeArea(
// child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// SizedBox(
// height: Get.height * 0.02,
// ),
// Card(
// margin: const EdgeInsets.symmetric(horizontal: 16),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(19),
// side: const BorderSide(color: Color(0xFFFDFDFD)),
// ),
// color: const Color(0xFFB4D1E5).withOpacity(0.9),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
//
// Card(
// child: SizedBox(
// width: Get.width,
// child: Padding(
// padding: const EdgeInsets.all(12),
// child: Row(
//
// children: [
// Text(
// "Product Name:",
// style: GoogleFonts.roboto(
// fontSize: Get.width * 0.04,
// fontWeight: FontWeight.w700,
// ),
// ),
// Text("${widget.product.name}"),
// ],
// ),
// ),
// ),
// ),
//
// InputField(
// hintText: "Enter New Stock Quantity:",
// labelText: "Enter New Stock Quantity:",
// controller: _textController,
// ),
// // InputField(
// // hintText: "Reason for Update: Restock",
// // labelText: "Reason for Update: Restock",
// // controller: _textController,
// // )
// ],
// ),
// ),
// ),
// SizedBox(height: Get.height * 0.04),
// SizedBox(
// width: Get.width * 0.9,
// height: Get.height * 0.06,
// child: ElevatedButton(
// onPressed: () {
//
// _onUpdateStock();
// },
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF00784C),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10),
// ),
// ),
// child: Text(
// "Update Stock Quantity",
// style: GoogleFonts.roboto(
// fontSize: Get.width * 0.05,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// );
// }
// }
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../controller/update_stock_controller.dart';
import '../../models/product_stock_model.dart';
import 'package:flutter/material.dart';
import '../../utils/show_snackbar.dart';
import '../../widgets/input_field.dart';
import 'inventory_management_screen.dart';
class InventoryUpdateStockScreen extends StatefulWidget {
final List<ProductStockModel> products;
final String selectedProductId;
const InventoryUpdateStockScreen({
super.key,
required this.products,
required this.selectedProductId,
});
@override
State<InventoryUpdateStockScreen> createState() => _InventoryUpdateStockScreenState();
}
class _InventoryUpdateStockScreenState extends State<InventoryUpdateStockScreen> {
late TextEditingController _textController;
final UpdateStockController _updateStockController = Get.put(UpdateStockController());
@override
void initState() {
super.initState();
// Initialize text controller with the stock of the selected product
final selectedProduct = widget.products.firstWhere((product) => product.productid == widget.selectedProductId);
_textController = TextEditingController(text: selectedProduct.stock.toString());
}
void _onUpdateStock() async {
try {
int? newStockQuantity = int.tryParse(_textController.text.trim());
if (newStockQuantity == null || newStockQuantity < 0) {
showSnackbar("Please enter a valid stock quantity.");
return;
}
// Update only the stock for the selected product while keeping others the same
List<ProductStockModel> updatedProductStockList = widget.products.map((product) {
if (product.productid == widget.selectedProductId) {
return ProductStockModel(
productid: product.productid,
name: product.name,
sku: product.sku,
stock: newStockQuantity,
openingInventory: newStockQuantity,
);
} else {
return product;
}
}).toList();
// Call the updateStock function with the updated list
final update = await _updateStockController.updateProductStock(updatedProductStockList);
showSnackbar("Opening Inventory for ${widget.selectedProductId} updated successfully");
Get.to(OpeningInventoryManagementScreen());
} catch (e) {
print("Error updating stock: $e");
showSnackbar("Error updating stock. Please try again.");
}
}
@override
Widget build(BuildContext context) {
final selectedProduct = widget.products.firstWhere((product) => product.productid == widget.selectedProductId);
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
leading: GestureDetector(
onTap: () {},
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset(
'assets/svg/menu.svg',
),
),
),
actions: [
GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
'assets/svg/back_arrow.svg',
),
),
),
],
title: const Text(
"Update Inventory",
),
),
body: Stack(
fit: StackFit.expand,
children: [
Image.asset(
'assets/images/image_1.png',
fit: BoxFit.cover,
),
SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: Get.height * 0.02),
Text(
"Product Name: ${selectedProduct.name}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w700,
),
),
InputField(
hintText: "Enter New Opening Inventory Quantity:",
labelText: "Enter New Opening Inventory Quantity:",
controller: _textController,
),
SizedBox(height: 8),
ElevatedButton(
onPressed: _onUpdateStock,
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
"Update Inventory Quantity",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.05,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
],
),
);
}
}

View File

@ -14,9 +14,11 @@ import '../../controller/place_order_controller.dart';
import '../../controller/place_order_service.dart'; import '../../controller/place_order_service.dart';
import '../../controller/product_controller.dart'; import '../../controller/product_controller.dart';
import '../../controller/product_service.dart'; import '../../controller/product_service.dart';
import '../../controller/shiptobilltoController.dart';
import '../../models/brand_model.dart'; import '../../models/brand_model.dart';
import '../../models/oder_place_model.dart'; import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart'; import '../../models/product_model1.dart';
import '../../models/shiping_billing_address_model.dart';
import '../../widgets/my_drawer.dart'; import '../../widgets/my_drawer.dart';
import '../../widgets/product_card.dart'; import '../../widgets/product_card.dart';
import 'order_confermation_screen.dart'; import 'order_confermation_screen.dart';
@ -39,6 +41,7 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
final OrderPlacedController _orderPlacedController = final OrderPlacedController _orderPlacedController =
Get.put(OrderPlacedController()); Get.put(OrderPlacedController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
final AddressController _addressController = Get.put(AddressController()); // Initialize AddressController
int currentPage = 1; int currentPage = 1;
String _groupValue = "cheque"; String _groupValue = "cheque";
@ -52,17 +55,25 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
String? _selectedShippingAddress; String? _selectedShippingAddress;
String? _selectedBillingAddress; String? _selectedBillingAddress;
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// _getOrder(); // _getOrder();
_addressController.fetchAddresses();
_loadSelectedAddress(); _loadSelectedAddress();
_loadSelectedPaymentMode(); _loadSelectedPaymentMode();
// _loadSelectedAddress();
if (_addressList.isNotEmpty) { // _loadSelectedPaymentMode();
_selectedShippingAddress = _addressList.first; //
_selectedBillingAddress = _addressList.first; // if (_addressList.isNotEmpty) {
} // _selectedShippingAddress = _addressList.first;
// _selectedBillingAddress = _addressList.first;
// }
} }
void _saveSelectedAddress() async { void _saveSelectedAddress() async {
@ -140,11 +151,35 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
); );
}).toList(); }).toList();
// Get the full address for shipping and billing
String? shippingAddress = _addressController.addressList.firstWhere(
(address) => address.id == _addressController.selectedShippingAddressId.value,
orElse: () => UserShippingAddress(
id: '',
street: '',
city: '',
state: '',
postalCode: '',
country: '', tradeName: '',
)).toStringFullAddress();
String? billingAddress = _addressController.addressList.firstWhere(
(address) => address.id == _addressController.selectedBillingAddressId.value,
orElse: () => UserShippingAddress(
id: '',
street: '',
city: '',
state: '',
postalCode: '',
country: '', tradeName: '',
)).toStringFullAddress();
// Update the placedOrder1 value // Update the placedOrder1 value
_orderPlacedController.placedOrder1.value= PlacedOrderModel( _orderPlacedController.placedOrder1.value= PlacedOrderModel(
paymentMode: _groupValue, paymentMode: _groupValue,
shipTo: _selectedShippingAddress!, shipTo: shippingAddress, // Full shipping address
billTo: _selectedBillingAddress!, billTo: billingAddress, // Full billing address
orderItems: orderItems, orderItems: orderItems,
gstTotal: _cartController.gstTotal.value, gstTotal: _cartController.gstTotal.value,
grandTotal: _cartController.grandTotal.value, grandTotal: _cartController.grandTotal.value,
@ -157,11 +192,16 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
showSnackbar("Order Placed Successfully"); showSnackbar("Order Placed Successfully");
Get.to(() => OrderConfermationScreen( Get.to(() => OrderConfermationScreen(
placedOrder: _orderPlacedController.placedOrder1.value, placedOrder: _orderPlacedController.placedOrder1.value,
)); ));
} }
} catch (e) { } catch (e) {
print("PlaceOrderScreen error: $e"); print("PlaceOrderScreen error: $e");
} }
} }
@ -219,15 +259,15 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
side: const BorderSide(color: Color(0xFFFDFDFD)), side: const BorderSide(color: Color(0xFFFDFDFD)),
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding( child:
Padding(
padding: EdgeInsets.all(Get.width * 0.04), padding: EdgeInsets.all(Get.width * 0.04),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(horizontal: Get.width * 0.04),
horizontal: Get.width * 0.04),
child: Text( child: Text(
'Shipping Information', 'Shipping Information',
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
@ -237,38 +277,54 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
), ),
), ),
), ),
SizedBox(height: 5,), SizedBox(height: 5),
DropdownButtonFormField<String>( Obx(() => Container(
decoration: InputDecoration(
labelText: 'Shipping Address:', child: DropdownButtonFormField<String>(
hintText: 'Select Shipping Address', decoration: InputDecoration(
border: OutlineInputBorder(), labelText: 'Shipping Address:',
hintText: 'Select Shipping Address',
border: OutlineInputBorder(),
),
value: _addressController.selectedShippingAddressId.value.isEmpty
? null // Show null if there's no selection yet
: _addressController.selectedShippingAddressId.value, // Set the selected ID
items: _addressController.addressList.map((UserShippingAddress address) {
return DropdownMenuItem<String>(
value: address.id, // Set the value as the address ID
child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} , ${address.country}"), // Display full address
);
}).toList(),
onChanged: (value) {
_addressController.onShippingAddressChanged(value); // Update the selected address
},
), ),
value: _selectedShippingAddress, )),
items: _addressList.map((String address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
);
}).toList(),
onChanged: _onShippingAddressChanged,
),
SizedBox(height: Get.height * 0.02), SizedBox(height: Get.height * 0.02),
DropdownButtonFormField<String>(
decoration: InputDecoration( // Billing Address Dropdown
labelText: 'Billing Address:', Obx(() => Container(
hintText: 'Select Billing Address',
border: OutlineInputBorder(), child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Billing Address:',
hintText: 'Select Billing Address',
border: OutlineInputBorder(),
),
value: _addressController.selectedBillingAddressId.value.isEmpty
? null // Show null if there's no selection yet
: _addressController.selectedBillingAddressId.value, // Set the selected ID
items: _addressController.addressList.map((UserShippingAddress address) {
return DropdownMenuItem<String>(
value: address.id, // Set the value as the address ID
child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} ${address.country}"), // Display full address
);
}).toList(),
onChanged: (value) {
_addressController.onBillingAddressChanged(value); // Update the selected address
},
), ),
value: _selectedBillingAddress, )),
items: _addressList.map((String address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
);
}).toList(),
onChanged: _onBillingAddressChanged,
),
Padding( Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: Get.width * 0.04), horizontal: Get.width * 0.04),

View File

@ -1,4 +1,5 @@
import 'package:cheminova/controller/get_order_placed_controller.dart'; import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/shiptobilltoController.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
@ -12,14 +13,18 @@ import '../../controller/cart_controller.dart';
import '../../controller/place_order_controller.dart'; import '../../controller/place_order_controller.dart';
import '../../models/oder_place_model.dart'; import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart'; import '../../models/product_model1.dart';
import '../../models/shiping_billing_address_model.dart';
class OrderConfermationScreen extends StatefulWidget { class OrderConfermationScreen extends StatefulWidget {
Product? productModel; // The selected product model Product? productModel; // The selected product model
PlacedOrderModel? placedOrder; // The order details after placement PlacedOrderModel? placedOrder; // The order details after placement
List<Product>? selectedProducts; // List of selected products for the order List<Product>? selectedProducts; // List of selected products for the order
// final UserShippingAddress? shippingAddress;
// final UserShippingAddress? billingAddress;
// Constructor to initialize the class with optional parameters // Constructor to initialize the class with optional parameters
OrderConfermationScreen({super.key,this.productModel,this.placedOrder,this.selectedProducts}); OrderConfermationScreen({super.key,this.productModel,this.placedOrder,this.selectedProducts,});
@override @override
State<OrderConfermationScreen> createState() => State<OrderConfermationScreen> createState() =>
@ -30,9 +35,11 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
final CartController _cartController = Get.put(CartController()); // Instance of CartController final CartController _cartController = Get.put(CartController()); // Instance of CartController
// Instance of OrderPlacedController // Instance of OrderPlacedController
final OrderPlacedController _placedController = Get.put(OrderPlacedController()); final OrderPlacedController _placedController = Get.put(OrderPlacedController());
final AddressController _addressController = Get.put(AddressController());
// Instance of GetPlacedOrderController // Instance of GetPlacedOrderController
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final orderItems = _placedController.placedOrder1; // Fetching the placed order details final orderItems = _placedController.placedOrder1; // Fetching the placed order details
@ -78,164 +85,172 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
SafeArea( SafeArea(
child: Column( child: SingleChildScrollView(
children: [ child: Column(
SizedBox( children: [
height: Get.height * 0.02, // Spacing from the top SizedBox(
), height: Get.height * 0.02, // Spacing from the top
Card(
margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19),
side: const BorderSide(color: Color(0xFFFDFDFD)),
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), Card(
child: Padding( margin: const EdgeInsets.symmetric(horizontal: 18),
padding: EdgeInsets.all(Get.width * 0.04), shape: RoundedRectangleBorder(
child: Column( borderRadius: BorderRadius.circular(19),
mainAxisSize: MainAxisSize.min, side: const BorderSide(color: Color(0xFFFDFDFD)),
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ color: const Color(0xFFB4D1E5).withOpacity(0.9),
Card( child: Padding(
child: SizedBox( padding: EdgeInsets.all(Get.width * 0.04),
width: Get.width, child: Column(
height: Get.height * 0.05, mainAxisSize: MainAxisSize.min,
child: Padding( crossAxisAlignment: CrossAxisAlignment.start,
padding: const EdgeInsets.all(8.0), children: [
child: Text( Card(
"Order Number:1234", child: SizedBox(
style: GoogleFonts.roboto( width: Get.width,
fontSize: Get.width * 0.04, height: Get.height * 0.05,
fontWeight: FontWeight.w400, child: Padding(
), padding: const EdgeInsets.all(8.0),
), child: Text(
), "Order Number:1234",
), style: GoogleFonts.roboto(
), fontSize: Get.width * 0.04,
Padding( fontWeight: FontWeight.w400,
padding: EdgeInsets.all(Get.width * 0.02),
child: Text(
'Order Summary',
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: Get.height * 0.22,
child: Padding(
padding: EdgeInsets.all(Get.width * 0.02),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: _cartController.selectedProducts.length,
itemBuilder: (context, index) =>
ProductCard(
productModel:_cartController.selectedProducts[index],
isCheckout: true,
),
), ),
), ),
), ),
Padding(
padding: EdgeInsets.all(Get.width * 0.02),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Subtotal',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.subtotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('GST',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.gstTotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Amount',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.grandTotal.value.toStringAsFixed(2)}'),
],
),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.all(Get.width * 0.02),
child: Text(
'Shipping Information',
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w500,
color: Colors.black,
), ),
), ),
), Padding(
Card( padding: EdgeInsets.all(Get.width * 0.02),
child: SizedBox( child: Text(
width: Get.width, 'Order Summary',
height: Get.height * 0.1, style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
Card(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( SizedBox(
padding: const EdgeInsets.all(8.0), height: Get.height * 0.22,
child: TextField( child: Padding(
controller: TextEditingController( padding: EdgeInsets.all(Get.width * 0.02),
text: widget.placedOrder!.shipTo, // Pre-filling the address child: ListView.builder(
), padding: EdgeInsets.zero,
decoration: InputDecoration( itemCount: _cartController.selectedProducts.length,
hintText: "Address : ${widget.placedOrder!.shipTo}", itemBuilder: (context, index) =>
hintStyle: GoogleFonts.roboto( ProductCard(
fontSize: Get.width * 0.04, productModel:_cartController.selectedProducts[index],
fontWeight: FontWeight.w400, isCheckout: true,
), ),
border: OutlineInputBorder(),
), ),
), ),
), ),
Padding(
]), padding: EdgeInsets.all(Get.width * 0.02),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Subtotal',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.subtotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('GST',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.gstTotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Amount',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.grandTotal.value.toStringAsFixed(2)}'),
],
),
],
),
),
],
),
), ),
), Padding(
Card( padding: EdgeInsets.all(Get.width * 0.02),
child: SizedBox( child: Text(
width: Get.width, 'Shipping Information',
height: Get.height * 0.05, style: GoogleFonts.roboto(
child: Padding( fontSize: Get.width * 0.04,
padding: const EdgeInsets.all(8.0), fontWeight: FontWeight.w500,
child: Text( color: Colors.black,
"Estimated Delivery Date: ${widget.placedOrder!.orderItems[0].createdAt}", ),
style: GoogleFonts.roboto( ),
fontSize: Get.width * 0.04, ),
fontWeight: FontWeight.w400, Card(
child: SizedBox(
width: Get.width,
height: Get.height * 0.1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: TextEditingController(
text:widget.placedOrder!.shipTo
// _addressController.selectedShippingAddressId != null
// ? '${widget.placedOrder?.shipTo}
// '${_addressController.addressList[0].city}, '
// '${_addressController.addressList[0].state}, '
// '${_addressController.addressList[0].postalCode}'
// : 'No address selected', // Pre-filling with full address if available // Pre-filling the address
),
decoration: InputDecoration(
hintText: "Address : ${widget.placedOrder!.shipTo}",
hintStyle: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
),
border: OutlineInputBorder(),
),
),
),
]),
),
),
Card(
child: SizedBox(
width: Get.width,
height: Get.height * 0.05,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Estimated Delivery Date: ${widget.placedOrder!.orderItems[0].createdAt}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
),
), ),
), ),
), ),
), ),
),
],
], ),
), ),
), ),
),
],
], ),
), ),
), ),
], ],

View File

@ -1,5 +1,6 @@
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:cheminova/controller/get_order_placed_controller.dart'; import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/shiptobilltoController.dart';
import 'package:cheminova/models/oder_place_model.dart'; import 'package:cheminova/models/oder_place_model.dart';
import 'package:cheminova/models/order_item_model.dart'; import 'package:cheminova/models/order_item_model.dart';
import 'package:cheminova/models/place_order_list_model.dart'; import 'package:cheminova/models/place_order_list_model.dart';
@ -32,6 +33,7 @@ class _OrderManagementDetailScreenState
extends State<OrderManagementDetailScreen> { extends State<OrderManagementDetailScreen> {
// Controllers for managing cart and placed orders // Controllers for managing cart and placed orders
final CartController _cartController = Get.put(CartController()); final CartController _cartController = Get.put(CartController());
final AddressController _addressController = Get.put(AddressController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// Function to format date from the API to a more readable format // Function to format date from the API to a more readable format
String formatDate(String apiDate) { String formatDate(String apiDate) {
@ -289,11 +291,12 @@ Future<void> adduni()async {
), ),
SizedBox( SizedBox(
width: Get.width, width: Get.width,
height: Get.height*0.06, height: Get.height * 0.10,
child: Padding( child: Padding(
padding: padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
const EdgeInsets.fromLTRB(8, 8, 8, 0), child: Wrap( // Use Wrap to allow wrapping
child: Row( crossAxisAlignment: WrapCrossAlignment.start,
direction: Axis.horizontal,
children: [ children: [
Text( Text(
"Address: ", "Address: ",
@ -302,13 +305,23 @@ Future<void> adduni()async {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
AutoSizeText("${widget.placedOrderList!.shipTo}",maxLines: 4, Text(
overflow:TextOverflow.ellipsis,) "${widget.placedOrderList!.shipTo.toString()}",
// Text(
// "${widget.placedOrderList!.shipTo}",
maxLines: 4,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
),
),
], ],
), ),
), ),
), ),
], ],
), ),
), ),

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:cheminova/models/place_order_list_model.dart'; import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/screens/order_management/order_management_detail_screen.dart'; import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
import 'package:cheminova/widgets/input_field.dart'; import 'package:cheminova/widgets/input_field.dart';
@ -57,6 +59,11 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
return formattedDate; return formattedDate;
} }
Future<void> searchOrder(String query) async {
{
_getPlacedOrderController.searchOrder();
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -108,7 +115,11 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
InputField( InputField(
hintText: "Search Order", hintText: "Search Order",
labelText: "Search Order", labelText: "Search Order",
controller: _searchController, controller: _searchController,
onChanged: (value) {
searchOrder(value);// Call search function with input value
},
), ),
SizedBox(height: Get.height * 0.035), SizedBox(height: Get.height * 0.035),
Card( Card(

View File

@ -7,6 +7,7 @@ class InputField extends StatefulWidget {
final TextEditingController controller; final TextEditingController controller;
final bool obscureText; final bool obscureText;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final void Function(String)? onChanged;
final String? Function(String?)? validator;// Add this line for validation final String? Function(String?)? validator;// Add this line for validation
InputField({ InputField({
@ -15,6 +16,7 @@ class InputField extends StatefulWidget {
required this.labelText, required this.labelText,
required this.controller, required this.controller,
this.obscureText = false, this.obscureText = false,
this.onChanged,
this.keyboardType = TextInputType.text, this.keyboardType = TextInputType.text,
this.validator, // Add this this.validator, // Add this
}); });