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_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="cheminova"
android:label="Principal Distributor"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
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;
buildSettings = {
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_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@ -484,7 +484,7 @@
isa = XCBuildConfiguration;
buildSettings = {
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_CXX_LANGUAGE_STANDARD = "gnu++0x";
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" : "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"
}
}
{"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"}}

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>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>com.example.cheminova</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

View File

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

View File

@ -8,16 +8,16 @@ class AnnouncementService {
final Dio _dio = Dio();
Future<List<AnnouncementModel>?> fetchAnnouncements(String token) async {
Future<List<AnnouncementModel>?> fetchAnnouncements() async {
try {
String url = ApiUrls.AnnaouncementUrl; // Base URL to fetch product manuals
final response = await commonApiService<List<AnnouncementModel>>(
method: "GET",
url: url,
additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token',
},
// additionalHeaders: { // Pass the token here
// 'Authorization': 'Bearer $token',
// },
fromJson: (json) {
if (json['announcements'] != null) {
// 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
subtotal.value = subTotal;
gstTotal.value = gstTotalAmount;
gstTotal.value = double.parse(gstTotalAmount.toStringAsFixed(2));
grandTotal.value = subtotal.value + gstTotal.value;
}
// 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
void removeFromCart(Product product) {
// 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/utils/api_urls.dart';
import 'package:cheminova/utils/common_api_service.dart';
@ -33,35 +35,26 @@ class HomeService {
}
// Function to send FCM token to the server
Future<Map<String, dynamic>?> fcmToken(Map<String, dynamic> data,
String? token) async {
Future<Map<String, dynamic>?> fcmToken(Map<String, dynamic> data, String? token) async {
try {
final response = await commonApiService<String>(
// Making a POST request to send the FCM token
final response = await commonApiService<Map<String, dynamic>>(
url: ApiUrls.fcmUrl,
method: 'POST',
body: data,
// Body data to be sent in the request
fromJson: (json) => json as String,
// Just return the string response
fromJson: (json) => json as Map<String, dynamic>, // Parse JSON response
additionalHeaders: {
// Pass the token here
'Authorization': 'Bearer $token',
// Bearer token for authenticated requests
},
);
if (response != null) {
// Since the response is a string, wrap it in a Map to avoid type issues
return {
'message': response
}; // Return the response in a map with 'message' as the key
return response; // Return parsed response
}
return null;
} catch (e) {
showSnackbar(e.toString()); // Handle any errors
showSnackbar(e.toString());
return null;
}
}
}

View File

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

View File

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

View File

@ -6,12 +6,18 @@ import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart';
import '../models/oder_place_model.dart';
import '../utils/app_interceptor.dart';
import '../utils/log_service.dart';
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 {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
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
await _rdOrderPlacedService.placRDeOrder(orderDetails, token!);
} catch (e) {
print("Error placing order: $e");
// print("Error placing order: $e");
showSnackbar("stock not available");
} finally {
isLoading.value = false;
}

View File

@ -6,16 +6,23 @@ import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import '../models/rd_order_item_model.dart';
import '../utils/app_interceptor.dart';
class RDOrderPlacedService {
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,
String token) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try {
// 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',
// Ensure this is your correct endpoint
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 {
final String id;
final String brandName;
List<BrandImage> images;
Brand({
required this.id,
required this.brandName,
required this.images,
});
factory Brand.fromJson(Map<String, dynamic> json) {
return Brand(
id: json['_id'],
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() {
return {
'_id': id,
'brandName': brandName,
"image": images.map((e) => e.toJson()).toList(),
};
}
@override
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 {
final String id;
final String paymentMode;
final String shipTo;
final String billTo;
final List<OrderItem> orderItems;
final List<RDOrderItem> orderItems;
final double subtotal;
final double gstTotal;
final double grandTotal;
@ -51,8 +57,8 @@ class GetRdCancelledModel {
paymentMode: json['paymentMode'],
shipTo: json['shipTo'],
billTo: json['billTo'],
orderItems: (json['orderItem'] as List<dynamic>)
.map((item) => OrderItem.fromJson(item))
orderItems: (json['orderItem'] as List)
.map((item) => RDOrderItem.fromJson(item))
.toList(),
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
@ -122,7 +128,7 @@ class OrderItem {
final double gst;
final int hsnCode;
final String description;
final List<String> images;
final List<BrandImage> images;
final int quantity;
final int remainingQuantity;
final String id;
@ -154,7 +160,9 @@ class OrderItem {
gst: json['GST'].toDouble(),
hsnCode: json['HSN_Code'],
description: json['description'] ?? '',
images: List<String>.from(json['image']),
images : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'],
remainingQuantity: json['remainingQuantity'],
id: json['_id'],

View File

@ -64,7 +64,7 @@ class OrderItem {
String description;
String productStatus;
final String addedBy;
List<String> image;
List<BrandImage> image;
DateTime createdAt;
DateTime updatedAt;
int count;
@ -124,7 +124,9 @@ class OrderItem {
description: json['description'],
productStatus: json['product_Status'],
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']),
updatedAt: DateTime.parse(json['updatedAt']),
count: json['count'],

View File

@ -1,3 +1,5 @@
import 'brand_model.dart';
class PlacedOrderList {
final String id;
final String paymentMode;
@ -95,6 +97,7 @@ class OrderItem1 {
final String brandName;
final double price;
final int quantity;
List<BrandImage>? image;
OrderItem1({
required this.sku,
@ -102,6 +105,7 @@ class OrderItem1 {
required this.categoryName,
required this.brandName,
required this.price,
this.image,
required this.quantity,
});
@ -112,6 +116,9 @@ class OrderItem1 {
categoryName: json['categoryName'],
brandName: json['brandName'],
price: json['price'].toDouble(),
image : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'],
);
}
@ -124,13 +131,14 @@ class OrderItem1 {
'brandName': brandName,
'price': price,
'quantity': quantity,
'image':image
};
}
@override
String toString() {
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,4 +1,6 @@
import 'brand_model.dart';
class RDOrderItem {
final String productId;
final String sku;
@ -9,7 +11,7 @@
final int gst; // Ensure GST is int
final int hsnCode; // Ensure HSN_Code is int
final String description;
final List<String> image;
final List<BrandImage> image;
int? quantity;
int? remainingQuantity;
int? processquantity;
@ -43,10 +45,13 @@
hsnCode: json['HSN_Code'] ?? 0,
// Handle HSN_Code as int
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,
// Handle quantity as int
processquantity: json['processquantity']??1,
processquantity: json['processQuantity']??1,
remainingQuantity: json['remainingQuantity'] ??
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';
// Main model for the order
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;
String id;
String paymentMode;
String shipTo;
String billTo;
List<RDOrderItem> orderItem;
double subtotal;
double gstTotal;
double grandTotal;
String status;
List<Invoice> invoices;
AddedBy addedBy;
String pd;
bool isCancelled;
bool isDelivered;
String deliveredDate;
String statusUpdatedAt;
String uniqueId;
String createdAt;
String 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,
required this.paymentMode,
required this.shipTo,
required this.billTo,
required this.orderItem,
required this.subtotal,
required this.gstTotal,
required this.grandTotal,
required this.status,
required this.invoices,
required this.addedBy,
required this.pd,
required this.isCancelled,
required this.isDelivered,
required this.deliveredDate,
required this.statusUpdatedAt,
required this.uniqueId,
required this.createdAt,
required 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()),
id: json['_id']??"1",
paymentMode: json['paymentMode']??"2343",
shipTo: json['shipTo']??"abc",
billTo: json['billTo']??"xyz",
orderItem: (json['orderItem'] as List)
.map((i) => RDOrderItem.fromJson(i))
.toList(),
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
grandTotal: json['grandTotal'].toDouble(),
status: json['status'],
invoices: (json['invoices'] as List)
.map((i) => Invoice.fromJson(i))
.toList(),
addedBy: AddedBy.fromJson(json['addedBy']??""),
pd: json['pd']??"",
isCancelled: json['iscancelled']??"",
isDelivered: json['isDelivered']??"",
deliveredDate: json['DeliveredDate']??"",
statusUpdatedAt: json['statusUpdatedAt']??"",
uniqueId: json['uniqueId']??"",
createdAt: json['createdAt']??"",
updatedAt: json['updatedAt']??"",
);
}
@ -76,51 +349,109 @@ class SingleGetOrderModel {
'paymentMode': paymentMode,
'shipTo': shipTo,
'billTo': billTo,
'orderItem': orderItem?.map((item) => item.toJson()).toList(),
'orderItem': orderItem.map((i) => i.toJson()).toList(),
'subtotal': subtotal,
'gstTotal': gstTotal,
'grandTotal': grandTotal,
'status': status,
'invoices': invoices,
'addedBy': addedBy?.toJson(),
'invoices': invoices.map((i) => i.toJson()).toList(),
'addedBy': addedBy.toJson(),
'pd': pd,
'iscancelled': isCancelled,
'isDelivered': isDelivered,
'DeliveredDate': deliveredDate,
'statusUpdatedAt': statusUpdatedAt?.toIso8601String(),
'statusUpdatedAt': statusUpdatedAt,
'uniqueId': uniqueId,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'createdAt': createdAt,
'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)';
// Model for individual order items
// 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,
};
}
}
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
// 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;
OrderItem({
InvoiceItem({
required this.productId,
required this.sku,
required this.name,
@ -129,30 +460,22 @@ class OrderItem {
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.processQuantity,
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'] ?? '',
factory InvoiceItem.fromJson(Map<String, dynamic> json) {
return InvoiceItem(
productId: json['productId']??"",
sku: json['SKU']??"",
name: json['name']??"",
categoryName: json['categoryName']??"",
brandName: json['brandName']??"",
price: json['price'].toDouble(),
gst: json['GST'].toDouble(),
hsnCode: json['HSN_Code']??"",
processQuantity: json['processquantity']??"",
id: json['_id']??"",
);
}
@ -166,23 +489,13 @@ class OrderItem {
'price': price,
'GST': gst,
'HSN_Code': hsnCode,
'description': description,
'image': image,
'quantity': quantity,
'remainingQuantity': remainingQuantity,
'processquantity': processQuantity,
'_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 {
final String id;
final String designation;
@ -229,7 +542,8 @@ class AddedBy {
addedBy: json['addedBy'] ?? '',
userType: json['userType'] ?? '',
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()),
updatedAt: DateTime.parse(json['updatedAt'] ?? DateTime.now().toString()),
mappedSC: json['mappedSC'] ?? '',
@ -267,3 +581,8 @@ class AddedBy {
'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:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@ -16,24 +134,15 @@ class AnnouncementScreen extends StatefulWidget {
}
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
DateTime parsedDate = DateTime.parse(apiDate).toLocal();
return DateFormat('EEE MMM dd yyyy').format(parsedDate);
}
@override
Widget build(BuildContext context) {
// Fetch announcements when the screen is built
_announcementController.fetchAnnouncements();
return CommonBackground(
@ -63,47 +172,61 @@ class _AnnouncementScreenState extends State<AnnouncementScreen> {
),
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(
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
//leading:Text(_announcementController.announcements[index].id),
title: Row(
// leading: CircleAvatar(
// backgroundColor: Colors.blue,
// child: Text(
// announcementList.uniqueId.toString().toUpperCase(),
// style: TextStyle(color: Colors.white),
// ),
// ),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Message :",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 14),),
Text(announcementList.message.toString(),style: TextStyle(fontSize: 12),),
Text(
"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: [
Text("UniqueID :" , style: TextStyle(fontWeight: FontWeight.bold),),
Text(announcementList.uniqueId.toString()),
Text(
"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());
void dispose() {
// Dispose of the text controllers when the screen is closed to free up resources
authController.currentpassController.dispose();
authController.newpassController.dispose();
authController.confirmpassController.dispose();
super.dispose();
}
// void dispose() {
// // Dispose of the text controllers when the screen is closed to free up resources
// authController.currentpassController.dispose();
// authController.newpassController.dispose();
// authController.confirmpassController.dispose();
// super.dispose();
// }
// Function to validate user input and initiate password change
void validateAndChangePassword() async {

View File

@ -1,9 +1,12 @@
import 'dart:convert';
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/login_screen.dart';
import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -15,7 +18,7 @@ import '../../../utils/secure__storage_service.dart';
class AuthController extends GetxController {
final authService = AuthService();
final Dio _dio = Dio();
final _storageService = SecureStorageService();
@ -28,6 +31,7 @@ class AuthController extends GetxController {
final HomeController _homeController = Get.put(HomeController());
RxBool isLoading = false.obs;
@override
void onInit(){
super.onInit();
@ -35,26 +39,106 @@ class AuthController extends GetxController {
NotificationServices().requestNotificationPermission();
}
// 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 {
SharedPreferences prefs = await SharedPreferences.getInstance();
isLoading.value = true;
// Call the login service with email and password
// Perform login API request
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!");
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());
}
else if(response == null){
showSnackbar("Please Enter Valid Email or Password");
} else {
showSnackbar("Please enter a 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 {
// isLoading(true);
// try {

View File

@ -1,10 +1,18 @@
import 'package:cheminova/utils/api_urls.dart';
import 'package:cheminova/utils/common_api_service.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 {
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
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
try {

View File

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

View File

@ -19,6 +19,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'kyc/kyc_retailer_info_screen.dart';
import 'opening Inventory/inventory_management_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@ -183,7 +184,7 @@ class _HomeScreenState extends State<HomeScreen> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
HomeCard(
title: 'RD Orders',
title: 'Retailer Orders',
onTap: () => Get.to(
() => 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,
description: 'Description 1',
category: ProductCategory.food,
image: 'assets/images/product.png',
image: "assets/images/new_product.jpeg",
//'assets/images/product.png',
)
];
final List<String> _filterList = [

View File

@ -179,13 +179,18 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
),
SizedBox(
height: Get.height * 0.6,
child: Obx(() {
child:
Obx(() {
// Filter the list based on the selected status
List<KycModel> filteredOrders =
selectedStatus == "All"
? _kycController.kycList
: _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(
padding: EdgeInsets.zero,
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(),
body: Obx(() {
body:
Obx(() {
// Show a loading indicator while data is being fetched
if (notificationController.isLoading.value) {
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/product_controller.dart';
import '../../controller/product_service.dart';
import '../../controller/shiptobilltoController.dart';
import '../../models/brand_model.dart';
import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
import '../../models/shiping_billing_address_model.dart';
import '../../widgets/my_drawer.dart';
import '../../widgets/product_card.dart';
import 'order_confermation_screen.dart';
@ -39,6 +41,7 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
final OrderPlacedController _orderPlacedController =
Get.put(OrderPlacedController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
final AddressController _addressController = Get.put(AddressController()); // Initialize AddressController
int currentPage = 1;
String _groupValue = "cheque";
@ -52,17 +55,25 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
String? _selectedShippingAddress;
String? _selectedBillingAddress;
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
@override
void initState() {
super.initState();
// _getOrder();
_addressController.fetchAddresses();
_loadSelectedAddress();
_loadSelectedPaymentMode();
if (_addressList.isNotEmpty) {
_selectedShippingAddress = _addressList.first;
_selectedBillingAddress = _addressList.first;
}
// _loadSelectedAddress();
// _loadSelectedPaymentMode();
//
// if (_addressList.isNotEmpty) {
// _selectedShippingAddress = _addressList.first;
// _selectedBillingAddress = _addressList.first;
// }
}
void _saveSelectedAddress() async {
@ -85,16 +96,34 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
_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 {
SharedPreferences prefs = await SharedPreferences.getInstance();
_addressController
.fetchAddresses(); // Ensure address list is updated
setState(() {
_selectedShippingAddress =
prefs.getString('selectedShippingAddress') ?? _addressList.first;
(prefs.getString('selectedShippingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
_selectedBillingAddress =
prefs.getString('selectedBillingAddress') ?? _addressList.first;
(prefs.getString('selectedBillingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
});
}
void _onPaymentModeChanged(String? value) {
setState(() {
_groupValue = value!;
@ -127,7 +156,14 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
hsnCode: product.hsnCode,
description: product.description,
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,
updatedAt: product.createdAt,
count: product.quantity,
@ -135,16 +171,40 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
//category:product.category,
category:Category(id: product.category.id, categoryName: product.category.categoryName),
// brand:product.brand,
brand:Brand(id: product.brand.id, brandName: product.brand.brandName),
brand:Brand(id: product.brand.id, brandName: product.brand.brandName,images: product.brand.images),
v: 0, addedBy: product.addedBy,
);
}).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
_orderPlacedController.placedOrder1.value= PlacedOrderModel(
paymentMode: _groupValue,
shipTo: _selectedShippingAddress!,
billTo: _selectedBillingAddress!,
shipTo: shippingAddress, // Full shipping address
billTo: billingAddress, // Full billing address
orderItems: orderItems,
gstTotal: _cartController.gstTotal.value,
grandTotal: _cartController.grandTotal.value,
@ -157,11 +217,16 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
showSnackbar("Order Placed Successfully");
Get.to(() => OrderConfermationScreen(
placedOrder: _orderPlacedController.placedOrder1.value,
));
}
} catch (e) {
print("PlaceOrderScreen error: $e");
}
}
@ -219,15 +284,15 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
side: const BorderSide(color: Color(0xFFFDFDFD)),
),
color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding(
child:
Padding(
padding: EdgeInsets.all(Get.width * 0.04),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: Get.width * 0.04),
padding: EdgeInsets.symmetric(horizontal: Get.width * 0.04),
child: Text(
'Shipping Information',
style: GoogleFonts.roboto(
@ -237,38 +302,54 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
),
),
),
SizedBox(height: 5,),
DropdownButtonFormField<String>(
SizedBox(height: 5),
Obx(() => Container(
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Shipping Address:',
hintText: 'Select Shipping Address',
border: OutlineInputBorder(),
),
value: _selectedShippingAddress,
items: _addressList.map((String address) {
value: _addressController.selectedShippingAddressId.value.isEmpty
? null // Show null if there's no selection yet
: _addressController.selectedShippingAddressId.value, // Set the selected ID
items: _addressController.addressList.map((UserShippingAddress address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
value: address.id, // Set the value as the address ID
child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} , ${address.country}"), // Display full address
);
}).toList(),
onChanged: _onShippingAddressChanged,
onChanged: (value) {
_addressController.onShippingAddressChanged(value); // Update the selected address
},
),
)),
SizedBox(height: Get.height * 0.02),
DropdownButtonFormField<String>(
// Billing Address Dropdown
Obx(() => Container(
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Billing Address:',
hintText: 'Select Billing Address',
border: OutlineInputBorder(),
),
value: _selectedBillingAddress,
items: _addressList.map((String address) {
value: _addressController.selectedBillingAddressId.value.isEmpty
? null // Show null if there's no selection yet
: _addressController.selectedBillingAddressId.value, // Set the selected ID
items: _addressController.addressList.map((UserShippingAddress address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
value: address.id, // Set the value as the address ID
child: Text("${address.street} ${address.city} ${address.state} \n ${address.postalCode} ${address.country}"), // Display full address
);
}).toList(),
onChanged: _onBillingAddressChanged,
onChanged: (value) {
_addressController.onBillingAddressChanged(value); // Update the selected address
},
),
)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: Get.width * 0.04),

View File

@ -1,4 +1,5 @@
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/utils/show_snackbar.dart';
import 'package:cheminova/widgets/my_drawer.dart';
@ -12,14 +13,18 @@ import '../../controller/cart_controller.dart';
import '../../controller/place_order_controller.dart';
import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
import '../../models/shiping_billing_address_model.dart';
class OrderConfermationScreen extends StatefulWidget {
Product? productModel; // The selected product model
PlacedOrderModel? placedOrder; // The order details after placement
List<Product>? selectedProducts; // List of selected products for the order
// final UserShippingAddress? shippingAddress;
// final UserShippingAddress? billingAddress;
// 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
State<OrderConfermationScreen> createState() =>
@ -30,9 +35,11 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
final CartController _cartController = Get.put(CartController()); // Instance of CartController
// Instance of OrderPlacedController
final OrderPlacedController _placedController = Get.put(OrderPlacedController());
final AddressController _addressController = Get.put(AddressController());
// Instance of GetPlacedOrderController
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
@override
Widget build(BuildContext context) {
final orderItems = _placedController.placedOrder1; // Fetching the placed order details
@ -78,6 +85,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
fit: BoxFit.cover,
),
SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
@ -197,7 +205,13 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
padding: const EdgeInsets.all(8.0),
child: TextField(
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(
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:cached_network_image/cached_network_image.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/order_item_model.dart';
import 'package:cheminova/models/place_order_list_model.dart';
@ -32,6 +34,7 @@ class _OrderManagementDetailScreenState
extends State<OrderManagementDetailScreen> {
// Controllers for managing cart and placed orders
final CartController _cartController = Get.put(CartController());
final AddressController _addressController = Get.put(AddressController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// Function to format date from the API to a more readable format
String formatDate(String apiDate) {
@ -70,7 +73,7 @@ Future<void> adduni()async {
.map((item) => (item.quantity))
.join(', ');
}
//String? imageurl;
@override
Widget build(BuildContext context) {
@ -221,6 +224,7 @@ Future<void> adduni()async {
itemCount: widget.placedOrderList?.orderItem.length ?? 0,
itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
return orderItem != null
? Card(
margin: const EdgeInsets.symmetric(vertical: 5.0),
@ -231,8 +235,26 @@ Future<void> adduni()async {
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/product.png", // Add the image URL here
// Image.asset(
// "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,
width: 50,
fit: BoxFit.cover,
@ -289,11 +311,12 @@ Future<void> adduni()async {
),
SizedBox(
width: Get.width,
height: Get.height*0.06,
height: Get.height * 0.10,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Wrap( // Use Wrap to allow wrapping
crossAxisAlignment: WrapCrossAlignment.start,
direction: Axis.horizontal,
children: [
Text(
"Address: ",
@ -302,13 +325,23 @@ Future<void> adduni()async {
fontWeight: FontWeight.bold,
),
),
AutoSizeText("${widget.placedOrderList!.shipTo}",maxLines: 4,
overflow:TextOverflow.ellipsis,)
Text(
"${widget.placedOrderList!.shipTo.toString()}",
// Text(
// "${widget.placedOrderList!.shipTo}",
maxLines: 4,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
),
),
],
),
),
),
],
),
),

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
import 'package:cheminova/widgets/input_field.dart';
@ -57,6 +59,11 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
return formattedDate;
}
Future<void> searchOrder(String query) async {
{
_getPlacedOrderController.searchOrder();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -108,7 +115,11 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
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(

View File

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

View File

@ -248,6 +248,19 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
_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(
height: Get.height * 0.6,
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_model1.dart';
import 'package:cheminova/screens/order/checkout_screen.dart';
@ -24,6 +25,7 @@ class ProductDetailScreen extends StatefulWidget {
class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController());// Initialize CartController
String? imageurl;
// Function to capitalize the first letter of a string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
@ -31,6 +33,9 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
}
@override
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(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -105,13 +110,21 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
),
borderRadius: BorderRadius.circular(15),
),
child: ClipRRect(
child:
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset("assets/images/product.png", fit: BoxFit.cover,),
// Image.asset(
// widget.product.image,
// fit: BoxFit.cover,
// ),
child:
imageurl!.startsWith('http') // Check if it's a network URL
? CachedNetworkImage(
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
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(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -205,7 +210,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.subtotal ?? 0}"),
Text("${subTotalProcesssItem}"),
],
),
Row(
@ -219,7 +224,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.gstTotal ?? 0}"),
Text("${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
],
),
Row(
@ -233,7 +238,7 @@ class _PartialPendingDialogScreenState extends State<PartialPendingDialogScreen>
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.grandTotal ?? 0}"),
Text("${grandTotalProcessItem}"),
],
),
],

View File

@ -359,8 +359,6 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
await controller.placeRDOrder();
showSnackbar("Partial order processed successfully.");
// Close the dialog before navigating to another screen
Navigator.of(context).pop();
// Navigate to the pending screen
Get.to(RdOrderPendingScreen());
@ -370,7 +368,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
TextButton(
onPressed: () {
//Get.back();
Navigator.of(context).pop();
Navigator.pop(context);
},
child: const Text("Cancel"),
),
@ -382,6 +380,10 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
@override
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(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -470,7 +472,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.subtotal ?? 0}"),
Text("${subTotalProcesssItem}"),
],
),
Row(
@ -484,7 +486,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.gstTotal ?? 0}"),
Text("${widget.placedOrderList!.gstTotal.toStringAsFixed(2) ?? 0}"),
],
),
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_processing_invoice_controller.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/single_get_order_model.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_update.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/my_drawer.dart';
import 'package:flutter/material.dart';
@ -15,12 +18,15 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.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';
class RdCancelledScreen extends StatefulWidget {
final PlacedOrdersResponse? getrdProduct;
final GetRdCancelledModel? getrdProduct;
RdCancelledScreen({super.key, this.getrdProduct});
@ -37,7 +43,11 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
"cancelled",
"delivered",];
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>();
@override
@ -49,11 +59,12 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
Future<void> _onRefresh() async {
await getOrder1();
await Future.delayed(Duration(seconds: 1));
}
Future<void> getOrder1() async {
await _getRdProductController.getRDCancleProduct();
if (_getRdProductController.productRDList.isEmpty) {
await _getRDCancleController.getRDCancleProduct();
if (_getRDCancleController.productRDList.isEmpty) {
print("No orders found.");
} else {
print("Orders fetched successfully");
@ -70,11 +81,133 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
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);
String formattedDate = DateFormat('EEE MMM dd yyyy hh:mm a').format(parsedDate);
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
Widget build(BuildContext context) {
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(),
body: Stack(
@ -128,6 +261,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
controller: _searchController,
),
SizedBox(height: Get.height * 0.035),
SizedBox(height: Get.height * 0.035),
Card(
margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder(
@ -140,63 +274,11 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
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: 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(
height: Get.height * 0.6,
child: Obx(() {
if (_getRdProductController.productRDList.isEmpty) {
if (_getRDCancleController.productRDList.isEmpty) {
return Center(
child: Text(
'No Orders Found',
@ -208,7 +290,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
final Set<String> uniqueOrderIds = {};
final List<GetRdCancelledModel> uniqueOrders = [];
for (var order in _getRdProductController.productRDList) {
for (var order in _getRDCancleController.productRDList) {
if (uniqueOrderIds.add(order.id)) {
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: const EdgeInsets.fromLTRB(16, 8, 8, 0),
@ -310,10 +401,12 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: ()=>
Get.to(() =>
RdCancelledDetailScreen(
placedOrderList: uniqueOrders[index])), // Navigate to detail screen
onPressed: (){
onOrderTap(index);
},
// Get.to(() =>
// RdOrderPendingScreenDetailScreen(
// placedOrderList: uniqueOrders[index])), // Navigate to detail screen
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF004791),
@ -348,3 +441,5 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
}
}

View File

@ -150,7 +150,7 @@ class _RdDeliveredDetailsScreenState
),
],
title: const Text(
"RD Delivered Order Details",
"Retailer Delivered Order Details",
),
),
body: Stack(
@ -298,7 +298,7 @@ class _RdDeliveredDetailsScreenState
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(),
body: Stack(

View File

@ -198,7 +198,10 @@ class _RdDispatchedDetailsDetailScreenState
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'),
),
@ -312,7 +315,7 @@ class _RdDispatchedDetailsDetailScreenState
),
],
title: const Text(
"RD Dispatched Order Details",
"Retailer Dispatched Order Details",
),
),
body: Stack(
@ -459,7 +462,7 @@ class _RdDispatchedDetailsDetailScreenState
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(),
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/models/rd_order_item_model.dart';
@ -26,12 +27,14 @@ class RdOrderDetailUpdateScreen extends StatefulWidget {
//final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
SingleGetOrderModel? placedOrderList;
final String orderId;
//final String orderId;
//final int orderIndex; // New parameter to receive the index
// PlacedOrderModel? placedOrderModel;
// 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
State<RdOrderDetailUpdateScreen> createState() =>
@ -46,6 +49,7 @@ class _RdOrderDetailUpdateScreenState
final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
String? orderId;
@ -226,6 +230,9 @@ class _RdOrderDetailUpdateScreenState
actions: [
TextButton(
onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation
if (reasonController.text.isEmpty) {
@ -245,9 +252,9 @@ class _RdOrderDetailUpdateScreenState
});
// Close the dialog after a short delay
Future.delayed(Duration(seconds: 1), () {
// Navigator.of(context).pop(); // Close the dialog
});
// Future.delayed(Duration(seconds: 1), () {
// // Navigator.of(context).pop(); // Close the dialog
// });
return; // Exit here to prevent further processing
}
@ -262,31 +269,33 @@ class _RdOrderDetailUpdateScreenState
Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) {
var productId = item.orderItem[0].productId;
for (var item in widget.placedOrderList!.orderItem) {
var productId = item.productId;
if (orderItemMap.containsKey(productId)) {
// If the product already exists, aggregate the quantity
var existingItem = orderItemMap[productId]!;
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);
// 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
orderItemMap[productId] = RDOrderItem(
productId: productId,
sku: item.orderItem[0].sku,
name: item.orderItem[0].name,
categoryName: item.orderItem[0].categoryName,
brandName: item.orderItem[0].brandName,
price: item.orderItem[0].price,
gst: item.orderItem[0].gst.toInt(),
hsnCode: item.orderItem[0].hsnCode,
description: item.orderItem[0].description,
sku: item.sku,
name: item.name,
categoryName: item.categoryName,
brandName: item.brandName,
price: item.price,
gst: item.gst.toInt(),
hsnCode: item.hsnCode,
description: item.description,
image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0,
quantity: item.quantity ?? 0,
remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.remainingQuantity ?? 0,
);
}
}
@ -309,7 +318,7 @@ class _RdOrderDetailUpdateScreenState
showSnackbar("Order processed and invoice created successfully");
Get.to(RdOrderProcessingScreen());
Navigator.of(context).pop();
// Navigator.of(context).pop();
// Close the dialog after a short delay
// Close the dialog
@ -440,7 +449,7 @@ class _RdOrderDetailUpdateScreenState
_buildRow("Order Date:", formatDate("${widget.placedOrderList!.createdAt}"), 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("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),
],
),
@ -458,6 +467,7 @@ class _RdOrderDetailUpdateScreenState
itemCount: widget.placedOrderList!.orderItem!.length ?? 0,
itemBuilder: (context, 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 GstTotalAmounProcessItem = (orderItem.price! * orderItem.quantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -471,8 +481,27 @@ class _RdOrderDetailUpdateScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/product.png",
// Image.asset(
// "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,
width: 50,
fit: BoxFit.cover,
@ -498,7 +527,7 @@ class _RdOrderDetailUpdateScreenState
Text("Price: ${orderItem.price}"),
Text("Subtotal : ${subTotalProcesssItem}"),
Text("GST : ${orderItem.gst}%"),
Text("GST Amount (₹) : ${GstTotalAmounProcessItem}"),
Text("GST Amount (₹) : ${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
Text("Total Amount : ${grandTotalProcessItem}"),
],
),

View File

@ -165,7 +165,7 @@ class _RdOrderScreenState extends State<RdOrderScreen> {
// Navigate to the details screen with the fetched order
Get.to(() => RdOrderDetailUpdateScreen(
placedOrderList: singleOrder,
orderId: orderId,
// orderId: orderId,
));
} else {
// 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(),
body: Stack(

View File

@ -1,4 +1,5 @@
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_rd_pending_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/get_single_invoice_controller.dart';
import '../../controller/rd_processing_order_controller.dart';
import '../../controller/rd_single_order_controller.dart';
import '../../models/get_invoice_model.dart';
import '../../models/product_model1.dart';
import '../../models/rd_order_item_model.dart';
@ -33,14 +35,16 @@ import '../../utils/show_snackbar.dart';
class RdOrderPendingScreenDetailScreen extends StatefulWidget {
//final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
SingleGetOrderModel? placedOrderList;
GetRdPendingModel? productpendingModel;
final String orderId;
GetInvoiceModel? placeInvoiceList;
final SingleGetOrderModel? placedOrderList;
// GetRdPendingModel? productpendingModel;
//final String orderId;
// GetInvoiceModel? placeInvoiceList;
// PlacedOrderModel? placedOrderModel;
// 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
State<RdOrderPendingScreenDetailScreen> createState() =>
@ -52,11 +56,12 @@ class _RdOrderPendingScreenDetailScreenState
extends State<RdOrderPendingScreenDetailScreen> {
// Controllers for managing cart and placed orders
final CartController _cartController = Get.put(CartController());
final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetRdPendingController _getRdPendingController = Get.put(GetRdPendingController());
final GetSingleInvoiceController _getSingleInvoiceController = Get.put(GetSingleInvoiceController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
final List<String> statusOptions = [
"new",
"pending",
@ -201,6 +206,9 @@ class _RdOrderPendingScreenDetailScreenState
actions: [
TextButton(
onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
{
if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation
@ -235,35 +243,47 @@ class _RdOrderPendingScreenDetailScreenState
Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) {
var productId = item.orderItem[0].productId;
for (var item in widget.placedOrderList!.orderItem) {
var productId = item.productId;
if (item.remainingQuantity != null && item.remainingQuantity! > 0) {
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]!;
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 {
existingItem.quantity = (existingItem.quantity ?? 0) + (item.quantity ?? 0);
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.remainingQuantity ?? 0);
existingItem.processquantity = existingItem.remainingQuantity; // Process all remaining stock
}
// 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
orderItemMap[productId] = RDOrderItem(
productId: productId,
sku: item.orderItem[0].sku,
name: item.orderItem[0].name,
categoryName: item.orderItem[0].categoryName,
brandName: item.orderItem[0].brandName,
price: item.orderItem[0].price,
gst: item.orderItem[0].gst.toInt(),
hsnCode: item.orderItem[0].hsnCode,
description: item.orderItem[0].description,
sku: item.sku,
name: item.name,
categoryName: item.categoryName,
brandName: item.brandName,
price: item.price,
gst: item.gst.toInt(),
hsnCode: item.hsnCode,
description: item.description,
image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0,
quantity: item.quantity ?? 0,
remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.remainingQuantity ?? 0,
);
}
}
}
// Convert the map to a list
List<RDOrderItem> orderItems = orderItemMap.values.toList();
@ -324,6 +344,27 @@ class _RdOrderPendingScreenDetailScreenState
}
@override
Widget build(BuildContext context) {
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(
extendBodyBehindAppBar: true,
@ -351,7 +392,7 @@ class _RdOrderPendingScreenDetailScreenState
),
],
title: const Text(
"RDPending Order Details",
"RetailerPending Order Details",
),
),
body: Stack(
@ -384,13 +425,13 @@ class _RdOrderPendingScreenDetailScreenState
children: [
Card(
child: Column(
child:
Column(
children: [
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text(
"Invoices",
style: GoogleFonts.roboto(
@ -400,12 +441,18 @@ class _RdOrderPendingScreenDetailScreenState
),
),
),
SizedBox(
width: Get.width,
// Displaying each invoice in a separate card
if (widget.placedOrderList!.invoices.isNotEmpty)
...widget.placedOrderList!.invoices.map((invoice) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Invoice ID
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -415,20 +462,12 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold,
),
),
Text(widget.placeInvoiceList!.invoiceId.toString()),
// Text(widget.placedOrderList!.uniqueId),
Text(invoice.invoiceId.toString()),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10), // Add spacing
// Items for this invoice
Text(
"Items: ",
style: GoogleFonts.roboto(
@ -436,12 +475,13 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10), // Add spacing between the title and the list of items
Column(
children: widget.placeInvoiceList!.items!.map((item) {
const SizedBox(height: 10), // Add spacing between title and items
// List of items in this invoice
Column(
children: invoice.items!.map((item) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), // Add some spacing between items
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -451,7 +491,7 @@ class _RdOrderPendingScreenDetailScreenState
style: GoogleFonts.roboto(
fontSize: Get.width * 0.03,
),
overflow: TextOverflow.ellipsis, // Handle long text
overflow: TextOverflow.ellipsis,
),
),
Text("x ${item.processQuantity.toString()}"),
@ -460,16 +500,11 @@ class _RdOrderPendingScreenDetailScreenState
);
}).toList(),
),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
const SizedBox(height: 10), // Add spacing between sections
// Sub Total
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -479,19 +514,12 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold,
),
),
Text("${widget.placeInvoiceList!.subtotal}"),
Text("${invoice.subtotal}"),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
// GST
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -501,17 +529,12 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold,
),
),
Text("${widget.placeInvoiceList!.gstTotal}"),
Text("${invoice.gstTotal.toStringAsFixed(2)}"),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
// Invoice Amount
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -521,17 +544,12 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.bold,
),
),
Text("${widget.placeInvoiceList!.invoiceAmount}"),
Text("${invoice.invoiceAmount}"),
],
),
),
),
SizedBox(
width: Get.width,
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Row(
// Courier Status
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -543,28 +561,29 @@ class _RdOrderPendingScreenDetailScreenState
),
ElevatedButton(
onPressed: () {},
// Get.to(() =>
// RdOrderDetailScreen(
// placedOrderList: uniqueOrders[index])), // Navigate to detail screen
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor:_getCourierStatusColor(widget.placeInvoiceList!.courierStatus.toString()),
backgroundColor: _getCourierStatusColor(invoice.courierStatus.toString()),
shape: RoundedRectangleBorder(
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}"),
)],
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
capitalizeFirstLetter(invoice.courierStatus.toString()),
),
),
],
),
],
),
),
);
}).toList(),
],
),
),
const SizedBox(height: 8),
const SizedBox(height: 8),
@ -591,9 +610,10 @@ class _RdOrderPendingScreenDetailScreenState
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: widget.placedOrderList?.orderItem!.length ?? 0,
itemCount: order.orderItem!.length ?? 0,
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 GstTotalAmount = (orderItem.price * orderItem.quantity!.toInt()) *(orderItem.gst/100 );
final grandTotal = subTotal + GstTotalAmount;
@ -607,8 +627,26 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/product.png",
// Image.asset(
// "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,
width: 50,
fit: BoxFit.cover,
@ -636,7 +674,7 @@ class _RdOrderPendingScreenDetailScreenState
Text("Price: ${orderItem.price}"),
Text("Subtotal: ${subTotal}"),
Text("GSt: ${orderItem.gst}%"),
Text("GST Amount (₹): ${GstTotalAmount}"),
Text("GST Amount (₹): ${GstTotalAmount.toStringAsFixed(2)}"),
Text("Total Amount (₹): ${grandTotal}"),
],
),
@ -678,18 +716,19 @@ class _RdOrderPendingScreenDetailScreenState
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: widget.placedOrderList?.orderItem
itemCount: order.orderItem
?.where((item) => item.remainingQuantity! > 0)
.length ?? 0,
itemBuilder: (context, index) {
// Filter items with non-zero quantities
final filteredItems = widget.placedOrderList!.orderItem!
final filteredItems =order!.orderItem!
.where((item) => item.remainingQuantity! > 0)
.toList();
final orderItem = filteredItems[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.remainingQuantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -703,8 +742,27 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/product.png",
/* Image.asset(
"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,
width: 50,
fit: BoxFit.cover,
@ -725,7 +783,7 @@ class _RdOrderPendingScreenDetailScreenState
Text("Price: ${orderItem.price}"),
Text("Subtotal: ${subTotalProcesssItem}"),
Text("Gst: ${orderItem.gst}%"),
Text("GST Total: ${GstTotalAmounProcessItem}"),
Text("GST Total: ${GstTotalAmounProcessItem.toStringAsFixed(2)}"),
Text("Total Amount: ${grandTotalProcessItem}"),
],
),
@ -775,7 +833,7 @@ class _RdOrderPendingScreenDetailScreenState
fontWeight: FontWeight.w500,
),
),
Text(capitalizeFirstLetter(widget.placeInvoiceList!.orderId!.paymentMode.toString())),
Text(capitalizeFirstLetter(widget.placedOrderList!.paymentMode.toString())),
// Text("${widget.placedOrderList!.paymentMode}",maxLines: 4,
// overflow:TextOverflow.ellipsis,)
],
@ -808,7 +866,7 @@ class _RdOrderPendingScreenDetailScreenState
),
SizedBox(width: Get.width*0.01,),
//Text(capitalizeFirstLetter(widget.placedOrderList!.status)),
Text(capitalizeFirstLetter(widget.placedOrderList!.status.toString()),maxLines: 4,
Text(capitalizeFirstLetter(order!.status.toString()),maxLines: 4,
overflow:TextOverflow.ellipsis,)
],
),
@ -1014,12 +1072,12 @@ class simple extends State<RdOrderPendingScreenDetailScreen> {
onPressed: () {},
style: ElevatedButton.styleFrom(
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(
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/models/get_rd_pennding_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_update.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
await _getRdPendingController.getRDPendingProduct();
// await _getRDProcessingInvoiceController.getRDProcessingInvoiceProduct();
// await _getSingleInvoiceController.fetchInvoice(_getRDProcessingInvoiceController.productProcessingRDList[0].id);
// Log the count of fetched orders
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
final orderId = _getRdPendingController.productRDList[index].id;
final invoiceId = _getRdPendingController.productRDList[index].invoices[0];
// 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, and avoid caching issues
final singleOrder = await GetSingleProductService().getSingleOrder(token, orderId);
final singleInvoice = await GetSingleInvoiceService().fetchInvoice(token, invoiceId.toString());
// 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(() => RdOrderPendingScreenDetailScreen(
placedOrderList: singleOrder,
orderId: orderId,
placeInvoiceList: singleInvoice,
placedOrderList: singleOrder, // Pass the single order instance
// orderId: orderId,
));
} else {
@ -144,6 +142,7 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
@override
Widget build(BuildContext context) {
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(),
body: Stack(

View File

@ -123,8 +123,10 @@ class _RdOrderProcessingDetailScreenState extends State<RdOrderProcessingDetailS
// Call the API to submit data
_getDispatchController.RDProcessingToDispatchProduct(widget.placeInvoiceList!.id.toString(), courierName, courierTrackingId);
showSnackbar("Order Status updated Order Dispatched");
Navigator.of(context).pop(); // Close the dialog after submission
Navigator.push(context, MaterialPageRoute(builder: (context){
return RdDispatchedScreen();
}));
//Navigator.of(context).pop(); // Close the dialog after submission
},
child: Text('Submit'),
),
@ -332,7 +334,7 @@ class _RdOrderProcessingDetailScreenState extends State<RdOrderProcessingDetailS
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(),
body: Stack(

View File

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

View File

@ -80,6 +80,14 @@ class ApiUrls {
//============================== Annaouncement Details ==============================//
static const String AnnaouncementUrl = '/api/announcement/PDs';
//============================== Annaouncement Details ==============================//
//============================== shipto Billto Details ==============================//
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:dio/dio.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
Future<BodyType?> commonApiService<BodyType>({
required String url,
required String method,
@ -18,7 +29,7 @@ Future<BodyType?> commonApiService<BodyType>({
}) async {
try {
// Initialize Dio for making HTTP requests
Dio dio = Dio();
Dio dio = createDio();
final Response response;
print("body : $body");

View File

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

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/models/user_model.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:flutter/material.dart';
import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
class MyDrawer extends StatefulWidget {
final UserModel? userModel;
@ -18,17 +228,34 @@ class MyDrawer extends StatefulWidget {
class _MyDrawerState extends State<MyDrawer> {
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
Widget build(BuildContext context) {
final user = homecontroller.user; // Get the current user from HomeController
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
child: Column(
children: <Widget>[
SizedBox(
height: 150,
width: double.infinity,
// Drawer header displaying user information
child: DrawerHeader(
//padding: EdgeInsets.zero,
decoration: const BoxDecoration(
color: Colors.black87,
),
@ -36,15 +263,16 @@ class _MyDrawerState extends State<MyDrawer> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
user!.name ?? "username",
user?.name ?? "username",
style: const TextStyle(
color: Colors.white,
fontSize: 18,
),
),
Text(
user!.uniqueId ?? 'Employee ID',
user?.uniqueId ?? 'Employee ID',
style: const TextStyle(
color: Colors.white,
fontSize: 20,
@ -96,11 +324,23 @@ class _MyDrawerState extends State<MyDrawer> {
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
Future logoutBox(BuildContext context) {
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/models/oder_place_model.dart';
import 'package:cheminova/models/order_item_model.dart';
import 'package:cheminova/models/place_order_list_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:flutter/material.dart';
import 'package:get/get.dart';
@ -16,6 +18,7 @@ class ProductCard extends StatefulWidget {
PlacedOrderModel? placedOrder;
PlacedOrderList? placedOrderList;
PlaceOrderItem1? placeorderItem;
PlacedOrdersResponse ? placeRDOrder;
ProductModel? product;
final bool isInCart;
final bool isCheckout;
@ -30,6 +33,7 @@ class ProductCard extends StatefulWidget {
this.placedOrder,
this.placedOrderList,
this.placeorderItem,
this.placeRDOrder,
this.isInCart = false,
this.isCheckout = false,
this.isConfirmation = false,
@ -44,6 +48,7 @@ class _ProductCardState extends State<ProductCard> {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
String? imageurl;
@override
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
int currentQuantity = isProductInCart
? _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(
// Navigate to the ProductDetailScreen on tap unless the product is in cart or checkout
onTap: () => widget.isInCart || widget.isCheckout
? null
: Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
child: SizedBox(
// height: Get.height * 0.21,
// width: Get.width *0.20,
child: Card(
child: Row(
children: [
@ -67,21 +79,26 @@ class _ProductCardState extends State<ProductCard> {
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,
child:
Container(
height: Get.height * 0.18,
width: Get.width * 0.32,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/product.png"),
image: imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover,
),
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
padding: const EdgeInsets.symmetric(horizontal: 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -102,106 +119,22 @@ class _ProductCardState extends State<ProductCard> {
),
),
// Display the price of the product
if (!widget.isCheckout)
widget.isInCart
?
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${widget.productModel!.price.toString()}",
style: GoogleFonts.roboto(
fontSize: 22,
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
if (showQuantity)
Text(
"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,
),
// SizedBox(
// width: 60,
// ),
IconButton(
onPressed: () {
_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(
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/rd_get_order_controller.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:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../utils/show_snackbar.dart';
class ProductCard1 extends StatefulWidget {
final RDOrderItem productModel; // The specific product to be displayed
int? quantity;
@ -24,16 +27,20 @@ class _ProductCard1State extends State<ProductCard1> {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
String? imageurl;
@override
Widget build(BuildContext context) {
final CartController _cartController = Get.put(CartController());
TextEditingController quantityController =
TextEditingController();
// Current quantity the user wants to process
int processQuantity = widget.productModel.processquantity ?? 1;
// Total available quantity
int availableQuantity = widget.productModel.remainingQuantity ?? 1;
imageurl = widget.productModel.image.isNotEmpty
? widget.productModel.image[0].url
: 'assets/images/no_image_available.jpg';
return Card(
child: Row(
@ -45,9 +52,12 @@ class _ProductCard1State extends State<ProductCard1> {
child: Container(
height: Get.height * 0.15,
width: Get.width * 0.31,
decoration: const BoxDecoration(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/product.png"),
image:
imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover,
),
),
@ -94,7 +104,7 @@ class _ProductCard1State extends State<ProductCard1> {
),
),
Text(
" ${widget.productModel.quantity}",
" ${widget.productModel.remainingQuantity}",
style: GoogleFonts.roboto(
fontSize: 15,
),
@ -158,6 +168,39 @@ class _ProductCard1State extends State<ProductCard1> {
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
SizedBox(
height: 22,

View File

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

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.44"
archive:
dependency: transitive
description:
name: archive
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
args:
dependency: transitive
description:
@ -41,6 +49,30 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -49,6 +81,22 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -302,14 +350,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
name: flutter_cache_manager
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.dev"
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:
dependency: "direct main"
description:
@ -424,6 +480,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
url: "https://pub.dev"
source: hosted
version: "4.5.2"
image_picker:
dependency: "direct main"
description:
@ -504,6 +568,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -528,14 +600,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
logger:
dependency: "direct main"
description:
@ -576,6 +640,30 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -672,6 +760,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description:
@ -680,6 +776,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
rxdart:
dependency: transitive
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shared_preferences:
dependency: "direct main"
description:
@ -757,6 +861,22 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -845,6 +965,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -1029,6 +1157,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.4.1 <4.0.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
# 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.
version: 1.0.0+1
version: 2.0.2+1
environment:
sdk: ">=3.4.1 <4.0.0"
@ -56,10 +56,21 @@ dependencies:
firebase_analytics: ^11.2.1
flutter_secure_storage: ^4.2.1
pretty_dio_logger: ^1.4.0
package_info_plus: ^8.1.3
cached_network_image: ^3.4.1
dev_dependencies:
flutter_test:
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
# encourage good coding practices. The lint set provided by the package is