Compare commits

...

5 Commits
main ... rita

Author SHA1 Message Date
e985fd194b new changes done 2025-04-28 13:34:34 +05:30
2c0797b687 new changes done 2025-02-06 15:44:18 +05:30
d101e82096 1) opening inventory api integration done
2) Billto shipto address api integration done
2024-10-30 16:34:18 +05:30
a545efca3b 1)Url added 2024-10-24 09:34:44 +05:30
ef2799cbd4 1) Cancelled file changes done 2024-10-23 13:55:09 +05:30
87 changed files with 6160 additions and 2382 deletions

View File

@ -1,12 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cheminova">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:label="cheminova" android:label="Principal Distributor"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/launcher_icon">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -427,7 +427,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
@ -484,7 +484,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";

View File

@ -1,122 +1 @@
{ {"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -9,7 +9,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>com.example.cheminova</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>

View File

@ -16,7 +16,7 @@ class AnnouncementController extends GetxController {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token'); String? token = prefs.getString('token');
final List<AnnouncementModel>? fetchedAnnouncements = final List<AnnouncementModel>? fetchedAnnouncements =
await _announcementService.fetchAnnouncements(token!); await _announcementService.fetchAnnouncements();
announcements.assignAll(fetchedAnnouncements as Iterable<AnnouncementModel>); announcements.assignAll(fetchedAnnouncements as Iterable<AnnouncementModel>);
} catch (e) { } catch (e) {
errorMessage.value = e.toString(); errorMessage.value = e.toString();

View File

@ -8,16 +8,16 @@ class AnnouncementService {
final Dio _dio = Dio(); final Dio _dio = Dio();
Future<List<AnnouncementModel>?> fetchAnnouncements(String token) async { Future<List<AnnouncementModel>?> fetchAnnouncements() async {
try { try {
String url = ApiUrls.AnnaouncementUrl; // Base URL to fetch product manuals String url = ApiUrls.AnnaouncementUrl; // Base URL to fetch product manuals
final response = await commonApiService<List<AnnouncementModel>>( final response = await commonApiService<List<AnnouncementModel>>(
method: "GET", method: "GET",
url: url, url: url,
additionalHeaders: { // Pass the token here // additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token', // 'Authorization': 'Bearer $token',
}, // },
fromJson: (json) { fromJson: (json) {
if (json['announcements'] != null) { if (json['announcements'] != null) {
// If the productManuals key is present, map the response to a list of ProductManualModel objects // If the productManuals key is present, map the response to a list of ProductManualModel objects

View File

@ -49,7 +49,7 @@ class CartController extends GetxController {
} }
// Update observable values // Update observable values
subtotal.value = subTotal; subtotal.value = subTotal;
gstTotal.value = gstTotalAmount; gstTotal.value = double.parse(gstTotalAmount.toStringAsFixed(2));
grandTotal.value = subtotal.value + gstTotal.value; grandTotal.value = subtotal.value + gstTotal.value;
} }
// Function to increase the quantity of a product in the cart // Function to increase the quantity of a product in the cart
@ -76,6 +76,15 @@ class CartController extends GetxController {
} }
} }
} }
void updateQuantity(Product product, int quantity) {
final existingProduct = cartList.firstWhereOrNull((p) => p.id == product.id);
if (existingProduct != null) {
existingProduct.quantity = quantity;
updateTotalPrice();// Notify listeners
}
}
// Function to remove a product from the cart // Function to remove a product from the cart
void removeFromCart(Product product) { void removeFromCart(Product product) {
// Remove the product from the cart list // Remove the product from the cart list

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/models/user_model.dart';
import 'package:cheminova/utils/api_urls.dart'; import 'package:cheminova/utils/api_urls.dart';
import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/common_api_service.dart';
@ -33,35 +35,26 @@ class HomeService {
} }
// Function to send FCM token to the server // Function to send FCM token to the server
Future<Map<String, dynamic>?> fcmToken(Map<String, dynamic> data, Future<Map<String, dynamic>?> fcmToken(Map<String, dynamic> data, String? token) async {
String? token) async {
try { try {
final response = await commonApiService<String>( final response = await commonApiService<Map<String, dynamic>>(
// Making a POST request to send the FCM token
url: ApiUrls.fcmUrl, url: ApiUrls.fcmUrl,
method: 'POST', method: 'POST',
body: data, body: data,
// Body data to be sent in the request fromJson: (json) => json as Map<String, dynamic>, // Parse JSON response
fromJson: (json) => json as String,
// Just return the string response
additionalHeaders: { additionalHeaders: {
// Pass the token here
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
// Bearer token for authenticated requests
}, },
); );
if (response != null) { if (response != null) {
// Since the response is a string, wrap it in a Map to avoid type issues return response; // Return parsed response
return {
'message': response
}; // Return the response in a map with 'message' as the key
} }
return null; return null;
} catch (e) { } catch (e) {
showSnackbar(e.toString()); // Handle any errors showSnackbar(e.toString());
return null; return null;
} }
} }
} }

View File

@ -2,13 +2,21 @@ import 'package:cheminova/models/kyc_model.dart';
import 'package:cheminova/utils/api_urls.dart'; import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import '../utils/app_interceptor.dart';
class KycService { class KycService {
// Function to fetch KYC data from the API // Function to fetch KYC data from the API
Future<List<dynamic>> getKycData(String token) async { Future<List<dynamic>> getKycData(String token) async {
try { try {
// Make a GET request to the KYC API endpoint with authorization token // Make a GET request to the KYC API endpoint with authorization token
var response = await Dio().get(
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
var response = await dio.get(
ApiUrls.getKycUrl, ApiUrls.getKycUrl,
// 'https://api.cnapp.co.in/api/kyc/getAll', // 'https://api.cnapp.co.in/api/kyc/getAll',
options: Options( options: Options(
@ -31,6 +39,8 @@ class KycService {
} }
Future<bool> approveKycStatus(String token, String kycId,String status) async { Future<bool> approveKycStatus(String token, String kycId,String status) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try { try {
// Prepare the payload for approval directly // Prepare the payload for approval directly
var payload = { var payload = {
@ -41,7 +51,7 @@ class KycService {
// print("Payload: $payload"); // print("Payload: $payload");
// Make a PATCH request to update the KYC status // Make a PATCH request to update the KYC status
var response = await Dio().patch( var response = await dio.patch(
'https://api.cnapp.co.in/api/kyc/update/$kycId', // URL with the KYC ID 'https://api.cnapp.co.in/api/kyc/update/$kycId', // URL with the KYC ID
data: payload, // Payload with the status data: payload, // Payload with the status
options: Options( options: Options(
@ -74,6 +84,8 @@ class KycService {
} }
Future<bool> rejectKycStatus( Future<bool> rejectKycStatus(
String token, String kycId, String? rejectionReason, String? user, String status) async { String token, String kycId, String? rejectionReason, String? user, String status) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try { try {
// Prepare the payload for the PATCH request // Prepare the payload for the PATCH request
var data = { var data = {
@ -92,7 +104,7 @@ class KycService {
print("Payload: $data"); print("Payload: $data");
// Make a PATCH request to update the KYC status // Make a PATCH request to update the KYC status
var response = await Dio().patch( var response = await dio.patch(
'https://api.cnapp.co.in/api/kyc/update/$kycId', 'https://api.cnapp.co.in/api/kyc/update/$kycId',
data: data, data: data,
options: Options( options: Options(

View File

@ -2,15 +2,17 @@ import 'package:dio/dio.dart';
import 'package:cheminova/models/notification_model.dart'; import 'package:cheminova/models/notification_model.dart';
import '../utils/api_urls.dart'; import '../utils/api_urls.dart';
import '../utils/app_interceptor.dart';
class NotificationService { class NotificationService {
final Dio _dio = Dio(); // final Dio _dio = Dio();
Future<List<NotificationModel>?> fetchNotifications(String token, String date) async { Future<List<NotificationModel>?> fetchNotifications(String token, String date) async {
final String url = ApiUrls.getNotificationUrl; final String url = ApiUrls.getNotificationUrl;
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try { try {
final response = await _dio.get( final response = await dio.get(
url, url,
options: Options( options: Options(
headers: { headers: {

View File

@ -6,12 +6,18 @@ import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import '../models/oder_place_model.dart'; import '../models/oder_place_model.dart';
import '../utils/app_interceptor.dart';
import '../utils/log_service.dart'; import '../utils/log_service.dart';
class OrderPlacedService { class OrderPlacedService {
final Dio dio = Dio(); //final Dio dio = Dio();
// OrderPlacedService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
// _dio.interceptors.add(AuthInterceptor());
// _dio.interceptors.add(PrettyDioLogger());
// }
Future<void> placeOrder(PlacedOrderModel orderDetails, String token) async { Future<void> placeOrder(PlacedOrderModel orderDetails, String token) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try { //try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}"); // logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await dio.post( final response = await dio.post(

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

@ -6,16 +6,23 @@ import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import '../models/rd_order_item_model.dart'; import '../models/rd_order_item_model.dart';
import '../utils/app_interceptor.dart';
class RDOrderPlacedService { class RDOrderPlacedService {
final Dio _dio = Dio(); // Create Dio instance final Dio _dio = Dio(); // Create Dio instance
// RDOrderPlacedService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
// _dio.interceptors.add(AuthInterceptor());
// _dio.interceptors.add(PrettyDioLogger());
// }
Future<void> placRDeOrder(PlacedOrdersProcessing orderDetails, Future<void> placRDeOrder(PlacedOrdersProcessing orderDetails,
String token) async { String token) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try { //try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}"); // logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await _dio.post( final response = await dio.post(
'https://api.cnapp.co.in/api/pd-process-order', 'https://api.cnapp.co.in/api/pd-process-order',
// Ensure this is your correct endpoint // Ensure this is your correct endpoint
data: jsonEncode(orderDetails.toJson()), data: jsonEncode(orderDetails.toJson()),

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,48 @@
import 'dart:convert';
import 'package:cheminova/models/product_stock_model.dart';
import 'package:dio/dio.dart';
import '../utils/api_urls.dart';
import '../utils/app_interceptor.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;
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
// 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

@ -1,27 +1,74 @@
class Brand { class Brand {
final String id; final String id;
final String brandName; final String brandName;
List<BrandImage> images;
Brand({ Brand({
required this.id, required this.id,
required this.brandName, required this.brandName,
required this.images,
}); });
factory Brand.fromJson(Map<String, dynamic> json) { factory Brand.fromJson(Map<String, dynamic> json) {
return Brand( return Brand(
id: json['_id'], id: json['_id'],
brandName: json['brandName'], brandName: json['brandName'],
// images: json["image"] != null
// ? (json["image"] as List).map((e) => BrandImage.fromJson(e)).toList()
// : [],
images: json["image"] != null // Ensure you use the correct key
? (json["image"] as List)
.map((e) => BrandImage.fromJson(e))
.toList()
: [],
); );
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'_id': id, '_id': id,
'brandName': brandName, 'brandName': brandName,
"image": images.map((e) => e.toJson()).toList(),
}; };
} }
@override @override
String toString() { String toString() {
return 'Brand(id: $id, brandName: $brandName,)'; return 'Brand(id: $id, brandName: $brandName,images: $images)';
}
}
class BrandImage {
String publicId;
String url;
String imageId;
BrandImage({
required this.publicId,
required this.url,
required this.imageId,
});
factory BrandImage.fromJson(Map<String, dynamic> json) {
return BrandImage(
publicId: json["public_id"] ?? "",
url: json["url"]?.toString() ?? "",
imageId: json["_id"] ?? "",
);
}
Map<String, dynamic> toJson() {
return {
"public_id": publicId,
"url": url,
"_id": imageId,
};
}
@override
String toString() {
return "BrandImage(publicId: $publicId, url: $url, imageId: $imageId)";
} }
} }

View File

@ -1,9 +1,15 @@
import 'package:cheminova/models/rd_order_item_model.dart';
import 'brand_model.dart';
class GetRdCancelledModel { class GetRdCancelledModel {
final String id; final String id;
final String paymentMode; final String paymentMode;
final String shipTo; final String shipTo;
final String billTo; final String billTo;
final List<OrderItem> orderItems; final List<RDOrderItem> orderItems;
final double subtotal; final double subtotal;
final double gstTotal; final double gstTotal;
final double grandTotal; final double grandTotal;
@ -51,8 +57,8 @@ class GetRdCancelledModel {
paymentMode: json['paymentMode'], paymentMode: json['paymentMode'],
shipTo: json['shipTo'], shipTo: json['shipTo'],
billTo: json['billTo'], billTo: json['billTo'],
orderItems: (json['orderItem'] as List<dynamic>) orderItems: (json['orderItem'] as List)
.map((item) => OrderItem.fromJson(item)) .map((item) => RDOrderItem.fromJson(item))
.toList(), .toList(),
subtotal: json['subtotal'].toDouble(), subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(), gstTotal: json['gstTotal'].toDouble(),
@ -122,7 +128,7 @@ class OrderItem {
final double gst; final double gst;
final int hsnCode; final int hsnCode;
final String description; final String description;
final List<String> images; final List<BrandImage> images;
final int quantity; final int quantity;
final int remainingQuantity; final int remainingQuantity;
final String id; final String id;
@ -154,7 +160,9 @@ class OrderItem {
gst: json['GST'].toDouble(), gst: json['GST'].toDouble(),
hsnCode: json['HSN_Code'], hsnCode: json['HSN_Code'],
description: json['description'] ?? '', description: json['description'] ?? '',
images: List<String>.from(json['image']), images : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'], quantity: json['quantity'],
remainingQuantity: json['remainingQuantity'], remainingQuantity: json['remainingQuantity'],
id: json['_id'], id: json['_id'],

View File

@ -64,7 +64,7 @@ class OrderItem {
String description; String description;
String productStatus; String productStatus;
final String addedBy; final String addedBy;
List<String> image; List<BrandImage> image;
DateTime createdAt; DateTime createdAt;
DateTime updatedAt; DateTime updatedAt;
int count; int count;
@ -124,7 +124,9 @@ class OrderItem {
description: json['description'], description: json['description'],
productStatus: json['product_Status'], productStatus: json['product_Status'],
addedBy: json['addedBy']['name'], // Assuming addedBy has a 'name' key addedBy: json['addedBy']['name'], // Assuming addedBy has a 'name' key
image: List<String>.from(json['image']), image: json['image'] is List
? (json['image'] as List).map((e) => BrandImage.fromJson(e)).toList()
: [BrandImage.fromJson(json['image'])],
createdAt: DateTime.parse(json['createdAt']), createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']), updatedAt: DateTime.parse(json['updatedAt']),
count: json['count'], count: json['count'],

View File

@ -1,3 +1,5 @@
import 'brand_model.dart';
class PlacedOrderList { class PlacedOrderList {
final String id; final String id;
final String paymentMode; final String paymentMode;
@ -95,6 +97,7 @@ class OrderItem1 {
final String brandName; final String brandName;
final double price; final double price;
final int quantity; final int quantity;
List<BrandImage>? image;
OrderItem1({ OrderItem1({
required this.sku, required this.sku,
@ -102,6 +105,7 @@ class OrderItem1 {
required this.categoryName, required this.categoryName,
required this.brandName, required this.brandName,
required this.price, required this.price,
this.image,
required this.quantity, required this.quantity,
}); });
@ -112,6 +116,9 @@ class OrderItem1 {
categoryName: json['categoryName'], categoryName: json['categoryName'],
brandName: json['brandName'], brandName: json['brandName'],
price: json['price'].toDouble(), price: json['price'].toDouble(),
image : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'], quantity: json['quantity'],
); );
} }
@ -124,13 +131,14 @@ class OrderItem1 {
'brandName': brandName, 'brandName': brandName,
'price': price, 'price': price,
'quantity': quantity, 'quantity': quantity,
'image':image
}; };
} }
@override @override
String toString() { String toString() {
return 'OrderItem(sku: $sku, name: $name, categoryName: $categoryName, ' return 'OrderItem(sku: $sku, name: $name, categoryName: $categoryName, '
'brandName: $brandName, price: $price, quantity: $quantity)'; 'brandName: $brandName, price: $price, quantity: $quantity,image:$image)';
} }
} }

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

@ -1,5 +1,7 @@
class RDOrderItem { import 'brand_model.dart';
class RDOrderItem {
final String productId; final String productId;
final String sku; final String sku;
final String name; final String name;
@ -9,7 +11,7 @@
final int gst; // Ensure GST is int final int gst; // Ensure GST is int
final int hsnCode; // Ensure HSN_Code is int final int hsnCode; // Ensure HSN_Code is int
final String description; final String description;
final List<String> image; final List<BrandImage> image;
int? quantity; int? quantity;
int? remainingQuantity; int? remainingQuantity;
int? processquantity; int? processquantity;
@ -43,10 +45,13 @@
hsnCode: json['HSN_Code'] ?? 0, hsnCode: json['HSN_Code'] ?? 0,
// Handle HSN_Code as int // Handle HSN_Code as int
description: json['description'] ?? '', description: json['description'] ?? '',
image: List<String>.from(json['image'] ?? []), //image: List<String>.from(json['image'] ?? []),
image : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'] ?? 0, quantity: json['quantity'] ?? 0,
// Handle quantity as int // Handle quantity as int
processquantity: json['processquantity']??1, processquantity: json['processQuantity']??1,
remainingQuantity: json['remainingQuantity'] ?? remainingQuantity: json['remainingQuantity'] ??
0, // Handle remainingQuantity as int 0, // Handle remainingQuantity as int
); );

View File

@ -1,72 +1,345 @@
// import 'package:cheminova/models/rd_order_item_model.dart';
//
// class SingleGetOrderModel {
// final String id;
// String? paymentMode;
// String? shipTo;
// String? billTo;
// List<RDOrderItem>? orderItem;
// double? subtotal;
// double? gstTotal;
// double? grandTotal;
// String? status;
// List<dynamic>? invoices;
// AddedBy? addedBy;
// String? pd;
// bool? isCancelled;
// bool? isDelivered;
// String? deliveredDate;
// DateTime? statusUpdatedAt;
// String? uniqueId;
// DateTime? createdAt;
// DateTime? updatedAt;
//
// SingleGetOrderModel({
// required this.id,
// this.paymentMode,
// this.shipTo,
// this.billTo,
// this.orderItem,
// this.subtotal,
// this.gstTotal,
// this.grandTotal,
// this.status,
// this.invoices,
// this.addedBy,
// this.pd,
// this.isCancelled,
// this.isDelivered,
// this.deliveredDate,
// this.statusUpdatedAt,
// this.uniqueId,
// this.createdAt,
// this.updatedAt,
// });
//
// factory SingleGetOrderModel.fromJson(Map<String, dynamic> json) {
// return SingleGetOrderModel(
// id: json['_id'] ?? '',
// paymentMode: json['paymentMode'] ?? '',
// shipTo: json['shipTo'] ?? '',
// billTo: json['billTo'] ?? '',
// orderItem: (json['orderItem'] as List<dynamic>?)
// ?.map((item) => RDOrderItem.fromJson(item))
// .toList() ??
// [],
// subtotal: (json['subtotal'] as num?)?.toDouble() ?? 0.0,
// gstTotal: (json['gstTotal'] as num?)?.toDouble() ?? 0.0,
// grandTotal: (json['grandTotal'] as num?)?.toDouble() ?? 0.0,
// status: json['status'] ?? '',
// invoices: json['invoices'] ?? [],
// addedBy: AddedBy.fromJson(json['addedBy'] ?? {}),
// pd: json['pd'] ?? '',
// isCancelled: json['iscancelled'] ?? false,
// isDelivered: json['isDelivered'] ?? false,
// deliveredDate: json['DeliveredDate'] ?? '',
// statusUpdatedAt: DateTime.parse(json['statusUpdatedAt'] ?? DateTime.now().toString()),
// uniqueId: json['uniqueId'] ?? '',
// createdAt: DateTime.parse(json['createdAt'] ?? DateTime.now().toString()),
// updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()),
// );
// }
//
// Map<String, dynamic> toJson() {
// return {
// '_id': id,
// 'paymentMode': paymentMode,
// 'shipTo': shipTo,
// 'billTo': billTo,
// 'orderItem': orderItem?.map((item) => item.toJson()).toList(),
// 'subtotal': subtotal,
// 'gstTotal': gstTotal,
// 'grandTotal': grandTotal,
// 'status': status,
// 'invoices': invoices,
// 'addedBy': addedBy?.toJson(),
// 'pd': pd,
// 'iscancelled': isCancelled,
// 'isDelivered': isDelivered,
// 'DeliveredDate': deliveredDate,
// 'statusUpdatedAt': statusUpdatedAt?.toIso8601String(),
// 'uniqueId': uniqueId,
// 'createdAt': createdAt?.toIso8601String(),
// 'updatedAt': updatedAt?.toIso8601String(),
// };
// }
//
// @override
// String toString() {
// return 'SingleGetOrderModel(id: $id, paymentMode: $paymentMode, shipTo: $shipTo, billTo: $billTo, '
// 'orderItem: $orderItem, subtotal: $subtotal, gstTotal: $gstTotal, grandTotal: $grandTotal, '
// 'status: $status, invoices: $invoices, addedBy: $addedBy, pd: $pd, '
// 'isCancelled: $isCancelled, isDelivered: $isDelivered, deliveredDate: $deliveredDate, '
// 'statusUpdatedAt: $statusUpdatedAt, uniqueId: $uniqueId, createdAt: $createdAt, updatedAt: $updatedAt)';
// }
// }
//
// class OrderItem {
// final String productId;
// final String sku;
// final String name;
// final String categoryName;
// final String brandName;
// final int price; // Use int for price
// final int gst; // Use int for GST
// final int hsnCode; // Use int for HSN Code
// final String description;
// final List<String> image; // Assuming images are stored as a list of strings
// final int quantity;
// final int remainingQuantity;
// int? processQuantity;
// final String id; // Use String for _id
//
// OrderItem({
// required this.productId,
// required this.sku,
// required this.name,
// required this.categoryName,
// required this.brandName,
// required this.price,
// required this.gst,
// required this.hsnCode,
// required this.description,
// required this.image,
// required this.quantity,
// required this.remainingQuantity,
// this.processQuantity = 1,
// required this.id,
// });
//
// factory OrderItem.fromJson(Map<String, dynamic> json) {
// return OrderItem(
// productId: json['productId'] ?? '',
// sku: json['SKU'] ?? '',
// name: json['name'] ?? '',
// categoryName: json['categoryName'] ?? '',
// brandName: json['brandName'] ?? '',
// price: (json['price'] as num?)?.toInt() ?? 0, // Handle as num
// gst: (json['GST'] as num?)?.toInt() ?? 0, // Handle as num
// hsnCode: (json['HSN_Code'] as num?)?.toInt() ?? 0, // Handle as num
// description: json['description'] ?? '',
// image: List<String>.from(json['image'] ?? []),
// quantity: (json['quantity'] as num?)?.toInt() ?? 0, // Handle as num
// remainingQuantity: (json['remainingQuantity'] as num?)?.toInt() ?? 0, // Handle as num
// processQuantity: (json['processQuantity']as num?)?.toInt()??0,
// id: json['_id'] ?? '',
// );
// }
//
// Map<String, dynamic> toJson() {
// return {
// 'productId': productId,
// 'SKU': sku,
// 'name': name,
// 'categoryName': categoryName,
// 'brandName': brandName,
// 'price': price,
// 'GST': gst,
// 'HSN_Code': hsnCode,
// 'description': description,
// 'image': image,
// 'quantity': quantity,
// 'remainingQuantity': remainingQuantity,
// '_id': id,
// };
// }
//
// @override
// String toString() {
// return 'OrderItem(productId: $productId, SKU: $sku, name: $name, categoryName: $categoryName, '
// 'brandName: $brandName, price: $price, GST: $gst, HSN_Code: $hsnCode, '
// 'description: $description, image: $image, quantity: $quantity, '
// 'remainingQuantity: $remainingQuantity, id: $id)';
// }
// }
//
// class AddedBy {
// final String id;
// final String designation;
// final String name;
// final String email;
// final String mobileNumber;
// final String principalDistributor;
// final String addedBy;
// final String userType;
// final String kyc;
// String? fcmToken;
// final DateTime createdAt;
// final DateTime updatedAt;
// final String mappedSC;
// final String uniqueId;
// final String mappedTM;
//
// AddedBy({
// required this.id,
// required this.designation,
// required this.name,
// required this.email,
// required this.mobileNumber,
// required this.principalDistributor,
// required this.addedBy,
// required this.userType,
// required this.kyc,
// this.fcmToken,
// required this.createdAt,
// required this.updatedAt,
// required this.mappedSC,
// required this.uniqueId,
// required this.mappedTM,
// });
//
// factory AddedBy.fromJson(Map<String, dynamic> json) {
// return AddedBy(
// id: json['_id'] ?? '',
// designation: json['designation'] ?? '',
// name: json['name'] ?? '',
// email: json['email'] ?? '',
// mobileNumber: json['mobile_number'] ?? '',
// principalDistributor: json['principal_distributer'] ?? '',
// addedBy: json['addedBy'] ?? '',
// userType: json['userType'] ?? '',
// kyc: json['kyc'] ?? '',
// fcmToken: json['fcm_token']?.toString(), // Handle null safely
// createdAt: DateTime.parse(json['createdAt'] ?? DateTime.now().toString()),
// updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()),
// mappedSC: json['mappedSC'] ?? '',
// uniqueId: json['uniqueId'] ?? '',
// mappedTM: json['mappedTM'] ?? '',
// );
// }
//
// Map<String, dynamic> toJson() {
// return {
// '_id': id,
// 'designation': designation,
// 'name': name,
// 'email': email,
// 'mobile_number': mobileNumber,
// 'principal_distributer': principalDistributor,
// 'addedBy': addedBy,
// 'userType': userType,
// 'kyc': kyc,
// 'fcm_token': fcmToken,
// 'createdAt': createdAt.toIso8601String(),
// 'updatedAt': updatedAt.toIso8601String(),
// 'mappedSC': mappedSC,
// 'uniqueId': uniqueId,
// 'mappedTM': mappedTM,
// };
// }
//
// @override
// String toString() {
// return 'AddedBy(id: $id, designation: $designation, name: $name, email: $email, '
// 'mobileNumber: $mobileNumber, principalDistributor: $principalDistributor, '
// 'addedBy: $addedBy, userType: $userType, kyc: $kyc, '
// 'fcmToken: $fcmToken, createdAt: $createdAt, updatedAt: $updatedAt, '
// 'mappedSC: $mappedSC, uniqueId: $uniqueId, mappedTM: $mappedTM)';
// }
// }
import 'dart:convert';
import 'package:cheminova/models/rd_order_item_model.dart'; import 'package:cheminova/models/rd_order_item_model.dart';
// Main model for the order
class SingleGetOrderModel { class SingleGetOrderModel {
final String id; String id;
String? paymentMode; String paymentMode;
String? shipTo; String shipTo;
String? billTo; String billTo;
List<RDOrderItem>? orderItem; List<RDOrderItem> orderItem;
double? subtotal; double subtotal;
double? gstTotal; double gstTotal;
double? grandTotal; double grandTotal;
String? status; String status;
List<dynamic>? invoices; List<Invoice> invoices;
AddedBy? addedBy; AddedBy addedBy;
String? pd; String pd;
bool? isCancelled; bool isCancelled;
bool? isDelivered; bool isDelivered;
String? deliveredDate; String deliveredDate;
DateTime? statusUpdatedAt; String statusUpdatedAt;
String? uniqueId; String uniqueId;
DateTime? createdAt; String createdAt;
DateTime? updatedAt; String updatedAt;
SingleGetOrderModel({ SingleGetOrderModel({
required this.id, required this.id,
this.paymentMode, required this.paymentMode,
this.shipTo, required this.shipTo,
this.billTo, required this.billTo,
this.orderItem, required this.orderItem,
this.subtotal, required this.subtotal,
this.gstTotal, required this.gstTotal,
this.grandTotal, required this.grandTotal,
this.status, required this.status,
this.invoices, required this.invoices,
this.addedBy, required this.addedBy,
this.pd, required this.pd,
this.isCancelled, required this.isCancelled,
this.isDelivered, required this.isDelivered,
this.deliveredDate, required this.deliveredDate,
this.statusUpdatedAt, required this.statusUpdatedAt,
this.uniqueId, required this.uniqueId,
this.createdAt, required this.createdAt,
this.updatedAt, required this.updatedAt,
}); });
factory SingleGetOrderModel.fromJson(Map<String, dynamic> json) { factory SingleGetOrderModel.fromJson(Map<String, dynamic> json) {
return SingleGetOrderModel( return SingleGetOrderModel(
id: json['_id'] ?? '', id: json['_id']??"1",
paymentMode: json['paymentMode'] ?? '', paymentMode: json['paymentMode']??"2343",
shipTo: json['shipTo'] ?? '', shipTo: json['shipTo']??"abc",
billTo: json['billTo'] ?? '', billTo: json['billTo']??"xyz",
orderItem: (json['orderItem'] as List<dynamic>?) orderItem: (json['orderItem'] as List)
?.map((item) => RDOrderItem.fromJson(item)) .map((i) => RDOrderItem.fromJson(i))
.toList() ?? .toList(),
[], subtotal: json['subtotal'].toDouble(),
subtotal: (json['subtotal'] as num?)?.toDouble() ?? 0.0, gstTotal: json['gstTotal'].toDouble(),
gstTotal: (json['gstTotal'] as num?)?.toDouble() ?? 0.0, grandTotal: json['grandTotal'].toDouble(),
grandTotal: (json['grandTotal'] as num?)?.toDouble() ?? 0.0, status: json['status'],
status: json['status'] ?? '', invoices: (json['invoices'] as List)
invoices: json['invoices'] ?? [], .map((i) => Invoice.fromJson(i))
addedBy: AddedBy.fromJson(json['addedBy'] ?? {}), .toList(),
pd: json['pd'] ?? '', addedBy: AddedBy.fromJson(json['addedBy']??""),
isCancelled: json['iscancelled'] ?? false, pd: json['pd']??"",
isDelivered: json['isDelivered'] ?? false, isCancelled: json['iscancelled']??"",
deliveredDate: json['DeliveredDate'] ?? '', isDelivered: json['isDelivered']??"",
statusUpdatedAt: DateTime.parse(json['statusUpdatedAt'] ?? DateTime.now().toString()), deliveredDate: json['DeliveredDate']??"",
uniqueId: json['uniqueId'] ?? '', statusUpdatedAt: json['statusUpdatedAt']??"",
createdAt: DateTime.parse(json['createdAt'] ?? DateTime.now().toString()), uniqueId: json['uniqueId']??"",
updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()), createdAt: json['createdAt']??"",
updatedAt: json['updatedAt']??"",
); );
} }
@ -76,51 +349,109 @@ class SingleGetOrderModel {
'paymentMode': paymentMode, 'paymentMode': paymentMode,
'shipTo': shipTo, 'shipTo': shipTo,
'billTo': billTo, 'billTo': billTo,
'orderItem': orderItem?.map((item) => item.toJson()).toList(), 'orderItem': orderItem.map((i) => i.toJson()).toList(),
'subtotal': subtotal, 'subtotal': subtotal,
'gstTotal': gstTotal, 'gstTotal': gstTotal,
'grandTotal': grandTotal, 'grandTotal': grandTotal,
'status': status, 'status': status,
'invoices': invoices, 'invoices': invoices.map((i) => i.toJson()).toList(),
'addedBy': addedBy?.toJson(), 'addedBy': addedBy.toJson(),
'pd': pd, 'pd': pd,
'iscancelled': isCancelled, 'iscancelled': isCancelled,
'isDelivered': isDelivered, 'isDelivered': isDelivered,
'DeliveredDate': deliveredDate, 'DeliveredDate': deliveredDate,
'statusUpdatedAt': statusUpdatedAt?.toIso8601String(), 'statusUpdatedAt': statusUpdatedAt,
'uniqueId': uniqueId, 'uniqueId': uniqueId,
'createdAt': createdAt?.toIso8601String(), 'createdAt': createdAt,
'updatedAt': updatedAt?.toIso8601String(), 'updatedAt': updatedAt,
}; };
} }
@override
String toString() {
return 'SingleGetOrderModel(id: $id, paymentMode: $paymentMode, shipTo: $shipTo, billTo: $billTo, '
'orderItem: $orderItem, subtotal: $subtotal, gstTotal: $gstTotal, grandTotal: $grandTotal, '
'status: $status, invoices: $invoices, addedBy: $addedBy, pd: $pd, '
'isCancelled: $isCancelled, isDelivered: $isDelivered, deliveredDate: $deliveredDate, '
'statusUpdatedAt: $statusUpdatedAt, uniqueId: $uniqueId, createdAt: $createdAt, updatedAt: $updatedAt)';
}
} }
class OrderItem { // Model for individual order items
final String productId;
final String sku;
final String name;
final String categoryName;
final String brandName;
final int price; // Use int for price
final int gst; // Use int for GST
final int hsnCode; // Use int for HSN Code
final String description;
final List<String> image; // Assuming images are stored as a list of strings
final int quantity;
final int remainingQuantity;
int? processQuantity;
final String id; // Use String for _id
OrderItem({
// Model for invoices
class Invoice {
Map<String, String> courierStatusTimeline;
String id;
String invoiceId;
String orderId;
List<InvoiceItem> items;
double subtotal;
double gstTotal;
double invoiceAmount;
String courierStatus;
int v;
String courierName;
String courierTrackingId;
Invoice({
required this.courierStatusTimeline,
required this.id,
required this.invoiceId,
required this.orderId,
required this.items,
required this.subtotal,
required this.gstTotal,
required this.invoiceAmount,
required this.courierStatus,
required this.v,
required this.courierName,
required this.courierTrackingId,
});
factory Invoice.fromJson(Map<String, dynamic> json) {
return Invoice(
courierStatusTimeline: Map<String, String>.from(json['courierstatus_timeline']??""),
id: json['_id']??"",
invoiceId: json['invoiceId']??"",
orderId: json['orderId']??"",
items: (json['items'] as List)
.map((i) => InvoiceItem.fromJson(i))
.toList(),
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
invoiceAmount: json['invoiceAmount'].toDouble(),
courierStatus: json['courierStatus'],
v: json['__v'],
courierName: json['courier_name']??"",
courierTrackingId: json['courier_tracking_id']??"",
);
}
Map<String, dynamic> toJson() {
return {
'courierstatus_timeline': courierStatusTimeline,
'_id': id,
'invoiceId': invoiceId,
'orderId': orderId,
'items': items.map((i) => i.toJson()).toList(),
'subtotal': subtotal,
'gstTotal': gstTotal,
'invoiceAmount': invoiceAmount,
'courierStatus': courierStatus,
'__v': v,
'courier_name': courierName,
'courier_tracking_id': courierTrackingId,
};
}
}
// Model for items in an invoice
class InvoiceItem {
String productId;
String sku;
String name;
String categoryName;
String brandName;
double price;
double gst;
int hsnCode;
int processQuantity;
String id;
InvoiceItem({
required this.productId, required this.productId,
required this.sku, required this.sku,
required this.name, required this.name,
@ -129,30 +460,22 @@ class OrderItem {
required this.price, required this.price,
required this.gst, required this.gst,
required this.hsnCode, required this.hsnCode,
required this.description, required this.processQuantity,
required this.image,
required this.quantity,
required this.remainingQuantity,
this.processQuantity = 1,
required this.id, required this.id,
}); });
factory OrderItem.fromJson(Map<String, dynamic> json) { factory InvoiceItem.fromJson(Map<String, dynamic> json) {
return OrderItem( return InvoiceItem(
productId: json['productId'] ?? '', productId: json['productId']??"",
sku: json['SKU'] ?? '', sku: json['SKU']??"",
name: json['name'] ?? '', name: json['name']??"",
categoryName: json['categoryName'] ?? '', categoryName: json['categoryName']??"",
brandName: json['brandName'] ?? '', brandName: json['brandName']??"",
price: (json['price'] as num?)?.toInt() ?? 0, // Handle as num price: json['price'].toDouble(),
gst: (json['GST'] as num?)?.toInt() ?? 0, // Handle as num gst: json['GST'].toDouble(),
hsnCode: (json['HSN_Code'] as num?)?.toInt() ?? 0, // Handle as num hsnCode: json['HSN_Code']??"",
description: json['description'] ?? '', processQuantity: json['processquantity']??"",
image: List<String>.from(json['image'] ?? []), id: json['_id']??"",
quantity: (json['quantity'] as num?)?.toInt() ?? 0, // Handle as num
remainingQuantity: (json['remainingQuantity'] as num?)?.toInt() ?? 0, // Handle as num
processQuantity: (json['processQuantity']as num?)?.toInt()??0,
id: json['_id'] ?? '',
); );
} }
@ -166,23 +489,13 @@ class OrderItem {
'price': price, 'price': price,
'GST': gst, 'GST': gst,
'HSN_Code': hsnCode, 'HSN_Code': hsnCode,
'description': description, 'processquantity': processQuantity,
'image': image,
'quantity': quantity,
'remainingQuantity': remainingQuantity,
'_id': id, '_id': id,
}; };
} }
@override
String toString() {
return 'OrderItem(productId: $productId, SKU: $sku, name: $name, categoryName: $categoryName, '
'brandName: $brandName, price: $price, GST: $gst, HSN_Code: $hsnCode, '
'description: $description, image: $image, quantity: $quantity, '
'remainingQuantity: $remainingQuantity, id: $id)';
}
} }
//Model for the user who added the order
class AddedBy { class AddedBy {
final String id; final String id;
final String designation; final String designation;
@ -229,7 +542,8 @@ class AddedBy {
addedBy: json['addedBy'] ?? '', addedBy: json['addedBy'] ?? '',
userType: json['userType'] ?? '', userType: json['userType'] ?? '',
kyc: json['kyc'] ?? '', kyc: json['kyc'] ?? '',
fcmToken: json['fcm_token']?.toString(), // Handle null safely fcmToken: json['fcm_token']?.toString(),
// Handle null safely
createdAt: DateTime.parse(json['createdAt'] ?? DateTime.now().toString()), createdAt: DateTime.parse(json['createdAt'] ?? DateTime.now().toString()),
updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()), updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()),
mappedSC: json['mappedSC'] ?? '', mappedSC: json['mappedSC'] ?? '',
@ -267,3 +581,8 @@ class AddedBy {
'mappedSC: $mappedSC, uniqueId: $uniqueId, mappedTM: $mappedTM)'; 'mappedSC: $mappedSC, uniqueId: $uniqueId, mappedTM: $mappedTM)';
} }
} }
// Function to parse the JSON string and create a SingleOrder object
SingleGetOrderModel parseSingleOrder(String jsonString) {
final jsonData = json.decode(jsonString);
return SingleGetOrderModel.fromJson(jsonData);
}

View File

@ -1,3 +1,121 @@
// 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:intl/intl.dart';
//
// import '../../controller/annaucement_controller.dart';
// import '../../widgets/comman_background.dart';
// import '../../widgets/common_appbar.dart';
//
// class AnnouncementScreen extends StatefulWidget {
// AnnouncementScreen({super.key});
//
// @override
// State<AnnouncementScreen> createState() => _AnnouncementScreenState();
// }
//
// class _AnnouncementScreenState extends State<AnnouncementScreen> {
// // Initialize the controller
// final AnnouncementController _announcementController = Get.put(AnnouncementController());
//
//
// String formatDate(String apiDate) {
// // Parse the API date string into a DateTime object
// DateTime parsedDate = DateTime.parse(apiDate).toLocal(); // Convert to local time
//
// // Format the date and time according to your specified format
// String formattedDate = DateFormat('EEE MMM dd yyyy').format(parsedDate);
//
// return formattedDate; // Return the formatted date string
// }
//
//
// @override
// Widget build(BuildContext context) {
// // Fetch announcements when the screen is built
// _announcementController.fetchAnnouncements();
//
// return CommonBackground(
// child: Scaffold(
// backgroundColor: Colors.transparent,
// appBar: CommonAppBar(
// actions: [
// IconButton(
// onPressed: () {
// Navigator.pop(context);
// },
// icon: SvgPicture.asset('assets/svg/back_arrow.svg'),
// padding: const EdgeInsets.only(right: 20),
// ),
// ],
// title: const Text(
// 'Announcement',
// style: TextStyle(
// fontSize: 20,
// color: Colors.black,
// fontWeight: FontWeight.w400,
// fontFamily: 'Anek',
// ),
// ),
// backgroundColor: Colors.transparent,
// elevation: 0,
// ),
// drawer: MyDrawer(),
// body: Obx(() {
// // Show loading indicator while fetching announcements
// if (_announcementController.isLoading.value) {
// return Center(child: CircularProgressIndicator());
// }
// // Show error message if there was an error
// if (_announcementController.errorMessage.isNotEmpty) {
// return Center(
// child: Text('Error: ${_announcementController.errorMessage}'),
// );
// }
// // Display the list of announcements
// return ListView.builder(
// itemCount: _announcementController.announcements.length,
// itemBuilder: (context, index) {
// final announcementList = _announcementController.announcements[index];
// print("asdf,${announcementList}");
// return Column(
// children: [
// Card(
// child: ListTile(
// //leading:Text(_announcementController.announcements[index].id),
// title: Row(
//
// children: [
// Text("Message :",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 14),),
// Text(announcementList.message.toString(),style: TextStyle(fontSize: 12),),
//
// ],
// ),
// subtitle: Row(
// children: [
// Text("UniqueID :" , style: TextStyle(fontWeight: FontWeight.bold),),
// Text(announcementList.uniqueId.toString()),
// ],
// ),
// trailing: Text(formatDate(announcementList.createdAt.toString()),style: TextStyle(fontSize: 10),),
// ),
//
// ),
//
// ],
// );
// },
// );
// }),
// ),
// );
// }
// }
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
@ -16,24 +134,15 @@ class AnnouncementScreen extends StatefulWidget {
} }
class _AnnouncementScreenState extends State<AnnouncementScreen> { class _AnnouncementScreenState extends State<AnnouncementScreen> {
// Initialize the controller
final AnnouncementController _announcementController = Get.put(AnnouncementController()); final AnnouncementController _announcementController = Get.put(AnnouncementController());
String formatDate(String apiDate) { String formatDate(String apiDate) {
// Parse the API date string into a DateTime object DateTime parsedDate = DateTime.parse(apiDate).toLocal();
DateTime parsedDate = DateTime.parse(apiDate).toLocal(); // Convert to local time return DateFormat('EEE MMM dd yyyy').format(parsedDate);
// Format the date and time according to your specified format
String formattedDate = DateFormat('EEE MMM dd yyyy').format(parsedDate);
return formattedDate; // Return the formatted date string
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Fetch announcements when the screen is built
_announcementController.fetchAnnouncements(); _announcementController.fetchAnnouncements();
return CommonBackground( return CommonBackground(
@ -63,47 +172,61 @@ class _AnnouncementScreenState extends State<AnnouncementScreen> {
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Obx(() { body: Obx(() {
// Show loading indicator while fetching announcements
if (_announcementController.isLoading.value) { if (_announcementController.isLoading.value) {
return Center(child: CircularProgressIndicator()); return Center(child: CircularProgressIndicator());
} }
// Show error message if there was an error
if (_announcementController.errorMessage.isNotEmpty) { if (_announcementController.errorMessage.isNotEmpty) {
return Center( return Center(
child: Text('Error: ${_announcementController.errorMessage}'), child: Text('Error: ${_announcementController.errorMessage}'),
); );
} }
// Display the list of announcements
return ListView.builder( return ListView.builder(
itemCount: _announcementController.announcements.length, itemCount: _announcementController.announcements.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final announcementList = _announcementController.announcements[index]; final announcementList = _announcementController.announcements[index];
print("asdf,${announcementList}"); return Card(
return Column( margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
children: [
Card(
child: ListTile( child: ListTile(
//leading:Text(_announcementController.announcements[index].id), // leading: CircleAvatar(
title: Row( // backgroundColor: Colors.blue,
// child: Text(
// announcementList.uniqueId.toString().toUpperCase(),
// style: TextStyle(color: Colors.white),
// ),
// ),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Message :",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 14),), Text(
Text(announcementList.message.toString(),style: TextStyle(fontSize: 12),), "Message:",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
),
Text(
announcementList.message.toString(),
style: TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
], ],
), ),
subtitle: Row( subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("UniqueID :" , style: TextStyle(fontWeight: FontWeight.bold),), Text(
Text(announcementList.uniqueId.toString()), "UniqueID:",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
announcementList.uniqueId.toString(),
style: TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
], ],
), ),
trailing: Text(formatDate(announcementList.createdAt.toString()),style: TextStyle(fontSize: 10),), trailing: Text(
formatDate(announcementList.createdAt.toString()),
style: TextStyle(fontSize: 10),
), ),
), ),
],
); );
}, },
); );

View File

@ -20,13 +20,13 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final authController = Get.put(AuthController()); final authController = Get.put(AuthController());
void dispose() { // void dispose() {
// Dispose of the text controllers when the screen is closed to free up resources // // Dispose of the text controllers when the screen is closed to free up resources
authController.currentpassController.dispose(); // authController.currentpassController.dispose();
authController.newpassController.dispose(); // authController.newpassController.dispose();
authController.confirmpassController.dispose(); // authController.confirmpassController.dispose();
super.dispose(); // super.dispose();
} // }
// Function to validate user input and initiate password change // Function to validate user input and initiate password change
void validateAndChangePassword() async { void validateAndChangePassword() async {

View File

@ -1,9 +1,12 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cheminova/controller/home_controller.dart'; import 'package:cheminova/controller/home_controller.dart';
import 'package:cheminova/controller/home_service.dart';
import 'package:cheminova/screens/authentication/controller/auth_service.dart'; import 'package:cheminova/screens/authentication/controller/auth_service.dart';
import 'package:cheminova/screens/authentication/login_screen.dart';
import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -15,7 +18,7 @@ import '../../../utils/secure__storage_service.dart';
class AuthController extends GetxController { class AuthController extends GetxController {
final authService = AuthService(); final authService = AuthService();
final Dio _dio = Dio();
final _storageService = SecureStorageService(); final _storageService = SecureStorageService();
@ -28,6 +31,7 @@ class AuthController extends GetxController {
final HomeController _homeController = Get.put(HomeController()); final HomeController _homeController = Get.put(HomeController());
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
@override @override
void onInit(){ void onInit(){
super.onInit(); super.onInit();
@ -35,26 +39,106 @@ class AuthController extends GetxController {
NotificationServices().requestNotificationPermission(); NotificationServices().requestNotificationPermission();
} }
// Function to handle user login // Function to handle user login
// Future<void> login() async {
// isLoading.value = true;
// // Call the login service with email and password
// final response = await authService.login({
// 'email': emailController.text,
// 'password': passwordController.text,
// });
// isLoading.value = false;
// update();
// if (response != null) {
// _homeController.fcmToken();
// showSnackbar("Your Successfully logged In!");
//
// Get.offAll(() => const HomeScreen());
// }
// else if(response == null){
// showSnackbar("Please Enter Valid Email or Password");
// }
// }
Future<void> login() async { Future<void> login() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
isLoading.value = true; isLoading.value = true;
// Call the login service with email and password
// Perform login API request
final response = await authService.login({ final response = await authService.login({
'email': emailController.text, 'email': emailController.text,
'password': passwordController.text, 'password': passwordController.text,
}); });
isLoading.value = false; isLoading.value = false;
update(); update();
if (response != null) {
_homeController.fcmToken();
showSnackbar("Your Successfully logged In!");
if (response != null && response['token'] != null) {
// Save the JWT token to SharedPreferences
String token = response['token'];
await prefs.setString('token', token);
// Fetch the FCM token and send it to the server
final fcmToken = await NotificationServices().getDeviceToken();
print('fcmToken: $fcmToken');
await HomeService().fcmToken({'fcmToken': fcmToken}, token);
showSnackbar("You successfully logged in!");
// Proceed to the HomeScreen after successful login
checkToken(); // Ensure the token is valid and the user is authenticated
Get.offAll(() => const HomeScreen()); Get.offAll(() => const HomeScreen());
} } else {
else if(response == null){ showSnackbar("Please enter a valid email or password");
showSnackbar("Please Enter Valid Email or Password");
} }
} }
Future<void> checkToken() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
if (token != null) {
// Token exists, proceed with the flow (maybe fetch user data or navigate to the home screen)
print('Token found: $token');
// You can also fetch the FCM token if necessary
final fcmToken = await NotificationServices().getDeviceToken();
print('fcmToken: $fcmToken');
// Optionally send the FCM token to the server if needed
// This might be where you're getting the error
await _homeController.fcmToken();
// Navigate to HomeScreen or perform other operations
Get.offAll(() => const HomeScreen());
} else {
// No token found, redirect to login screen
Get.offAll(() => const LoginScreen());
}
}
// Function to validate the token
// Future<bool> isTokenValid(String token) async {
// try {
// final response = await authService.validateToken(token);
// return response['isValid'] ?? false; // Adjust based on your API response
// } catch (e) {
// print("Token validation failed: $e");
// return false;
// }
// }
// Future<(bool, String)> login() async { // Future<(bool, String)> login() async {
// isLoading(true); // isLoading(true);
// try { // try {

View File

@ -1,10 +1,18 @@
import 'package:cheminova/utils/api_urls.dart'; import 'package:cheminova/utils/api_urls.dart';
import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/common_api_service.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import '../../../utils/app_interceptor.dart';
class AuthService { class AuthService {
final Dio _dio;
AuthService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
_dio.interceptors.add(AuthInterceptor());
_dio.interceptors.add(PrettyDioLogger());
}
// Function to handle user login // Function to handle user login
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async { Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
try { try {

View File

@ -24,9 +24,15 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Initialize the HomeController using GetX // Initialize the HomeController using GetX
final homecontroller = Get.put(HomeController()); final homecontroller = Get.put(HomeController());
@override @override
void initState() {
// TODO: implement initState
super.initState();
homecontroller.getUser();
}
@override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Accessing the user details from the HomeController // Accessing the user details from the HomeController
final user = homecontroller!.user; final user = homecontroller.user;
return Stack( return Stack(
children: [ children: [
CommonBackground( CommonBackground(
@ -52,7 +58,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
], ],
), ),
// Main content of the profile screen // Main content of the profile screen
body: SingleChildScrollView( body: user == null
? const Center(child: CircularProgressIndicator())
:
SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -70,7 +79,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
children: [ children: [
const SizedBox(height: 20), const SizedBox(height: 20),
// Displaying individual profile items // Displaying individual profile items
_buildProfileItem('Name', user!.name), _buildProfileItem('Name', user.name),
_buildProfileItem('ID', user.uniqueId), _buildProfileItem('ID', user.uniqueId),
_buildProfileItem('Email ID', user.email), _buildProfileItem('Email ID', user.email),
_buildProfileItem('Mobile Number', user.phone), _buildProfileItem('Mobile Number', user.phone),

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});
@ -183,7 +184,7 @@ class _HomeScreenState extends State<HomeScreen> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
HomeCard( HomeCard(
title: 'RD Orders', title: 'Retailer Orders',
onTap: () => Get.to( onTap: () => Get.to(
() => RdOrderScreen(), () => RdOrderScreen(),
), ),
@ -196,6 +197,27 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
HomeCard(
title: 'Opening Inventory',
onTap: () => Get.to(
() => OpeningInventoryManagementScreen(),
),
),
// HomeCard(
// title: 'Announcement',
// onTap: () => Get.to(
// () => AnnouncementScreen(),
// ),
// ),
], ],
), ),
], ],

View File

@ -23,7 +23,8 @@ class _InventoryManagementScreenState extends State<InventoryManagementScreen> {
quantity: 100, quantity: 100,
description: 'Description 1', description: 'Description 1',
category: ProductCategory.food, category: ProductCategory.food,
image: 'assets/images/product.png', image: "assets/images/new_product.jpeg",
//'assets/images/product.png',
) )
]; ];
final List<String> _filterList = [ final List<String> _filterList = [

View File

@ -179,13 +179,18 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
), ),
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: Obx(() { child:
Obx(() {
// Filter the list based on the selected status // Filter the list based on the selected status
List<KycModel> filteredOrders = List<KycModel> filteredOrders =
selectedStatus == "All" selectedStatus == "All"
? _kycController.kycList ? _kycController.kycList
: _kycController.kycList.where((kyc) => kyc.status == selectedStatus).toList(); : _kycController.kycList.where((kyc) => kyc.status == selectedStatus).toList();
filteredOrders.sort((a, b) {
DateTime dateA = DateTime.parse(filteredOrders[0].createdAt.toString()); // Assuming createdAt is a string
DateTime dateB = DateTime.parse(filteredOrders[0].createdAt.toString());
return dateB.compareTo(dateA); // Sort in descending order
});
return ListView.builder( return ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
shrinkWrap: true, shrinkWrap: true,

View File

@ -0,0 +1,213 @@
// import 'dart:io';
//
// import 'package:cheminova/screens/kyc/retailer_screen.dart';
// import 'package:cheminova/screens/kyc/upload_document_screen.dart';
// import 'package:cheminova/screens/kyc/verify_document_screen.dart';
// import 'package:cheminova/widgets/my_drawer.dart';
// import 'package:flutter_svg/flutter_svg.dart';
// import 'package:image_picker/image_picker.dart';
// import 'package:flutter/material.dart';
//
// import '../../widgets/comman_background.dart';
// import '../../widgets/common_appbar.dart';
//
//
// class CollectKycScreen extends StatefulWidget {
// const CollectKycScreen({super.key});
//
// @override
// State<CollectKycScreen> createState() => CollectKycScreenState();
// }
//
// class CollectKycScreenState extends State<CollectKycScreen>
// with SingleTickerProviderStateMixin {
// late TabController _tabController;
// bool isLoading = false;
//
// final _pages = [
// // RetailerDetailsScreen(),
// const UploadDocumentScreen(),
// const VerifyDocumentsScreen()
// ];
//
// @override
// void initState() {
// _tabController = TabController(length: 3, vsync: this);
// super.initState();
// }
//
// final locationController = TextEditingController();
// final notesController = TextEditingController();
// final dealerController = TextEditingController();
// final productController = TextEditingController();
// final qualityController = TextEditingController();
// final marketNameController = TextEditingController();
// final districtController = TextEditingController();
// final stateController = TextEditingController();
// final pincodeController = TextEditingController();
// final aadharcardController = TextEditingController();
// final pancardController = TextEditingController();
//
// File? _selfieImage;
// File? _pesticideLicenseImage;
// File? _fertilizerLicenseImage;
//
// final ImagePicker _picker = ImagePicker();
//
// Future<void> _pickImage(ImageSource source, bool isSelfie) async {
// final pickedFile = await _picker.pickImage(source: source);
//
// setState(() {
// if (pickedFile != null) {
// if (isSelfie) {
// _selfieImage = File(pickedFile.path);
// }
// }
// });
// }
//
// Future<void> _pickLicenseImage(ImageSource source, bool isPesticide) async {
// final pickedFile = await _picker.pickImage(source: source);
//
// setState(() {
// if (pickedFile != null) {
// if (isPesticide) {
// _pesticideLicenseImage = File(pickedFile.path);
// } else {
// _fertilizerLicenseImage = File(pickedFile.path);
// }
// }
// });
// }
//
// void _showPicker(BuildContext context, bool isSelfie) {
// showModalBottomSheet(
// context: context,
// builder: (BuildContext bc) {
// return SafeArea(
// child: Wrap(
// children: <Widget>[
// ListTile(
// leading: const Icon(Icons.photo_library),
// title: const Text('Photo Library'),
// onTap: () {
// _pickImage(ImageSource.gallery, isSelfie);
// Navigator.of(context).pop();
// },
// ),
// ListTile(
// leading: const Icon(Icons.photo_camera),
// title: const Text('Camera'),
// onTap: () {
// _pickImage(ImageSource.camera, isSelfie);
// Navigator.of(context).pop();
// },
// ),
// ],
// ),
// );
// },
// );
// }
//
// void _showLicensePicker(BuildContext context, bool isPesticide) {
// showModalBottomSheet(
// context: context,
// builder: (BuildContext bc) {
// return SafeArea(
// child: Wrap(
// children: <Widget>[
// ListTile(
// leading: const Icon(Icons.photo_library),
// title: const Text('Photo Library'),
// onTap: () {
// _pickLicenseImage(ImageSource.gallery, isPesticide);
// Navigator.of(context).pop();
// },
// ),
// ListTile(
// leading: const Icon(Icons.photo_camera),
// title: const Text('Camera'),
// onTap: () {
// _pickLicenseImage(ImageSource.camera, isPesticide);
// Navigator.of(context).pop();
// },
// ),
// ],
// ),
// );
// },
// );
// }
//
// @override
// Widget build(BuildContext context) {
// return Stack(
// children: [
// CommonBackground(
// child: DefaultTabController(
// length: 3,
// child: Scaffold(
// backgroundColor: Colors.transparent,
// appBar: PreferredSize(
// preferredSize: const Size.fromHeight(100),
// child: CommonAppBar(
// actions: [
// IconButton(
// onPressed: () {
// Navigator.pop(context);
// },
// icon: SvgPicture.asset("assets/svg/back_arrow.svg"),
// //Image.asset('assets/Back_attendance.png'),
// padding: const EdgeInsets.only(right: 20),
// ),
// ],
// title: const Text(
// 'Collect KYC Data',
// style: TextStyle(
// fontSize: 20,
// color: Colors.black,
// fontWeight: FontWeight.w400,
// fontFamily: 'Anek',
// ),
// ),
// backgroundColor: Colors.transparent,
// elevation: 0,
// bottom: TabBar(
// controller: _tabController,
// padding: const EdgeInsets.symmetric(horizontal: 10),
// dividerColor: Colors.transparent,
// indicatorColor: Colors.yellow,
// labelColor: Colors.white,
// unselectedLabelColor: Colors.black,
// indicatorSize: TabBarIndicatorSize.tab,
// indicator: BoxDecoration(
// color: Colors.blue,
// borderRadius: BorderRadius.circular(10),
// ),
// tabs: const [
// Tab(text: 'Details'),
// Tab(text: 'Documents'),
// Tab(text: 'Verify'),
// ],
// ),
// ),
// ),
// drawer: const MyDrawer(),
// body: TabBarView(
// controller: _tabController,
// physics: const NeverScrollableScrollPhysics(),
// children: _pages,
// ),
// ),
// ),
// ),
// if (isLoading)
// Container(
// color: Colors.black.withOpacity(0.5),
// child: const Center(child: CircularProgressIndicator()),
// ),
// ],
// );
// }
// }

View File

@ -67,7 +67,8 @@ class NotificationScreen extends StatelessWidget {
), ),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Obx(() { body:
Obx(() {
// Show a loading indicator while data is being fetched // Show a loading indicator while data is being fetched
if (notificationController.isLoading.value) { if (notificationController.isLoading.value) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());

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 {
@ -85,16 +96,34 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
_saveSelectedAddress(); _saveSelectedAddress();
} }
// void _loadSelectedAddress() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
// setState(() {
// _selectedShippingAddress =
// prefs.getString('selectedShippingAddress') ?? _addressList.first;
// _selectedBillingAddress =
// prefs.getString('selectedBillingAddress') ?? _addressList.first;
// });
// }
void _loadSelectedAddress() async { void _loadSelectedAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
_addressController
.fetchAddresses(); // Ensure address list is updated
setState(() { setState(() {
_selectedShippingAddress = _selectedShippingAddress =
prefs.getString('selectedShippingAddress') ?? _addressList.first; (prefs.getString('selectedShippingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
_selectedBillingAddress = _selectedBillingAddress =
prefs.getString('selectedBillingAddress') ?? _addressList.first; (prefs.getString('selectedBillingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
}); });
} }
void _onPaymentModeChanged(String? value) { void _onPaymentModeChanged(String? value) {
setState(() { setState(() {
_groupValue = value!; _groupValue = value!;
@ -127,7 +156,14 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
hsnCode: product.hsnCode, hsnCode: product.hsnCode,
description: product.description, description: product.description,
productStatus: product.productStatus, productStatus: product.productStatus,
image: [],
// image:[],
image: product.brand.images.isNotEmpty
? product.brand.images.map((image) => BrandImage(
publicId: image.publicId, // or any other identifier
imageId: image.imageId, url: image.url,
)).toList()
:[],
createdAt: product.createdAt, createdAt: product.createdAt,
updatedAt: product.createdAt, updatedAt: product.createdAt,
count: product.quantity, count: product.quantity,
@ -135,16 +171,40 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
//category:product.category, //category:product.category,
category:Category(id: product.category.id, categoryName: product.category.categoryName), category:Category(id: product.category.id, categoryName: product.category.categoryName),
// brand:product.brand, // brand:product.brand,
brand:Brand(id: product.brand.id, brandName: product.brand.brandName), brand:Brand(id: product.brand.id, brandName: product.brand.brandName,images: product.brand.images),
v: 0, addedBy: product.addedBy, v: 0, addedBy: product.addedBy,
); );
}).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 +217,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 +284,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 +302,54 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
), ),
), ),
), ),
SizedBox(height: 5,), SizedBox(height: 5),
DropdownButtonFormField<String>( Obx(() => Container(
child: DropdownButtonFormField<String>(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Shipping Address:', labelText: 'Shipping Address:',
hintText: 'Select Shipping Address', hintText: 'Select Shipping Address',
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
value: _selectedShippingAddress, value: _addressController.selectedShippingAddressId.value.isEmpty
items: _addressList.map((String address) { ? 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>( return DropdownMenuItem<String>(
value: address, value: address.id, // Set the value as the address ID
child: Text(address), child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} , ${address.country}"), // Display full address
); );
}).toList(), }).toList(),
onChanged: _onShippingAddressChanged, onChanged: (value) {
_addressController.onShippingAddressChanged(value); // Update the selected address
},
), ),
)),
SizedBox(height: Get.height * 0.02), SizedBox(height: Get.height * 0.02),
DropdownButtonFormField<String>(
// Billing Address Dropdown
Obx(() => Container(
child: DropdownButtonFormField<String>(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Billing Address:', labelText: 'Billing Address:',
hintText: 'Select Billing Address', hintText: 'Select Billing Address',
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
value: _selectedBillingAddress, value: _addressController.selectedBillingAddressId.value.isEmpty
items: _addressList.map((String address) { ? 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>( return DropdownMenuItem<String>(
value: address, value: address.id, // Set the value as the address ID
child: Text(address), child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} ${address.country}"), // Display full address
); );
}).toList(), }).toList(),
onChanged: _onBillingAddressChanged, onChanged: (value) {
_addressController.onBillingAddressChanged(value); // Update the selected address
},
), ),
)),
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,6 +85,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
SafeArea( SafeArea(
child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(
@ -197,7 +205,13 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: TextField( child: TextField(
controller: TextEditingController( controller: TextEditingController(
text: widget.placedOrder!.shipTo, // Pre-filling the address 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( decoration: InputDecoration(
hintText: "Address : ${widget.placedOrder!.shipTo}", hintText: "Address : ${widget.placedOrder!.shipTo}",
@ -238,6 +252,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
], ],
), ),
), ),
),
], ],
), ),
); );

View File

@ -1,5 +1,7 @@
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.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 +34,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) {
@ -70,7 +73,7 @@ Future<void> adduni()async {
.map((item) => (item.quantity)) .map((item) => (item.quantity))
.join(', '); .join(', ');
} }
//String? imageurl;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -221,6 +224,7 @@ Future<void> adduni()async {
itemCount: widget.placedOrderList?.orderItem.length ?? 0, itemCount: widget.placedOrderList?.orderItem.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem[index]; final orderItem = widget.placedOrderList!.orderItem[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
return orderItem != null return orderItem != null
? Card( ? Card(
margin: const EdgeInsets.symmetric(vertical: 5.0), margin: const EdgeInsets.symmetric(vertical: 5.0),
@ -231,8 +235,26 @@ Future<void> adduni()async {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
children: [ children: [
Image.asset( // Image.asset(
"assets/images/product.png", // Add the image URL here // "assets/images/new_product.jpeg",
// // "assets/images/product.png", // Add the image URL here
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
// imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50, height: 50,
width: 50, width: 50,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -289,11 +311,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 +325,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

@ -123,7 +123,8 @@ class _CartScreenState extends State<CartScreen> {
), ),
); );
} }
return Column( return SingleChildScrollView(
child: Column(
children: [ children: [
SizedBox( SizedBox(
height: Get.height * 0.02, height: Get.height * 0.02,
@ -141,21 +142,21 @@ class _CartScreenState extends State<CartScreen> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// "Select All" Checkbox // "Select All" Checkbox
Row( // Row(
children: [ // children: [
Checkbox( // Checkbox(
value: _selectAll, // value: _selectAll,
onChanged: _toggleSelectAll, // onChanged: _toggleSelectAll,
), // ),
Text( // Text(
"Select All", // Label for the select all checkbox // "Select All", // Label for the select all checkbox
style: GoogleFonts.roboto( // style: GoogleFonts.roboto(
fontSize: 16, // fontSize: 16,
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
), // ),
), // ),
], // ],
), // ),
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: ListView.builder( child: ListView.builder(
@ -164,17 +165,17 @@ class _CartScreenState extends State<CartScreen> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Row( return Row(
children: [ children: [
Checkbox( // Checkbox(
value: _cartController.selectedProducts.contains( // value: _cartController.selectedProducts.contains(
_cartController.cartList[index]), // Checkbox for individual product selection // _cartController.cartList[index]), // Checkbox for individual product selection
onChanged: (value) { // onChanged: (value) {
_cartController.toggleProductSelection( // _cartController.toggleProductSelection(
_cartController.cartList[index], // _cartController.cartList[index],
value!, // value!,
); // );
_checkIfAllSelected(); // Check if all are selected after each toggle // _checkIfAllSelected(); // Check if all are selected after each toggle
}, // },
), // ),
Expanded( Expanded(
child: ProductCard( child: ProductCard(
productModel: productModel:
@ -263,6 +264,7 @@ class _CartScreenState extends State<CartScreen> {
), ),
), ),
], ],
),
); );
}), }),
), ),

View File

@ -248,6 +248,19 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
_buildFilterDropdown(index), _buildFilterDropdown(index),
), ),
), ),
SizedBox(
// height: Get.height * 0.1,
child:_products.isEmpty // Check if no products found
? Center(
child: Padding(
padding: const EdgeInsets.all(40.0),
child: Text(
"No products found!",
style: TextStyle(fontSize: 16),
),
),
) : SizedBox(),
),
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: ListView.builder( child: ListView.builder(
@ -272,6 +285,7 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
}, },
), ),
), ),
], ],
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/models/product_model1.dart'; import 'package:cheminova/models/product_model1.dart';
import 'package:cheminova/screens/order/checkout_screen.dart'; import 'package:cheminova/screens/order/checkout_screen.dart';
@ -24,6 +25,7 @@ class ProductDetailScreen extends StatefulWidget {
class _ProductDetailScreenState extends State<ProductDetailScreen> { class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController());// Initialize CartController final CartController _cartController = Get.put(CartController());// Initialize CartController
String? imageurl;
// Function to capitalize the first letter of a string // Function to capitalize the first letter of a string
String capitalizeFirstLetter(String text) { String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text; if (text.isEmpty) return text;
@ -31,6 +33,9 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
imageurl = widget.productModel!.brand.images.isNotEmpty
? widget.productModel!.brand.images[0].url
: 'assets/images/no_image_available.jpg'; // Use a fallback image URL or handle it accordingly
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -105,13 +110,21 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
), ),
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
child: ClipRRect( child:
ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
child: Image.asset("assets/images/product.png", fit: BoxFit.cover,), child:
// Image.asset( imageurl!.startsWith('http') // Check if it's a network URL
// widget.product.image, ? CachedNetworkImage(
// fit: BoxFit.cover, imageUrl: imageurl!,
// ), fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
imageurl!,
fit: BoxFit.cover,
),
), ),
), ),
), ),

View File

@ -122,6 +122,11 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final order = widget.placedOrderList!.orderItem[0];
final subTotalProcesssItem = order.price! * order.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (order.price! * order.remainingQuantity!.toInt()) *(order.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -205,7 +210,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.subtotal ?? 0}"), Text("${subTotalProcesssItem}"),
], ],
), ),
Row( Row(
@ -219,7 +224,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.gstTotal ?? 0}"), Text("${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
], ],
), ),
Row( Row(
@ -233,7 +238,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.grandTotal ?? 0}"), Text("${grandTotalProcessItem}"),
], ],
), ),
], ],

View File

@ -359,8 +359,6 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
await controller.placeRDOrder(); await controller.placeRDOrder();
showSnackbar("Partial order processed successfully."); showSnackbar("Partial order processed successfully.");
// Close the dialog before navigating to another screen
Navigator.of(context).pop();
// Navigate to the pending screen // Navigate to the pending screen
Get.to(RdOrderPendingScreen()); Get.to(RdOrderPendingScreen());
@ -370,7 +368,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
TextButton( TextButton(
onPressed: () { onPressed: () {
//Get.back(); //Get.back();
Navigator.of(context).pop(); Navigator.pop(context);
}, },
child: const Text("Cancel"), child: const Text("Cancel"),
), ),
@ -382,6 +380,10 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final order = widget.placedOrderList!.orderItem[0];
final subTotalProcesssItem = order.price! * order.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (order.price! * order.remainingQuantity!.toInt()) *(order.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -470,7 +472,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.subtotal ?? 0}"), Text("${subTotalProcesssItem}"),
], ],
), ),
Row( Row(
@ -484,7 +486,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.gstTotal ?? 0}"), Text("${widget.placedOrderList!.gstTotal.toStringAsFixed(2) ?? 0}"),
], ],
), ),
Row( Row(

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,16 @@
import 'package:cheminova/controller/get_rd_cancle_controller.dart';
import 'package:cheminova/controller/get_rd_pending_controller.dart';
import 'package:cheminova/controller/rd_get_order_controller.dart'; import 'package:cheminova/controller/rd_get_order_controller.dart';
import 'package:cheminova/controller/rd_processing_invoice_controller.dart';
import 'package:cheminova/models/get_rd_cancelled_model.dart'; import 'package:cheminova/models/get_rd_cancelled_model.dart';
import 'package:cheminova/models/get_rd_pennding_model.dart';
import 'package:cheminova/models/rd_get_order_model.dart'; import 'package:cheminova/models/rd_get_order_model.dart';
import 'package:cheminova/models/single_get_order_model.dart'; import 'package:cheminova/models/single_get_order_model.dart';
import 'package:cheminova/screens/rd%20orders/rd_cancelled_details_screen.dart'; import 'package:cheminova/screens/rd%20orders/rd_cancelled_details_screen.dart';
import 'package:cheminova/screens/rd%20orders/rd_dispatched_details_screen.dart';
import 'package:cheminova/screens/rd%20orders/rd_order_details_screen.dart'; import 'package:cheminova/screens/rd%20orders/rd_order_details_screen.dart';
import 'package:cheminova/screens/rd%20orders/rd_order_details_update.dart';
import 'package:cheminova/screens/rd%20orders/rd_pending_deatils.dart'; import 'package:cheminova/screens/rd%20orders/rd_pending_deatils.dart';
import 'package:cheminova/screens/rd%20orders/rd_processing_details.dart';
import 'package:cheminova/widgets/input_field.dart'; import 'package:cheminova/widgets/input_field.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -15,12 +18,15 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../controller/get_rd_cancle_controller.dart'; import '../../controller/get_single_invoice_Service.dart';
import '../../controller/get_single_invoice_controller.dart';
import '../../controller/rd_get_single_service.dart';
import '../order_management/order_management_detail_screen.dart'; import '../order_management/order_management_detail_screen.dart';
class RdCancelledScreen extends StatefulWidget { class RdCancelledScreen extends StatefulWidget {
final PlacedOrdersResponse? getrdProduct; final GetRdCancelledModel? getrdProduct;
RdCancelledScreen({super.key, this.getrdProduct}); RdCancelledScreen({super.key, this.getrdProduct});
@ -37,7 +43,11 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
"cancelled", "cancelled",
"delivered",]; "delivered",];
int _selectedIndex = 0; int _selectedIndex = 0;
final GetRDCancleController _getRdProductController = Get.put(GetRDCancleController()); final GetRDCancleController _getRDCancleController = Get.put(GetRDCancleController());
// final GetSingleInvoiceController _getSingleInvoiceController = Get.put(GetSingleInvoiceController());
// final GetRDProcessingInvoiceController _getRDProcessingInvoiceController = Get.put(GetRDProcessingInvoiceController());
// // final GetProductRDController _getRdProductController =
// // Get.put(GetProductRDController());
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>(); final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
@override @override
@ -49,11 +59,12 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
Future<void> _onRefresh() async { Future<void> _onRefresh() async {
await getOrder1(); await getOrder1();
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
} }
Future<void> getOrder1() async { Future<void> getOrder1() async {
await _getRdProductController.getRDCancleProduct(); await _getRDCancleController.getRDCancleProduct();
if (_getRdProductController.productRDList.isEmpty) { if (_getRDCancleController.productRDList.isEmpty) {
print("No orders found."); print("No orders found.");
} else { } else {
print("Orders fetched successfully"); print("Orders fetched successfully");
@ -70,11 +81,133 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
DateTime parsedDate = DateTime.parse(apiDate).toLocal(); // Convert to local time DateTime parsedDate = DateTime.parse(apiDate).toLocal(); // Convert to local time
// Format the date and time according to your specified format // Format the date and time according to your specified format
String formattedDate = DateFormat('EEE MMM dd yyyy').format(parsedDate); String formattedDate = DateFormat('EEE MMM dd yyyy hh:mm a').format(parsedDate);
return formattedDate; // Return the formatted date string return formattedDate; // Return the formatted date string
} }
void onOrderTap(int index) async {
try {
// Fetch orders and ensure you wait for it to complete
await _getRDCancleController.getRDCancleProduct();
// Log the count of fetched orders
print('Fetched orders count: ${_getRDCancleController.productRDList.length}');
// Check if the productRDList is populated
if (_getRDCancleController.productRDList.isNotEmpty) {
// Ensure the index is valid
if (index >= 0 && index < _getRDCancleController.productRDList.length) {
// Get the order ID from the list based on the index
final orderId = _getRDCancleController.productRDList[index].id;
// final invoiceId = _getRDCancleController.productRDList[index].invoices;
print("orderId canceeled,$orderId");
// Retrieve the token from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
// Check if the token is not null
if (token != null) {
// Fetch the single order using the order ID
final SingleGetOrderModel? singleOrder = await GetSingleProductService().getSingleOrder(token, orderId);
// Check if the single order was fetched successfully
if (singleOrder != null) {
// Navigate to the details screen with the fetched order
Get.to(() => RdOrderCancelledScreenDetailScreen(
placedOrderList: singleOrder, // Pass the single order instance
//orderId: orderId,
));
} else {
// Handle the case where the single order could not be fetched
Get.snackbar("Error", "Unable to fetch order details.");
}
} else {
// Handle the case where the token is null
Get.snackbar("Error", "User not authenticated.");
}
} else {
// Handle the case when the index is out of bounds
Get.snackbar("Error", "Invalid order selection.");
}
} else {
// Handle the case when the list is empty
Get.snackbar("Error", "No orders available to display.");
}
} catch (e) {
// Log any errors that occur during the process
print('Error in onOrderTap: $e');
Get.snackbar("Error", "An unexpected error occurred.");
}
}
// void onOrderTap(int index) async {
// try {
// // Fetch orders and wait for it to complete
// await _getRDCancleController.getRDCancleProduct();
//
// // Debugging: Check if data is actually fetched
// print('Fetched orders count: ${_getRDCancleController.productRDList.length}');
//
// // Ensure the list is not empty after fetching
// if (_getRDCancleController.productRDList.isEmpty) {
// Get.snackbar("Error", "No orders available to display.");
// return;
// }
//
// // Ensure index is within range
// if (index < 0 || index >= _getRDCancleController.productRDList.length) {
// Get.snackbar("Error", "Invalid order selection.");
// return;
// }
//
// // Retrieve order details
// final order = _getRDCancleController.productRDList[index].id;
// // final invoice = _getRDCancleController.productRDList[index].invoices[index];
// // Ensure invoices are available
// if (order.isEmpty) {
// Get.snackbar("Error", "No invoice found for this order.");
// return;
// }
//
// final orderId = order;
// //final invoiceId = invoice;
//
// print("Cancelled Order ID: $orderId");
//
// // Retrieve token
// SharedPreferences prefs = await SharedPreferences.getInstance();
// String? token = prefs.getString('token');
//
// if (token == null) {
// Get.snackbar("Error", "User not authenticated.");
// return;
// }
//
// // Fetch single order details
// final SingleGetOrderModel? singleOrder =
// await GetSingleProductService().getSingleOrder(token, orderId);
//
// if (singleOrder == null) {
// Get.snackbar("Error", "Unable to fetch order details.");
// return;
// }
//
// // Navigate to details screen
// await Get.to(() => RdOrderCancelledScreenDetailScreen(
// placedOrderList: singleOrder, // Pass fetched order
// orderId: orderId,
// ));
// } catch (e) {
// print('Error in onOrderTap: $e');
// Get.snackbar("Error", "An unexpected error occurred.");
// }
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -103,7 +236,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
), ),
), ),
], ],
title: const Text("RD Cancelled Order"), title: const Text("Retailer Cancelled Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(
@ -128,6 +261,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
controller: _searchController, controller: _searchController,
), ),
SizedBox(height: Get.height * 0.035), SizedBox(height: Get.height * 0.035),
SizedBox(height: Get.height * 0.035),
Card( Card(
margin: const EdgeInsets.symmetric(horizontal: 18), margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -140,63 +274,11 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ 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: GestureDetector(
// onTap: () {
// setState(() {
// _selectedIndex = index; // Update selected index
// });
// // Navigate to different screens based on selected tab
// switch (_filterList[index]) {
// case "new":
// // Get.to(YourScreen1()); // Navigate to "new" orders screen
// break;
// case "pending":
// // Get.to(YourScreen2()); // Navigate to "pending" orders screen
// break;
// case "processing":
// // Get.to(YourScreen3()); // Navigate to "processing" orders screen
// break;
// // Add more cases for other statuses
// case "dispatched":
// // Get.to(YourScreen4()); // Navigate to dispatched orders
// break;
// case "cancelled":
// // Get.to(YourScreen5()); // Navigate to cancelled orders
// break;
// case "delivered":
// //Get.to(YourScreen6()); // Navigate to delivered orders
// break;
// default:
// // Get.to(YourScreen1()); // Default screen
// }
// },
// child: Chip(
// label: Text(capitalizeFirstLetter( _filterList[index])
// ,
// style: GoogleFonts.roboto(
// fontSize: 14,
// fontWeight: FontWeight.w500,
// color: _selectedIndex == index ? Colors.white : Colors.black, // Change color when selected
// ),
// ),
// backgroundColor: _selectedIndex == index ? Colors.blue : Colors.grey[300], // Change color when selected
// ),
// ),
// ),
// ),
// ),
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: Obx(() { child: Obx(() {
if (_getRdProductController.productRDList.isEmpty) { if (_getRDCancleController.productRDList.isEmpty) {
return Center( return Center(
child: Text( child: Text(
'No Orders Found', 'No Orders Found',
@ -208,7 +290,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
final Set<String> uniqueOrderIds = {}; final Set<String> uniqueOrderIds = {};
final List<GetRdCancelledModel> uniqueOrders = []; final List<GetRdCancelledModel> uniqueOrders = [];
for (var order in _getRdProductController.productRDList) { for (var order in _getRDCancleController.productRDList) {
if (uniqueOrderIds.add(order.id)) { if (uniqueOrderIds.add(order.id)) {
uniqueOrders.add(order); uniqueOrders.add(order);
} }
@ -282,7 +364,16 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
], ],
), ),
), ),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Order Value: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text("${order.grandTotal}")
],
),
),
Padding( Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0), padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
@ -310,10 +401,12 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ElevatedButton( child: ElevatedButton(
onPressed: ()=> onPressed: (){
Get.to(() => onOrderTap(index);
RdCancelledDetailScreen( },
placedOrderList: uniqueOrders[index])), // Navigate to detail screen // Get.to(() =>
// RdOrderPendingScreenDetailScreen(
// placedOrderList: uniqueOrders[index])), // Navigate to detail screen
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor: const Color(0xFF004791), backgroundColor: const Color(0xFF004791),
@ -348,3 +441,5 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
} }
} }

View File

@ -150,7 +150,7 @@ class _RdDeliveredDetailsScreenState
), ),
], ],
title: const Text( title: const Text(
"RD Delivered Order Details", "Retailer Delivered Order Details",
), ),
), ),
body: Stack( body: Stack(
@ -298,7 +298,7 @@ class _RdDeliveredDetailsScreenState
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.gstTotal}"), Text("${widget.placedOrderList!.gstTotal.toStringAsFixed(2)}"),
], ],
), ),
), ),

View File

@ -163,7 +163,7 @@ class _RdDeliveredScreenState extends State<RdDeliveredScreen> {
), ),
), ),
], ],
title: const Text("RD Delivered Order"), title: const Text("Retailer Delivered Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(

View File

@ -198,7 +198,10 @@ class _RdDispatchedDetailsDetailScreenState
SnackBar(content: Text('Please select a delivery date.')), SnackBar(content: Text('Please select a delivery date.')),
); );
} }
Navigator.of(context).pop(); // Close the dialog after submission Navigator.push(context, MaterialPageRoute(builder: (context){
return RdDeliveredScreen();
}));
// Navigator.of(context).pop(); // Close the dialog after submission
}, },
child: Text('Confirm'), child: Text('Confirm'),
), ),
@ -312,7 +315,7 @@ class _RdDispatchedDetailsDetailScreenState
), ),
], ],
title: const Text( title: const Text(
"RD Dispatched Order Details", "Retailer Dispatched Order Details",
), ),
), ),
body: Stack( body: Stack(
@ -459,7 +462,7 @@ class _RdDispatchedDetailsDetailScreenState
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placedOrderList!.gstTotal}"), Text("${widget.placedOrderList!.gstTotal.toStringAsFixed(2)}"),
], ],
), ),
), ),

View File

@ -172,7 +172,7 @@ class _RdDispatchedScreenState extends State<RdDispatchedScreen> {
), ),
), ),
], ],
title: const Text("RD Dispatched Order"), title: const Text("Retailer Dispatched Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/rd_single_order_controller.dart'; import 'package:cheminova/controller/rd_single_order_controller.dart';
import 'package:cheminova/models/rd_order_item_model.dart'; import 'package:cheminova/models/rd_order_item_model.dart';
@ -26,12 +27,14 @@ class RdOrderDetailUpdateScreen extends StatefulWidget {
//final Product? productModel; //final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen // PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
SingleGetOrderModel? placedOrderList; SingleGetOrderModel? placedOrderList;
final String orderId; //final String orderId;
//final int orderIndex; // New parameter to receive the index //final int orderIndex; // New parameter to receive the index
// PlacedOrderModel? placedOrderModel; // PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details // Constructor for initializing the screen with placed order details
RdOrderDetailUpdateScreen({super.key,this.placedOrderList,required this.orderId}); RdOrderDetailUpdateScreen({super.key,this.placedOrderList,
//required this.orderId
});
@override @override
State<RdOrderDetailUpdateScreen> createState() => State<RdOrderDetailUpdateScreen> createState() =>
@ -46,6 +49,7 @@ class _RdOrderDetailUpdateScreenState
final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController()); final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController()); final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController()); final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
String? orderId; String? orderId;
@ -226,6 +230,9 @@ class _RdOrderDetailUpdateScreenState
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
if (selectedStatus == "cancelled") { if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation // Ensure the reason is provided for cancellation
if (reasonController.text.isEmpty) { if (reasonController.text.isEmpty) {
@ -245,9 +252,9 @@ class _RdOrderDetailUpdateScreenState
}); });
// Close the dialog after a short delay // Close the dialog after a short delay
Future.delayed(Duration(seconds: 1), () { // Future.delayed(Duration(seconds: 1), () {
// Navigator.of(context).pop(); // Close the dialog // // Navigator.of(context).pop(); // Close the dialog
}); // });
return; // Exit here to prevent further processing return; // Exit here to prevent further processing
} }
@ -262,31 +269,33 @@ class _RdOrderDetailUpdateScreenState
Map<String, RDOrderItem> orderItemMap = {}; Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities // Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) { for (var item in widget.placedOrderList!.orderItem) {
var productId = item.orderItem[0].productId; var productId = item.productId;
if (orderItemMap.containsKey(productId)) { if (orderItemMap.containsKey(productId)) {
// If the product already exists, aggregate the quantity // If the product already exists, aggregate the quantity
var existingItem = orderItemMap[productId]!; var existingItem = orderItemMap[productId]!;
existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0); // var existingItem = orderItemMap[productId]!;
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0); existingItem.quantity = ((existingItem.quantity ?? 0) + (item.quantity ?? 0));
existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0); // existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
// existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
// existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
} else { } else {
// If it's a new product, add it to the map // If it's a new product, add it to the map
orderItemMap[productId] = RDOrderItem( orderItemMap[productId] = RDOrderItem(
productId: productId, productId: productId,
sku: item.orderItem[0].sku, sku: item.sku,
name: item.orderItem[0].name, name: item.name,
categoryName: item.orderItem[0].categoryName, categoryName: item.categoryName,
brandName: item.orderItem[0].brandName, brandName: item.brandName,
price: item.orderItem[0].price, price: item.price,
gst: item.orderItem[0].gst.toInt(), gst: item.gst.toInt(),
hsnCode: item.orderItem[0].hsnCode, hsnCode: item.hsnCode,
description: item.orderItem[0].description, description: item.description,
image: [], // Handle images appropriately image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0, quantity: item.quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0, remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0, processquantity: item.remainingQuantity ?? 0,
); );
} }
} }
@ -309,7 +318,7 @@ class _RdOrderDetailUpdateScreenState
showSnackbar("Order processed and invoice created successfully"); showSnackbar("Order processed and invoice created successfully");
Get.to(RdOrderProcessingScreen()); Get.to(RdOrderProcessingScreen());
Navigator.of(context).pop(); // Navigator.of(context).pop();
// Close the dialog after a short delay // Close the dialog after a short delay
// Close the dialog // Close the dialog
@ -440,7 +449,7 @@ class _RdOrderDetailUpdateScreenState
_buildRow("Order Date:", formatDate("${widget.placedOrderList!.createdAt}"), Get.width * 0.04), _buildRow("Order Date:", formatDate("${widget.placedOrderList!.createdAt}"), Get.width * 0.04),
_buildRow("Total Items:", "${widget.placedOrderList!.orderItem!.length}", Get.width * 0.04), _buildRow("Total Items:", "${widget.placedOrderList!.orderItem!.length}", Get.width * 0.04),
_buildRow("Sub Total:", "${widget.placedOrderList!.subtotal}", Get.width * 0.04), _buildRow("Sub Total:", "${widget.placedOrderList!.subtotal}", Get.width * 0.04),
_buildRow("GST:", "${widget.placedOrderList!.gstTotal}", Get.width * 0.04), _buildRow("GST:", "${widget.placedOrderList!.gstTotal.toStringAsFixed(2)}", Get.width * 0.04),
_buildRow("Total Amount:", "${widget.placedOrderList!.grandTotal}", Get.width * 0.04), _buildRow("Total Amount:", "${widget.placedOrderList!.grandTotal}", Get.width * 0.04),
], ],
), ),
@ -458,6 +467,7 @@ class _RdOrderDetailUpdateScreenState
itemCount: widget.placedOrderList!.orderItem!.length ?? 0, itemCount: widget.placedOrderList!.orderItem!.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem![index]; final orderItem = widget.placedOrderList!.orderItem![index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.quantity!.toInt(); final subTotalProcesssItem = orderItem.price! * orderItem.quantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.quantity!.toInt()) *(orderItem.gst!/100 ); final GstTotalAmounProcessItem = (orderItem.price! * orderItem.quantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem; final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -471,8 +481,27 @@ class _RdOrderDetailUpdateScreenState
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
children: [ children: [
Image.asset( // Image.asset(
"assets/images/product.png", // "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50, height: 50,
width: 50, width: 50,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -498,7 +527,7 @@ class _RdOrderDetailUpdateScreenState
Text("Price: ${orderItem.price}"), Text("Price: ${orderItem.price}"),
Text("Subtotal : ${subTotalProcesssItem}"), Text("Subtotal : ${subTotalProcesssItem}"),
Text("GST : ${orderItem.gst}%"), Text("GST : ${orderItem.gst}%"),
Text("GST Amount (₹) : ${GstTotalAmounProcessItem}"), Text("GST Amount (₹) : ${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
Text("Total Amount : ${grandTotalProcessItem}"), Text("Total Amount : ${grandTotalProcessItem}"),
], ],
), ),

View File

@ -165,7 +165,7 @@ class _RdOrderScreenState extends State<RdOrderScreen> {
// Navigate to the details screen with the fetched order // Navigate to the details screen with the fetched order
Get.to(() => RdOrderDetailUpdateScreen( Get.to(() => RdOrderDetailUpdateScreen(
placedOrderList: singleOrder, placedOrderList: singleOrder,
orderId: orderId, // orderId: orderId,
)); ));
} else { } else {
// Handle the case where the single order could not be fetched // Handle the case where the single order could not be fetched
@ -224,7 +224,7 @@ class _RdOrderScreenState extends State<RdOrderScreen> {
), ),
), ),
], ],
title: const Text("RD Order"), title: const Text("Retailer Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(

View File

@ -1,4 +1,5 @@
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/get_order_placed_controller.dart'; import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/get_rd_pending_controller.dart'; import 'package:cheminova/controller/get_rd_pending_controller.dart';
import 'package:cheminova/controller/rd_get_order_controller.dart'; import 'package:cheminova/controller/rd_get_order_controller.dart';
@ -24,6 +25,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../controller/cart_controller.dart'; import '../../controller/cart_controller.dart';
import '../../controller/get_single_invoice_controller.dart'; import '../../controller/get_single_invoice_controller.dart';
import '../../controller/rd_processing_order_controller.dart'; import '../../controller/rd_processing_order_controller.dart';
import '../../controller/rd_single_order_controller.dart';
import '../../models/get_invoice_model.dart'; import '../../models/get_invoice_model.dart';
import '../../models/product_model1.dart'; import '../../models/product_model1.dart';
import '../../models/rd_order_item_model.dart'; import '../../models/rd_order_item_model.dart';
@ -33,14 +35,16 @@ import '../../utils/show_snackbar.dart';
class RdOrderPendingScreenDetailScreen extends StatefulWidget { class RdOrderPendingScreenDetailScreen extends StatefulWidget {
//final Product? productModel; //final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen // PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
SingleGetOrderModel? placedOrderList; final SingleGetOrderModel? placedOrderList;
GetRdPendingModel? productpendingModel; // GetRdPendingModel? productpendingModel;
final String orderId; //final String orderId;
GetInvoiceModel? placeInvoiceList; // GetInvoiceModel? placeInvoiceList;
// PlacedOrderModel? placedOrderModel; // PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details // Constructor for initializing the screen with placed order details
RdOrderPendingScreenDetailScreen({super.key,this.placedOrderList,required this.orderId,this.placeInvoiceList}); RdOrderPendingScreenDetailScreen({super.key,this.placedOrderList,
// required this.orderId
});
@override @override
State<RdOrderPendingScreenDetailScreen> createState() => State<RdOrderPendingScreenDetailScreen> createState() =>
@ -52,11 +56,12 @@ class _RdOrderPendingScreenDetailScreenState
extends State<RdOrderPendingScreenDetailScreen> { extends State<RdOrderPendingScreenDetailScreen> {
// 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 RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetRdPendingController _getRdPendingController = Get.put(GetRdPendingController()); final GetRdPendingController _getRdPendingController = Get.put(GetRdPendingController());
final GetSingleInvoiceController _getSingleInvoiceController = Get.put(GetSingleInvoiceController()); final GetSingleInvoiceController _getSingleInvoiceController = Get.put(GetSingleInvoiceController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController()); final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController()); final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
final List<String> statusOptions = [ final List<String> statusOptions = [
"new", "new",
"pending", "pending",
@ -201,6 +206,9 @@ class _RdOrderPendingScreenDetailScreenState
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
{ {
if (selectedStatus == "cancelled") { if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation // Ensure the reason is provided for cancellation
@ -235,35 +243,47 @@ class _RdOrderPendingScreenDetailScreenState
Map<String, RDOrderItem> orderItemMap = {}; Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities // Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) { for (var item in widget.placedOrderList!.orderItem) {
var productId = item.orderItem[0].productId; var productId = item.productId;
if (item.remainingQuantity != null && item.remainingQuantity! > 0) {
if (orderItemMap.containsKey(productId)) { if (orderItemMap.containsKey(productId)) {
// If the product already exists, aggregate the quantity // If the product already exists, aggregate the remaining quantity
var existingItem = orderItemMap[productId]!; var existingItem = orderItemMap[productId]!;
existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0); existingItem.quantity = (existingItem.quantity ?? 0) + (item.quantity ?? 0);
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0); existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.remainingQuantity ?? 0);
existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0); existingItem.processquantity = existingItem.remainingQuantity; // Process all remaining stock
} else { }
// if (orderItemMap.containsKey(productId)) {
// // If the product already exists, aggregate the quantity
// var existingItem = orderItemMap[productId]!;
// // var existingItem = orderItemMap[productId]!;
// existingItem.quantity = ((existingItem.quantity ?? 0) + (item.quantity ?? 0));
// existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
// existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
// existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
else {
// If it's a new product, add it to the map // If it's a new product, add it to the map
orderItemMap[productId] = RDOrderItem( orderItemMap[productId] = RDOrderItem(
productId: productId, productId: productId,
sku: item.orderItem[0].sku, sku: item.sku,
name: item.orderItem[0].name, name: item.name,
categoryName: item.orderItem[0].categoryName, categoryName: item.categoryName,
brandName: item.orderItem[0].brandName, brandName: item.brandName,
price: item.orderItem[0].price, price: item.price,
gst: item.orderItem[0].gst.toInt(), gst: item.gst.toInt(),
hsnCode: item.orderItem[0].hsnCode, hsnCode: item.hsnCode,
description: item.orderItem[0].description, description: item.description,
image: [], // Handle images appropriately image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0, quantity: item.quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0, remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0, processquantity: item.remainingQuantity ?? 0,
); );
} }
} }
}
// Convert the map to a list // Convert the map to a list
List<RDOrderItem> orderItems = orderItemMap.values.toList(); List<RDOrderItem> orderItems = orderItemMap.values.toList();
@ -324,7 +344,28 @@ class _RdOrderPendingScreenDetailScreenState
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// int remainingQuantity = (widget.placedOrderList!.orderItem![0].quantity)! -(widget.placedOrderList!.orderItem![0].remainingQuantity!.toInt()); if (widget.placedOrderList == null) {
return Center(child: Text('No order details available'));
}
// Safely get the order and invoice list
final order = widget.placedOrderList!;
final invoices = order.invoices;
// Check if the invoices list contains at least 4 items
List<String>? invoiceIds;
if (invoices.isNotEmpty) {
// Ensure there are at least 4 invoices
if (invoices.length >= 4) {
// Get the ID of the 4th invoice (index 3)
invoiceIds = [invoices[3].invoiceId!]; // Assuming invoiceId is a String
} else {
invoiceIds = []; // Fallback if not enough invoices
}
} else {
invoiceIds = []; // Fallback if no invoices available
}
//int remainingQuantity = (widget.placedOrderList!.orderItem![0].quantity)! -(widget.placedOrderList!.orderItem![0].remainingQuantity!.toInt());
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -351,7 +392,7 @@ class _RdOrderPendingScreenDetailScreenState
), ),
], ],
title: const Text( title: const Text(
"RDPending Order Details", "RetailerPending Order Details",
), ),
), ),
body: Stack( body: Stack(
@ -384,13 +425,13 @@ class _RdOrderPendingScreenDetailScreenState
children: [ children: [
Card( Card(
child: Column( child:
Column(
children: [ children: [
SizedBox( SizedBox(
width: Get.width, width: Get.width,
child: Padding( child: Padding(
padding: padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text( child: Text(
"Invoices", "Invoices",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
@ -400,12 +441,18 @@ class _RdOrderPendingScreenDetailScreenState
), ),
), ),
), ),
SizedBox( // Displaying each invoice in a separate card
width: Get.width, if (widget.placedOrderList!.invoices.isNotEmpty)
...widget.placedOrderList!.invoices.map((invoice) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
child: Padding( child: Padding(
padding: padding: const EdgeInsets.all(8.0),
const EdgeInsets.fromLTRB(8, 8, 8, 0), child: Column(
child: Row( crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Invoice ID
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
@ -415,20 +462,12 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text(widget.placeInvoiceList!.invoiceId.toString()), Text(invoice.invoiceId.toString()),
// Text(widget.placedOrderList!.uniqueId),
], ],
), ),
), const SizedBox(height: 10), // Add spacing
),
SizedBox(
width: Get.width,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Items for this invoice
Text( Text(
"Items: ", "Items: ",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
@ -436,12 +475,13 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
SizedBox(height: 10), // Add spacing between the title and the list of items const SizedBox(height: 10), // Add spacing between title and items
Column(
children: widget.placeInvoiceList!.items!.map((item) {
// List of items in this invoice
Column(
children: invoice.items!.map((item) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), // Add some spacing between items padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -451,7 +491,7 @@ class _RdOrderPendingScreenDetailScreenState
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.03, fontSize: Get.width * 0.03,
), ),
overflow: TextOverflow.ellipsis, // Handle long text overflow: TextOverflow.ellipsis,
), ),
), ),
Text("x ${item.processQuantity.toString()}"), Text("x ${item.processQuantity.toString()}"),
@ -460,111 +500,90 @@ class _RdOrderPendingScreenDetailScreenState
); );
}).toList(), }).toList(),
), ),
],
), const SizedBox(height: 10), // Add spacing between sections
),
), // Sub Total
SizedBox( Row(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Sub Total : ", "Sub Total:",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placeInvoiceList!.subtotal}"), Text("${invoice.subtotal}"),
], ],
), ),
),
),
// GST
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"GST:",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text("${invoice.gstTotal.toStringAsFixed(2)}"),
],
),
SizedBox( // Invoice Amount
width: Get.width, Row(
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"GST : ", "Invoice Amount:",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placeInvoiceList!.gstTotal}"), Text("${invoice.invoiceAmount}"),
], ],
), ),
),
), // Courier Status
SizedBox( Row(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Invoice Amount: ", "Courier Status:",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text("${widget.placeInvoiceList!.invoiceAmount}"),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Courier Status : ",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
ElevatedButton( ElevatedButton(
onPressed: (){}, onPressed: () {},
// Get.to(() =>
// RdOrderDetailScreen(
// placedOrderList: uniqueOrders[index])), // Navigate to detail screen
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor:_getCourierStatusColor(widget.placeInvoiceList!.courierStatus.toString()), backgroundColor: _getCourierStatusColor(invoice.courierStatus.toString()),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)), borderRadius: BorderRadius.circular(10),
),
child: Text(capitalizeFirstLetter(widget.placeInvoiceList!.courierStatus.toString()),
// Text(widget.placedOrderList!.status.toString())
//Text(widget.placedOrderList!.status, style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
),
//Text("${widget.placedOrderList!.gstTotal}"),
)],
), ),
), ),
child: Text(
capitalizeFirstLetter(invoice.courierStatus.toString()),
),
),
],
), ),
], ],
), ),
), ),
);
}).toList(),
],
),
),
const SizedBox(height: 8), const SizedBox(height: 8),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -591,9 +610,10 @@ class _RdOrderPendingScreenDetailScreenState
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: widget.placedOrderList?.orderItem!.length ?? 0, itemCount: order.orderItem!.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem![index]; final orderItem =order.orderItem![index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotal = orderItem.price * orderItem.quantity!.toInt(); final subTotal = orderItem.price * orderItem.quantity!.toInt();
final GstTotalAmount = (orderItem.price * orderItem.quantity!.toInt()) *(orderItem.gst/100 ); final GstTotalAmount = (orderItem.price * orderItem.quantity!.toInt()) *(orderItem.gst/100 );
final grandTotal = subTotal + GstTotalAmount; final grandTotal = subTotal + GstTotalAmount;
@ -607,8 +627,26 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
children: [ children: [
Image.asset( // Image.asset(
"assets/images/product.png", // "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50, height: 50,
width: 50, width: 50,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -636,7 +674,7 @@ class _RdOrderPendingScreenDetailScreenState
Text("Price: ${orderItem.price}"), Text("Price: ${orderItem.price}"),
Text("Subtotal: ${subTotal}"), Text("Subtotal: ${subTotal}"),
Text("GSt: ${orderItem.gst}%"), Text("GSt: ${orderItem.gst}%"),
Text("GST Amount (₹): ${GstTotalAmount}"), Text("GST Amount (₹): ${GstTotalAmount.toStringAsFixed(2)}"),
Text("Total Amount (₹): ${grandTotal}"), Text("Total Amount (₹): ${grandTotal}"),
], ],
), ),
@ -678,18 +716,19 @@ class _RdOrderPendingScreenDetailScreenState
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: widget.placedOrderList?.orderItem itemCount: order.orderItem
?.where((item) => item.remainingQuantity! > 0) ?.where((item) => item.remainingQuantity! > 0)
.length ?? 0, .length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
// Filter items with non-zero quantities // Filter items with non-zero quantities
final filteredItems = widget.placedOrderList!.orderItem! final filteredItems =order!.orderItem!
.where((item) => item.remainingQuantity! > 0) .where((item) => item.remainingQuantity! > 0)
.toList(); .toList();
final orderItem = filteredItems[index]; final orderItem = filteredItems[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.remainingQuantity!.toInt(); final subTotalProcesssItem = orderItem.price! * orderItem.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.remainingQuantity!.toInt()) *(orderItem.gst!/100 ); final GstTotalAmounProcessItem = (orderItem.price! * orderItem.remainingQuantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem; final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -703,8 +742,27 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
children: [ children: [
Image.asset( /* Image.asset(
"assets/images/product.png", "assets/images/new_product.jpeg",
// "assets/images/product.png",
height: 50,
width: 50,
fit: BoxFit.cover,
),*/
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50, height: 50,
width: 50, width: 50,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -725,7 +783,7 @@ class _RdOrderPendingScreenDetailScreenState
Text("Price: ${orderItem.price}"), Text("Price: ${orderItem.price}"),
Text("Subtotal: ${subTotalProcesssItem}"), Text("Subtotal: ${subTotalProcesssItem}"),
Text("Gst: ${orderItem.gst}%"), Text("Gst: ${orderItem.gst}%"),
Text("GST Total: ${GstTotalAmounProcessItem}"), Text("GST Total: ${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
Text("Total Amount: ${grandTotalProcessItem}"), Text("Total Amount: ${grandTotalProcessItem}"),
], ],
), ),
@ -775,7 +833,7 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
Text(capitalizeFirstLetter(widget.placeInvoiceList!.orderId!.paymentMode.toString())), Text(capitalizeFirstLetter(widget.placedOrderList!.paymentMode.toString())),
// Text("${widget.placedOrderList!.paymentMode}",maxLines: 4, // Text("${widget.placedOrderList!.paymentMode}",maxLines: 4,
// overflow:TextOverflow.ellipsis,) // overflow:TextOverflow.ellipsis,)
], ],
@ -808,7 +866,7 @@ class _RdOrderPendingScreenDetailScreenState
), ),
SizedBox(width: Get.width*0.01,), SizedBox(width: Get.width*0.01,),
//Text(capitalizeFirstLetter(widget.placedOrderList!.status)), //Text(capitalizeFirstLetter(widget.placedOrderList!.status)),
Text(capitalizeFirstLetter(widget.placedOrderList!.status.toString()),maxLines: 4, Text(capitalizeFirstLetter(order!.status.toString()),maxLines: 4,
overflow:TextOverflow.ellipsis,) overflow:TextOverflow.ellipsis,)
], ],
), ),
@ -1014,12 +1072,12 @@ class simple extends State<RdOrderPendingScreenDetailScreen> {
onPressed: () {}, onPressed: () {},
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor: _getCourierStatusColor(widget.placeInvoiceList!.courierStatus.toString()), // Call the method here backgroundColor: _getCourierStatusColor(widget.placedOrderList!.invoices[0]!.courierStatus.toString()), // Call the method here
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
), ),
child: Text(widget.placeInvoiceList!.courierStatus.toString()), child: Text(widget.placedOrderList!.invoices[0]!.courierStatus.toString()),
), ),
], ],
), ),

View File

@ -4,6 +4,7 @@ import 'package:cheminova/controller/rd_get_order_controller.dart';
import 'package:cheminova/controller/rd_processing_invoice_controller.dart'; import 'package:cheminova/controller/rd_processing_invoice_controller.dart';
import 'package:cheminova/models/get_rd_pennding_model.dart'; import 'package:cheminova/models/get_rd_pennding_model.dart';
import 'package:cheminova/models/rd_get_order_model.dart'; import 'package:cheminova/models/rd_get_order_model.dart';
import 'package:cheminova/models/single_get_order_model.dart';
import 'package:cheminova/screens/rd%20orders/rd_order_details_screen.dart'; import 'package:cheminova/screens/rd%20orders/rd_order_details_screen.dart';
import 'package:cheminova/screens/rd%20orders/rd_order_details_update.dart'; import 'package:cheminova/screens/rd%20orders/rd_order_details_update.dart';
import 'package:cheminova/screens/rd%20orders/rd_pending_deatils.dart'; import 'package:cheminova/screens/rd%20orders/rd_pending_deatils.dart';
@ -88,9 +89,6 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
// Fetch orders and ensure you wait for it to complete // Fetch orders and ensure you wait for it to complete
await _getRdPendingController.getRDPendingProduct(); await _getRdPendingController.getRDPendingProduct();
// await _getRDProcessingInvoiceController.getRDProcessingInvoiceProduct();
// await _getSingleInvoiceController.fetchInvoice(_getRDProcessingInvoiceController.productProcessingRDList[0].id);
// Log the count of fetched orders // Log the count of fetched orders
print('Fetched orders count: ${_getRdPendingController.productRDList.length}'); print('Fetched orders count: ${_getRdPendingController.productRDList.length}');
@ -101,22 +99,22 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
// Get the order ID from the list based on the index // Get the order ID from the list based on the index
final orderId = _getRdPendingController.productRDList[index].id; final orderId = _getRdPendingController.productRDList[index].id;
final invoiceId = _getRdPendingController.productRDList[index].invoices[0]; final invoiceId = _getRdPendingController.productRDList[index].invoices[0];
// Retrieve the token from SharedPreferences // Retrieve the token from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token'); String? token = prefs.getString('token');
// Check if the token is not null // Check if the token is not null
if (token != null) { if (token != null) {
// Fetch the single order using the order ID, and avoid caching issues // Fetch the single order using the order ID
final singleOrder = await GetSingleProductService().getSingleOrder(token, orderId); final SingleGetOrderModel? singleOrder = await GetSingleProductService().getSingleOrder(token, orderId);
final singleInvoice = await GetSingleInvoiceService().fetchInvoice(token, invoiceId.toString());
// Check if the single order was fetched successfully // Check if the single order was fetched successfully
if (singleOrder != null) { if (singleOrder != null) {
// Navigate to the details screen with the fetched order // Navigate to the details screen with the fetched order
Get.to(() => RdOrderPendingScreenDetailScreen( Get.to(() => RdOrderPendingScreenDetailScreen(
placedOrderList: singleOrder, placedOrderList: singleOrder, // Pass the single order instance
orderId: orderId, // orderId: orderId,
placeInvoiceList: singleInvoice,
)); ));
} else { } else {
@ -144,6 +142,7 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -172,7 +171,7 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
), ),
), ),
], ],
title: const Text("RD Pending Order"), title: const Text("Retailer Pending Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(

View File

@ -123,8 +123,10 @@ class _RdOrderProcessingDetailScreenState extends State<RdOrderProcessingDetailS
// Call the API to submit data // Call the API to submit data
_getDispatchController.RDProcessingToDispatchProduct(widget.placeInvoiceList!.id.toString(), courierName, courierTrackingId); _getDispatchController.RDProcessingToDispatchProduct(widget.placeInvoiceList!.id.toString(), courierName, courierTrackingId);
showSnackbar("Order Status updated Order Dispatched"); showSnackbar("Order Status updated Order Dispatched");
Navigator.push(context, MaterialPageRoute(builder: (context){
Navigator.of(context).pop(); // Close the dialog after submission return RdDispatchedScreen();
}));
//Navigator.of(context).pop(); // Close the dialog after submission
}, },
child: Text('Submit'), child: Text('Submit'),
), ),
@ -332,7 +334,7 @@ class _RdOrderProcessingDetailScreenState extends State<RdOrderProcessingDetailS
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text("${widget.placeInvoiceList!.gstTotal}"), Text("${widget.placeInvoiceList!.gstTotal?.toStringAsFixed(2)}"),
], ],
), ),
), ),

View File

@ -172,7 +172,7 @@ class _RdOrderProcessingScreenState extends State<RdOrderProcessingScreen> {
), ),
), ),
], ],
title: const Text("RD Processing Order"), title: const Text("Retailer Processing Order"),
), ),
drawer: MyDrawer(), drawer: MyDrawer(),
body: Stack( body: Stack(

View File

@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'authentication/controller/auth_controller.dart';
class SplashScreen extends StatefulWidget { class SplashScreen extends StatefulWidget {
const SplashScreen({super.key}); const SplashScreen({super.key});
@ -16,8 +18,9 @@ class _SplashScreenState extends State<SplashScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Timer(const Duration(seconds: 2), () { Future.delayed(Duration(seconds: 2), () {
Get.offAll(() => const LoginScreen()); final authController = Get.put(AuthController());
authController.checkToken();
}); });
} }

View File

@ -80,6 +80,14 @@ class ApiUrls {
//============================== Annaouncement Details ==============================// //============================== Annaouncement Details ==============================//
static const String AnnaouncementUrl = '/api/announcement/PDs'; static const String AnnaouncementUrl = '/api/announcement/PDs';
//============================== Annaouncement Details ==============================// //============================== shipto Billto Details ==============================//
static const String ShiptoandBilltoAddressUrl = '/api/shipping/address/user/address'; static const String ShiptoandBilltoAddressUrl = '/api/shipping/address/user/address';
//============================== Product stock Details ==============================//
static const String ProductStockUrl = '/api/pd/stock';
//============================== Product Update stock Details ==============================//
static const String ProductUpdateStockUrl = '${baseUrl}/api/pd/stock-update';
} }

View File

@ -0,0 +1,31 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthInterceptor extends Interceptor {
@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('token');
if (token != null) {
debugPrint('token-->\n $token\n');
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// Handle the response if needed
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401) {}
return handler.next(err);
}
}

View File

@ -5,7 +5,18 @@ import 'package:cheminova/utils/constants.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'app_interceptor.dart';
Dio createDio() {
final dio = Dio();
dio.interceptors.add((AuthInterceptor()));
return dio;
}
// Generic API service function that handles API requests with optional file uploads // Generic API service function that handles API requests with optional file uploads
Future<BodyType?> commonApiService<BodyType>({ Future<BodyType?> commonApiService<BodyType>({
required String url, required String url,
required String method, required String method,
@ -18,7 +29,7 @@ Future<BodyType?> commonApiService<BodyType>({
}) async { }) async {
try { try {
// Initialize Dio for making HTTP requests // Initialize Dio for making HTTP requests
Dio dio = Dio(); Dio dio = createDio();
final Response response; final Response response;
print("body : $body"); print("body : $body");

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
}); });

View File

@ -1,3 +1,212 @@
// import 'package:cheminova/controller/home_controller.dart';
// import 'package:cheminova/models/user_model.dart';
// import 'package:cheminova/screens/authentication/change_password_screen.dart';
// import 'package:cheminova/screens/authentication/login_screen.dart';
// import 'package:cheminova/screens/authentication/profile_screen.dart';
// import 'package:cheminova/screens/home_screen.dart';
// import 'package:flutter/material.dart';
// import 'package:get/get.dart';
//
// class MyDrawer extends StatefulWidget {
// final UserModel? userModel;
//
// MyDrawer({super.key, this.userModel});
//
// @override
// State<MyDrawer> createState() => _MyDrawerState();
// }
//
// class _MyDrawerState extends State<MyDrawer> {
// final homecontroller = Get.put(HomeController()); // Initialize HomeController
// @override
// Widget build(BuildContext context) {
// final user = homecontroller.user; // Get the current user from HomeController
// return Drawer(
// child: ListView(
// padding: EdgeInsets.zero,
// children: <Widget>[
// SizedBox(
// height: 150,
// // Drawer header displaying user information
// child: DrawerHeader(
// decoration: const BoxDecoration(
// color: Colors.black87,
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Text(
// user?.name ?? "username",
// style: const TextStyle(
// color: Colors.white,
// fontSize: 18,
// ),
// ),
// Text(
// user?.uniqueId ?? 'Employee ID',
// style: const TextStyle(
// color: Colors.white,
// fontSize: 20,
// ),
// ),
// ],
// ),
// ),
// ),
// // Navigation tile for Home
// ListTile(
// leading: const Icon(Icons.home),
// title: const Text('Home'),
// onTap: () {
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(builder: (context) => const HomeScreen()),
// (route) => false, // Remove all previous routes
// );
// },
// ),
// // Navigation tile for Profile
// ListTile(
// leading: const Icon(Icons.account_circle),
// title: const Text('Profile'),
// onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => ProfileScreen()),
// );
// },
// ),
// // Navigation tile for Change Password
// ListTile(
// leading: const Icon(Icons.settings),
// title: const Text('Change Password'),
// onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => ChangePasswordScreen()),
// );
// },
// ),
// // Navigation tile for Logout
// ListTile(
// leading: const Icon(Icons.exit_to_app),
// title: const Text('Logout'),
// onTap: () {
// logoutBox(context);
// },
// ),
//
//
//
//
// SizedBox(
// height: 700,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: Center(
// child: Text(
// 'Version 2.0.0',
// style: TextStyle(color: Colors.grey[600], fontSize: 12),
// ),
// ),
// ),
// ),
// ],
// ),
// );
// }
// }
// // Function to display logout confirmation dialog
// Future logoutBox(BuildContext context) {
// Size size = MediaQuery.of(context).size;
// return showDialog(
// context: context,
// builder: (BuildContext context) {
// return AlertDialog(
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(6.0),
// ),
// backgroundColor: Colors.white,
// alignment: Alignment.center,
// title: const Text('Are you sure you want to log out?'),
// titleTextStyle: const TextStyle(
// fontSize: 20, fontWeight: FontWeight.w400, color: Colors.black),
// actionsAlignment: MainAxisAlignment.center,
// actionsPadding: const EdgeInsets.only(left: 10, right: 10, bottom: 20),
// actions: [
// Row(
// children: [
// Expanded(
// child: SizedBox(
// height: (size.height / 50.52) * 2,
// child: ElevatedButton(
// style: ButtonStyle(
// elevation: MaterialStateProperty.all(0),
// backgroundColor: MaterialStateProperty.all<Color>(
// Colors.black),
// shape: MaterialStateProperty.all<RoundedRectangleBorder>(
// RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(6.0),
// )),
// ),
// onPressed: () async {
// Navigator.pop(context);
// },
// child: const Text(
// "No",
// style: TextStyle(
// fontSize: 17,
// color: Colors.white,
// fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// const SizedBox(width: 5),
// Expanded(
// child: SizedBox(
// height: (size.height / 50.52) * 2,
// child: ElevatedButton(
// style: ButtonStyle(
// elevation: MaterialStateProperty.all(0),
// backgroundColor:
// MaterialStateProperty.all<Color>(Colors.white),
// shape:
// MaterialStateProperty.all<RoundedRectangleBorder>(
// RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(6.0),
// side: const BorderSide(
// color: Colors.purple, width: 1))),
// ),
// onPressed: () async {
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(
// builder: (context) => LoginScreen()),
// (route) => false,
// );
// },
// child: const Text(
// "Yes",
// style: TextStyle(
// fontSize: 17,
// color: Colors.purple,
// fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// ],
// )
// ],
// );
// },
// );
// }
import 'package:cheminova/controller/home_controller.dart'; import 'package:cheminova/controller/home_controller.dart';
import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/models/user_model.dart';
import 'package:cheminova/screens/authentication/change_password_screen.dart'; import 'package:cheminova/screens/authentication/change_password_screen.dart';
@ -6,6 +215,7 @@ import 'package:cheminova/screens/authentication/profile_screen.dart';
import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/home_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
class MyDrawer extends StatefulWidget { class MyDrawer extends StatefulWidget {
final UserModel? userModel; final UserModel? userModel;
@ -18,17 +228,34 @@ class MyDrawer extends StatefulWidget {
class _MyDrawerState extends State<MyDrawer> { class _MyDrawerState extends State<MyDrawer> {
final homecontroller = Get.put(HomeController()); // Initialize HomeController final homecontroller = Get.put(HomeController()); // Initialize HomeController
String _appVersion = '';
@override
void initState() {
super.initState();
_getAppVersion();
}
Future<void> _getAppVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform(
);
setState(() {
_appVersion = packageInfo.version; // 1.0.0
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final user = homecontroller.user; // Get the current user from HomeController final user = homecontroller.user; // Get the current user from HomeController
return Drawer( return Drawer(
child: ListView( child: Column(
padding: EdgeInsets.zero,
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(
height: 150, height: 150,
width: double.infinity,
// Drawer header displaying user information // Drawer header displaying user information
child: DrawerHeader( child: DrawerHeader(
//padding: EdgeInsets.zero,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.black87, color: Colors.black87,
), ),
@ -36,15 +263,16 @@ class _MyDrawerState extends State<MyDrawer> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
user!.name ?? "username", user?.name ?? "username",
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 18, fontSize: 18,
), ),
), ),
Text( Text(
user!.uniqueId ?? 'Employee ID', user?.uniqueId ?? 'Employee ID',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 20, fontSize: 20,
@ -96,11 +324,23 @@ class _MyDrawerState extends State<MyDrawer> {
logoutBox(context); logoutBox(context);
}, },
), ),
// Spacer to push the version text to the bottom
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(
'Version: $_appVersion',
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
),
),
], ],
), ),
); );
} }
} }
// Function to display logout confirmation dialog // Function to display logout confirmation dialog
Future logoutBox(BuildContext context) { Future logoutBox(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
@ -188,3 +428,4 @@ Future logoutBox(BuildContext context) {
}, },
); );
} }

View File

@ -1,8 +1,10 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/cart_controller.dart'; import 'package:cheminova/controller/cart_controller.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';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/models/rd_get_order_model.dart';
import 'package:cheminova/screens/product/product_detail_screen.dart'; import 'package:cheminova/screens/product/product_detail_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -16,6 +18,7 @@ class ProductCard extends StatefulWidget {
PlacedOrderModel? placedOrder; PlacedOrderModel? placedOrder;
PlacedOrderList? placedOrderList; PlacedOrderList? placedOrderList;
PlaceOrderItem1? placeorderItem; PlaceOrderItem1? placeorderItem;
PlacedOrdersResponse ? placeRDOrder;
ProductModel? product; ProductModel? product;
final bool isInCart; final bool isInCart;
final bool isCheckout; final bool isCheckout;
@ -30,6 +33,7 @@ class ProductCard extends StatefulWidget {
this.placedOrder, this.placedOrder,
this.placedOrderList, this.placedOrderList,
this.placeorderItem, this.placeorderItem,
this.placeRDOrder,
this.isInCart = false, this.isInCart = false,
this.isCheckout = false, this.isCheckout = false,
this.isConfirmation = false, this.isConfirmation = false,
@ -44,6 +48,7 @@ class _ProductCardState extends State<ProductCard> {
if (text.isEmpty) return text; if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase(); return text[0].toUpperCase() + text.substring(1).toLowerCase();
} }
String? imageurl;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -53,13 +58,20 @@ class _ProductCardState extends State<ProductCard> {
// Get the current quantity of the product, either from the cart or the default value // Get the current quantity of the product, either from the cart or the default value
int currentQuantity = isProductInCart int currentQuantity = isProductInCart
? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity ? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
: widget.productModel!.quantity; : widget.productModel!.quantity ??1;
TextEditingController quantityController =
TextEditingController(text: currentQuantity.toString());
imageurl = widget.productModel!.brand.images.isNotEmpty
? widget.productModel!.brand.images[0].url
: 'assets/images/no_image_available.jpg'; // Use a fallback image URL or handle it accordingly
return GestureDetector( return GestureDetector(
// Navigate to the ProductDetailScreen on tap unless the product is in cart or checkout // Navigate to the ProductDetailScreen on tap unless the product is in cart or checkout
onTap: () => widget.isInCart || widget.isCheckout onTap: () => widget.isInCart || widget.isCheckout
? null ? null
: Get.to(() => ProductDetailScreen(productModel: widget.productModel)), : Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
child: SizedBox(
// height: Get.height * 0.21,
// width: Get.width *0.20,
child: Card( child: Card(
child: Row( child: Row(
children: [ children: [
@ -67,21 +79,26 @@ class _ProductCardState extends State<ProductCard> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
child: Container( child:
height: Get.height * 0.15, Container(
width: Get.width * 0.31, height: Get.height * 0.18,
width: Get.width * 0.32,
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage("assets/images/product.png"), image: imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
), ),
), ),
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0), padding: const EdgeInsets.symmetric(horizontal: 0.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -102,106 +119,22 @@ class _ProductCardState extends State<ProductCard> {
), ),
), ),
// Display the price of the product // Display the price of the product
if (!widget.isCheckout)
widget.isInCart
?
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text( Text(
"${widget.productModel!.price.toString()}", "${widget.productModel!.price.toString()}",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 22, fontSize: 20,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
if (showQuantity) // SizedBox(
Text( // width: 60,
"Quantity: ${currentQuantity}", // ),
style: GoogleFonts.roboto(
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
// Display quantity adjustment buttons and remove button if the product is in cart
if (!widget.isCheckout)
widget.isInCart
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: Get.height * 0.04,
width: Get.width * 0.21,
decoration: BoxDecoration(
color: const Color(0xFF004791),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: 24,
width: 24,
child: ElevatedButton(
onPressed: () {
_cartController.decreaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
Text(
"${currentQuantity}",
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
SizedBox(
height: 22,
width: 22,
child: ElevatedButton(
onPressed: () {
_cartController.increaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
],
),
),
SizedBox(
width: 2.0,
),
IconButton( IconButton(
onPressed: () { onPressed: () {
_cartController.removeFromCart(widget.productModel!); _cartController.removeFromCart(widget.productModel!);
@ -216,6 +149,225 @@ class _ProductCardState extends State<ProductCard> {
), ),
), ),
], ],
)
:SizedBox(),
if (showQuantity)
SizedBox(
height: Get.height * 0.04,
child: Text(
"Quantity: ${currentQuantity}",
style: GoogleFonts.roboto(
color: Color(0xFF004791),
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
),
// Display quantity adjustment buttons and remove button if the product is in cart
if (!widget.isCheckout)
widget.isInCart
?
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: Get.height * 0.05,
width: Get.width * 0.40,
decoration: BoxDecoration(
color: const Color(0xFF004791),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: 25,
width: 25,
child: ElevatedButton(
onPressed: () {
_cartController.decreaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
backgroundColor:Color(0xFF004791),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
// Text(
// "${currentQuantity}",
// style: const TextStyle(
// color: Colors.white,
// fontSize: 16,
// ),
// Expanded(
// child: TextFormField(
// // decoration:InputDecoration(
// // border: InputBorder.none,
// // ),
//
// controller: quantityController,
// style: TextStyle(color: Color(0xFF004791),fontWeight: FontWeight.bold),
// keyboardType: TextInputType.number,
//
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? currentQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// setState(() {
// currentQuantity = enteredQuantity;
// _cartController.updateQuantity(
// widget.productModel!, currentQuantity);
// });
// },
// decoration: const InputDecoration(
//
// contentPadding: EdgeInsets.only(left: 8.0,right: 8.0,bottom: 8.0),
// border: OutlineInputBorder(
// //
// ),
// ),
// ),
// ),
SizedBox(width: 5,),
Expanded(
child: TextFormField(
controller: quantityController,
style: const TextStyle(
color: Color(0xFF004791),
fontWeight: FontWeight.bold,
fontSize: 16,
),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onFieldSubmitted: (value) {
int enteredQuantity = int.tryParse(value) ?? currentQuantity;
if (enteredQuantity <= 0) {
showSnackbar("Quantity must be at least 1");
enteredQuantity = 1;
}
setState(() {
currentQuantity = enteredQuantity;
_cartController.updateQuantity(widget.productModel!, currentQuantity);
});
},
decoration: InputDecoration(
labelText: "Enter Quantity",
labelStyle: const TextStyle(
color: Color(0xFF004791),
fontWeight: FontWeight.w600,
fontSize: 14,
),
hintText: "",
hintStyle: const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.w400,
fontSize: 14,
),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xFF004791),
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xFF004791),
width: 2,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Colors.red,
width: 1.5,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Colors.red,
width: 2,
),
),
),
),
),
SizedBox(width: 5,),
SizedBox(
height: 25,
width: 25,
child: ElevatedButton(
onPressed: () {
_cartController.increaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF004791),
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
SizedBox(
width: 1.0,
),
// IconButton(
// onPressed: () {
// _cartController.removeFromCart(widget.productModel!);
// showSnackbar("Product has been removed successfully!");
// setState(() {
// currentQuantity = 1;
// });
// },
// icon: const Icon(
// Icons.delete_outline_rounded,
// color: Colors.red,
// ),
// ),
],
) )
: ElevatedButton( : ElevatedButton(
onPressed: () { onPressed: () {
@ -249,6 +401,211 @@ class _ProductCardState extends State<ProductCard> {
], ],
), ),
), ),
),
); );
} }
} }
//
// class ProductCard extends StatefulWidget {
// final Product? productModel;
// PlacedOrderModel? placedOrder;
// PlacedOrderList? placedOrderList;
// PlaceOrderItem1? placeorderItem;
// PlacedOrdersResponse ? placeRDOrder;
// ProductModel? product;
// final bool isInCart;
// final bool isCheckout;
// final bool isConfirmation;
// int? quantity;
//
// ProductCard({
// super.key,
// this.product,
// this.quantity = 1,
// this.productModel,
// this.placedOrder,
// this.placedOrderList,
// this.placeorderItem,
// this.placeRDOrder,
// this.isInCart = false,
// this.isCheckout = false,
// this.isConfirmation = false,
// });
//
// @override
// State<ProductCard> createState() => _ProductCardState();
// }
//
// class _ProductCardState extends State<ProductCard> {
// final CartController _cartController = Get.put(CartController());
//
// String capitalizeFirstLetter(String text) {
// if (text.isEmpty) return text;
// return text[0].toUpperCase() + text.substring(1).toLowerCase();
// }
//
// @override
// Widget build(BuildContext context) {
// bool showQuantity = widget.isInCart || widget.isCheckout || widget.isConfirmation;
// bool isProductInCart = _cartController.cartList.any((p) => p.id == widget.productModel!.id);
//
// // Get the current quantity of the product
// int currentQuantity = isProductInCart
// ? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
// : widget.productModel!.quantity ?? 1;
//
// TextEditingController quantityController =
// TextEditingController(text: currentQuantity.toString());
//
// return GestureDetector(
// onTap: () => widget.isInCart || widget.isCheckout
// ? null
// : Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
// child: Card(
// child: Row(
// children: [
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: ClipRRect(
// borderRadius: BorderRadius.circular(15.0),
// child: Container(
// height: Get.height * 0.15,
// width: Get.width * 0.31,
// decoration: const BoxDecoration(
// image: DecorationImage(
// image: AssetImage("assets/images/product.png"),
// fit: BoxFit.cover,
// ),
// ),
// ),
// ),
// ),
// Expanded(
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 3.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// capitalizeFirstLetter(widget.productModel!.name),
// style: GoogleFonts.roboto(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// ),
// ),
// Text(
// capitalizeFirstLetter(widget.productModel!.category!.categoryName),
// style: GoogleFonts.roboto(
// fontSize: 14,
// fontWeight: FontWeight.w400,
// ),
// ),
// Text(
// "${widget.productModel!.price.toString()}",
// style: GoogleFonts.roboto(
// fontSize: 22,
// fontWeight: FontWeight.w700,
// ),
// ),
// if (showQuantity)
// Row(
// children: [
// SizedBox(
// width: 50,
// child: TextFormField(
// controller: quantityController,
// keyboardType: TextInputType.number,
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? currentQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// setState(() {
// currentQuantity = enteredQuantity;
// _cartController.updateQuantity(
// widget.productModel!, currentQuantity);
// });
// },
// decoration: const InputDecoration(
// contentPadding: EdgeInsets.all(8),
// border: OutlineInputBorder(),
// ),
// ),
// ),
// IconButton(
// onPressed: () {
// _cartController.decreaseQuantity(widget.productModel!);
// setState(() {
// currentQuantity = _cartController
// .cartList
// .firstWhere((p) => p.id == widget.productModel!.id)
// .quantity;
// quantityController.text = currentQuantity.toString();
// });
// },
// icon: const Icon(Icons.remove),
// ),
// IconButton(
// onPressed: () {
// _cartController.increaseQuantity(widget.productModel!);
// setState(() {
// currentQuantity = _cartController
// .cartList
// .firstWhere((p) => p.id == widget.productModel!.id)
// .quantity;
// quantityController.text = currentQuantity.toString();
// });
// },
// icon: const Icon(Icons.add),
// ),
// ],
// ),
// if (!widget.isCheckout)
// widget.isInCart
// ? Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// ElevatedButton(
// onPressed: () {
// _cartController.removeFromCart(widget.productModel!);
// showSnackbar("Product removed successfully!");
// setState(() {
// currentQuantity = 1;
// quantityController.text = currentQuantity.toString();
// });
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.red,
// ),
// child: const Text("Remove"),
// ),
// ],
// )
// : ElevatedButton(
// onPressed: () {
// if (isProductInCart) {
// showSnackbar("Product already added to cart");
// } else {
// _cartController.addToCart(widget.productModel!);
// showSnackbar("Product added to cart successfully!");
// }
// },
// child: const Text("Add To Cart"),
// ),
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// );
// }
// }

View File

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/cart_controller.dart'; import 'package:cheminova/controller/cart_controller.dart';
import 'package:cheminova/controller/rd_get_order_controller.dart'; import 'package:cheminova/controller/rd_get_order_controller.dart';
import 'package:cheminova/models/rd_get_order_model.dart'; import 'package:cheminova/models/rd_get_order_model.dart';
@ -5,6 +6,8 @@ import 'package:cheminova/models/rd_order_item_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../utils/show_snackbar.dart';
class ProductCard1 extends StatefulWidget { class ProductCard1 extends StatefulWidget {
final RDOrderItem productModel; // The specific product to be displayed final RDOrderItem productModel; // The specific product to be displayed
int? quantity; int? quantity;
@ -24,16 +27,20 @@ class _ProductCard1State extends State<ProductCard1> {
if (text.isEmpty) return text; if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase(); return text[0].toUpperCase() + text.substring(1).toLowerCase();
} }
String? imageurl;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final CartController _cartController = Get.put(CartController()); final CartController _cartController = Get.put(CartController());
TextEditingController quantityController =
TextEditingController();
// Current quantity the user wants to process // Current quantity the user wants to process
int processQuantity = widget.productModel.processquantity ?? 1; int processQuantity = widget.productModel.processquantity ?? 1;
// Total available quantity // Total available quantity
int availableQuantity = widget.productModel.remainingQuantity ?? 1; int availableQuantity = widget.productModel.remainingQuantity ?? 1;
imageurl = widget.productModel.image.isNotEmpty
? widget.productModel.image[0].url
: 'assets/images/no_image_available.jpg';
return Card( return Card(
child: Row( child: Row(
@ -45,9 +52,12 @@ class _ProductCard1State extends State<ProductCard1> {
child: Container( child: Container(
height: Get.height * 0.15, height: Get.height * 0.15,
width: Get.width * 0.31, width: Get.width * 0.31,
decoration: const BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage("assets/images/product.png"), image:
imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
@ -94,7 +104,7 @@ class _ProductCard1State extends State<ProductCard1> {
), ),
), ),
Text( Text(
" ${widget.productModel.quantity}", " ${widget.productModel.remainingQuantity}",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 15, fontSize: 15,
), ),
@ -158,6 +168,39 @@ class _ProductCard1State extends State<ProductCard1> {
fontSize: 16, fontSize: 16,
), ),
), ),
// Expanded(
// child: TextFormField(
// // decoration:InputDecoration(
// // border: InputBorder.none,
// // ),
//
// controller: quantityController,
// style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold),
// keyboardType: TextInputType.number,
//
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? processQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// // setState(() {
// // // widget.productModel.processquantity = enteredQuantity;
// // // // _cartController.updateQuantity(
// // // // widget.productModel.processquantity!, processQuantity);
// // processQuantity = enteredQuantity;
// // widget.productModel.processquantity = processQuantity;
// // });
// },
// decoration: const InputDecoration(
//
// contentPadding: EdgeInsets.only(left: 8.0,right: 8.0,bottom: 8.0),
// // border: OutlineInputBorder(),
// ),
// ),
// ),
// Increase quantity button // Increase quantity button
SizedBox( SizedBox(
height: 22, height: 22,

View File

@ -12,8 +12,10 @@ import firebase_core
import firebase_crashlytics import firebase_crashlytics
import firebase_messaging import firebase_messaging
import flutter_local_notifications import flutter_local_notifications
import package_info_plus
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
import sqflite
import syncfusion_pdfviewer_macos import syncfusion_pdfviewer_macos
import url_launcher_macos import url_launcher_macos
@ -25,8 +27,10 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin")) SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
} }

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.44" version: "1.3.44"
archive:
dependency: transitive
description:
name: archive
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -41,6 +49,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
cached_network_image:
dependency: "direct main"
description:
name: cached_network_image
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@ -49,6 +81,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -302,14 +350,22 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_lints: flutter_cache_manager:
dependency: "direct dev" dependency: transitive
description: description:
name: flutter_lints name: flutter_cache_manager
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.4.1"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c
url: "https://pub.dev"
source: hosted
version: "0.14.3"
flutter_local_notifications: flutter_local_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
@ -424,6 +480,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
url: "https://pub.dev"
source: hosted
version: "4.5.2"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -504,6 +568,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.7.1"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev"
source: hosted
version: "4.9.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@ -528,14 +600,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
logger: logger:
dependency: "direct main" dependency: "direct main"
description: description:
@ -576,6 +640,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.6" version: "1.0.6"
octo_image:
dependency: transitive
description:
name: octo_image
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
sha256: "739e0a5c3c4055152520fa321d0645ee98e932718b4c8efeeb51451968fe0790"
url: "https://pub.dev"
source: hosted
version: "8.1.3"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b
url: "https://pub.dev"
source: hosted
version: "3.0.2"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -672,6 +760,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
pretty_dio_logger: pretty_dio_logger:
dependency: "direct main" dependency: "direct main"
description: description:
@ -680,6 +776,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
rxdart:
dependency: transitive
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@ -757,6 +861,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.0"
sqflite:
dependency: transitive
description:
name: sqflite
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
url: "https://pub.dev"
source: hosted
version: "2.3.3+1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -845,6 +965,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "26.2.14" version: "26.2.14"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -1029,6 +1157,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.5.0" version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks: sdks:
dart: ">=3.4.1 <4.0.0" dart: ">=3.4.1 <4.0.0"
flutter: ">=3.22.0" flutter: ">=3.22.0"

View File

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 2.0.2+1
environment: environment:
sdk: ">=3.4.1 <4.0.0" sdk: ">=3.4.1 <4.0.0"
@ -56,17 +56,28 @@ dependencies:
firebase_analytics: ^11.2.1 firebase_analytics: ^11.2.1
flutter_secure_storage: ^4.2.1 flutter_secure_storage: ^4.2.1
pretty_dio_logger: ^1.4.0 pretty_dio_logger: ^1.4.0
package_info_plus: ^8.1.3
cached_network_image: ^3.4.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_launcher_icons: ^0.14.3
flutter_launcher_icons:
android: "launcher_icon"
ios: true
image_path: "assets/images/app-icon-principal-distributor.png"
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your # activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # rules and activating additional ones.
flutter_lints: ^3.0.0 flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec