diff --git a/lib/controller/product_stock_controller.dart b/lib/controller/product_stock_controller.dart new file mode 100644 index 0000000..1b36ed6 --- /dev/null +++ b/lib/controller/product_stock_controller.dart @@ -0,0 +1,56 @@ +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 = [].obs; + + // Service to fetch data + final ProductStockService productStockService = ProductStockService(); + + // Loading state + var isLoading = false.obs; + + // Method to fetch product manuals from the service + FuturefetchProductStock() 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; + } + + } + + + void updateProductInventory(int index, ProductStockModel newInventory) { + productStockList[index] = newInventory ; + productStockList.refresh(); // Refresh the list to reflect changes + } + @override + void onInit() { + // Fetch product manuals when the controller is initialized + fetchProductStock(); + super.onInit(); + } +} + diff --git a/lib/controller/product_stock_service.dart b/lib/controller/product_stock_service.dart new file mode 100644 index 0000000..9827744 --- /dev/null +++ b/lib/controller/product_stock_service.dart @@ -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?> getProductStock(String token) async { + try { + String url = ApiUrls.ProductStockUrl; // Base URL to fetch product manuals + + final response = await commonApiService>( + 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 productstock = (json['stocks'] as List) + .map((manualJson) => ProductStockModel.fromJson(manualJson as Map)) + .toList(); + return productstock; // Return the list of product manuals + } else { + return []; + } + }, + ); + return response; + } catch (e) { + + print(e.toString()); + return null; + } + } +} diff --git a/lib/controller/shiptoandbillto_service.dart b/lib/controller/shiptoandbillto_service.dart new file mode 100644 index 0000000..cd36a86 --- /dev/null +++ b/lib/controller/shiptoandbillto_service.dart @@ -0,0 +1,40 @@ + +import '../models/shippingandBilling_address_model.dart'; +import '../utils/api_urls.dart'; +import '../utils/common_api_service.dart'; + +class ShiptoandbilltoService { + + + Future?> fetchshiptobillAddress(String token) async { + try { + String url = ApiUrls + .ShiptoandBilltoAddressUrl; // Base URL to fetch product manuals + + final response = await commonApiService>( + method: "GET", + url: url, + additionalHeaders: { // Pass the token here + 'Authorization': 'Bearer $token', + }, + fromJson: (json) { + if (json['UserShippingAddress'] != null) { + // If the productManuals key is present, map the response to a list of ProductManualModel objects + final List< + UserShippingAddress> productManuals = (json['UserShippingAddress'] as List) + .map((manualJson) => UserShippingAddress.fromJson(manualJson)) + .toList(); + return productManuals; // Return the list of product manuals + } else { + return []; + } + }, + ); + return response; + } catch (e) { + print("fkfgghgh ,${e.toString()}"); + //print(e.toString()); + return null; + } + } +} diff --git a/lib/controller/shiptobilltoController.dart b/lib/controller/shiptobilltoController.dart new file mode 100644 index 0000000..fdcc375 --- /dev/null +++ b/lib/controller/shiptobilltoController.dart @@ -0,0 +1,101 @@ +// import 'package:cheminova/controller/shiptoandbillto_service.dart'; +// import 'package:cheminova/models/shiping_billing_address_model.dart'; +// import 'package:get/get.dart'; +// import 'package:shared_preferences/shared_preferences.dart'; +// +// class AddressController extends GetxController { +// final ShiptoandbilltoService _productService = ShiptoandbilltoService(); +// +// var addressList = [].obs; // Observable list of addresses +// var selectedShippingAddressId = ''.obs; +// var selectedBillingAddressId = ''.obs; +// +// @override +// void onInit() { +// super.onInit(); +// _loadAddresses(); +// } +// +// void _loadAddresses() async { +// try { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// String? token = prefs.getString('token'); +// final response = await _productService.fetchshiptobillAddress(token!); +// addressList.assignAll(response as Iterable); +// +// // Load previously selected addresses +// selectedShippingAddressId.value = prefs.getString('selectedShippingAddress') ?? ''; +// selectedBillingAddressId.value = prefs.getString('selectedBillingAddress') ?? ''; +// +// // Set the default selection to the first address if available +// if (addressList.isNotEmpty) { +// if (selectedShippingAddressId.value.isEmpty) { +// selectedShippingAddressId.value = addressList.first.id; +// } +// if (selectedBillingAddressId.value.isEmpty) { +// selectedBillingAddressId.value = addressList.first.id; +// } +// } +// } catch (e) { +// print("Exception: $e"); +// } +// } +// +// void _saveSelectedAddress() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// await prefs.setString('selectedShippingAddress', selectedShippingAddressId.value); +// await prefs.setString('selectedBillingAddress', selectedBillingAddressId.value); +// } +// +// void onShippingAddressChanged(String? value) { +// if (value != null) { +// selectedShippingAddressId.value = value; +// _saveSelectedAddress(); +// } +// } +// +// void onBillingAddressChanged(String? value) { +// if (value != null) { +// selectedBillingAddressId.value = value; +// _saveSelectedAddress(); +// } +// } +// } + + +import 'package:cheminova/controller/shiptoandbillto_service.dart'; +import 'package:get/get_rx/src/rx_types/rx_types.dart'; +import 'package:get/get_state_manager/src/simple/get_controllers.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../models/shippingandBilling_address_model.dart'; + + + +class AddressController extends GetxController { + RxList addressList = [].obs; + RxString selectedShippingAddressId = ''.obs; + RxString selectedBillingAddressId = ''.obs; + Rx selectedShippingAddress = Rx(null); + Rx selectedBillingAddress = Rx(null); + + void fetchAddresses() async { + // Fetch the addresses from the API + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + var response = await ShiptoandbilltoService().fetchshiptobillAddress(token!); + if (response!= null) { + addressList.value = response; + } + } + + void onShippingAddressChanged(String? value) { + selectedShippingAddressId.value = value ?? ''; + selectedShippingAddress.value = addressList.firstWhere((address) => address.id == value); + } + + void onBillingAddressChanged(String? value) { + selectedBillingAddressId.value = value ?? ''; + selectedBillingAddress.value = addressList.firstWhere((address) => address.id == value,); + } +} diff --git a/lib/controller/update_stock_controller.dart b/lib/controller/update_stock_controller.dart new file mode 100644 index 0000000..04665ba --- /dev/null +++ b/lib/controller/update_stock_controller.dart @@ -0,0 +1,33 @@ +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 updateProductStock(List 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 { + + } + } + +} \ No newline at end of file diff --git a/lib/controller/update_stock_service.dart b/lib/controller/update_stock_service.dart new file mode 100644 index 0000000..c9896c5 --- /dev/null +++ b/lib/controller/update_stock_service.dart @@ -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 UpdateStockProduct(String token, List 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'); + } + } + +} + diff --git a/lib/models/product_stock_model.dart b/lib/models/product_stock_model.dart new file mode 100644 index 0000000..670848f --- /dev/null +++ b/lib/models/product_stock_model.dart @@ -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 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 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)'; + } +} diff --git a/lib/models/shippingandBilling_address_model.dart b/lib/models/shippingandBilling_address_model.dart new file mode 100644 index 0000000..6cf9d6e --- /dev/null +++ b/lib/models/shippingandBilling_address_model.dart @@ -0,0 +1,56 @@ + +class UserShippingAddress { + final String id; + final String name; + final String phoneNumber; + final String street; + final String district; + final String city; + final String state; + final String postalCode; + final String country; + final String tradeName; + final bool isDefault; + final String user; + DateTime? createdAt; + DateTime? updatedAt; + + UserShippingAddress({ + required this.id, + required this.name, + required this.phoneNumber, + required this.street, + required this.district, + required this.city, + required this.state, + required this.postalCode, + required this.country, + required this.tradeName, + required this.isDefault, + required this.user, + this.createdAt, + this.updatedAt, + }); + + factory UserShippingAddress.fromJson(Map json) { + return UserShippingAddress( + id: json['_id'] ?? '', + name: json['Name'] ?? '', + phoneNumber: json['phoneNumber'] ?? '', + street: json['street'] ?? '', + district: json['district'] ?? '', + city: json['city'] ?? '', + state: json['state'] ?? '', + postalCode: json['postalCode'] ?? '', + country: json['country'] ?? '', + tradeName: json['tradeName'] ?? '', + isDefault: json['isDefault'] ?? false, + user: json['user'] ?? '', + createdAt: DateTime.parse(json['createdAt']), + updatedAt: DateTime.parse(json['updatedAt']), + ); + } + String toStringFullAddress() { + return "$street, $city, $state, $postalCode, $country"; + } +} diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 54ef839..1133204 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,6 +1,7 @@ import 'package:cheminova/controller/home_controller.dart'; import 'package:cheminova/screens/announment/announment_screen.dart'; import 'package:cheminova/screens/inventory/inventory_management_screen.dart'; +import 'package:cheminova/screens/opening%20Inventory/inventory_management_screen.dart'; import 'package:cheminova/screens/order/order_tracking_screen.dart'; import 'package:cheminova/screens/order_management/order_management_screen.dart'; import 'package:cheminova/screens/product/product_catalog_screen.dart'; @@ -139,6 +140,12 @@ class _HomeScreenState extends State { () => AnnouncementScreen(), // Navigates to RetailDistributerOnBoardingScreen. ), ), + HomeCard( + title: 'Opening Inventory', + onTap: () => Get.to( + () => OpeningInventoryManagementScreen(), // Navigates to RetailDistributerOnBoardingScreen. + ), + ), ], ), ], diff --git a/lib/screens/opening Inventory/inventory_management_screen.dart b/lib/screens/opening Inventory/inventory_management_screen.dart new file mode 100644 index 0000000..23303e1 --- /dev/null +++ b/lib/screens/opening Inventory/inventory_management_screen.dart @@ -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 createState() => _OpeningInventoryManagementScreenState(); +} + +class _OpeningInventoryManagementScreenState extends State { + final _searchController = TextEditingController(); + //final List _filterList = ["Order Status", "Date Range"]; + + final ProductStockController _getProductStockController = Get.put(ProductStockController()); + final CartController _cartController = Get.put(CartController()); + final GlobalKey _refreshIndicatorKey = + GlobalKey(); + + @override + void initState() { + super.initState(); + getOrder1(); // Fetch orders when the screen initializes + } + + Future _onRefresh() async { + await getOrder1(); + await Future.delayed(Duration(seconds: 1)); + } + // Fetches orders from the API + Future 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 uniqueOrderIds = {}; + final List 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)), + ), + ), + ) + ], + ), + ), + ); + }, + ); + }), + ) + ], + ), + ), + ), + ], + ), + ), + ), + ), + ), + ], + ), + ); + } +} + diff --git a/lib/screens/opening Inventory/inventory_product_detail_screen.dart b/lib/screens/opening Inventory/inventory_product_detail_screen.dart new file mode 100644 index 0000000..45fcc9d --- /dev/null +++ b/lib/screens/opening Inventory/inventory_product_detail_screen.dart @@ -0,0 +1,226 @@ +import 'package:cheminova/models/product_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:get/get.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class OpeningInventoryProductDetailScreen extends StatefulWidget { + final ProductModel product; + + const OpeningInventoryProductDetailScreen({ + super.key, + required this.product, + }); + + @override + State createState() => + _OpeningInventoryProductDetailScreenState(); +} + +class _OpeningInventoryProductDetailScreenState + extends State { + @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( + "Inventory Product Detail", + ), + ), + 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: [ + SizedBox( + width: Get.width, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + height: Get.height * 0.4, + width: Get.width * 0.7, + decoration: BoxDecoration( + border: Border.all( + width: 4, + color: Colors.white, + ), + borderRadius: BorderRadius.circular(15), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.asset( + widget.product.image, + fit: BoxFit.cover, + ), + ), + ), + ), + ), + Card( + child: Column( + children: [ + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Text( + "Product Name: ${widget.product.name}", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 8), + child: Text( + "Descrition: ${widget.product.description}", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + Card( + child: Column( + children: [ + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Text( + "Stock Information", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Text( + "Current Stock: ${widget.product.quantity}", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Text( + "Minimum Stock Level: 20", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Text( + "Last Restock Date: MM/DD/YYYY", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + SizedBox( + width: Get.width, + child: Padding( + padding: + const EdgeInsets.fromLTRB(8, 8, 8, 8), + child: Text( + "Supplier: ABC Supplier", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/opening Inventory/update_stock_screen.dart b/lib/screens/opening Inventory/update_stock_screen.dart new file mode 100644 index 0000000..7c4acb1 --- /dev/null +++ b/lib/screens/opening Inventory/update_stock_screen.dart @@ -0,0 +1,367 @@ +// +// import 'package:flutter_svg/svg.dart'; +// import 'package:get/get.dart'; +// import 'package:get/get_core/src/get_main.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 ProductStockModel product; +// +// const InventoryUpdateStockScreen({ +// super.key, +// required this.product, +// }); +// +// @override +// State createState() => _InventoryUpdateStockScreenState(); +// } +// +// class _InventoryUpdateStockScreenState extends State { +// final _textController = TextEditingController(); +// final UpdateStockController _updateStockController = Get.put(UpdateStockController()); +// +// // Map to store the updated stock quantities for each product +// final Map _updatedStockMap = {}; +// +// @override +// void initState() { +// super.initState(); +// // Set the initial value of the text controller if there's an updated stock for the current product +// _textController.text = _updatedStockMap[widget.product.productid]?.toString() ?? widget.product.stock.toString(); +// } +// +// 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; +// } +// +// // Update the map with the new stock quantity for the current product +// setState(() { +// _updatedStockMap[widget.product.productid] = newStockQuantity; +// }); +// +// // Create a list of ProductStockModel instances with updated stock +// List productStockList = [ +// ProductStockModel( +// productid: widget.product.productid, +// name: widget.product.name, +// sku: widget.product.sku, +// stock: widget.product.stock, +// openingInventory: 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("Opening Inventory updated successfully"); +// Get.to(OpeningInventoryManagementScreen()); +// } catch (e) { +// print("Error updating stock: $e"); +// showSnackbar("Error updating stock. Please try again."); +// } +// } +// +// @override +// void didUpdateWidget(covariant InventoryUpdateStockScreen oldWidget) { +// super.didUpdateWidget(oldWidget); +// // Update the text controller with the new product's stock or the previously updated value +// _textController.text = _updatedStockMap[widget.product.productid]?.toString() ?? widget.product.stock.toString(); +// } +// +// @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 Opening Inventory Quantity:", +// labelText: "Enter New Opening Inventory Quantity:", +// 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 Inventory 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 products; + final String selectedProductId; + + const InventoryUpdateStockScreen({ + super.key, + required this.products, + required this.selectedProductId, + }); + + @override + State createState() => _InventoryUpdateStockScreenState(); +} + +class _InventoryUpdateStockScreenState extends State { + 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 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, + ), + ), + ), + ], + ), + ), + ], + ), + ); + } +} + + + + diff --git a/lib/screens/order/checkout_screen.dart b/lib/screens/order/checkout_screen.dart index d8e58a0..90d2ccc 100644 --- a/lib/screens/order/checkout_screen.dart +++ b/lib/screens/order/checkout_screen.dart @@ -1,3 +1,434 @@ +// import 'dart:ffi'; +// import 'package:cheminova/controller/get_order_placed_controller.dart'; +// import 'package:cheminova/models/added_by_model.dart'; +// import 'package:cheminova/models/category_model.dart'; +// import 'package:cheminova/utils/show_snackbar.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:shared_preferences/shared_preferences.dart'; +// +// import '../../controller/cart_controller.dart'; +// import '../../controller/place_order_controller.dart'; +// import '../../controller/place_order_service.dart'; +// import '../../controller/product_controller.dart'; +// import '../../controller/product_service.dart'; +// import '../../models/brand_model.dart'; +// import '../../models/oder_place_model.dart'; +// import '../../models/product_model1.dart'; +// import '../../widgets/my_drawer.dart'; +// import '../../widgets/product_card.dart'; +// import 'order_confermation_screen.dart'; +// +// class CheckoutScreen extends StatefulWidget { +// final Product? productModel; +// +// PlacedOrderModel? placeOrder; +// List? selectedProducts; +// CheckoutScreen({super.key, this.productModel, this.placeOrder,this.selectedProducts}); +// +// @override +// State createState() => _CheckoutScreenState(); +// } +// +// class _CheckoutScreenState extends State { +// final CartController _cartController = Get.put(CartController()); +// final ProductService _productService = ProductService(); +// final ProductController _productController = Get.put(ProductController()); +// final OrderPlacedController _orderPlacedController = +// Get.put(OrderPlacedController()); +// final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); +// +// int currentPage = 1; +// String _groupValue = "cheque"; +// +// final List _addressList = [ +// 'Home - 123 Street, City', +// 'Office - 456 Avenue, City', +// 'Warehouse - 789 Blvd, City', +// ]; +// +// String? _selectedShippingAddress; +// String? _selectedBillingAddress; +// +// @override +// void initState() { +// super.initState(); +// // _getOrder(); +// _loadSelectedAddress(); +// _loadSelectedPaymentMode(); +// +// if (_addressList.isNotEmpty) { +// _selectedShippingAddress = _addressList.first; +// _selectedBillingAddress = _addressList.first; +// } +// } +// +// void _saveSelectedAddress() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// await prefs.setString('selectedShippingAddress', _selectedShippingAddress!); +// await prefs.setString('selectedBillingAddress', _selectedBillingAddress!); +// } +// +// void _onShippingAddressChanged(String? value) { +// setState(() { +// _selectedShippingAddress = value; +// }); +// _saveSelectedAddress(); +// } +// +// void _onBillingAddressChanged(String? value) { +// setState(() { +// _selectedBillingAddress = value; +// }); +// _saveSelectedAddress(); +// } +// +// void _loadSelectedAddress() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// setState(() { +// _selectedShippingAddress = +// prefs.getString('selectedShippingAddress') ?? _addressList.first; +// _selectedBillingAddress = +// prefs.getString('selectedBillingAddress') ?? _addressList.first; +// }); +// } +// +// void _onPaymentModeChanged(String? value) { +// setState(() { +// _groupValue = value!; +// }); +// _saveSelectedPaymentMode(); +// } +// +// void _saveSelectedPaymentMode() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// await prefs.setString('selectedPaymentMode', _groupValue); +// } +// +// void _loadSelectedPaymentMode() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// setState(() { +// _groupValue = prefs.getString('selectedPaymentMode') ?? 'cheque'; +// }); +// } +// +// // void _getOrder(){ +// // final details = _getPlacedOrderController.getOrder(widget.productModel!.id); +// // print("dffgfg,$details"); +// // } +// void _onPlaceOrder() async { +// try { +// // Map the cart items (Product) to OrderItem objects +// List orderItems = _cartController.selectedProducts.map((product) { +// return OrderItem( +// id: product.id, +// name: product.name, +// price: product.price.toDouble(), +// sku: product.sku, +// gst: product.gst.toDouble(), +// hsnCode: product.hsnCode, +// description: product.description, +// productStatus: product.productStatus, +// image: [], +// createdAt: product.createdAt, +// updatedAt: product.createdAt, +// count: product.quantity, +// +// //category:product.category, +// category:Category(id: product.category.id, categoryName: product.category.categoryName), +// // brand:product.brand, +// brand:Brand(id: product.brand.id, brandName: product.brand.brandName), +// v: 0, addedBy: product.addedBy, +// ); +// }).toList(); +// +// // Update the placedOrder1 value +// _orderPlacedController.placedOrder1.value= PlacedOrderModel( +// paymentMode: _groupValue, +// shipTo: _selectedShippingAddress!, +// billTo: _selectedBillingAddress!, +// orderItems: orderItems, +// gstTotal: _cartController.gstTotal.value, +// grandTotal: _cartController.grandTotal.value, +// subtotal: _cartController.subtotal.value, +// ); +// +// await _orderPlacedController.placeOrder(); +// +// if (_orderPlacedController.isLoading.value) { +// showSnackbar("Order Placed Successfully"); +// Get.to(() => OrderConfermationScreen( +// placedOrder: _orderPlacedController.placedOrder1.value, +// )); +// } +// } catch (e) { +// print("PlaceOrderScreen error: $e"); +// } +// } +// +// +// +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// extendBodyBehindAppBar: true, +// appBar: AppBar( +// 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: EdgeInsets.all(Get.width * 0.02), +// child: SvgPicture.asset( +// 'assets/svg/back_arrow.svg', +// ), +// ), +// ), +// ], +// title: const Text("Checkout"), +// ), +// drawer: const MyDrawer(), +// body: Stack( +// fit: StackFit.expand, +// children: [ +// Image.asset( +// 'assets/images/image_1.png', +// fit: BoxFit.cover, +// ), +// SafeArea( +// child: Column( +// children: [ +// SizedBox(height: Get.height * 0.02), +// Card( +// margin: EdgeInsets.symmetric(horizontal: Get.width * 0.05), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(19), +// side: const BorderSide(color: Color(0xFFFDFDFD)), +// ), +// color: const Color(0xFFB4D1E5).withOpacity(0.9), +// child: Padding( +// padding: EdgeInsets.all(Get.width * 0.04), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Padding( +// padding: EdgeInsets.symmetric( +// horizontal: Get.width * 0.04), +// child: Text( +// 'Shipping Information', +// style: GoogleFonts.roboto( +// fontSize: Get.width * 0.04, +// fontWeight: FontWeight.w500, +// color: Colors.black, +// ), +// ), +// ), +// SizedBox(height: 5,), +// DropdownButtonFormField( +// decoration: InputDecoration( +// labelText: 'Shipping Address:', +// hintText: 'Select Shipping Address', +// border: OutlineInputBorder(), +// ), +// value: _selectedShippingAddress, +// items: _addressList.map((String address) { +// return DropdownMenuItem( +// value: address, +// child: Text(address), +// ); +// }).toList(), +// onChanged: _onShippingAddressChanged, +// ), +// SizedBox(height: Get.height * 0.02), +// DropdownButtonFormField( +// decoration: InputDecoration( +// labelText: 'Billing Address:', +// hintText: 'Select Billing Address', +// border: OutlineInputBorder(), +// ), +// value: _selectedBillingAddress, +// items: _addressList.map((String address) { +// return DropdownMenuItem( +// value: address, +// child: Text(address), +// ); +// }).toList(), +// onChanged: _onBillingAddressChanged, +// ), +// Padding( +// padding: EdgeInsets.symmetric( +// horizontal: Get.width * 0.04), +// child: Text( +// 'Payment Information', +// style: GoogleFonts.roboto( +// fontSize: Get.width * 0.04, +// fontWeight: FontWeight.w500, +// color: Colors.black, +// ), +// ), +// ), +// Card( +// child: ListView( +// padding: EdgeInsets.zero, +// shrinkWrap: true, +// children: [ +// SizedBox( +// height: Get.height * 0.035, +// child: RadioListTile( +// title: const Text("Cheque"), +// contentPadding: EdgeInsets.zero, +// value: "cheque", +// groupValue: _groupValue, +// onChanged: _onPaymentModeChanged, +// ), +// ), +// SizedBox( +// height: Get.height * 0.035, +// child: RadioListTile( +// title: const Text("Online transfer"), +// contentPadding: EdgeInsets.zero, +// value: "online-transfer", +// groupValue: _groupValue, +// onChanged: _onPaymentModeChanged, +// ), +// ), +// SizedBox( +// child: RadioListTile( +// title: const Text("Credit"), +// contentPadding: EdgeInsets.zero, +// value: "credit", +// groupValue: _groupValue, +// onChanged: _onPaymentModeChanged, +// ), +// ), +// ], +// ), +// ), +// Padding( +// padding: EdgeInsets.symmetric( +// horizontal: Get.width * 0.04), +// child: Text( +// 'Order Summary', +// style: GoogleFonts.roboto( +// fontSize: Get.width * 0.04, +// fontWeight: FontWeight.w500, +// 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( +// itemCount: _cartController.selectedProducts.length, +// itemBuilder: (context, index) { +// final cartItem = +// _cartController.cartList[index]; +// return ProductCard( +// productModel:_cartController.selectedProducts[index] , +// isCheckout: true, +// quantity: _cartController.cartList[0].quantity, +// +// +// // ListTile( +// // title: Text(cartItem.name ?? 'N/A'), +// // subtitle: Text( +// // 'Quantity: ${cartItem.quantity}'), +// // trailing: Text( +// // 'Price: \₹${cartItem.price.toStringAsFixed(2)}'), +// // ); +// );}, +// ), +// ), +// ), +// 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)}'), +// ], +// ), +// ], +// ), +// ), +// ], +// ), +// ), +// +// ], +// ), +// ), +// ), +// SizedBox(height: 10.0,), +// Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// ElevatedButton( +// onPressed: _onPlaceOrder, +// style: ElevatedButton.styleFrom( +// foregroundColor: Colors.white, +// backgroundColor: const Color(0xFF00784C), +// padding: EdgeInsets.symmetric( +// horizontal: Get.width * 0.20, +// vertical: Get.height * 0.02), +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(10), +// ), +// ), +// child: const Text("Place Order"), +// ), +// ], +// ), +// ], +// ), +// ), +// ], +// ), +// ); +// } +// } import 'dart:ffi'; import 'package:cheminova/controller/get_order_placed_controller.dart'; import 'package:cheminova/models/added_by_model.dart'; @@ -14,9 +445,12 @@ import '../../controller/place_order_controller.dart'; import '../../controller/place_order_service.dart'; import '../../controller/product_controller.dart'; import '../../controller/product_service.dart'; +import '../../controller/shiptobilltoController.dart'; import '../../models/brand_model.dart'; import '../../models/oder_place_model.dart'; import '../../models/product_model1.dart'; + +import '../../models/shippingandBilling_address_model.dart'; import '../../widgets/my_drawer.dart'; import '../../widgets/product_card.dart'; import 'order_confermation_screen.dart'; @@ -25,7 +459,7 @@ class CheckoutScreen extends StatefulWidget { final Product? productModel; PlacedOrderModel? placeOrder; - List? selectedProducts; + List? selectedProducts; CheckoutScreen({super.key, this.productModel, this.placeOrder,this.selectedProducts}); @override @@ -39,6 +473,7 @@ class _CheckoutScreenState extends State { final OrderPlacedController _orderPlacedController = Get.put(OrderPlacedController()); final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); + final AddressController _addressController = Get.put(AddressController()); // Initialize AddressController int currentPage = 1; String _groupValue = "cheque"; @@ -52,17 +487,25 @@ class _CheckoutScreenState extends State { String? _selectedShippingAddress; String? _selectedBillingAddress; + + String capitalizeFirstLetter(String text) { + if (text.isEmpty) return text; + return text[0].toUpperCase() + text.substring(1).toLowerCase(); + } @override void initState() { super.initState(); // _getOrder(); + _addressController.fetchAddresses(); _loadSelectedAddress(); _loadSelectedPaymentMode(); - - if (_addressList.isNotEmpty) { - _selectedShippingAddress = _addressList.first; - _selectedBillingAddress = _addressList.first; - } + // _loadSelectedAddress(); + // _loadSelectedPaymentMode(); + // + // if (_addressList.isNotEmpty) { + // _selectedShippingAddress = _addressList.first; + // _selectedBillingAddress = _addressList.first; + // } } void _saveSelectedAddress() async { @@ -114,10 +557,6 @@ class _CheckoutScreenState extends State { }); } - // void _getOrder(){ - // final details = _getPlacedOrderController.getOrder(widget.productModel!.id); - // print("dffgfg,$details"); - // } void _onPlaceOrder() async { try { // Map the cart items (Product) to OrderItem objects @@ -144,11 +583,35 @@ class _CheckoutScreenState extends State { ); }).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: '', name: '', phoneNumber: '', district: '', isDefault: false, user: '', + )).toStringFullAddress(); + + String? billingAddress = _addressController.addressList.firstWhere( + (address) => address.id == _addressController.selectedBillingAddressId.value, + orElse: () => UserShippingAddress( + id: '', + street: '', + city: '', + state: '', + postalCode: '', + country: '', tradeName: '', name: '', phoneNumber: '', district: '', isDefault: false, user: '', createdAt: null, + )).toStringFullAddress(); + // Update the placedOrder1 value _orderPlacedController.placedOrder1.value= PlacedOrderModel( paymentMode: _groupValue, - shipTo: _selectedShippingAddress!, - billTo: _selectedBillingAddress!, + shipTo: shippingAddress, // Full shipping address + billTo: billingAddress, // Full billing address orderItems: orderItems, gstTotal: _cartController.gstTotal.value, grandTotal: _cartController.grandTotal.value, @@ -161,11 +624,16 @@ class _CheckoutScreenState extends State { showSnackbar("Order Placed Successfully"); Get.to(() => OrderConfermationScreen( placedOrder: _orderPlacedController.placedOrder1.value, + )); } + + } catch (e) { print("PlaceOrderScreen error: $e"); } + + } @@ -204,7 +672,7 @@ class _CheckoutScreenState extends State { ], title: const Text("Checkout"), ), - drawer: const MyDrawer(), + drawer: MyDrawer(), body: Stack( fit: StackFit.expand, children: [ @@ -223,15 +691,15 @@ class _CheckoutScreenState extends State { side: const BorderSide(color: Color(0xFFFDFDFD)), ), color: const Color(0xFFB4D1E5).withOpacity(0.9), - child: Padding( + child: + Padding( padding: EdgeInsets.all(Get.width * 0.04), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.symmetric( - horizontal: Get.width * 0.04), + padding: EdgeInsets.symmetric(horizontal: Get.width * 0.04), child: Text( 'Shipping Information', style: GoogleFonts.roboto( @@ -241,38 +709,58 @@ class _CheckoutScreenState extends State { ), ), ), - SizedBox(height: 5,), - DropdownButtonFormField( - decoration: InputDecoration( - labelText: 'Shipping Address:', - hintText: 'Select Shipping Address', - border: OutlineInputBorder(), + SizedBox(height: 5), + Obx(() => Container( + + child: DropdownButtonFormField( + decoration: InputDecoration( + 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( + value: address.id, // Set the value as the address ID + child: Text("${address.street} ${address.city}\n ${address.state} \n ${address.postalCode} , ${address.country}",style: TextStyle(fontSize: 15),), // Display full address + ); + }).toList(), + onChanged: (value) { + _addressController.onShippingAddressChanged(value); // Update the selected address + }, ), - value: _selectedShippingAddress, - items: _addressList.map((String address) { - return DropdownMenuItem( - value: address, - child: Text(address), - ); - }).toList(), - onChanged: _onShippingAddressChanged, - ), + )), SizedBox(height: Get.height * 0.02), - DropdownButtonFormField( - decoration: InputDecoration( - labelText: 'Billing Address:', - hintText: 'Select Billing Address', - border: OutlineInputBorder(), + +// Billing Address Dropdown + Obx(() => Container( + child: DropdownButtonFormField( + decoration: InputDecoration( + labelText: 'Billing Address:', + hintText: 'Select Billing Address', + border: OutlineInputBorder(), + ), + value: _addressController.selectedBillingAddressId.value.isEmpty + ? null + : _addressController.selectedBillingAddressId.value, + items: _addressController.addressList + .where((address) => address.isDefault == true) // Filter only default addresses + .map((UserShippingAddress address) { + return DropdownMenuItem( + value: address.id, + child: Text( + "${address.street} ${address.city}${address.state}\n${address.postalCode}, ${address.country}", + style: TextStyle(fontSize: 15), + ), + ); + }).toList(), + onChanged: (value) { + _addressController.onBillingAddressChanged(value); + }, ), - value: _selectedBillingAddress, - items: _addressList.map((String address) { - return DropdownMenuItem( - value: address, - child: Text(address), - ); - }).toList(), - onChanged: _onBillingAddressChanged, - ), + )), Padding( padding: EdgeInsets.symmetric( horizontal: Get.width * 0.04), @@ -370,7 +858,7 @@ class _CheckoutScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Subtotal',style: TextStyle(fontWeight: FontWeight.bold)), Text('₹${_cartController.subtotal.value.toStringAsFixed(2)}'), diff --git a/lib/screens/order_management/order_management_detail_screen.dart b/lib/screens/order_management/order_management_detail_screen.dart index 77db590..2ae87b3 100644 --- a/lib/screens/order_management/order_management_detail_screen.dart +++ b/lib/screens/order_management/order_management_detail_screen.dart @@ -282,11 +282,12 @@ Future adduni()async { ), SizedBox( width: Get.width, - height: Get.height*0.06, + height: Get.height * 0.10, child: Padding( - padding: - const EdgeInsets.fromLTRB(8, 8, 8, 0), - child: Row( + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + child: Wrap( // Use Wrap to allow wrapping + crossAxisAlignment: WrapCrossAlignment.start, + direction: Axis.horizontal, children: [ Text( "Address: ", @@ -295,8 +296,17 @@ Future adduni()async { fontWeight: FontWeight.bold, ), ), - AutoSizeText("${widget.placedOrderList!.shipTo}",maxLines: 4, - overflow:TextOverflow.ellipsis,) + Text( + "${widget.placedOrderList!.shipTo.toString()}", + // Text( + // "${widget.placedOrderList!.shipTo}", + maxLines: 4, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + + ), + ), ], ), ), diff --git a/lib/utils/api_urls.dart b/lib/utils/api_urls.dart index 535c9e1..eba08d5 100644 --- a/lib/utils/api_urls.dart +++ b/lib/utils/api_urls.dart @@ -16,4 +16,14 @@ class ApiUrls { static const String inventoryManangementOrdersStock ='${baseUrl}/api/stock'; static const String announcementUrl ='${baseUrl}/api/announcement/RDs?page%3D1=rowsPerPage=5'; + + //============================== Product stock Details ==============================// + static const String ProductStockUrl = '/api/rd/stock'; + + //============================== Product Update stock Details ==============================// + static const String ProductUpdateStockUrl = '${baseUrl}/api/rd/stock-update'; + + + //============================== shipto Billto Details ==============================// + static const String ShiptoandBilltoAddressUrl = '/api/rd/shipping/address'; } diff --git a/lib/widgets/input_field.dart b/lib/widgets/input_field.dart index ae7c3d5..d5e93a6 100644 --- a/lib/widgets/input_field.dart +++ b/lib/widgets/input_field.dart @@ -7,6 +7,7 @@ class InputField extends StatefulWidget { final TextEditingController controller; final bool obscureText; final TextInputType? keyboardType; + final void Function(String)? onChanged; final String? Function(String?)? validator;// Add this line for validation InputField({ @@ -15,6 +16,7 @@ class InputField extends StatefulWidget { required this.labelText, required this.controller, this.obscureText = false, + this.onChanged, this.keyboardType = TextInputType.text, this.validator, // Add this }); diff --git a/pubspec.lock b/pubspec.lock index e143114..a979e44 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -500,18 +500,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: @@ -548,18 +548,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.12.0" mime: dependency: transitive description: @@ -849,10 +849,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.0" timezone: dependency: transitive description: @@ -977,10 +977,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.1" web: dependency: transitive description: